liballoc: Unconfigure tests during normal build

Remove additional libcore-like restrictions from liballoc, turns out the testing works ok if the tests are a part of liballoc itself.
This commit is contained in:
Vadim Petrochenkov 2019-08-02 01:40:56 +03:00
parent 310b9fc760
commit 3d0d6ee271
13 changed files with 1682 additions and 1707 deletions

View File

@ -10,6 +10,9 @@ use core::usize;
#[doc(inline)]
pub use core::alloc::*;
#[cfg(test)]
mod tests;
extern "Rust" {
// These are the magic symbols to call the global allocator. rustc generates
// them from the `#[global_allocator]` attribute if there is one, or uses the
@ -244,36 +247,3 @@ pub fn handle_alloc_error(layout: Layout) -> ! {
}
unsafe { oom_impl(layout) }
}
#[cfg(test)]
mod tests {
extern crate test;
use test::Bencher;
use crate::boxed::Box;
use crate::alloc::{Global, Alloc, Layout, handle_alloc_error};
#[test]
fn allocate_zeroed() {
unsafe {
let layout = Layout::from_size_align(1024, 1).unwrap();
let ptr = Global.alloc_zeroed(layout.clone())
.unwrap_or_else(|_| handle_alloc_error(layout));
let mut i = ptr.cast::<u8>().as_ptr();
let end = i.add(layout.size());
while i < end {
assert_eq!(*i, 0);
i = i.offset(1);
}
Global.dealloc(ptr, layout);
}
}
#[bench]
#[cfg(not(miri))] // Miri does not support benchmarks
fn alloc_owned_small(b: &mut Bencher) {
b.iter(|| {
let _: Box<_> = box 10;
})
}
}

View File

@ -0,0 +1,30 @@
use super::*;
extern crate test;
use test::Bencher;
use crate::boxed::Box;
#[test]
fn allocate_zeroed() {
unsafe {
let layout = Layout::from_size_align(1024, 1).unwrap();
let ptr = Global.alloc_zeroed(layout.clone())
.unwrap_or_else(|_| handle_alloc_error(layout));
let mut i = ptr.cast::<u8>().as_ptr();
let end = i.add(layout.size());
while i < end {
assert_eq!(*i, 0);
i = i.offset(1);
}
Global.dealloc(ptr, layout);
}
}
#[bench]
#[cfg(not(miri))] // Miri does not support benchmarks
fn alloc_owned_small(b: &mut Bencher) {
b.iter(|| {
let _: Box<_> = box 10;
})
}

View File

@ -23,6 +23,9 @@ use core::ptr::NonNull;
use crate::boxed::Box;
use super::SpecExtend;
#[cfg(test)]
mod tests;
/// A doubly-linked list with owned nodes.
///
/// The `LinkedList` allows pushing and popping elements at either end
@ -1244,273 +1247,3 @@ unsafe impl<T: Send> Send for IterMut<'_, T> {}
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: Sync> Sync for IterMut<'_, T> {}
#[cfg(test)]
mod tests {
use std::thread;
use std::vec::Vec;
use rand::{thread_rng, RngCore};
use super::{LinkedList, Node};
#[cfg(test)]
fn list_from<T: Clone>(v: &[T]) -> LinkedList<T> {
v.iter().cloned().collect()
}
pub fn check_links<T>(list: &LinkedList<T>) {
unsafe {
let mut len = 0;
let mut last_ptr: Option<&Node<T>> = None;
let mut node_ptr: &Node<T>;
match list.head {
None => {
// tail node should also be None.
assert!(list.tail.is_none());
assert_eq!(0, list.len);
return;
}
Some(node) => node_ptr = &*node.as_ptr(),
}
loop {
match (last_ptr, node_ptr.prev) {
(None, None) => {}
(None, _) => panic!("prev link for head"),
(Some(p), Some(pptr)) => {
assert_eq!(p as *const Node<T>, pptr.as_ptr() as *const Node<T>);
}
_ => panic!("prev link is none, not good"),
}
match node_ptr.next {
Some(next) => {
last_ptr = Some(node_ptr);
node_ptr = &*next.as_ptr();
len += 1;
}
None => {
len += 1;
break;
}
}
}
// verify that the tail node points to the last node.
let tail = list.tail.as_ref().expect("some tail node").as_ref();
assert_eq!(tail as *const Node<T>, node_ptr as *const Node<T>);
// check that len matches interior links.
assert_eq!(len, list.len);
}
}
#[test]
fn test_append() {
// Empty to empty
{
let mut m = LinkedList::<i32>::new();
let mut n = LinkedList::new();
m.append(&mut n);
check_links(&m);
assert_eq!(m.len(), 0);
assert_eq!(n.len(), 0);
}
// Non-empty to empty
{
let mut m = LinkedList::new();
let mut n = LinkedList::new();
n.push_back(2);
m.append(&mut n);
check_links(&m);
assert_eq!(m.len(), 1);
assert_eq!(m.pop_back(), Some(2));
assert_eq!(n.len(), 0);
check_links(&m);
}
// Empty to non-empty
{
let mut m = LinkedList::new();
let mut n = LinkedList::new();
m.push_back(2);
m.append(&mut n);
check_links(&m);
assert_eq!(m.len(), 1);
assert_eq!(m.pop_back(), Some(2));
check_links(&m);
}
// Non-empty to non-empty
let v = vec![1, 2, 3, 4, 5];
let u = vec![9, 8, 1, 2, 3, 4, 5];
let mut m = list_from(&v);
let mut n = list_from(&u);
m.append(&mut n);
check_links(&m);
let mut sum = v;
sum.extend_from_slice(&u);
assert_eq!(sum.len(), m.len());
for elt in sum {
assert_eq!(m.pop_front(), Some(elt))
}
assert_eq!(n.len(), 0);
// let's make sure it's working properly, since we
// did some direct changes to private members
n.push_back(3);
assert_eq!(n.len(), 1);
assert_eq!(n.pop_front(), Some(3));
check_links(&n);
}
#[test]
fn test_insert_prev() {
let mut m = list_from(&[0, 2, 4, 6, 8]);
let len = m.len();
{
let mut it = m.iter_mut();
it.insert_next(-2);
loop {
match it.next() {
None => break,
Some(elt) => {
it.insert_next(*elt + 1);
match it.peek_next() {
Some(x) => assert_eq!(*x, *elt + 2),
None => assert_eq!(8, *elt),
}
}
}
}
it.insert_next(0);
it.insert_next(1);
}
check_links(&m);
assert_eq!(m.len(), 3 + len * 2);
assert_eq!(m.into_iter().collect::<Vec<_>>(),
[-2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1]);
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
#[cfg(not(miri))] // Miri does not support threads
fn test_send() {
let n = list_from(&[1, 2, 3]);
thread::spawn(move || {
check_links(&n);
let a: &[_] = &[&1, &2, &3];
assert_eq!(a, &*n.iter().collect::<Vec<_>>());
})
.join()
.ok()
.unwrap();
}
#[test]
fn test_fuzz() {
for _ in 0..25 {
fuzz_test(3);
fuzz_test(16);
#[cfg(not(miri))] // Miri is too slow
fuzz_test(189);
}
}
#[test]
fn test_26021() {
// There was a bug in split_off that failed to null out the RHS's head's prev ptr.
// This caused the RHS's dtor to walk up into the LHS at drop and delete all of
// its nodes.
//
// https://github.com/rust-lang/rust/issues/26021
let mut v1 = LinkedList::new();
v1.push_front(1);
v1.push_front(1);
v1.push_front(1);
v1.push_front(1);
let _ = v1.split_off(3); // Dropping this now should not cause laundry consumption
assert_eq!(v1.len(), 3);
assert_eq!(v1.iter().len(), 3);
assert_eq!(v1.iter().collect::<Vec<_>>().len(), 3);
}
#[test]
fn test_split_off() {
let mut v1 = LinkedList::new();
v1.push_front(1);
v1.push_front(1);
v1.push_front(1);
v1.push_front(1);
// test all splits
for ix in 0..1 + v1.len() {
let mut a = v1.clone();
let b = a.split_off(ix);
check_links(&a);
check_links(&b);
a.extend(b);
assert_eq!(v1, a);
}
}
#[cfg(test)]
fn fuzz_test(sz: i32) {
let mut m: LinkedList<_> = LinkedList::new();
let mut v = vec![];
for i in 0..sz {
check_links(&m);
let r: u8 = thread_rng().next_u32() as u8;
match r % 6 {
0 => {
m.pop_back();
v.pop();
}
1 => {
if !v.is_empty() {
m.pop_front();
v.remove(0);
}
}
2 | 4 => {
m.push_front(-i);
v.insert(0, -i);
}
3 | 5 | _ => {
m.push_back(i);
v.push(i);
}
}
}
check_links(&m);
let mut i = 0;
for (a, &b) in m.into_iter().zip(&v) {
i += 1;
assert_eq!(a, b);
}
assert_eq!(i, v.len());
}
#[test]
fn drain_filter_test() {
let mut m: LinkedList<u32> = LinkedList::new();
m.extend(&[1, 2, 3, 4, 5, 6]);
let deleted = m.drain_filter(|v| *v < 4).collect::<Vec<_>>();
check_links(&m);
assert_eq!(deleted, &[1, 2, 3]);
assert_eq!(m.into_iter().collect::<Vec<_>>(), &[4, 5, 6]);
}
#[test]
fn drain_to_empty_test() {
let mut m: LinkedList<u32> = LinkedList::new();
m.extend(&[1, 2, 3, 4, 5, 6]);
let deleted = m.drain_filter(|_| true).collect::<Vec<_>>();
check_links(&m);
assert_eq!(deleted, &[1, 2, 3, 4, 5, 6]);
assert_eq!(m.into_iter().collect::<Vec<_>>(), &[]);
}
}

View File

@ -0,0 +1,265 @@
use super::*;
use std::thread;
use std::vec::Vec;
use rand::{thread_rng, RngCore};
fn list_from<T: Clone>(v: &[T]) -> LinkedList<T> {
v.iter().cloned().collect()
}
pub fn check_links<T>(list: &LinkedList<T>) {
unsafe {
let mut len = 0;
let mut last_ptr: Option<&Node<T>> = None;
let mut node_ptr: &Node<T>;
match list.head {
None => {
// tail node should also be None.
assert!(list.tail.is_none());
assert_eq!(0, list.len);
return;
}
Some(node) => node_ptr = &*node.as_ptr(),
}
loop {
match (last_ptr, node_ptr.prev) {
(None, None) => {}
(None, _) => panic!("prev link for head"),
(Some(p), Some(pptr)) => {
assert_eq!(p as *const Node<T>, pptr.as_ptr() as *const Node<T>);
}
_ => panic!("prev link is none, not good"),
}
match node_ptr.next {
Some(next) => {
last_ptr = Some(node_ptr);
node_ptr = &*next.as_ptr();
len += 1;
}
None => {
len += 1;
break;
}
}
}
// verify that the tail node points to the last node.
let tail = list.tail.as_ref().expect("some tail node").as_ref();
assert_eq!(tail as *const Node<T>, node_ptr as *const Node<T>);
// check that len matches interior links.
assert_eq!(len, list.len);
}
}
#[test]
fn test_append() {
// Empty to empty
{
let mut m = LinkedList::<i32>::new();
let mut n = LinkedList::new();
m.append(&mut n);
check_links(&m);
assert_eq!(m.len(), 0);
assert_eq!(n.len(), 0);
}
// Non-empty to empty
{
let mut m = LinkedList::new();
let mut n = LinkedList::new();
n.push_back(2);
m.append(&mut n);
check_links(&m);
assert_eq!(m.len(), 1);
assert_eq!(m.pop_back(), Some(2));
assert_eq!(n.len(), 0);
check_links(&m);
}
// Empty to non-empty
{
let mut m = LinkedList::new();
let mut n = LinkedList::new();
m.push_back(2);
m.append(&mut n);
check_links(&m);
assert_eq!(m.len(), 1);
assert_eq!(m.pop_back(), Some(2));
check_links(&m);
}
// Non-empty to non-empty
let v = vec![1, 2, 3, 4, 5];
let u = vec![9, 8, 1, 2, 3, 4, 5];
let mut m = list_from(&v);
let mut n = list_from(&u);
m.append(&mut n);
check_links(&m);
let mut sum = v;
sum.extend_from_slice(&u);
assert_eq!(sum.len(), m.len());
for elt in sum {
assert_eq!(m.pop_front(), Some(elt))
}
assert_eq!(n.len(), 0);
// let's make sure it's working properly, since we
// did some direct changes to private members
n.push_back(3);
assert_eq!(n.len(), 1);
assert_eq!(n.pop_front(), Some(3));
check_links(&n);
}
#[test]
fn test_insert_prev() {
let mut m = list_from(&[0, 2, 4, 6, 8]);
let len = m.len();
{
let mut it = m.iter_mut();
it.insert_next(-2);
loop {
match it.next() {
None => break,
Some(elt) => {
it.insert_next(*elt + 1);
match it.peek_next() {
Some(x) => assert_eq!(*x, *elt + 2),
None => assert_eq!(8, *elt),
}
}
}
}
it.insert_next(0);
it.insert_next(1);
}
check_links(&m);
assert_eq!(m.len(), 3 + len * 2);
assert_eq!(m.into_iter().collect::<Vec<_>>(),
[-2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1]);
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
#[cfg(not(miri))] // Miri does not support threads
fn test_send() {
let n = list_from(&[1, 2, 3]);
thread::spawn(move || {
check_links(&n);
let a: &[_] = &[&1, &2, &3];
assert_eq!(a, &*n.iter().collect::<Vec<_>>());
})
.join()
.ok()
.unwrap();
}
#[test]
fn test_fuzz() {
for _ in 0..25 {
fuzz_test(3);
fuzz_test(16);
#[cfg(not(miri))] // Miri is too slow
fuzz_test(189);
}
}
#[test]
fn test_26021() {
// There was a bug in split_off that failed to null out the RHS's head's prev ptr.
// This caused the RHS's dtor to walk up into the LHS at drop and delete all of
// its nodes.
//
// https://github.com/rust-lang/rust/issues/26021
let mut v1 = LinkedList::new();
v1.push_front(1);
v1.push_front(1);
v1.push_front(1);
v1.push_front(1);
let _ = v1.split_off(3); // Dropping this now should not cause laundry consumption
assert_eq!(v1.len(), 3);
assert_eq!(v1.iter().len(), 3);
assert_eq!(v1.iter().collect::<Vec<_>>().len(), 3);
}
#[test]
fn test_split_off() {
let mut v1 = LinkedList::new();
v1.push_front(1);
v1.push_front(1);
v1.push_front(1);
v1.push_front(1);
// test all splits
for ix in 0..1 + v1.len() {
let mut a = v1.clone();
let b = a.split_off(ix);
check_links(&a);
check_links(&b);
a.extend(b);
assert_eq!(v1, a);
}
}
#[cfg(test)]
fn fuzz_test(sz: i32) {
let mut m: LinkedList<_> = LinkedList::new();
let mut v = vec![];
for i in 0..sz {
check_links(&m);
let r: u8 = thread_rng().next_u32() as u8;
match r % 6 {
0 => {
m.pop_back();
v.pop();
}
1 => {
if !v.is_empty() {
m.pop_front();
v.remove(0);
}
}
2 | 4 => {
m.push_front(-i);
v.insert(0, -i);
}
3 | 5 | _ => {
m.push_back(i);
v.push(i);
}
}
}
check_links(&m);
let mut i = 0;
for (a, &b) in m.into_iter().zip(&v) {
i += 1;
assert_eq!(a, b);
}
assert_eq!(i, v.len());
}
#[test]
fn drain_filter_test() {
let mut m: LinkedList<u32> = LinkedList::new();
m.extend(&[1, 2, 3, 4, 5, 6]);
let deleted = m.drain_filter(|v| *v < 4).collect::<Vec<_>>();
check_links(&m);
assert_eq!(deleted, &[1, 2, 3]);
assert_eq!(m.into_iter().collect::<Vec<_>>(), &[4, 5, 6]);
}
#[test]
fn drain_to_empty_test() {
let mut m: LinkedList<u32> = LinkedList::new();
m.extend(&[1, 2, 3, 4, 5, 6]);
let deleted = m.drain_filter(|_| true).collect::<Vec<_>>();
check_links(&m);
assert_eq!(deleted, &[1, 2, 3, 4, 5, 6]);
assert_eq!(m.into_iter().collect::<Vec<_>>(), &[]);
}

View File

@ -1,5 +1,3 @@
// ignore-tidy-filelength
//! A double-ended queue implemented with a growable ring buffer.
//!
//! This queue has `O(1)` amortized inserts and removals from both ends of the
@ -24,6 +22,9 @@ use crate::collections::CollectionAllocErr;
use crate::raw_vec::RawVec;
use crate::vec::Vec;
#[cfg(test)]
mod tests;
const INITIAL_CAPACITY: usize = 7; // 2^3 - 1
const MINIMUM_CAPACITY: usize = 1; // 2 - 1
#[cfg(target_pointer_width = "16")]
@ -2838,387 +2839,3 @@ impl<T> From<VecDeque<T>> for Vec<T> {
}
}
}
#[cfg(test)]
mod tests {
use ::test;
use super::VecDeque;
#[bench]
#[cfg(not(miri))] // Miri does not support benchmarks
fn bench_push_back_100(b: &mut test::Bencher) {
let mut deq = VecDeque::with_capacity(101);
b.iter(|| {
for i in 0..100 {
deq.push_back(i);
}
deq.head = 0;
deq.tail = 0;
})
}
#[bench]
#[cfg(not(miri))] // Miri does not support benchmarks
fn bench_push_front_100(b: &mut test::Bencher) {
let mut deq = VecDeque::with_capacity(101);
b.iter(|| {
for i in 0..100 {
deq.push_front(i);
}
deq.head = 0;
deq.tail = 0;
})
}
#[bench]
#[cfg(not(miri))] // Miri does not support benchmarks
fn bench_pop_back_100(b: &mut test::Bencher) {
let mut deq = VecDeque::<i32>::with_capacity(101);
b.iter(|| {
deq.head = 100;
deq.tail = 0;
while !deq.is_empty() {
test::black_box(deq.pop_back());
}
})
}
#[bench]
#[cfg(not(miri))] // Miri does not support benchmarks
fn bench_pop_front_100(b: &mut test::Bencher) {
let mut deq = VecDeque::<i32>::with_capacity(101);
b.iter(|| {
deq.head = 100;
deq.tail = 0;
while !deq.is_empty() {
test::black_box(deq.pop_front());
}
})
}
#[test]
fn test_swap_front_back_remove() {
fn test(back: bool) {
// This test checks that every single combination of tail position and length is tested.
// Capacity 15 should be large enough to cover every case.
let mut tester = VecDeque::with_capacity(15);
let usable_cap = tester.capacity();
let final_len = usable_cap / 2;
for len in 0..final_len {
let expected: VecDeque<_> = if back {
(0..len).collect()
} else {
(0..len).rev().collect()
};
for tail_pos in 0..usable_cap {
tester.tail = tail_pos;
tester.head = tail_pos;
if back {
for i in 0..len * 2 {
tester.push_front(i);
}
for i in 0..len {
assert_eq!(tester.swap_remove_back(i), Some(len * 2 - 1 - i));
}
} else {
for i in 0..len * 2 {
tester.push_back(i);
}
for i in 0..len {
let idx = tester.len() - 1 - i;
assert_eq!(tester.swap_remove_front(idx), Some(len * 2 - 1 - i));
}
}
assert!(tester.tail < tester.cap());
assert!(tester.head < tester.cap());
assert_eq!(tester, expected);
}
}
}
test(true);
test(false);
}
#[test]
fn test_insert() {
// This test checks that every single combination of tail position, length, and
// insertion position is tested. Capacity 15 should be large enough to cover every case.
let mut tester = VecDeque::with_capacity(15);
// can't guarantee we got 15, so have to get what we got.
// 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else
// this test isn't covering what it wants to
let cap = tester.capacity();
// len is the length *after* insertion
for len in 1..cap {
// 0, 1, 2, .., len - 1
let expected = (0..).take(len).collect::<VecDeque<_>>();
for tail_pos in 0..cap {
for to_insert in 0..len {
tester.tail = tail_pos;
tester.head = tail_pos;
for i in 0..len {
if i != to_insert {
tester.push_back(i);
}
}
tester.insert(to_insert, to_insert);
assert!(tester.tail < tester.cap());
assert!(tester.head < tester.cap());
assert_eq!(tester, expected);
}
}
}
}
#[test]
fn test_remove() {
// This test checks that every single combination of tail position, length, and
// removal position is tested. Capacity 15 should be large enough to cover every case.
let mut tester = VecDeque::with_capacity(15);
// can't guarantee we got 15, so have to get what we got.
// 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else
// this test isn't covering what it wants to
let cap = tester.capacity();
// len is the length *after* removal
for len in 0..cap - 1 {
// 0, 1, 2, .., len - 1
let expected = (0..).take(len).collect::<VecDeque<_>>();
for tail_pos in 0..cap {
for to_remove in 0..=len {
tester.tail = tail_pos;
tester.head = tail_pos;
for i in 0..len {
if i == to_remove {
tester.push_back(1234);
}
tester.push_back(i);
}
if to_remove == len {
tester.push_back(1234);
}
tester.remove(to_remove);
assert!(tester.tail < tester.cap());
assert!(tester.head < tester.cap());
assert_eq!(tester, expected);
}
}
}
}
#[test]
fn test_drain() {
let mut tester: VecDeque<usize> = VecDeque::with_capacity(7);
let cap = tester.capacity();
for len in 0..=cap {
for tail in 0..=cap {
for drain_start in 0..=len {
for drain_end in drain_start..=len {
tester.tail = tail;
tester.head = tail;
for i in 0..len {
tester.push_back(i);
}
// Check that we drain the correct values
let drained: VecDeque<_> = tester.drain(drain_start..drain_end).collect();
let drained_expected: VecDeque<_> = (drain_start..drain_end).collect();
assert_eq!(drained, drained_expected);
// We shouldn't have changed the capacity or made the
// head or tail out of bounds
assert_eq!(tester.capacity(), cap);
assert!(tester.tail < tester.cap());
assert!(tester.head < tester.cap());
// We should see the correct values in the VecDeque
let expected: VecDeque<_> = (0..drain_start)
.chain(drain_end..len)
.collect();
assert_eq!(expected, tester);
}
}
}
}
}
#[test]
fn test_shrink_to_fit() {
// This test checks that every single combination of head and tail position,
// is tested. Capacity 15 should be large enough to cover every case.
let mut tester = VecDeque::with_capacity(15);
// can't guarantee we got 15, so have to get what we got.
// 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else
// this test isn't covering what it wants to
let cap = tester.capacity();
tester.reserve(63);
let max_cap = tester.capacity();
for len in 0..=cap {
// 0, 1, 2, .., len - 1
let expected = (0..).take(len).collect::<VecDeque<_>>();
for tail_pos in 0..=max_cap {
tester.tail = tail_pos;
tester.head = tail_pos;
tester.reserve(63);
for i in 0..len {
tester.push_back(i);
}
tester.shrink_to_fit();
assert!(tester.capacity() <= cap);
assert!(tester.tail < tester.cap());
assert!(tester.head < tester.cap());
assert_eq!(tester, expected);
}
}
}
#[test]
fn test_split_off() {
// This test checks that every single combination of tail position, length, and
// split position is tested. Capacity 15 should be large enough to cover every case.
let mut tester = VecDeque::with_capacity(15);
// can't guarantee we got 15, so have to get what we got.
// 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else
// this test isn't covering what it wants to
let cap = tester.capacity();
// len is the length *before* splitting
for len in 0..cap {
// index to split at
for at in 0..=len {
// 0, 1, 2, .., at - 1 (may be empty)
let expected_self = (0..).take(at).collect::<VecDeque<_>>();
// at, at + 1, .., len - 1 (may be empty)
let expected_other = (at..).take(len - at).collect::<VecDeque<_>>();
for tail_pos in 0..cap {
tester.tail = tail_pos;
tester.head = tail_pos;
for i in 0..len {
tester.push_back(i);
}
let result = tester.split_off(at);
assert!(tester.tail < tester.cap());
assert!(tester.head < tester.cap());
assert!(result.tail < result.cap());
assert!(result.head < result.cap());
assert_eq!(tester, expected_self);
assert_eq!(result, expected_other);
}
}
}
}
#[test]
fn test_from_vec() {
use crate::vec::Vec;
for cap in 0..35 {
for len in 0..=cap {
let mut vec = Vec::with_capacity(cap);
vec.extend(0..len);
let vd = VecDeque::from(vec.clone());
assert!(vd.cap().is_power_of_two());
assert_eq!(vd.len(), vec.len());
assert!(vd.into_iter().eq(vec));
}
}
}
#[test]
fn test_vec_from_vecdeque() {
use crate::vec::Vec;
fn create_vec_and_test_convert(capacity: usize, offset: usize, len: usize) {
let mut vd = VecDeque::with_capacity(capacity);
for _ in 0..offset {
vd.push_back(0);
vd.pop_front();
}
vd.extend(0..len);
let vec: Vec<_> = Vec::from(vd.clone());
assert_eq!(vec.len(), vd.len());
assert!(vec.into_iter().eq(vd));
}
#[cfg(not(miri))] // Miri is too slow
let max_pwr = 7;
#[cfg(miri)]
let max_pwr = 5;
for cap_pwr in 0..max_pwr {
// Make capacity as a (2^x)-1, so that the ring size is 2^x
let cap = (2i32.pow(cap_pwr) - 1) as usize;
// In these cases there is enough free space to solve it with copies
for len in 0..((cap + 1) / 2) {
// Test contiguous cases
for offset in 0..(cap - len) {
create_vec_and_test_convert(cap, offset, len)
}
// Test cases where block at end of buffer is bigger than block at start
for offset in (cap - len)..(cap - (len / 2)) {
create_vec_and_test_convert(cap, offset, len)
}
// Test cases where block at start of buffer is bigger than block at end
for offset in (cap - (len / 2))..cap {
create_vec_and_test_convert(cap, offset, len)
}
}
// Now there's not (necessarily) space to straighten the ring with simple copies,
// the ring will use swapping when:
// (cap + 1 - offset) > (cap + 1 - len) && (len - (cap + 1 - offset)) > (cap + 1 - len))
// right block size > free space && left block size > free space
for len in ((cap + 1) / 2)..cap {
// Test contiguous cases
for offset in 0..(cap - len) {
create_vec_and_test_convert(cap, offset, len)
}
// Test cases where block at end of buffer is bigger than block at start
for offset in (cap - len)..(cap - (len / 2)) {
create_vec_and_test_convert(cap, offset, len)
}
// Test cases where block at start of buffer is bigger than block at end
for offset in (cap - (len / 2))..cap {
create_vec_and_test_convert(cap, offset, len)
}
}
}
}
#[test]
fn issue_53529() {
use crate::boxed::Box;
let mut dst = VecDeque::new();
dst.push_front(Box::new(1));
dst.push_front(Box::new(2));
assert_eq!(*dst.pop_back().unwrap(), 1);
let mut src = VecDeque::new();
src.push_front(Box::new(2));
dst.append(&mut src);
for a in dst {
assert_eq!(*a, 2);
}
}
}

View File

@ -0,0 +1,379 @@
use super::*;
use ::test;
#[bench]
#[cfg(not(miri))] // Miri does not support benchmarks
fn bench_push_back_100(b: &mut test::Bencher) {
let mut deq = VecDeque::with_capacity(101);
b.iter(|| {
for i in 0..100 {
deq.push_back(i);
}
deq.head = 0;
deq.tail = 0;
})
}
#[bench]
#[cfg(not(miri))] // Miri does not support benchmarks
fn bench_push_front_100(b: &mut test::Bencher) {
let mut deq = VecDeque::with_capacity(101);
b.iter(|| {
for i in 0..100 {
deq.push_front(i);
}
deq.head = 0;
deq.tail = 0;
})
}
#[bench]
#[cfg(not(miri))] // Miri does not support benchmarks
fn bench_pop_back_100(b: &mut test::Bencher) {
let mut deq = VecDeque::<i32>::with_capacity(101);
b.iter(|| {
deq.head = 100;
deq.tail = 0;
while !deq.is_empty() {
test::black_box(deq.pop_back());
}
})
}
#[bench]
#[cfg(not(miri))] // Miri does not support benchmarks
fn bench_pop_front_100(b: &mut test::Bencher) {
let mut deq = VecDeque::<i32>::with_capacity(101);
b.iter(|| {
deq.head = 100;
deq.tail = 0;
while !deq.is_empty() {
test::black_box(deq.pop_front());
}
})
}
#[test]
fn test_swap_front_back_remove() {
fn test(back: bool) {
// This test checks that every single combination of tail position and length is tested.
// Capacity 15 should be large enough to cover every case.
let mut tester = VecDeque::with_capacity(15);
let usable_cap = tester.capacity();
let final_len = usable_cap / 2;
for len in 0..final_len {
let expected: VecDeque<_> = if back {
(0..len).collect()
} else {
(0..len).rev().collect()
};
for tail_pos in 0..usable_cap {
tester.tail = tail_pos;
tester.head = tail_pos;
if back {
for i in 0..len * 2 {
tester.push_front(i);
}
for i in 0..len {
assert_eq!(tester.swap_remove_back(i), Some(len * 2 - 1 - i));
}
} else {
for i in 0..len * 2 {
tester.push_back(i);
}
for i in 0..len {
let idx = tester.len() - 1 - i;
assert_eq!(tester.swap_remove_front(idx), Some(len * 2 - 1 - i));
}
}
assert!(tester.tail < tester.cap());
assert!(tester.head < tester.cap());
assert_eq!(tester, expected);
}
}
}
test(true);
test(false);
}
#[test]
fn test_insert() {
// This test checks that every single combination of tail position, length, and
// insertion position is tested. Capacity 15 should be large enough to cover every case.
let mut tester = VecDeque::with_capacity(15);
// can't guarantee we got 15, so have to get what we got.
// 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else
// this test isn't covering what it wants to
let cap = tester.capacity();
// len is the length *after* insertion
for len in 1..cap {
// 0, 1, 2, .., len - 1
let expected = (0..).take(len).collect::<VecDeque<_>>();
for tail_pos in 0..cap {
for to_insert in 0..len {
tester.tail = tail_pos;
tester.head = tail_pos;
for i in 0..len {
if i != to_insert {
tester.push_back(i);
}
}
tester.insert(to_insert, to_insert);
assert!(tester.tail < tester.cap());
assert!(tester.head < tester.cap());
assert_eq!(tester, expected);
}
}
}
}
#[test]
fn test_remove() {
// This test checks that every single combination of tail position, length, and
// removal position is tested. Capacity 15 should be large enough to cover every case.
let mut tester = VecDeque::with_capacity(15);
// can't guarantee we got 15, so have to get what we got.
// 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else
// this test isn't covering what it wants to
let cap = tester.capacity();
// len is the length *after* removal
for len in 0..cap - 1 {
// 0, 1, 2, .., len - 1
let expected = (0..).take(len).collect::<VecDeque<_>>();
for tail_pos in 0..cap {
for to_remove in 0..=len {
tester.tail = tail_pos;
tester.head = tail_pos;
for i in 0..len {
if i == to_remove {
tester.push_back(1234);
}
tester.push_back(i);
}
if to_remove == len {
tester.push_back(1234);
}
tester.remove(to_remove);
assert!(tester.tail < tester.cap());
assert!(tester.head < tester.cap());
assert_eq!(tester, expected);
}
}
}
}
#[test]
fn test_drain() {
let mut tester: VecDeque<usize> = VecDeque::with_capacity(7);
let cap = tester.capacity();
for len in 0..=cap {
for tail in 0..=cap {
for drain_start in 0..=len {
for drain_end in drain_start..=len {
tester.tail = tail;
tester.head = tail;
for i in 0..len {
tester.push_back(i);
}
// Check that we drain the correct values
let drained: VecDeque<_> = tester.drain(drain_start..drain_end).collect();
let drained_expected: VecDeque<_> = (drain_start..drain_end).collect();
assert_eq!(drained, drained_expected);
// We shouldn't have changed the capacity or made the
// head or tail out of bounds
assert_eq!(tester.capacity(), cap);
assert!(tester.tail < tester.cap());
assert!(tester.head < tester.cap());
// We should see the correct values in the VecDeque
let expected: VecDeque<_> = (0..drain_start)
.chain(drain_end..len)
.collect();
assert_eq!(expected, tester);
}
}
}
}
}
#[test]
fn test_shrink_to_fit() {
// This test checks that every single combination of head and tail position,
// is tested. Capacity 15 should be large enough to cover every case.
let mut tester = VecDeque::with_capacity(15);
// can't guarantee we got 15, so have to get what we got.
// 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else
// this test isn't covering what it wants to
let cap = tester.capacity();
tester.reserve(63);
let max_cap = tester.capacity();
for len in 0..=cap {
// 0, 1, 2, .., len - 1
let expected = (0..).take(len).collect::<VecDeque<_>>();
for tail_pos in 0..=max_cap {
tester.tail = tail_pos;
tester.head = tail_pos;
tester.reserve(63);
for i in 0..len {
tester.push_back(i);
}
tester.shrink_to_fit();
assert!(tester.capacity() <= cap);
assert!(tester.tail < tester.cap());
assert!(tester.head < tester.cap());
assert_eq!(tester, expected);
}
}
}
#[test]
fn test_split_off() {
// This test checks that every single combination of tail position, length, and
// split position is tested. Capacity 15 should be large enough to cover every case.
let mut tester = VecDeque::with_capacity(15);
// can't guarantee we got 15, so have to get what we got.
// 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else
// this test isn't covering what it wants to
let cap = tester.capacity();
// len is the length *before* splitting
for len in 0..cap {
// index to split at
for at in 0..=len {
// 0, 1, 2, .., at - 1 (may be empty)
let expected_self = (0..).take(at).collect::<VecDeque<_>>();
// at, at + 1, .., len - 1 (may be empty)
let expected_other = (at..).take(len - at).collect::<VecDeque<_>>();
for tail_pos in 0..cap {
tester.tail = tail_pos;
tester.head = tail_pos;
for i in 0..len {
tester.push_back(i);
}
let result = tester.split_off(at);
assert!(tester.tail < tester.cap());
assert!(tester.head < tester.cap());
assert!(result.tail < result.cap());
assert!(result.head < result.cap());
assert_eq!(tester, expected_self);
assert_eq!(result, expected_other);
}
}
}
}
#[test]
fn test_from_vec() {
use crate::vec::Vec;
for cap in 0..35 {
for len in 0..=cap {
let mut vec = Vec::with_capacity(cap);
vec.extend(0..len);
let vd = VecDeque::from(vec.clone());
assert!(vd.cap().is_power_of_two());
assert_eq!(vd.len(), vec.len());
assert!(vd.into_iter().eq(vec));
}
}
}
#[test]
fn test_vec_from_vecdeque() {
use crate::vec::Vec;
fn create_vec_and_test_convert(capacity: usize, offset: usize, len: usize) {
let mut vd = VecDeque::with_capacity(capacity);
for _ in 0..offset {
vd.push_back(0);
vd.pop_front();
}
vd.extend(0..len);
let vec: Vec<_> = Vec::from(vd.clone());
assert_eq!(vec.len(), vd.len());
assert!(vec.into_iter().eq(vd));
}
#[cfg(not(miri))] // Miri is too slow
let max_pwr = 7;
#[cfg(miri)]
let max_pwr = 5;
for cap_pwr in 0..max_pwr {
// Make capacity as a (2^x)-1, so that the ring size is 2^x
let cap = (2i32.pow(cap_pwr) - 1) as usize;
// In these cases there is enough free space to solve it with copies
for len in 0..((cap + 1) / 2) {
// Test contiguous cases
for offset in 0..(cap - len) {
create_vec_and_test_convert(cap, offset, len)
}
// Test cases where block at end of buffer is bigger than block at start
for offset in (cap - len)..(cap - (len / 2)) {
create_vec_and_test_convert(cap, offset, len)
}
// Test cases where block at start of buffer is bigger than block at end
for offset in (cap - (len / 2))..cap {
create_vec_and_test_convert(cap, offset, len)
}
}
// Now there's not (necessarily) space to straighten the ring with simple copies,
// the ring will use swapping when:
// (cap + 1 - offset) > (cap + 1 - len) && (len - (cap + 1 - offset)) > (cap + 1 - len))
// right block size > free space && left block size > free space
for len in ((cap + 1) / 2)..cap {
// Test contiguous cases
for offset in 0..(cap - len) {
create_vec_and_test_convert(cap, offset, len)
}
// Test cases where block at end of buffer is bigger than block at start
for offset in (cap - len)..(cap - (len / 2)) {
create_vec_and_test_convert(cap, offset, len)
}
// Test cases where block at start of buffer is bigger than block at end
for offset in (cap - (len / 2))..cap {
create_vec_and_test_convert(cap, offset, len)
}
}
}
}
#[test]
fn issue_53529() {
use crate::boxed::Box;
let mut dst = VecDeque::new();
dst.push_front(Box::new(1));
dst.push_front(Box::new(2));
assert_eq!(*dst.pop_back().unwrap(), 1);
let mut src = VecDeque::new();
src.push_front(Box::new(2));
dst.append(&mut src);
for a in dst {
assert_eq!(*a, 2);
}
}

View File

@ -11,6 +11,9 @@ use crate::alloc::{Alloc, Layout, Global, handle_alloc_error};
use crate::collections::CollectionAllocErr::{self, *};
use crate::boxed::Box;
#[cfg(test)]
mod tests;
/// A low-level utility for more ergonomically allocating, reallocating, and deallocating
/// a buffer of memory on the heap without having to worry about all the corner cases
/// involved. This type is excellent for building your own data structures like Vec and VecDeque.
@ -748,82 +751,3 @@ fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> {
fn capacity_overflow() -> ! {
panic!("capacity overflow")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn allocator_param() {
use crate::alloc::AllocErr;
// Writing a test of integration between third-party
// allocators and RawVec is a little tricky because the RawVec
// API does not expose fallible allocation methods, so we
// cannot check what happens when allocator is exhausted
// (beyond detecting a panic).
//
// Instead, this just checks that the RawVec methods do at
// least go through the Allocator API when it reserves
// storage.
// A dumb allocator that consumes a fixed amount of fuel
// before allocation attempts start failing.
struct BoundedAlloc { fuel: usize }
unsafe impl Alloc for BoundedAlloc {
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
let size = layout.size();
if size > self.fuel {
return Err(AllocErr);
}
match Global.alloc(layout) {
ok @ Ok(_) => { self.fuel -= size; ok }
err @ Err(_) => err,
}
}
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
Global.dealloc(ptr, layout)
}
}
let a = BoundedAlloc { fuel: 500 };
let mut v: RawVec<u8, _> = RawVec::with_capacity_in(50, a);
assert_eq!(v.a.fuel, 450);
v.reserve(50, 150); // (causes a realloc, thus using 50 + 150 = 200 units of fuel)
assert_eq!(v.a.fuel, 250);
}
#[test]
fn reserve_does_not_overallocate() {
{
let mut v: RawVec<u32> = RawVec::new();
// First `reserve` allocates like `reserve_exact`
v.reserve(0, 9);
assert_eq!(9, v.capacity());
}
{
let mut v: RawVec<u32> = RawVec::new();
v.reserve(0, 7);
assert_eq!(7, v.capacity());
// 97 if more than double of 7, so `reserve` should work
// like `reserve_exact`.
v.reserve(7, 90);
assert_eq!(97, v.capacity());
}
{
let mut v: RawVec<u32> = RawVec::new();
v.reserve(0, 12);
assert_eq!(12, v.capacity());
v.reserve(12, 3);
// 3 is less than half of 12, so `reserve` must grow
// exponentially. At the time of writing this test grow
// factor is 2, so new capacity is 24, however, grow factor
// of 1.5 is OK too. Hence `>= 18` in assert.
assert!(v.capacity() >= 12 + 12 / 2);
}
}
}

View File

@ -0,0 +1,73 @@
use super::*;
#[test]
fn allocator_param() {
use crate::alloc::AllocErr;
// Writing a test of integration between third-party
// allocators and RawVec is a little tricky because the RawVec
// API does not expose fallible allocation methods, so we
// cannot check what happens when allocator is exhausted
// (beyond detecting a panic).
//
// Instead, this just checks that the RawVec methods do at
// least go through the Allocator API when it reserves
// storage.
// A dumb allocator that consumes a fixed amount of fuel
// before allocation attempts start failing.
struct BoundedAlloc { fuel: usize }
unsafe impl Alloc for BoundedAlloc {
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
let size = layout.size();
if size > self.fuel {
return Err(AllocErr);
}
match Global.alloc(layout) {
ok @ Ok(_) => { self.fuel -= size; ok }
err @ Err(_) => err,
}
}
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
Global.dealloc(ptr, layout)
}
}
let a = BoundedAlloc { fuel: 500 };
let mut v: RawVec<u8, _> = RawVec::with_capacity_in(50, a);
assert_eq!(v.a.fuel, 450);
v.reserve(50, 150); // (causes a realloc, thus using 50 + 150 = 200 units of fuel)
assert_eq!(v.a.fuel, 250);
}
#[test]
fn reserve_does_not_overallocate() {
{
let mut v: RawVec<u32> = RawVec::new();
// First `reserve` allocates like `reserve_exact`
v.reserve(0, 9);
assert_eq!(9, v.capacity());
}
{
let mut v: RawVec<u32> = RawVec::new();
v.reserve(0, 7);
assert_eq!(7, v.capacity());
// 97 if more than double of 7, so `reserve` should work
// like `reserve_exact`.
v.reserve(7, 90);
assert_eq!(97, v.capacity());
}
{
let mut v: RawVec<u32> = RawVec::new();
v.reserve(0, 12);
assert_eq!(12, v.capacity());
v.reserve(12, 3);
// 3 is less than half of 12, so `reserve` must grow
// exponentially. At the time of writing this test grow
// factor is 2, so new capacity is 24, however, grow factor
// of 1.5 is OK too. Hence `>= 18` in assert.
assert!(v.capacity() >= 12 + 12 / 2);
}
}

View File

@ -252,6 +252,9 @@ use crate::alloc::{Global, Alloc, Layout, box_free, handle_alloc_error};
use crate::string::String;
use crate::vec::Vec;
#[cfg(test)]
mod tests;
struct RcBox<T: ?Sized> {
strong: Cell<usize>,
weak: Cell<usize>,
@ -1851,436 +1854,6 @@ impl<T: ?Sized> RcBoxPtr<T> for RcBox<T> {
}
}
#[cfg(test)]
mod tests {
use super::{Rc, Weak};
use std::boxed::Box;
use std::cell::RefCell;
use std::option::Option::{self, None, Some};
use std::result::Result::{Err, Ok};
use std::mem::drop;
use std::clone::Clone;
use std::convert::From;
#[test]
fn test_clone() {
let x = Rc::new(RefCell::new(5));
let y = x.clone();
*x.borrow_mut() = 20;
assert_eq!(*y.borrow(), 20);
}
#[test]
fn test_simple() {
let x = Rc::new(5);
assert_eq!(*x, 5);
}
#[test]
fn test_simple_clone() {
let x = Rc::new(5);
let y = x.clone();
assert_eq!(*x, 5);
assert_eq!(*y, 5);
}
#[test]
fn test_destructor() {
let x: Rc<Box<_>> = Rc::new(box 5);
assert_eq!(**x, 5);
}
#[test]
fn test_live() {
let x = Rc::new(5);
let y = Rc::downgrade(&x);
assert!(y.upgrade().is_some());
}
#[test]
fn test_dead() {
let x = Rc::new(5);
let y = Rc::downgrade(&x);
drop(x);
assert!(y.upgrade().is_none());
}
#[test]
fn weak_self_cyclic() {
struct Cycle {
x: RefCell<Option<Weak<Cycle>>>,
}
let a = Rc::new(Cycle { x: RefCell::new(None) });
let b = Rc::downgrade(&a.clone());
*a.x.borrow_mut() = Some(b);
// hopefully we don't double-free (or leak)...
}
#[test]
fn is_unique() {
let x = Rc::new(3);
assert!(Rc::is_unique(&x));
let y = x.clone();
assert!(!Rc::is_unique(&x));
drop(y);
assert!(Rc::is_unique(&x));
let w = Rc::downgrade(&x);
assert!(!Rc::is_unique(&x));
drop(w);
assert!(Rc::is_unique(&x));
}
#[test]
fn test_strong_count() {
let a = Rc::new(0);
assert!(Rc::strong_count(&a) == 1);
let w = Rc::downgrade(&a);
assert!(Rc::strong_count(&a) == 1);
let b = w.upgrade().expect("upgrade of live rc failed");
assert!(Rc::strong_count(&b) == 2);
assert!(Rc::strong_count(&a) == 2);
drop(w);
drop(a);
assert!(Rc::strong_count(&b) == 1);
let c = b.clone();
assert!(Rc::strong_count(&b) == 2);
assert!(Rc::strong_count(&c) == 2);
}
#[test]
fn test_weak_count() {
let a = Rc::new(0);
assert!(Rc::strong_count(&a) == 1);
assert!(Rc::weak_count(&a) == 0);
let w = Rc::downgrade(&a);
assert!(Rc::strong_count(&a) == 1);
assert!(Rc::weak_count(&a) == 1);
drop(w);
assert!(Rc::strong_count(&a) == 1);
assert!(Rc::weak_count(&a) == 0);
let c = a.clone();
assert!(Rc::strong_count(&a) == 2);
assert!(Rc::weak_count(&a) == 0);
drop(c);
}
#[test]
fn weak_counts() {
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), None);
assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
let a = Rc::new(0);
let w = Rc::downgrade(&a);
assert_eq!(Weak::strong_count(&w), 1);
assert_eq!(Weak::weak_count(&w), Some(1));
let w2 = w.clone();
assert_eq!(Weak::strong_count(&w), 1);
assert_eq!(Weak::weak_count(&w), Some(2));
assert_eq!(Weak::strong_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(2));
drop(w);
assert_eq!(Weak::strong_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(1));
let a2 = a.clone();
assert_eq!(Weak::strong_count(&w2), 2);
assert_eq!(Weak::weak_count(&w2), Some(1));
drop(a2);
drop(a);
assert_eq!(Weak::strong_count(&w2), 0);
assert_eq!(Weak::weak_count(&w2), Some(1));
drop(w2);
}
#[test]
fn try_unwrap() {
let x = Rc::new(3);
assert_eq!(Rc::try_unwrap(x), Ok(3));
let x = Rc::new(4);
let _y = x.clone();
assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4)));
let x = Rc::new(5);
let _w = Rc::downgrade(&x);
assert_eq!(Rc::try_unwrap(x), Ok(5));
}
#[test]
fn into_from_raw() {
let x = Rc::new(box "hello");
let y = x.clone();
let x_ptr = Rc::into_raw(x);
drop(y);
unsafe {
assert_eq!(**x_ptr, "hello");
let x = Rc::from_raw(x_ptr);
assert_eq!(**x, "hello");
assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello"));
}
}
#[test]
fn test_into_from_raw_unsized() {
use std::fmt::Display;
use std::string::ToString;
let rc: Rc<str> = Rc::from("foo");
let ptr = Rc::into_raw(rc.clone());
let rc2 = unsafe { Rc::from_raw(ptr) };
assert_eq!(unsafe { &*ptr }, "foo");
assert_eq!(rc, rc2);
let rc: Rc<dyn Display> = Rc::new(123);
let ptr = Rc::into_raw(rc.clone());
let rc2 = unsafe { Rc::from_raw(ptr) };
assert_eq!(unsafe { &*ptr }.to_string(), "123");
assert_eq!(rc2.to_string(), "123");
}
#[test]
fn get_mut() {
let mut x = Rc::new(3);
*Rc::get_mut(&mut x).unwrap() = 4;
assert_eq!(*x, 4);
let y = x.clone();
assert!(Rc::get_mut(&mut x).is_none());
drop(y);
assert!(Rc::get_mut(&mut x).is_some());
let _w = Rc::downgrade(&x);
assert!(Rc::get_mut(&mut x).is_none());
}
#[test]
fn test_cowrc_clone_make_unique() {
let mut cow0 = Rc::new(75);
let mut cow1 = cow0.clone();
let mut cow2 = cow1.clone();
assert!(75 == *Rc::make_mut(&mut cow0));
assert!(75 == *Rc::make_mut(&mut cow1));
assert!(75 == *Rc::make_mut(&mut cow2));
*Rc::make_mut(&mut cow0) += 1;
*Rc::make_mut(&mut cow1) += 2;
*Rc::make_mut(&mut cow2) += 3;
assert!(76 == *cow0);
assert!(77 == *cow1);
assert!(78 == *cow2);
// none should point to the same backing memory
assert!(*cow0 != *cow1);
assert!(*cow0 != *cow2);
assert!(*cow1 != *cow2);
}
#[test]
fn test_cowrc_clone_unique2() {
let mut cow0 = Rc::new(75);
let cow1 = cow0.clone();
let cow2 = cow1.clone();
assert!(75 == *cow0);
assert!(75 == *cow1);
assert!(75 == *cow2);
*Rc::make_mut(&mut cow0) += 1;
assert!(76 == *cow0);
assert!(75 == *cow1);
assert!(75 == *cow2);
// cow1 and cow2 should share the same contents
// cow0 should have a unique reference
assert!(*cow0 != *cow1);
assert!(*cow0 != *cow2);
assert!(*cow1 == *cow2);
}
#[test]
fn test_cowrc_clone_weak() {
let mut cow0 = Rc::new(75);
let cow1_weak = Rc::downgrade(&cow0);
assert!(75 == *cow0);
assert!(75 == *cow1_weak.upgrade().unwrap());
*Rc::make_mut(&mut cow0) += 1;
assert!(76 == *cow0);
assert!(cow1_weak.upgrade().is_none());
}
#[test]
fn test_show() {
let foo = Rc::new(75);
assert_eq!(format!("{:?}", foo), "75");
}
#[test]
fn test_unsized() {
let foo: Rc<[i32]> = Rc::new([1, 2, 3]);
assert_eq!(foo, foo.clone());
}
#[test]
fn test_from_owned() {
let foo = 123;
let foo_rc = Rc::from(foo);
assert!(123 == *foo_rc);
}
#[test]
fn test_new_weak() {
let foo: Weak<usize> = Weak::new();
assert!(foo.upgrade().is_none());
}
#[test]
fn test_ptr_eq() {
let five = Rc::new(5);
let same_five = five.clone();
let other_five = Rc::new(5);
assert!(Rc::ptr_eq(&five, &same_five));
assert!(!Rc::ptr_eq(&five, &other_five));
}
#[test]
fn test_from_str() {
let r: Rc<str> = Rc::from("foo");
assert_eq!(&r[..], "foo");
}
#[test]
fn test_copy_from_slice() {
let s: &[u32] = &[1, 2, 3];
let r: Rc<[u32]> = Rc::from(s);
assert_eq!(&r[..], [1, 2, 3]);
}
#[test]
fn test_clone_from_slice() {
#[derive(Clone, Debug, Eq, PartialEq)]
struct X(u32);
let s: &[X] = &[X(1), X(2), X(3)];
let r: Rc<[X]> = Rc::from(s);
assert_eq!(&r[..], s);
}
#[test]
#[should_panic]
fn test_clone_from_slice_panic() {
use std::string::{String, ToString};
struct Fail(u32, String);
impl Clone for Fail {
fn clone(&self) -> Fail {
if self.0 == 2 {
panic!();
}
Fail(self.0, self.1.clone())
}
}
let s: &[Fail] = &[
Fail(0, "foo".to_string()),
Fail(1, "bar".to_string()),
Fail(2, "baz".to_string()),
];
// Should panic, but not cause memory corruption
let _r: Rc<[Fail]> = Rc::from(s);
}
#[test]
fn test_from_box() {
let b: Box<u32> = box 123;
let r: Rc<u32> = Rc::from(b);
assert_eq!(*r, 123);
}
#[test]
fn test_from_box_str() {
use std::string::String;
let s = String::from("foo").into_boxed_str();
let r: Rc<str> = Rc::from(s);
assert_eq!(&r[..], "foo");
}
#[test]
fn test_from_box_slice() {
let s = vec![1, 2, 3].into_boxed_slice();
let r: Rc<[u32]> = Rc::from(s);
assert_eq!(&r[..], [1, 2, 3]);
}
#[test]
fn test_from_box_trait() {
use std::fmt::Display;
use std::string::ToString;
let b: Box<dyn Display> = box 123;
let r: Rc<dyn Display> = Rc::from(b);
assert_eq!(r.to_string(), "123");
}
#[test]
fn test_from_box_trait_zero_sized() {
use std::fmt::Debug;
let b: Box<dyn Debug> = box ();
let r: Rc<dyn Debug> = Rc::from(b);
assert_eq!(format!("{:?}", r), "()");
}
#[test]
fn test_from_vec() {
let v = vec![1, 2, 3];
let r: Rc<[u32]> = Rc::from(v);
assert_eq!(&r[..], [1, 2, 3]);
}
#[test]
fn test_downcast() {
use std::any::Any;
let r1: Rc<dyn Any> = Rc::new(i32::max_value());
let r2: Rc<dyn Any> = Rc::new("abc");
assert!(r1.clone().downcast::<u32>().is_err());
let r1i32 = r1.downcast::<i32>();
assert!(r1i32.is_ok());
assert_eq!(r1i32.unwrap(), Rc::new(i32::max_value()));
assert!(r2.clone().downcast::<i32>().is_err());
let r2str = r2.downcast::<&'static str>();
assert!(r2str.is_ok());
assert_eq!(r2str.unwrap(), Rc::new("abc"));
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> borrow::Borrow<T> for Rc<T> {
fn borrow(&self) -> &T {

427
src/liballoc/rc/tests.rs Normal file
View File

@ -0,0 +1,427 @@
use super::*;
use std::boxed::Box;
use std::cell::RefCell;
use std::option::Option::{self, None, Some};
use std::result::Result::{Err, Ok};
use std::mem::drop;
use std::clone::Clone;
use std::convert::From;
#[test]
fn test_clone() {
let x = Rc::new(RefCell::new(5));
let y = x.clone();
*x.borrow_mut() = 20;
assert_eq!(*y.borrow(), 20);
}
#[test]
fn test_simple() {
let x = Rc::new(5);
assert_eq!(*x, 5);
}
#[test]
fn test_simple_clone() {
let x = Rc::new(5);
let y = x.clone();
assert_eq!(*x, 5);
assert_eq!(*y, 5);
}
#[test]
fn test_destructor() {
let x: Rc<Box<_>> = Rc::new(box 5);
assert_eq!(**x, 5);
}
#[test]
fn test_live() {
let x = Rc::new(5);
let y = Rc::downgrade(&x);
assert!(y.upgrade().is_some());
}
#[test]
fn test_dead() {
let x = Rc::new(5);
let y = Rc::downgrade(&x);
drop(x);
assert!(y.upgrade().is_none());
}
#[test]
fn weak_self_cyclic() {
struct Cycle {
x: RefCell<Option<Weak<Cycle>>>,
}
let a = Rc::new(Cycle { x: RefCell::new(None) });
let b = Rc::downgrade(&a.clone());
*a.x.borrow_mut() = Some(b);
// hopefully we don't double-free (or leak)...
}
#[test]
fn is_unique() {
let x = Rc::new(3);
assert!(Rc::is_unique(&x));
let y = x.clone();
assert!(!Rc::is_unique(&x));
drop(y);
assert!(Rc::is_unique(&x));
let w = Rc::downgrade(&x);
assert!(!Rc::is_unique(&x));
drop(w);
assert!(Rc::is_unique(&x));
}
#[test]
fn test_strong_count() {
let a = Rc::new(0);
assert!(Rc::strong_count(&a) == 1);
let w = Rc::downgrade(&a);
assert!(Rc::strong_count(&a) == 1);
let b = w.upgrade().expect("upgrade of live rc failed");
assert!(Rc::strong_count(&b) == 2);
assert!(Rc::strong_count(&a) == 2);
drop(w);
drop(a);
assert!(Rc::strong_count(&b) == 1);
let c = b.clone();
assert!(Rc::strong_count(&b) == 2);
assert!(Rc::strong_count(&c) == 2);
}
#[test]
fn test_weak_count() {
let a = Rc::new(0);
assert!(Rc::strong_count(&a) == 1);
assert!(Rc::weak_count(&a) == 0);
let w = Rc::downgrade(&a);
assert!(Rc::strong_count(&a) == 1);
assert!(Rc::weak_count(&a) == 1);
drop(w);
assert!(Rc::strong_count(&a) == 1);
assert!(Rc::weak_count(&a) == 0);
let c = a.clone();
assert!(Rc::strong_count(&a) == 2);
assert!(Rc::weak_count(&a) == 0);
drop(c);
}
#[test]
fn weak_counts() {
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), None);
assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
let a = Rc::new(0);
let w = Rc::downgrade(&a);
assert_eq!(Weak::strong_count(&w), 1);
assert_eq!(Weak::weak_count(&w), Some(1));
let w2 = w.clone();
assert_eq!(Weak::strong_count(&w), 1);
assert_eq!(Weak::weak_count(&w), Some(2));
assert_eq!(Weak::strong_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(2));
drop(w);
assert_eq!(Weak::strong_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(1));
let a2 = a.clone();
assert_eq!(Weak::strong_count(&w2), 2);
assert_eq!(Weak::weak_count(&w2), Some(1));
drop(a2);
drop(a);
assert_eq!(Weak::strong_count(&w2), 0);
assert_eq!(Weak::weak_count(&w2), Some(1));
drop(w2);
}
#[test]
fn try_unwrap() {
let x = Rc::new(3);
assert_eq!(Rc::try_unwrap(x), Ok(3));
let x = Rc::new(4);
let _y = x.clone();
assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4)));
let x = Rc::new(5);
let _w = Rc::downgrade(&x);
assert_eq!(Rc::try_unwrap(x), Ok(5));
}
#[test]
fn into_from_raw() {
let x = Rc::new(box "hello");
let y = x.clone();
let x_ptr = Rc::into_raw(x);
drop(y);
unsafe {
assert_eq!(**x_ptr, "hello");
let x = Rc::from_raw(x_ptr);
assert_eq!(**x, "hello");
assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello"));
}
}
#[test]
fn test_into_from_raw_unsized() {
use std::fmt::Display;
use std::string::ToString;
let rc: Rc<str> = Rc::from("foo");
let ptr = Rc::into_raw(rc.clone());
let rc2 = unsafe { Rc::from_raw(ptr) };
assert_eq!(unsafe { &*ptr }, "foo");
assert_eq!(rc, rc2);
let rc: Rc<dyn Display> = Rc::new(123);
let ptr = Rc::into_raw(rc.clone());
let rc2 = unsafe { Rc::from_raw(ptr) };
assert_eq!(unsafe { &*ptr }.to_string(), "123");
assert_eq!(rc2.to_string(), "123");
}
#[test]
fn get_mut() {
let mut x = Rc::new(3);
*Rc::get_mut(&mut x).unwrap() = 4;
assert_eq!(*x, 4);
let y = x.clone();
assert!(Rc::get_mut(&mut x).is_none());
drop(y);
assert!(Rc::get_mut(&mut x).is_some());
let _w = Rc::downgrade(&x);
assert!(Rc::get_mut(&mut x).is_none());
}
#[test]
fn test_cowrc_clone_make_unique() {
let mut cow0 = Rc::new(75);
let mut cow1 = cow0.clone();
let mut cow2 = cow1.clone();
assert!(75 == *Rc::make_mut(&mut cow0));
assert!(75 == *Rc::make_mut(&mut cow1));
assert!(75 == *Rc::make_mut(&mut cow2));
*Rc::make_mut(&mut cow0) += 1;
*Rc::make_mut(&mut cow1) += 2;
*Rc::make_mut(&mut cow2) += 3;
assert!(76 == *cow0);
assert!(77 == *cow1);
assert!(78 == *cow2);
// none should point to the same backing memory
assert!(*cow0 != *cow1);
assert!(*cow0 != *cow2);
assert!(*cow1 != *cow2);
}
#[test]
fn test_cowrc_clone_unique2() {
let mut cow0 = Rc::new(75);
let cow1 = cow0.clone();
let cow2 = cow1.clone();
assert!(75 == *cow0);
assert!(75 == *cow1);
assert!(75 == *cow2);
*Rc::make_mut(&mut cow0) += 1;
assert!(76 == *cow0);
assert!(75 == *cow1);
assert!(75 == *cow2);
// cow1 and cow2 should share the same contents
// cow0 should have a unique reference
assert!(*cow0 != *cow1);
assert!(*cow0 != *cow2);
assert!(*cow1 == *cow2);
}
#[test]
fn test_cowrc_clone_weak() {
let mut cow0 = Rc::new(75);
let cow1_weak = Rc::downgrade(&cow0);
assert!(75 == *cow0);
assert!(75 == *cow1_weak.upgrade().unwrap());
*Rc::make_mut(&mut cow0) += 1;
assert!(76 == *cow0);
assert!(cow1_weak.upgrade().is_none());
}
#[test]
fn test_show() {
let foo = Rc::new(75);
assert_eq!(format!("{:?}", foo), "75");
}
#[test]
fn test_unsized() {
let foo: Rc<[i32]> = Rc::new([1, 2, 3]);
assert_eq!(foo, foo.clone());
}
#[test]
fn test_from_owned() {
let foo = 123;
let foo_rc = Rc::from(foo);
assert!(123 == *foo_rc);
}
#[test]
fn test_new_weak() {
let foo: Weak<usize> = Weak::new();
assert!(foo.upgrade().is_none());
}
#[test]
fn test_ptr_eq() {
let five = Rc::new(5);
let same_five = five.clone();
let other_five = Rc::new(5);
assert!(Rc::ptr_eq(&five, &same_five));
assert!(!Rc::ptr_eq(&five, &other_five));
}
#[test]
fn test_from_str() {
let r: Rc<str> = Rc::from("foo");
assert_eq!(&r[..], "foo");
}
#[test]
fn test_copy_from_slice() {
let s: &[u32] = &[1, 2, 3];
let r: Rc<[u32]> = Rc::from(s);
assert_eq!(&r[..], [1, 2, 3]);
}
#[test]
fn test_clone_from_slice() {
#[derive(Clone, Debug, Eq, PartialEq)]
struct X(u32);
let s: &[X] = &[X(1), X(2), X(3)];
let r: Rc<[X]> = Rc::from(s);
assert_eq!(&r[..], s);
}
#[test]
#[should_panic]
fn test_clone_from_slice_panic() {
use std::string::{String, ToString};
struct Fail(u32, String);
impl Clone for Fail {
fn clone(&self) -> Fail {
if self.0 == 2 {
panic!();
}
Fail(self.0, self.1.clone())
}
}
let s: &[Fail] = &[
Fail(0, "foo".to_string()),
Fail(1, "bar".to_string()),
Fail(2, "baz".to_string()),
];
// Should panic, but not cause memory corruption
let _r: Rc<[Fail]> = Rc::from(s);
}
#[test]
fn test_from_box() {
let b: Box<u32> = box 123;
let r: Rc<u32> = Rc::from(b);
assert_eq!(*r, 123);
}
#[test]
fn test_from_box_str() {
use std::string::String;
let s = String::from("foo").into_boxed_str();
let r: Rc<str> = Rc::from(s);
assert_eq!(&r[..], "foo");
}
#[test]
fn test_from_box_slice() {
let s = vec![1, 2, 3].into_boxed_slice();
let r: Rc<[u32]> = Rc::from(s);
assert_eq!(&r[..], [1, 2, 3]);
}
#[test]
fn test_from_box_trait() {
use std::fmt::Display;
use std::string::ToString;
let b: Box<dyn Display> = box 123;
let r: Rc<dyn Display> = Rc::from(b);
assert_eq!(r.to_string(), "123");
}
#[test]
fn test_from_box_trait_zero_sized() {
use std::fmt::Debug;
let b: Box<dyn Debug> = box ();
let r: Rc<dyn Debug> = Rc::from(b);
assert_eq!(format!("{:?}", r), "()");
}
#[test]
fn test_from_vec() {
let v = vec![1, 2, 3];
let r: Rc<[u32]> = Rc::from(v);
assert_eq!(&r[..], [1, 2, 3]);
}
#[test]
fn test_downcast() {
use std::any::Any;
let r1: Rc<dyn Any> = Rc::new(i32::max_value());
let r2: Rc<dyn Any> = Rc::new("abc");
assert!(r1.clone().downcast::<u32>().is_err());
let r1i32 = r1.downcast::<i32>();
assert!(r1i32.is_ok());
assert_eq!(r1i32.unwrap(), Rc::new(i32::max_value()));
assert!(r2.clone().downcast::<i32>().is_err());
let r2str = r2.downcast::<&'static str>();
assert!(r2str.is_ok());
assert_eq!(r2str.unwrap(), Rc::new("abc"));
}

View File

@ -30,6 +30,9 @@ use crate::rc::is_dangling;
use crate::string::String;
use crate::vec::Vec;
#[cfg(test)]
mod tests;
/// A soft limit on the amount of references that may be made to an `Arc`.
///
/// Going above this limit will abort your program (although not
@ -1915,489 +1918,6 @@ impl<'a, T: 'a + Clone> ArcFromIter<&'a T, slice::Iter<'a, T>> for Arc<[T]> {
}
}
#[cfg(test)]
mod tests {
use std::boxed::Box;
use std::clone::Clone;
use std::sync::mpsc::channel;
use std::mem::drop;
use std::ops::Drop;
use std::option::Option::{self, None, Some};
use std::sync::atomic::{self, Ordering::{Acquire, SeqCst}};
use std::thread;
use std::sync::Mutex;
use std::convert::From;
use super::{Arc, Weak};
use crate::vec::Vec;
struct Canary(*mut atomic::AtomicUsize);
impl Drop for Canary {
fn drop(&mut self) {
unsafe {
match *self {
Canary(c) => {
(*c).fetch_add(1, SeqCst);
}
}
}
}
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
#[cfg(not(miri))] // Miri does not support threads
fn manually_share_arc() {
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let arc_v = Arc::new(v);
let (tx, rx) = channel();
let _t = thread::spawn(move || {
let arc_v: Arc<Vec<i32>> = rx.recv().unwrap();
assert_eq!((*arc_v)[3], 4);
});
tx.send(arc_v.clone()).unwrap();
assert_eq!((*arc_v)[2], 3);
assert_eq!((*arc_v)[4], 5);
}
#[test]
fn test_arc_get_mut() {
let mut x = Arc::new(3);
*Arc::get_mut(&mut x).unwrap() = 4;
assert_eq!(*x, 4);
let y = x.clone();
assert!(Arc::get_mut(&mut x).is_none());
drop(y);
assert!(Arc::get_mut(&mut x).is_some());
let _w = Arc::downgrade(&x);
assert!(Arc::get_mut(&mut x).is_none());
}
#[test]
fn weak_counts() {
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), None);
assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
let a = Arc::new(0);
let w = Arc::downgrade(&a);
assert_eq!(Weak::strong_count(&w), 1);
assert_eq!(Weak::weak_count(&w), Some(1));
let w2 = w.clone();
assert_eq!(Weak::strong_count(&w), 1);
assert_eq!(Weak::weak_count(&w), Some(2));
assert_eq!(Weak::strong_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(2));
drop(w);
assert_eq!(Weak::strong_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(1));
let a2 = a.clone();
assert_eq!(Weak::strong_count(&w2), 2);
assert_eq!(Weak::weak_count(&w2), Some(1));
drop(a2);
drop(a);
assert_eq!(Weak::strong_count(&w2), 0);
assert_eq!(Weak::weak_count(&w2), Some(1));
drop(w2);
}
#[test]
fn try_unwrap() {
let x = Arc::new(3);
assert_eq!(Arc::try_unwrap(x), Ok(3));
let x = Arc::new(4);
let _y = x.clone();
assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4)));
let x = Arc::new(5);
let _w = Arc::downgrade(&x);
assert_eq!(Arc::try_unwrap(x), Ok(5));
}
#[test]
fn into_from_raw() {
let x = Arc::new(box "hello");
let y = x.clone();
let x_ptr = Arc::into_raw(x);
drop(y);
unsafe {
assert_eq!(**x_ptr, "hello");
let x = Arc::from_raw(x_ptr);
assert_eq!(**x, "hello");
assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello"));
}
}
#[test]
fn test_into_from_raw_unsized() {
use std::fmt::Display;
use std::string::ToString;
let arc: Arc<str> = Arc::from("foo");
let ptr = Arc::into_raw(arc.clone());
let arc2 = unsafe { Arc::from_raw(ptr) };
assert_eq!(unsafe { &*ptr }, "foo");
assert_eq!(arc, arc2);
let arc: Arc<dyn Display> = Arc::new(123);
let ptr = Arc::into_raw(arc.clone());
let arc2 = unsafe { Arc::from_raw(ptr) };
assert_eq!(unsafe { &*ptr }.to_string(), "123");
assert_eq!(arc2.to_string(), "123");
}
#[test]
fn test_cowarc_clone_make_mut() {
let mut cow0 = Arc::new(75);
let mut cow1 = cow0.clone();
let mut cow2 = cow1.clone();
assert!(75 == *Arc::make_mut(&mut cow0));
assert!(75 == *Arc::make_mut(&mut cow1));
assert!(75 == *Arc::make_mut(&mut cow2));
*Arc::make_mut(&mut cow0) += 1;
*Arc::make_mut(&mut cow1) += 2;
*Arc::make_mut(&mut cow2) += 3;
assert!(76 == *cow0);
assert!(77 == *cow1);
assert!(78 == *cow2);
// none should point to the same backing memory
assert!(*cow0 != *cow1);
assert!(*cow0 != *cow2);
assert!(*cow1 != *cow2);
}
#[test]
fn test_cowarc_clone_unique2() {
let mut cow0 = Arc::new(75);
let cow1 = cow0.clone();
let cow2 = cow1.clone();
assert!(75 == *cow0);
assert!(75 == *cow1);
assert!(75 == *cow2);
*Arc::make_mut(&mut cow0) += 1;
assert!(76 == *cow0);
assert!(75 == *cow1);
assert!(75 == *cow2);
// cow1 and cow2 should share the same contents
// cow0 should have a unique reference
assert!(*cow0 != *cow1);
assert!(*cow0 != *cow2);
assert!(*cow1 == *cow2);
}
#[test]
fn test_cowarc_clone_weak() {
let mut cow0 = Arc::new(75);
let cow1_weak = Arc::downgrade(&cow0);
assert!(75 == *cow0);
assert!(75 == *cow1_weak.upgrade().unwrap());
*Arc::make_mut(&mut cow0) += 1;
assert!(76 == *cow0);
assert!(cow1_weak.upgrade().is_none());
}
#[test]
fn test_live() {
let x = Arc::new(5);
let y = Arc::downgrade(&x);
assert!(y.upgrade().is_some());
}
#[test]
fn test_dead() {
let x = Arc::new(5);
let y = Arc::downgrade(&x);
drop(x);
assert!(y.upgrade().is_none());
}
#[test]
fn weak_self_cyclic() {
struct Cycle {
x: Mutex<Option<Weak<Cycle>>>,
}
let a = Arc::new(Cycle { x: Mutex::new(None) });
let b = Arc::downgrade(&a.clone());
*a.x.lock().unwrap() = Some(b);
// hopefully we don't double-free (or leak)...
}
#[test]
fn drop_arc() {
let mut canary = atomic::AtomicUsize::new(0);
let x = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize));
drop(x);
assert!(canary.load(Acquire) == 1);
}
#[test]
fn drop_arc_weak() {
let mut canary = atomic::AtomicUsize::new(0);
let arc = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize));
let arc_weak = Arc::downgrade(&arc);
assert!(canary.load(Acquire) == 0);
drop(arc);
assert!(canary.load(Acquire) == 1);
drop(arc_weak);
}
#[test]
fn test_strong_count() {
let a = Arc::new(0);
assert!(Arc::strong_count(&a) == 1);
let w = Arc::downgrade(&a);
assert!(Arc::strong_count(&a) == 1);
let b = w.upgrade().expect("");
assert!(Arc::strong_count(&b) == 2);
assert!(Arc::strong_count(&a) == 2);
drop(w);
drop(a);
assert!(Arc::strong_count(&b) == 1);
let c = b.clone();
assert!(Arc::strong_count(&b) == 2);
assert!(Arc::strong_count(&c) == 2);
}
#[test]
fn test_weak_count() {
let a = Arc::new(0);
assert!(Arc::strong_count(&a) == 1);
assert!(Arc::weak_count(&a) == 0);
let w = Arc::downgrade(&a);
assert!(Arc::strong_count(&a) == 1);
assert!(Arc::weak_count(&a) == 1);
let x = w.clone();
assert!(Arc::weak_count(&a) == 2);
drop(w);
drop(x);
assert!(Arc::strong_count(&a) == 1);
assert!(Arc::weak_count(&a) == 0);
let c = a.clone();
assert!(Arc::strong_count(&a) == 2);
assert!(Arc::weak_count(&a) == 0);
let d = Arc::downgrade(&c);
assert!(Arc::weak_count(&c) == 1);
assert!(Arc::strong_count(&c) == 2);
drop(a);
drop(c);
drop(d);
}
#[test]
fn show_arc() {
let a = Arc::new(5);
assert_eq!(format!("{:?}", a), "5");
}
// Make sure deriving works with Arc<T>
#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Debug, Default)]
struct Foo {
inner: Arc<i32>,
}
#[test]
fn test_unsized() {
let x: Arc<[i32]> = Arc::new([1, 2, 3]);
assert_eq!(format!("{:?}", x), "[1, 2, 3]");
let y = Arc::downgrade(&x.clone());
drop(x);
assert!(y.upgrade().is_none());
}
#[test]
fn test_from_owned() {
let foo = 123;
let foo_arc = Arc::from(foo);
assert!(123 == *foo_arc);
}
#[test]
fn test_new_weak() {
let foo: Weak<usize> = Weak::new();
assert!(foo.upgrade().is_none());
}
#[test]
fn test_ptr_eq() {
let five = Arc::new(5);
let same_five = five.clone();
let other_five = Arc::new(5);
assert!(Arc::ptr_eq(&five, &same_five));
assert!(!Arc::ptr_eq(&five, &other_five));
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
#[cfg(not(miri))] // Miri does not support threads
fn test_weak_count_locked() {
let mut a = Arc::new(atomic::AtomicBool::new(false));
let a2 = a.clone();
let t = thread::spawn(move || {
for _i in 0..1000000 {
Arc::get_mut(&mut a);
}
a.store(true, SeqCst);
});
while !a2.load(SeqCst) {
let n = Arc::weak_count(&a2);
assert!(n < 2, "bad weak count: {}", n);
}
t.join().unwrap();
}
#[test]
fn test_from_str() {
let r: Arc<str> = Arc::from("foo");
assert_eq!(&r[..], "foo");
}
#[test]
fn test_copy_from_slice() {
let s: &[u32] = &[1, 2, 3];
let r: Arc<[u32]> = Arc::from(s);
assert_eq!(&r[..], [1, 2, 3]);
}
#[test]
fn test_clone_from_slice() {
#[derive(Clone, Debug, Eq, PartialEq)]
struct X(u32);
let s: &[X] = &[X(1), X(2), X(3)];
let r: Arc<[X]> = Arc::from(s);
assert_eq!(&r[..], s);
}
#[test]
#[should_panic]
fn test_clone_from_slice_panic() {
use std::string::{String, ToString};
struct Fail(u32, String);
impl Clone for Fail {
fn clone(&self) -> Fail {
if self.0 == 2 {
panic!();
}
Fail(self.0, self.1.clone())
}
}
let s: &[Fail] = &[
Fail(0, "foo".to_string()),
Fail(1, "bar".to_string()),
Fail(2, "baz".to_string()),
];
// Should panic, but not cause memory corruption
let _r: Arc<[Fail]> = Arc::from(s);
}
#[test]
fn test_from_box() {
let b: Box<u32> = box 123;
let r: Arc<u32> = Arc::from(b);
assert_eq!(*r, 123);
}
#[test]
fn test_from_box_str() {
use std::string::String;
let s = String::from("foo").into_boxed_str();
let r: Arc<str> = Arc::from(s);
assert_eq!(&r[..], "foo");
}
#[test]
fn test_from_box_slice() {
let s = vec![1, 2, 3].into_boxed_slice();
let r: Arc<[u32]> = Arc::from(s);
assert_eq!(&r[..], [1, 2, 3]);
}
#[test]
fn test_from_box_trait() {
use std::fmt::Display;
use std::string::ToString;
let b: Box<dyn Display> = box 123;
let r: Arc<dyn Display> = Arc::from(b);
assert_eq!(r.to_string(), "123");
}
#[test]
fn test_from_box_trait_zero_sized() {
use std::fmt::Debug;
let b: Box<dyn Debug> = box ();
let r: Arc<dyn Debug> = Arc::from(b);
assert_eq!(format!("{:?}", r), "()");
}
#[test]
fn test_from_vec() {
let v = vec![1, 2, 3];
let r: Arc<[u32]> = Arc::from(v);
assert_eq!(&r[..], [1, 2, 3]);
}
#[test]
fn test_downcast() {
use std::any::Any;
let r1: Arc<dyn Any + Send + Sync> = Arc::new(i32::max_value());
let r2: Arc<dyn Any + Send + Sync> = Arc::new("abc");
assert!(r1.clone().downcast::<u32>().is_err());
let r1i32 = r1.downcast::<i32>();
assert!(r1i32.is_ok());
assert_eq!(r1i32.unwrap(), Arc::new(i32::max_value()));
assert!(r2.clone().downcast::<i32>().is_err());
let r2str = r2.downcast::<&'static str>();
assert!(r2str.is_ok());
assert_eq!(r2str.unwrap(), Arc::new("abc"));
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> borrow::Borrow<T> for Arc<T> {
fn borrow(&self) -> &T {

480
src/liballoc/sync/tests.rs Normal file
View File

@ -0,0 +1,480 @@
use super::*;
use std::boxed::Box;
use std::clone::Clone;
use std::sync::mpsc::channel;
use std::mem::drop;
use std::ops::Drop;
use std::option::Option::{self, None, Some};
use std::sync::atomic::{self, Ordering::{Acquire, SeqCst}};
use std::thread;
use std::sync::Mutex;
use std::convert::From;
use crate::vec::Vec;
struct Canary(*mut atomic::AtomicUsize);
impl Drop for Canary {
fn drop(&mut self) {
unsafe {
match *self {
Canary(c) => {
(*c).fetch_add(1, SeqCst);
}
}
}
}
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
#[cfg(not(miri))] // Miri does not support threads
fn manually_share_arc() {
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let arc_v = Arc::new(v);
let (tx, rx) = channel();
let _t = thread::spawn(move || {
let arc_v: Arc<Vec<i32>> = rx.recv().unwrap();
assert_eq!((*arc_v)[3], 4);
});
tx.send(arc_v.clone()).unwrap();
assert_eq!((*arc_v)[2], 3);
assert_eq!((*arc_v)[4], 5);
}
#[test]
fn test_arc_get_mut() {
let mut x = Arc::new(3);
*Arc::get_mut(&mut x).unwrap() = 4;
assert_eq!(*x, 4);
let y = x.clone();
assert!(Arc::get_mut(&mut x).is_none());
drop(y);
assert!(Arc::get_mut(&mut x).is_some());
let _w = Arc::downgrade(&x);
assert!(Arc::get_mut(&mut x).is_none());
}
#[test]
fn weak_counts() {
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), None);
assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
let a = Arc::new(0);
let w = Arc::downgrade(&a);
assert_eq!(Weak::strong_count(&w), 1);
assert_eq!(Weak::weak_count(&w), Some(1));
let w2 = w.clone();
assert_eq!(Weak::strong_count(&w), 1);
assert_eq!(Weak::weak_count(&w), Some(2));
assert_eq!(Weak::strong_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(2));
drop(w);
assert_eq!(Weak::strong_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(1));
let a2 = a.clone();
assert_eq!(Weak::strong_count(&w2), 2);
assert_eq!(Weak::weak_count(&w2), Some(1));
drop(a2);
drop(a);
assert_eq!(Weak::strong_count(&w2), 0);
assert_eq!(Weak::weak_count(&w2), Some(1));
drop(w2);
}
#[test]
fn try_unwrap() {
let x = Arc::new(3);
assert_eq!(Arc::try_unwrap(x), Ok(3));
let x = Arc::new(4);
let _y = x.clone();
assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4)));
let x = Arc::new(5);
let _w = Arc::downgrade(&x);
assert_eq!(Arc::try_unwrap(x), Ok(5));
}
#[test]
fn into_from_raw() {
let x = Arc::new(box "hello");
let y = x.clone();
let x_ptr = Arc::into_raw(x);
drop(y);
unsafe {
assert_eq!(**x_ptr, "hello");
let x = Arc::from_raw(x_ptr);
assert_eq!(**x, "hello");
assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello"));
}
}
#[test]
fn test_into_from_raw_unsized() {
use std::fmt::Display;
use std::string::ToString;
let arc: Arc<str> = Arc::from("foo");
let ptr = Arc::into_raw(arc.clone());
let arc2 = unsafe { Arc::from_raw(ptr) };
assert_eq!(unsafe { &*ptr }, "foo");
assert_eq!(arc, arc2);
let arc: Arc<dyn Display> = Arc::new(123);
let ptr = Arc::into_raw(arc.clone());
let arc2 = unsafe { Arc::from_raw(ptr) };
assert_eq!(unsafe { &*ptr }.to_string(), "123");
assert_eq!(arc2.to_string(), "123");
}
#[test]
fn test_cowarc_clone_make_mut() {
let mut cow0 = Arc::new(75);
let mut cow1 = cow0.clone();
let mut cow2 = cow1.clone();
assert!(75 == *Arc::make_mut(&mut cow0));
assert!(75 == *Arc::make_mut(&mut cow1));
assert!(75 == *Arc::make_mut(&mut cow2));
*Arc::make_mut(&mut cow0) += 1;
*Arc::make_mut(&mut cow1) += 2;
*Arc::make_mut(&mut cow2) += 3;
assert!(76 == *cow0);
assert!(77 == *cow1);
assert!(78 == *cow2);
// none should point to the same backing memory
assert!(*cow0 != *cow1);
assert!(*cow0 != *cow2);
assert!(*cow1 != *cow2);
}
#[test]
fn test_cowarc_clone_unique2() {
let mut cow0 = Arc::new(75);
let cow1 = cow0.clone();
let cow2 = cow1.clone();
assert!(75 == *cow0);
assert!(75 == *cow1);
assert!(75 == *cow2);
*Arc::make_mut(&mut cow0) += 1;
assert!(76 == *cow0);
assert!(75 == *cow1);
assert!(75 == *cow2);
// cow1 and cow2 should share the same contents
// cow0 should have a unique reference
assert!(*cow0 != *cow1);
assert!(*cow0 != *cow2);
assert!(*cow1 == *cow2);
}
#[test]
fn test_cowarc_clone_weak() {
let mut cow0 = Arc::new(75);
let cow1_weak = Arc::downgrade(&cow0);
assert!(75 == *cow0);
assert!(75 == *cow1_weak.upgrade().unwrap());
*Arc::make_mut(&mut cow0) += 1;
assert!(76 == *cow0);
assert!(cow1_weak.upgrade().is_none());
}
#[test]
fn test_live() {
let x = Arc::new(5);
let y = Arc::downgrade(&x);
assert!(y.upgrade().is_some());
}
#[test]
fn test_dead() {
let x = Arc::new(5);
let y = Arc::downgrade(&x);
drop(x);
assert!(y.upgrade().is_none());
}
#[test]
fn weak_self_cyclic() {
struct Cycle {
x: Mutex<Option<Weak<Cycle>>>,
}
let a = Arc::new(Cycle { x: Mutex::new(None) });
let b = Arc::downgrade(&a.clone());
*a.x.lock().unwrap() = Some(b);
// hopefully we don't double-free (or leak)...
}
#[test]
fn drop_arc() {
let mut canary = atomic::AtomicUsize::new(0);
let x = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize));
drop(x);
assert!(canary.load(Acquire) == 1);
}
#[test]
fn drop_arc_weak() {
let mut canary = atomic::AtomicUsize::new(0);
let arc = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize));
let arc_weak = Arc::downgrade(&arc);
assert!(canary.load(Acquire) == 0);
drop(arc);
assert!(canary.load(Acquire) == 1);
drop(arc_weak);
}
#[test]
fn test_strong_count() {
let a = Arc::new(0);
assert!(Arc::strong_count(&a) == 1);
let w = Arc::downgrade(&a);
assert!(Arc::strong_count(&a) == 1);
let b = w.upgrade().expect("");
assert!(Arc::strong_count(&b) == 2);
assert!(Arc::strong_count(&a) == 2);
drop(w);
drop(a);
assert!(Arc::strong_count(&b) == 1);
let c = b.clone();
assert!(Arc::strong_count(&b) == 2);
assert!(Arc::strong_count(&c) == 2);
}
#[test]
fn test_weak_count() {
let a = Arc::new(0);
assert!(Arc::strong_count(&a) == 1);
assert!(Arc::weak_count(&a) == 0);
let w = Arc::downgrade(&a);
assert!(Arc::strong_count(&a) == 1);
assert!(Arc::weak_count(&a) == 1);
let x = w.clone();
assert!(Arc::weak_count(&a) == 2);
drop(w);
drop(x);
assert!(Arc::strong_count(&a) == 1);
assert!(Arc::weak_count(&a) == 0);
let c = a.clone();
assert!(Arc::strong_count(&a) == 2);
assert!(Arc::weak_count(&a) == 0);
let d = Arc::downgrade(&c);
assert!(Arc::weak_count(&c) == 1);
assert!(Arc::strong_count(&c) == 2);
drop(a);
drop(c);
drop(d);
}
#[test]
fn show_arc() {
let a = Arc::new(5);
assert_eq!(format!("{:?}", a), "5");
}
// Make sure deriving works with Arc<T>
#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Debug, Default)]
struct Foo {
inner: Arc<i32>,
}
#[test]
fn test_unsized() {
let x: Arc<[i32]> = Arc::new([1, 2, 3]);
assert_eq!(format!("{:?}", x), "[1, 2, 3]");
let y = Arc::downgrade(&x.clone());
drop(x);
assert!(y.upgrade().is_none());
}
#[test]
fn test_from_owned() {
let foo = 123;
let foo_arc = Arc::from(foo);
assert!(123 == *foo_arc);
}
#[test]
fn test_new_weak() {
let foo: Weak<usize> = Weak::new();
assert!(foo.upgrade().is_none());
}
#[test]
fn test_ptr_eq() {
let five = Arc::new(5);
let same_five = five.clone();
let other_five = Arc::new(5);
assert!(Arc::ptr_eq(&five, &same_five));
assert!(!Arc::ptr_eq(&five, &other_five));
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
#[cfg(not(miri))] // Miri does not support threads
fn test_weak_count_locked() {
let mut a = Arc::new(atomic::AtomicBool::new(false));
let a2 = a.clone();
let t = thread::spawn(move || {
for _i in 0..1000000 {
Arc::get_mut(&mut a);
}
a.store(true, SeqCst);
});
while !a2.load(SeqCst) {
let n = Arc::weak_count(&a2);
assert!(n < 2, "bad weak count: {}", n);
}
t.join().unwrap();
}
#[test]
fn test_from_str() {
let r: Arc<str> = Arc::from("foo");
assert_eq!(&r[..], "foo");
}
#[test]
fn test_copy_from_slice() {
let s: &[u32] = &[1, 2, 3];
let r: Arc<[u32]> = Arc::from(s);
assert_eq!(&r[..], [1, 2, 3]);
}
#[test]
fn test_clone_from_slice() {
#[derive(Clone, Debug, Eq, PartialEq)]
struct X(u32);
let s: &[X] = &[X(1), X(2), X(3)];
let r: Arc<[X]> = Arc::from(s);
assert_eq!(&r[..], s);
}
#[test]
#[should_panic]
fn test_clone_from_slice_panic() {
use std::string::{String, ToString};
struct Fail(u32, String);
impl Clone for Fail {
fn clone(&self) -> Fail {
if self.0 == 2 {
panic!();
}
Fail(self.0, self.1.clone())
}
}
let s: &[Fail] = &[
Fail(0, "foo".to_string()),
Fail(1, "bar".to_string()),
Fail(2, "baz".to_string()),
];
// Should panic, but not cause memory corruption
let _r: Arc<[Fail]> = Arc::from(s);
}
#[test]
fn test_from_box() {
let b: Box<u32> = box 123;
let r: Arc<u32> = Arc::from(b);
assert_eq!(*r, 123);
}
#[test]
fn test_from_box_str() {
use std::string::String;
let s = String::from("foo").into_boxed_str();
let r: Arc<str> = Arc::from(s);
assert_eq!(&r[..], "foo");
}
#[test]
fn test_from_box_slice() {
let s = vec![1, 2, 3].into_boxed_slice();
let r: Arc<[u32]> = Arc::from(s);
assert_eq!(&r[..], [1, 2, 3]);
}
#[test]
fn test_from_box_trait() {
use std::fmt::Display;
use std::string::ToString;
let b: Box<dyn Display> = box 123;
let r: Arc<dyn Display> = Arc::from(b);
assert_eq!(r.to_string(), "123");
}
#[test]
fn test_from_box_trait_zero_sized() {
use std::fmt::Debug;
let b: Box<dyn Debug> = box ();
let r: Arc<dyn Debug> = Arc::from(b);
assert_eq!(format!("{:?}", r), "()");
}
#[test]
fn test_from_vec() {
let v = vec![1, 2, 3];
let r: Arc<[u32]> = Arc::from(v);
assert_eq!(&r[..], [1, 2, 3]);
}
#[test]
fn test_downcast() {
use std::any::Any;
let r1: Arc<dyn Any + Send + Sync> = Arc::new(i32::max_value());
let r2: Arc<dyn Any + Send + Sync> = Arc::new("abc");
assert!(r1.clone().downcast::<u32>().is_err());
let r1i32 = r1.downcast::<i32>();
assert!(r1i32.is_ok());
assert_eq!(r1i32.unwrap(), Arc::new(i32::max_value()));
assert!(r2.clone().downcast::<i32>().is_err());
let r2str = r2.downcast::<&'static str>();
assert!(r2str.is_ok());
assert_eq!(r2str.unwrap(), Arc::new("abc"));
}

View File

@ -1,11 +1,9 @@
//! Tidy check to ensure `#[test]` and `#[bench]` are not used directly inside
//! `libcore` or `liballoc`.
//! Tidy check to ensure `#[test]` and `#[bench]` are not used directly inside `libcore`.
//!
//! `#![no_std]` libraries cannot be tested directly due to duplicating lang
//! items. All tests and benchmarks must be written externally in `libcore/{tests,benches}`
//! or `liballoc/{tests,benches}`.
//! `#![no_core]` libraries cannot be tested directly due to duplicating lang
//! items. All tests and benchmarks must be written externally in `libcore/{tests,benches}`.
//!
//! Outside of libcore and liballoc tests and benchmarks should be outlined into separate files
//! Outside of libcore tests and benchmarks should be outlined into separate files
//! named `tests.rs` or `benches.rs`, or directories named `tests` or `benches` unconfigured
//! during normal build.
@ -13,22 +11,12 @@ use std::path::Path;
pub fn check(root_path: &Path, bad: &mut bool) {
let libcore = &root_path.join("libcore");
let liballoc = &root_path.join("liballoc");
let libcore_tests = &root_path.join("libcore/tests");
let liballoc_tests = &root_path.join("liballoc/tests");
let libcore_benches = &root_path.join("libcore/benches");
let liballoc_benches = &root_path.join("liballoc/benches");
let is_core_or_alloc = |path: &Path| {
let is_core = path.starts_with(libcore) &&
!(path.starts_with(libcore_tests) || path.starts_with(libcore_benches));
let is_alloc = path.starts_with(liballoc) &&
!(path.starts_with(liballoc_tests) || path.starts_with(liballoc_benches));
is_core || is_alloc
let is_core = |path: &Path| {
path.starts_with(libcore) &&
!(path.starts_with(libcore_tests) || path.starts_with(libcore_benches))
};
let fixme = [
"liballoc",
"libstd",
];
let mut skip = |path: &Path| {
let file_name = path.file_name().unwrap_or_default();
@ -36,12 +24,12 @@ pub fn check(root_path: &Path, bad: &mut bool) {
super::filter_dirs(path) ||
path.ends_with("src/test") ||
path.ends_with("src/doc") ||
(file_name == "tests" || file_name == "benches") && !is_core_or_alloc(path) ||
fixme.iter().any(|p| path.ends_with(p))
path.ends_with("src/libstd") || // FIXME?
(file_name == "tests" || file_name == "benches") && !is_core(path)
} else {
let extension = path.extension().unwrap_or_default();
extension != "rs" ||
(file_name == "tests.rs" || file_name == "benches.rs") && !is_core_or_alloc(path)
(file_name == "tests.rs" || file_name == "benches.rs") && !is_core(path)
}
};
@ -51,7 +39,6 @@ pub fn check(root_path: &Path, bad: &mut bool) {
&mut |entry, contents| {
let path = entry.path();
let is_libcore = path.starts_with(libcore);
let is_liballoc = path.starts_with(liballoc);
for (i, line) in contents.lines().enumerate() {
let line = line.trim();
let is_test = || line.contains("#[test]") && !line.contains("`#[test]");
@ -60,9 +47,6 @@ pub fn check(root_path: &Path, bad: &mut bool) {
let explanation = if is_libcore {
"libcore unit tests and benchmarks must be placed into \
`libcore/tests` or `libcore/benches`"
} else if is_liballoc {
"liballoc unit tests and benchmarks must be placed into \
`liballoc/tests` or `liballoc/benches`"
} else {
"unit tests and benchmarks must be placed into \
separate files or directories named \