diff options
| author | XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> | 2020-02-26 21:39:30 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-02-26 21:39:30 +0100 |
| commit | 526280a853f31bbc3120334dfe46e19ea4dbaa25 (patch) | |
| tree | cd35561be4cdcd7591d98bae715726c0e40995b7 /src/liballoc/tests | |
| parent | e7a344fb745a0a663e21be947b2619df05df6d31 (diff) | |
| parent | abc3073c92df034636a823c5382ece2186d22b9e (diff) | |
| download | rust-526280a853f31bbc3120334dfe46e19ea4dbaa25.tar.gz rust-526280a853f31bbc3120334dfe46e19ea4dbaa25.zip | |
Merge branch 'master' into relnotes-1.42.0
Diffstat (limited to 'src/liballoc/tests')
| -rw-r--r-- | src/liballoc/tests/binary_heap.rs | 33 | ||||
| -rw-r--r-- | src/liballoc/tests/btree/map.rs | 85 | ||||
| -rw-r--r-- | src/liballoc/tests/btree/set.rs | 27 | ||||
| -rw-r--r-- | src/liballoc/tests/lib.rs | 1 | ||||
| -rw-r--r-- | src/liballoc/tests/linked_list.rs | 70 | ||||
| -rw-r--r-- | src/liballoc/tests/slice.rs | 80 | ||||
| -rw-r--r-- | src/liballoc/tests/str.rs | 43 | ||||
| -rw-r--r-- | src/liballoc/tests/string.rs | 4 | ||||
| -rw-r--r-- | src/liballoc/tests/vec.rs | 64 | ||||
| -rw-r--r-- | src/liballoc/tests/vec_deque.rs | 74 |
10 files changed, 448 insertions, 33 deletions
diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs index f49ca713921..be5516f54f3 100644 --- a/src/liballoc/tests/binary_heap.rs +++ b/src/liballoc/tests/binary_heap.rs @@ -1,6 +1,8 @@ use std::collections::binary_heap::{Drain, PeekMut}; use std::collections::BinaryHeap; use std::iter::TrustedLen; +use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::sync::atomic::{AtomicU32, Ordering}; #[test] fn test_iterator() { @@ -276,6 +278,37 @@ fn test_drain_sorted() { } #[test] +fn test_drain_sorted_leak() { + static DROPS: AtomicU32 = AtomicU32::new(0); + + #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] + struct D(u32, bool); + + impl Drop for D { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + + if self.1 { + panic!("panic in `drop`"); + } + } + } + + let mut q = BinaryHeap::from(vec![ + D(0, false), + D(1, false), + D(2, false), + D(3, true), + D(4, false), + D(5, false), + ]); + + catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).ok(); + + assert_eq!(DROPS.load(Ordering::SeqCst), 6); +} + +#[test] fn test_extend_ref() { let mut a = BinaryHeap::new(); a.push(1); diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index 0d009507fc7..fd07a4d3926 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -5,7 +5,9 @@ use std::fmt::Debug; use std::iter::FromIterator; use std::ops::Bound::{self, Excluded, Included, Unbounded}; use std::ops::RangeBounds; +use std::panic::catch_unwind; use std::rc::Rc; +use std::sync::atomic::{AtomicU32, Ordering}; use super::DeterministicRng; @@ -15,7 +17,7 @@ fn test_basic_large() { #[cfg(not(miri))] // Miri is too slow let size = 10000; #[cfg(miri)] - let size = 200; + let size = 144; // to obtain height 3 tree (having edges to both kinds of nodes) assert_eq!(map.len(), 0); for i in 0..size { @@ -23,6 +25,11 @@ fn test_basic_large() { assert_eq!(map.len(), i + 1); } + assert_eq!(map.first_key_value(), Some((&0, &0))); + assert_eq!(map.last_key_value(), Some((&(size - 1), &(10 * (size - 1))))); + assert_eq!(map.first_entry().unwrap().key(), &0); + assert_eq!(map.last_entry().unwrap().key(), &(size - 1)); + for i in 0..size { assert_eq!(map.get(&i).unwrap(), &(i * 10)); } @@ -376,8 +383,8 @@ fn test_range_small() { } #[test] -fn test_range_depth_2() { - // Assuming that node.CAPACITY is 11, having 12 pairs implies a depth 2 tree +fn test_range_height_2() { + // Assuming that node.CAPACITY is 11, having 12 pairs implies a height 2 tree // with 2 leaves. Depending on details we don't want or need to rely upon, // the single key at the root will be 6 or 7. @@ -519,7 +526,7 @@ fn test_range_1000() { #[cfg(not(miri))] // Miri is too slow let size = 1000; #[cfg(miri)] - let size = 200; + let size = 144; // to obtain height 3 tree (having edges to both kinds of nodes) let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); fn test(map: &BTreeMap<u32, u32>, size: u32, min: Bound<&u32>, max: Bound<&u32>) { @@ -556,14 +563,15 @@ fn test_range_borrowed_key() { #[test] fn test_range() { - #[cfg(not(miri))] // Miri is too slow let size = 200; + #[cfg(not(miri))] // Miri is too slow + let step = 1; #[cfg(miri)] - let size = 30; + let step = 66; let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); - for i in 0..size { - for j in i..size { + for i in (0..size).step_by(step) { + for j in (i..size).step_by(step) { let mut kvs = map.range((Included(&i), Included(&j))).map(|(&k, &v)| (k, v)); let mut pairs = (i..=j).map(|i| (i, i)); @@ -578,14 +586,15 @@ fn test_range() { #[test] fn test_range_mut() { - #[cfg(not(miri))] // Miri is too slow let size = 200; + #[cfg(not(miri))] // Miri is too slow + let step = 1; #[cfg(miri)] - let size = 30; + let step = 66; let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); - for i in 0..size { - for j in i..size { + for i in (0..size).step_by(step) { + for j in (i..size).step_by(step) { let mut kvs = map.range_mut((Included(&i), Included(&j))).map(|(&k, &mut v)| (k, v)); let mut pairs = (i..=j).map(|i| (i, i)); @@ -753,10 +762,7 @@ fn test_bad_zst() { #[test] fn test_clone() { let mut map = BTreeMap::new(); - #[cfg(not(miri))] // Miri is too slow - let size = 100; - #[cfg(miri)] - let size = 30; + let size = 12; // to obtain height 2 tree (having edges to leaf nodes) assert_eq!(map.len(), 0); for i in 0..size { @@ -783,24 +789,36 @@ fn test_clone() { assert_eq!(map.len(), size / 2 - i - 1); assert_eq!(map, map.clone()); } + + // Full 2-level and minimal 3-level tree (sizes 143, 144 -- the only ones we clone for). + for i in 1..=144 { + assert_eq!(map.insert(i, i), None); + assert_eq!(map.len(), i); + if i >= 143 { + assert_eq!(map, map.clone()); + } + } } #[test] fn test_clone_from() { let mut map1 = BTreeMap::new(); - let size = 30; + let max_size = 12; // to obtain height 2 tree (having edges to leaf nodes) - for i in 0..size { + // Range to max_size inclusive, because i is the size of map1 being tested. + for i in 0..=max_size { let mut map2 = BTreeMap::new(); for j in 0..i { let mut map1_copy = map2.clone(); - map1_copy.clone_from(&map1); + map1_copy.clone_from(&map1); // small cloned from large assert_eq!(map1_copy, map1); let mut map2_copy = map1.clone(); - map2_copy.clone_from(&map2); + map2_copy.clone_from(&map2); // large cloned from small assert_eq!(map2_copy, map2); map2.insert(100 * j + 1, 2 * j + 1); } + map2.clone_from(&map1); // same length + assert_eq!(map2, map1); map1.insert(i, 10 * i); } } @@ -951,6 +969,7 @@ create_append_test!(test_append_145, 145); // Tests for several randomly chosen sizes. create_append_test!(test_append_170, 170); create_append_test!(test_append_181, 181); +#[cfg(not(miri))] // Miri is too slow create_append_test!(test_append_239, 239); #[cfg(not(miri))] // Miri is too slow create_append_test!(test_append_1700, 1700); @@ -1000,3 +1019,29 @@ fn test_split_off_large_random_sorted() { assert!(map.into_iter().eq(data.clone().into_iter().filter(|x| x.0 < key))); assert!(right.into_iter().eq(data.into_iter().filter(|x| x.0 >= key))); } + +#[test] +fn test_into_iter_drop_leak() { + static DROPS: AtomicU32 = AtomicU32::new(0); + + struct D; + + impl Drop for D { + fn drop(&mut self) { + if DROPS.fetch_add(1, Ordering::SeqCst) == 3 { + panic!("panic in `drop`"); + } + } + } + + let mut map = BTreeMap::new(); + map.insert("a", D); + map.insert("b", D); + map.insert("c", D); + map.insert("d", D); + map.insert("e", D); + + catch_unwind(move || drop(map.into_iter())).ok(); + + assert_eq!(DROPS.load(Ordering::SeqCst), 5); +} diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 265ef758cc5..1a2b62d026b 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -487,21 +487,26 @@ fn test_first_last() { a.insert(2); assert_eq!(a.first(), Some(&1)); assert_eq!(a.last(), Some(&2)); - a.insert(3); + for i in 3..=12 { + a.insert(i); + } assert_eq!(a.first(), Some(&1)); - assert_eq!(a.last(), Some(&3)); - - assert_eq!(a.len(), 3); + assert_eq!(a.last(), Some(&12)); assert_eq!(a.pop_first(), Some(1)); - assert_eq!(a.len(), 2); - assert_eq!(a.pop_last(), Some(3)); - assert_eq!(a.len(), 1); + assert_eq!(a.pop_last(), Some(12)); assert_eq!(a.pop_first(), Some(2)); - assert_eq!(a.len(), 0); - assert_eq!(a.pop_last(), None); - assert_eq!(a.len(), 0); + assert_eq!(a.pop_last(), Some(11)); + assert_eq!(a.pop_first(), Some(3)); + assert_eq!(a.pop_last(), Some(10)); + assert_eq!(a.pop_first(), Some(4)); + assert_eq!(a.pop_first(), Some(5)); + assert_eq!(a.pop_first(), Some(6)); + assert_eq!(a.pop_first(), Some(7)); + assert_eq!(a.pop_first(), Some(8)); + assert_eq!(a.clone().pop_last(), Some(9)); + assert_eq!(a.pop_first(), Some(9)); assert_eq!(a.pop_first(), None); - assert_eq!(a.len(), 0); + assert_eq!(a.pop_last(), None); } fn rand_data(len: usize) -> Vec<u32> { diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index c1ae67a1a33..ea75f8903c3 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -12,6 +12,7 @@ #![feature(binary_heap_into_iter_sorted)] #![feature(binary_heap_drain_sorted)] #![feature(vec_remove_item)] +#![feature(split_inclusive)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/src/liballoc/tests/linked_list.rs b/src/liballoc/tests/linked_list.rs index b7736515b26..afcb9e03fd0 100644 --- a/src/liballoc/tests/linked_list.rs +++ b/src/liballoc/tests/linked_list.rs @@ -1,5 +1,5 @@ use std::collections::LinkedList; -use std::panic::catch_unwind; +use std::panic::{catch_unwind, AssertUnwindSafe}; #[test] fn test_basic() { @@ -532,6 +532,74 @@ fn drain_filter_complex() { } #[test] +fn drain_filter_drop_panic_leak() { + static mut DROPS: i32 = 0; + + struct D(bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.0 { + panic!("panic in `drop`"); + } + } + } + + let mut q = LinkedList::new(); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_front(D(false)); + q.push_front(D(true)); + q.push_front(D(false)); + + catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).ok(); + + assert_eq!(unsafe { DROPS }, 8); + assert!(q.is_empty()); +} + +#[test] +fn drain_filter_pred_panic_leak() { + static mut DROPS: i32 = 0; + + #[derive(Debug)] + struct D(u32); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + } + } + + let mut q = LinkedList::new(); + q.push_back(D(3)); + q.push_back(D(4)); + q.push_back(D(5)); + q.push_back(D(6)); + q.push_back(D(7)); + q.push_front(D(2)); + q.push_front(D(1)); + q.push_front(D(0)); + + catch_unwind(AssertUnwindSafe(|| { + drop(q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true })) + })) + .ok(); + + assert_eq!(unsafe { DROPS }, 2); // 0 and 1 + assert_eq!(q.len(), 6); +} + +#[test] fn test_drop() { static mut DROPS: i32 = 0; struct Elem; diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index 51ddb5e7a4e..3d6b4bff5e0 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -852,6 +852,86 @@ fn test_splitator() { } #[test] +fn test_splitator_inclusive() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]]; + assert_eq!(xs.split_inclusive(|x| *x % 2 == 0).collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive(|x| *x == 1).collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive(|x| *x == 5).collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive(|x| *x == 10).collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.split_inclusive(|_| true).collect::<Vec<&[i32]>>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.split_inclusive(|x| *x == 5).collect::<Vec<&[i32]>>(), splits); +} + +#[test] +fn test_splitator_inclusive_reverse() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]]; + assert_eq!(xs.split_inclusive(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]]; + assert_eq!(xs.split_inclusive(|x| *x == 1).rev().collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive(|x| *x == 10).rev().collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.split_inclusive(|_| true).rev().collect::<Vec<_>>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.split_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits); +} + +#[test] +fn test_splitator_mut_inclusive() { + let xs = &mut [1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]]; + assert_eq!(xs.split_inclusive_mut(|x| *x % 2 == 0).collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 1).collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 10).collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.split_inclusive_mut(|_| true).collect::<Vec<_>>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits); +} + +#[test] +fn test_splitator_mut_inclusive_reverse() { + let xs = &mut [1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]]; + assert_eq!(xs.split_inclusive_mut(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 1).rev().collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 10).rev().collect::<Vec<_>>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.split_inclusive_mut(|_| true).rev().collect::<Vec<_>>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits); +} + +#[test] fn test_splitnator() { let xs = &[1, 2, 3, 4, 5]; diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index d3c72615696..b703df6f3cb 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -1248,6 +1248,49 @@ fn test_split_char_iterator_no_trailing() { } #[test] +fn test_split_char_iterator_inclusive() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let split: Vec<&str> = data.split_inclusive('\n').collect(); + assert_eq!(split, ["\n", "Märy häd ä little lämb\n", "Little lämb\n"]); + + let uppercase_separated = "SheePSharKTurtlECaT"; + let mut first_char = true; + let split: Vec<&str> = uppercase_separated + .split_inclusive(|c: char| { + let split = !first_char && c.is_uppercase(); + first_char = split; + split + }) + .collect(); + assert_eq!(split, ["SheeP", "SharK", "TurtlE", "CaT"]); +} + +#[test] +fn test_split_char_iterator_inclusive_rev() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let split: Vec<&str> = data.split_inclusive('\n').rev().collect(); + assert_eq!(split, ["Little lämb\n", "Märy häd ä little lämb\n", "\n"]); + + // Note that the predicate is stateful and thus dependent + // on the iteration order. + // (A different predicate is needed for reverse iterator vs normal iterator.) + // Not sure if anything can be done though. + let uppercase_separated = "SheePSharKTurtlECaT"; + let mut term_char = true; + let split: Vec<&str> = uppercase_separated + .split_inclusive(|c: char| { + let split = term_char && c.is_uppercase(); + term_char = c.is_uppercase(); + split + }) + .rev() + .collect(); + assert_eq!(split, ["CaT", "TurtlE", "SharK", "SheeP"]); +} + +#[test] fn test_rsplit() { let data = "\nMäry häd ä little lämb\nLittle lämb\n"; diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index dd444958459..08859b2b24b 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -50,7 +50,11 @@ fn test_from_utf8() { let xs = b"hello\xFF".to_vec(); let err = String::from_utf8(xs).unwrap_err(); + assert_eq!(err.as_bytes(), b"hello\xff"); + let err_clone = err.clone(); + assert_eq!(err, err_clone); assert_eq!(err.into_bytes(), b"hello\xff".to_vec()); + assert_eq!(err_clone.utf8_error().valid_up_to(), 5); } #[test] diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 2a9bfefc713..9c4ac52acac 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use std::collections::TryReserveError::*; use std::mem::size_of; +use std::panic::{catch_unwind, AssertUnwindSafe}; use std::vec::{Drain, IntoIter}; use std::{isize, usize}; @@ -586,6 +587,44 @@ fn test_drain_inclusive_out_of_bounds() { } #[test] +fn test_drain_leak() { + static mut DROPS: i32 = 0; + + #[derive(Debug, PartialEq)] + struct D(u32, bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.1 { + panic!("panic in `drop`"); + } + } + } + + let mut v = vec![ + D(0, false), + D(1, false), + D(2, false), + D(3, false), + D(4, true), + D(5, false), + D(6, false), + ]; + + catch_unwind(AssertUnwindSafe(|| { + v.drain(2..=5); + })) + .ok(); + + assert_eq!(unsafe { DROPS }, 4); + assert_eq!(v, vec![D(0, false), D(1, false), D(6, false),]); +} + +#[test] fn test_splice() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; @@ -727,6 +766,31 @@ fn test_into_iter_clone() { } #[test] +fn test_into_iter_leak() { + static mut DROPS: i32 = 0; + + struct D(bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.0 { + panic!("panic in `drop`"); + } + } + } + + let v = vec![D(false), D(true), D(false)]; + + catch_unwind(move || drop(v.into_iter())).ok(); + + assert_eq!(unsafe { DROPS }, 3); +} + +#[test] fn test_cow_from() { let borrowed: &[_] = &["borrowed", "(slice)"]; let owned = vec!["owned", "(vec)"]; diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 1ab3694a3ca..101dd67d97a 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -2,7 +2,7 @@ use std::collections::TryReserveError::*; use std::collections::{vec_deque::Drain, VecDeque}; use std::fmt::Debug; use std::mem::size_of; -use std::panic::catch_unwind; +use std::panic::{catch_unwind, AssertUnwindSafe}; use std::{isize, usize}; use crate::hash; @@ -1573,3 +1573,75 @@ fn test_try_rfold_moves_iter() { assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None); assert_eq!(iter.next_back(), Some(&70)); } + +#[test] +fn truncate_leak() { + static mut DROPS: i32 = 0; + + struct D(bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.0 { + panic!("panic in `drop`"); + } + } + } + + let mut q = VecDeque::new(); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_front(D(true)); + q.push_front(D(false)); + q.push_front(D(false)); + + catch_unwind(AssertUnwindSafe(|| q.truncate(1))).ok(); + + assert_eq!(unsafe { DROPS }, 7); +} + +#[test] +fn test_drain_leak() { + static mut DROPS: i32 = 0; + + #[derive(Debug, PartialEq)] + struct D(u32, bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.1 { + panic!("panic in `drop`"); + } + } + } + + let mut v = VecDeque::new(); + v.push_back(D(4, false)); + v.push_back(D(5, false)); + v.push_back(D(6, false)); + v.push_front(D(3, false)); + v.push_front(D(2, true)); + v.push_front(D(1, false)); + v.push_front(D(0, false)); + + catch_unwind(AssertUnwindSafe(|| { + v.drain(1..=4); + })) + .ok(); + + assert_eq!(unsafe { DROPS }, 4); + assert_eq!(v.len(), 3); + drop(v); + assert_eq!(unsafe { DROPS }, 7); +} |
