view src/test_util.rs @ 95:da4beef6e417

Add `current_key()` function to SSIterator. In case we are not interested in the actual value, but just want to check that an entry exists, we only need access to the key and can save the time to copy the (possible large) value. In addition, returning the key as a reference to an already existing field allows even more optimized acccess.
author Thomas Krause <krauseto@hu-berlin.de>
date Sat, 04 Apr 2020 18:56:28 +0200
parents 638c945c4d82
children
line wrap: on
line source

use crate::cmp::{Cmp, DefaultCmp};
use crate::types::{current_key_val, SSIterator};

use std::cmp::Ordering;

/// TestSSIter is an SSIterator over a vector, to be used for testing purposes.
pub struct TestSSIter<'a> {
    v: Vec<(&'a [u8], &'a [u8])>,
    ix: usize,
    init: bool,
}

impl<'a> TestSSIter<'a> {
    pub fn new(c: Vec<(&'a [u8], &'a [u8])>) -> TestSSIter<'a> {
        return TestSSIter {
            v: c,
            ix: 0,
            init: false,
        };
    }
}

impl<'a> SSIterator for TestSSIter<'a> {
    fn advance(&mut self) -> bool {
        if self.ix == self.v.len() - 1 {
            self.ix += 1;
            false
        } else if !self.init {
            self.init = true;
            true
        } else {
            self.ix += 1;
            true
        }
    }
    fn reset(&mut self) {
        self.ix = 0;
        self.init = false;
    }
    fn current(&self, key: &mut Vec<u8>, val: &mut Vec<u8>) -> bool {
        if self.init && self.ix < self.v.len() {
            key.clear();
            val.clear();
            key.extend_from_slice(self.v[self.ix].0);
            val.extend_from_slice(self.v[self.ix].1);
            true
        } else {
            false
        }
    }

    fn current_key(&self) -> Option<&[u8]> {
        if self.init && self.ix < self.v.len() {
            Some(self.v[self.ix].0)
        } else {
            None
        }
    }

    fn valid(&self) -> bool {
        self.init && self.ix < self.v.len()
    }
    fn seek(&mut self, k: &[u8]) {
        self.ix = 0;
        self.init = true;
        while self.ix < self.v.len() && DefaultCmp.cmp(self.v[self.ix].0, k) == Ordering::Less {
            self.ix += 1;
        }
    }
    fn prev(&mut self) -> bool {
        if !self.init || self.ix == 0 {
            self.init = false;
            false
        } else {
            self.ix -= 1;
            true
        }
    }
}

/// SSIteratorIter implements std::iter::Iterator for an SSIterator.
pub struct SSIteratorIter<'a, It: 'a> {
    inner: &'a mut It,
}

impl<'a, It: SSIterator> SSIteratorIter<'a, It> {
    pub fn wrap(it: &'a mut It) -> SSIteratorIter<'a, It> {
        SSIteratorIter { inner: it }
    }
}

impl<'a, It: SSIterator> Iterator for SSIteratorIter<'a, It> {
    type Item = (Vec<u8>, Vec<u8>);
    fn next(&mut self) -> Option<Self::Item> {
        SSIterator::next(self.inner)
    }
}

/// This shared test takes an iterator over a set of exactly four elements and tests that it
/// fulfills the generic iterator properties. Every iterator defined in this code base should pass
/// this test.
pub fn test_iterator_properties<It: SSIterator>(mut it: It) {
    assert!(!it.valid());
    assert!(it.advance());
    assert!(it.valid());
    let first = current_key_val(&it);
    assert_eq!(first.as_ref().unwrap().0, it.current_key().unwrap());
    assert!(it.advance());
    let second = current_key_val(&it);
    assert_eq!(second.as_ref().unwrap().0, it.current_key().unwrap());
    assert!(it.advance());
    let third = current_key_val(&it);
    assert_eq!(third.as_ref().unwrap().0, it.current_key().unwrap());
    // fourth (last) element
    assert!(it.advance());
    assert!(it.valid());
    let fourth = current_key_val(&it);
    assert_eq!(fourth.as_ref().unwrap().0, it.current_key().unwrap());
    // past end is invalid
    assert!(!it.advance());
    assert!(!it.valid());

    it.reset();
    it.seek(&fourth.as_ref().unwrap().0);
    assert!(it.valid());
    it.seek(&second.as_ref().unwrap().0);
    assert!(it.valid());
    it.prev();
    assert_eq!(first, current_key_val(&it));

    it.reset();
    assert!(!it.valid());
    assert!(it.advance());
    assert_eq!(first, current_key_val(&it));
    assert!(it.advance());
    assert_eq!(second, current_key_val(&it));
    assert!(it.advance());
    assert_eq!(third, current_key_val(&it));
    assert!(it.prev());
    assert_eq!(second, current_key_val(&it));
    assert!(it.prev());
    assert_eq!(first, current_key_val(&it));
    assert!(!it.prev());
    assert!(!it.valid());
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_test_util_basic() {
        let v = vec![
            ("abc".as_bytes(), "def".as_bytes()),
            ("abd".as_bytes(), "deg".as_bytes()),
        ];
        let mut iter = TestSSIter::new(v);
        assert_eq!(
            iter.next(),
            Some((Vec::from("abc".as_bytes()), Vec::from("def".as_bytes())))
        );
    }

    #[test]
    fn test_test_util_ssiter_properties() {
        time_test!();
        let v;
        {
            time_test!("init");
            v = vec![
                ("abc".as_bytes(), "def".as_bytes()),
                ("abd".as_bytes(), "deg".as_bytes()),
                ("abe".as_bytes(), "deg".as_bytes()),
                ("abf".as_bytes(), "deg".as_bytes()),
            ];
        }
        test_iterator_properties(TestSSIter::new(v));
    }
}