blob: 90f8d846cb02c5a05d56f0a6105fc122179720b7 [file] [log] [blame]
use crate::cmp::{Cmp, DefaultCmp};
use crate::types::{current_key_val, LdbIterator};
use std::cmp::Ordering;
/// TestLdbIter is an LdbIterator over a vector, to be used for testing purposes.
pub struct TestLdbIter<'a> {
v: Vec<(&'a [u8], &'a [u8])>,
ix: usize,
init: bool,
}
impl<'a> TestLdbIter<'a> {
pub fn new(c: Vec<(&'a [u8], &'a [u8])>) -> TestLdbIter<'a> {
return TestLdbIter {
v: c,
ix: 0,
init: false,
};
}
}
impl<'a> LdbIterator for TestLdbIter<'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 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
}
}
}
/// LdbIteratorIter implements std::iter::Iterator for an LdbIterator.
pub struct LdbIteratorIter<'a, It: 'a> {
inner: &'a mut It,
}
impl<'a, It: LdbIterator> LdbIteratorIter<'a, It> {
pub fn wrap(it: &'a mut It) -> LdbIteratorIter<'a, It> {
LdbIteratorIter { inner: it }
}
}
impl<'a, It: LdbIterator> Iterator for LdbIteratorIter<'a, It> {
type Item = (Vec<u8>, Vec<u8>);
fn next(&mut self) -> Option<Self::Item> {
LdbIterator::next(self.inner)
}
}
/// This shared test takes an iterator with 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: LdbIterator>(mut it: It) {
assert!(!it.valid());
assert!(it.advance());
assert!(it.valid());
let first = current_key_val(&it);
assert!(it.advance());
let second = current_key_val(&it);
assert!(it.advance());
let third = current_key_val(&it);
// fourth (last) element
assert!(it.advance());
assert!(it.valid());
let fourth = current_key_val(&it);
// 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(feature = "enclave_unit_test")]
pub mod tests {
use super::*;
use teaclave_test_utils::*;
pub fn run_tests() -> bool {
run_tests!(test_test_util_basic, test_test_util_ldbiter_properties,)
}
fn test_test_util_basic() {
let v = vec![
("abc".as_bytes(), "def".as_bytes()),
("abd".as_bytes(), "deg".as_bytes()),
];
let mut iter = TestLdbIter::new(v);
assert_eq!(
iter.next(),
Some((Vec::from("abc".as_bytes()), Vec::from("def".as_bytes())))
);
}
fn test_test_util_ldbiter_properties() {
let v;
{
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(TestLdbIter::new(v));
}
}