Skip to content

Commit

Permalink
More BTreeMap test cases, some exposing undefined behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
ssomers committed Jul 22, 2020
1 parent 7d31ffc commit 2152d18
Showing 1 changed file with 80 additions and 0 deletions.
80 changes: 80 additions & 0 deletions src/liballoc/tests/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::collections::BTreeMap;
use std::convert::TryFrom;
use std::fmt::Debug;
use std::iter::FromIterator;
use std::mem;
use std::ops::Bound::{self, Excluded, Included, Unbounded};
use std::ops::RangeBounds;
use std::panic::{catch_unwind, AssertUnwindSafe};
Expand All @@ -25,6 +26,20 @@ const MIN_INSERTS_HEIGHT_1: usize = NODE_CAPACITY + 1;
// It's not the minimum size: removing an element from such a tree does not always reduce height.
const MIN_INSERTS_HEIGHT_2: usize = NODE_CAPACITY + (NODE_CAPACITY + 1) * NODE_CAPACITY + 1;

// Gather all references from a mutable iterator and make sure Miri notices if
// using them is dangerous.
fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>) {
// Gather all those references.
let mut refs: Vec<&mut T> = iter.collect();
// Use them all. Twice, to be sure we got all interleavings.
for r in refs.iter_mut() {
mem::swap(dummy, r);
}
for r in refs {
mem::swap(dummy, r);
}
}

#[test]
fn test_basic_large() {
let mut map = BTreeMap::new();
Expand Down Expand Up @@ -268,7 +283,14 @@ fn test_iter_mut_mutation() {
}

#[test]
#[cfg_attr(miri, ignore)] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
fn test_values_mut() {
let mut a: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)).collect();
test_all_refs(&mut 13, a.values_mut());
}

#[test]
fn test_values_mut_mutation() {
let mut a = BTreeMap::new();
a.insert(1, String::from("hello"));
a.insert(2, String::from("goodbye"));
Expand All @@ -281,6 +303,36 @@ fn test_values_mut() {
assert_eq!(values, [String::from("hello!"), String::from("goodbye!")]);
}

#[test]
#[cfg_attr(miri, ignore)] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
fn test_iter_entering_root_twice() {
let mut map: BTreeMap<_, _> = (0..2).map(|i| (i, i)).collect();
let mut it = map.iter_mut();
let front = it.next().unwrap();
let back = it.next_back().unwrap();
assert_eq!(front, (&0, &mut 0));
assert_eq!(back, (&1, &mut 1));
*front.1 = 24;
*back.1 = 42;
assert_eq!(front, (&0, &mut 24));
assert_eq!(back, (&1, &mut 42));
}

#[test]
#[cfg_attr(miri, ignore)] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
fn test_iter_descending_to_same_node_twice() {
let mut map: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)).collect();
let mut it = map.iter_mut();
// Descend into first child.
let front = it.next().unwrap();
// Descend into first child again, after running through second child.
while it.next_back().is_some() {}
// Check immutable access.
assert_eq!(front, (&0, &mut 0));
// Perform mutable access.
*front.1 = 42;
}

#[test]
fn test_iter_mixed() {
// Miri is too slow
Expand Down Expand Up @@ -1283,6 +1335,34 @@ fn test_split_off_empty_left() {
assert!(right.into_iter().eq(data));
}

// In a tree with 3 levels, if all but a part of the first leaf node is split off,
// make sure fix_top eliminates both top levels.
#[test]
fn test_split_off_tiny_left_height_2() {
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
let mut left: BTreeMap<_, _> = pairs.clone().collect();
let right = left.split_off(&1);
assert_eq!(left.len(), 1);
assert_eq!(right.len(), MIN_INSERTS_HEIGHT_2 - 1);
assert_eq!(*left.first_key_value().unwrap().0, 0);
assert_eq!(*right.first_key_value().unwrap().0, 1);
}

// In a tree with 3 levels, if only part of the last leaf node is split off,
// make sure fix_top eliminates both top levels.
#[test]
fn test_split_off_tiny_right_height_2() {
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
let last = MIN_INSERTS_HEIGHT_2 - 1;
let mut left: BTreeMap<_, _> = pairs.clone().collect();
assert_eq!(*left.last_key_value().unwrap().0, last);
let right = left.split_off(&last);
assert_eq!(left.len(), MIN_INSERTS_HEIGHT_2 - 1);
assert_eq!(right.len(), 1);
assert_eq!(*left.last_key_value().unwrap().0, last - 1);
assert_eq!(*right.last_key_value().unwrap().0, last);
}

#[test]
fn test_split_off_large_random_sorted() {
// Miri is too slow
Expand Down

0 comments on commit 2152d18

Please sign in to comment.