1
Fork 0

std: move "mod tests/benches" to separate files

Also doing fmt inplace as requested.
This commit is contained in:
Lzu Tao 2020-08-27 13:45:01 +00:00
parent db6cbfc49c
commit a4e926daee
120 changed files with 16569 additions and 16699 deletions

View file

@ -66,6 +66,9 @@
#![unstable(feature = "backtrace", issue = "53487")]
#[cfg(test)]
mod tests;
// NB: A note on resolution of a backtrace:
//
// Backtraces primarily happen in two steps, one is where we actually capture
@ -438,55 +441,3 @@ impl RawFrame {
}
}
}
#[test]
fn test_debug() {
let backtrace = Backtrace {
inner: Inner::Captured(Mutex::new(Capture {
actual_start: 1,
resolved: true,
frames: vec![
BacktraceFrame {
frame: RawFrame::Fake,
symbols: vec![BacktraceSymbol {
name: Some(b"std::backtrace::Backtrace::create".to_vec()),
filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())),
lineno: Some(100),
}],
},
BacktraceFrame {
frame: RawFrame::Fake,
symbols: vec![BacktraceSymbol {
name: Some(b"__rust_maybe_catch_panic".to_vec()),
filename: None,
lineno: None,
}],
},
BacktraceFrame {
frame: RawFrame::Fake,
symbols: vec![
BacktraceSymbol {
name: Some(b"std::rt::lang_start_internal".to_vec()),
filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())),
lineno: Some(300),
},
BacktraceSymbol {
name: Some(b"std::rt::lang_start".to_vec()),
filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())),
lineno: Some(400),
},
],
},
],
})),
};
#[rustfmt::skip]
let expected = "Backtrace [\
\n { fn: \"__rust_maybe_catch_panic\" },\
\n { fn: \"std::rt::lang_start_internal\", file: \"rust/rt.rs\", line: 300 },\
\n { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },\
\n]";
assert_eq!(format!("{:#?}", backtrace), expected);
}

View file

@ -0,0 +1,53 @@
use super::*;
#[test]
fn test_debug() {
let backtrace = Backtrace {
inner: Inner::Captured(Mutex::new(Capture {
actual_start: 1,
resolved: true,
frames: vec![
BacktraceFrame {
frame: RawFrame::Fake,
symbols: vec![BacktraceSymbol {
name: Some(b"std::backtrace::Backtrace::create".to_vec()),
filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())),
lineno: Some(100),
}],
},
BacktraceFrame {
frame: RawFrame::Fake,
symbols: vec![BacktraceSymbol {
name: Some(b"__rust_maybe_catch_panic".to_vec()),
filename: None,
lineno: None,
}],
},
BacktraceFrame {
frame: RawFrame::Fake,
symbols: vec![
BacktraceSymbol {
name: Some(b"std::rt::lang_start_internal".to_vec()),
filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())),
lineno: Some(300),
},
BacktraceSymbol {
name: Some(b"std::rt::lang_start".to_vec()),
filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())),
lineno: Some(400),
},
],
},
],
})),
};
#[rustfmt::skip]
let expected = "Backtrace [\
\n { fn: \"__rust_maybe_catch_panic\" },\
\n { fn: \"std::rt::lang_start_internal\", file: \"rust/rt.rs\", line: 300 },\
\n { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },\
\n]";
assert_eq!(format!("{:#?}", backtrace), expected);
}

View file

@ -1,4 +1,5 @@
// ignore-tidy-filelength
#[cfg(test)]
mod tests;
use self::Entry::*;
@ -2754,933 +2755,3 @@ fn assert_covariance() {
d
}
}
#[cfg(test)]
mod test_map {
use super::Entry::{Occupied, Vacant};
use super::HashMap;
use super::RandomState;
use crate::cell::RefCell;
use rand::{thread_rng, Rng};
use realstd::collections::TryReserveError::*;
// https://github.com/rust-lang/rust/issues/62301
fn _assert_hashmap_is_unwind_safe() {
fn assert_unwind_safe<T: crate::panic::UnwindSafe>() {}
assert_unwind_safe::<HashMap<(), crate::cell::UnsafeCell<()>>>();
}
#[test]
fn test_zero_capacities() {
type HM = HashMap<i32, i32>;
let m = HM::new();
assert_eq!(m.capacity(), 0);
let m = HM::default();
assert_eq!(m.capacity(), 0);
let m = HM::with_hasher(RandomState::new());
assert_eq!(m.capacity(), 0);
let m = HM::with_capacity(0);
assert_eq!(m.capacity(), 0);
let m = HM::with_capacity_and_hasher(0, RandomState::new());
assert_eq!(m.capacity(), 0);
let mut m = HM::new();
m.insert(1, 1);
m.insert(2, 2);
m.remove(&1);
m.remove(&2);
m.shrink_to_fit();
assert_eq!(m.capacity(), 0);
let mut m = HM::new();
m.reserve(0);
assert_eq!(m.capacity(), 0);
}
#[test]
fn test_create_capacity_zero() {
let mut m = HashMap::with_capacity(0);
assert!(m.insert(1, 1).is_none());
assert!(m.contains_key(&1));
assert!(!m.contains_key(&0));
}
#[test]
fn test_insert() {
let mut m = HashMap::new();
assert_eq!(m.len(), 0);
assert!(m.insert(1, 2).is_none());
assert_eq!(m.len(), 1);
assert!(m.insert(2, 4).is_none());
assert_eq!(m.len(), 2);
assert_eq!(*m.get(&1).unwrap(), 2);
assert_eq!(*m.get(&2).unwrap(), 4);
}
#[test]
fn test_clone() {
let mut m = HashMap::new();
assert_eq!(m.len(), 0);
assert!(m.insert(1, 2).is_none());
assert_eq!(m.len(), 1);
assert!(m.insert(2, 4).is_none());
assert_eq!(m.len(), 2);
let m2 = m.clone();
assert_eq!(*m2.get(&1).unwrap(), 2);
assert_eq!(*m2.get(&2).unwrap(), 4);
assert_eq!(m2.len(), 2);
}
thread_local! { static DROP_VECTOR: RefCell<Vec<i32>> = RefCell::new(Vec::new()) }
#[derive(Hash, PartialEq, Eq)]
struct Droppable {
k: usize,
}
impl Droppable {
fn new(k: usize) -> Droppable {
DROP_VECTOR.with(|slot| {
slot.borrow_mut()[k] += 1;
});
Droppable { k }
}
}
impl Drop for Droppable {
fn drop(&mut self) {
DROP_VECTOR.with(|slot| {
slot.borrow_mut()[self.k] -= 1;
});
}
}
impl Clone for Droppable {
fn clone(&self) -> Droppable {
Droppable::new(self.k)
}
}
#[test]
fn test_drops() {
DROP_VECTOR.with(|slot| {
*slot.borrow_mut() = vec![0; 200];
});
{
let mut m = HashMap::new();
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 0);
}
});
for i in 0..100 {
let d1 = Droppable::new(i);
let d2 = Droppable::new(i + 100);
m.insert(d1, d2);
}
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 1);
}
});
for i in 0..50 {
let k = Droppable::new(i);
let v = m.remove(&k);
assert!(v.is_some());
DROP_VECTOR.with(|v| {
assert_eq!(v.borrow()[i], 1);
assert_eq!(v.borrow()[i + 100], 1);
});
}
DROP_VECTOR.with(|v| {
for i in 0..50 {
assert_eq!(v.borrow()[i], 0);
assert_eq!(v.borrow()[i + 100], 0);
}
for i in 50..100 {
assert_eq!(v.borrow()[i], 1);
assert_eq!(v.borrow()[i + 100], 1);
}
});
}
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 0);
}
});
}
#[test]
fn test_into_iter_drops() {
DROP_VECTOR.with(|v| {
*v.borrow_mut() = vec![0; 200];
});
let hm = {
let mut hm = HashMap::new();
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 0);
}
});
for i in 0..100 {
let d1 = Droppable::new(i);
let d2 = Droppable::new(i + 100);
hm.insert(d1, d2);
}
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 1);
}
});
hm
};
// By the way, ensure that cloning doesn't screw up the dropping.
drop(hm.clone());
{
let mut half = hm.into_iter().take(50);
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 1);
}
});
for _ in half.by_ref() {}
DROP_VECTOR.with(|v| {
let nk = (0..100).filter(|&i| v.borrow()[i] == 1).count();
let nv = (0..100).filter(|&i| v.borrow()[i + 100] == 1).count();
assert_eq!(nk, 50);
assert_eq!(nv, 50);
});
};
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 0);
}
});
}
#[test]
fn test_empty_remove() {
let mut m: HashMap<i32, bool> = HashMap::new();
assert_eq!(m.remove(&0), None);
}
#[test]
fn test_empty_entry() {
let mut m: HashMap<i32, bool> = HashMap::new();
match m.entry(0) {
Occupied(_) => panic!(),
Vacant(_) => {}
}
assert!(*m.entry(0).or_insert(true));
assert_eq!(m.len(), 1);
}
#[test]
fn test_empty_iter() {
let mut m: HashMap<i32, bool> = HashMap::new();
assert_eq!(m.drain().next(), None);
assert_eq!(m.keys().next(), None);
assert_eq!(m.values().next(), None);
assert_eq!(m.values_mut().next(), None);
assert_eq!(m.iter().next(), None);
assert_eq!(m.iter_mut().next(), None);
assert_eq!(m.len(), 0);
assert!(m.is_empty());
assert_eq!(m.into_iter().next(), None);
}
#[test]
fn test_lots_of_insertions() {
let mut m = HashMap::new();
// Try this a few times to make sure we never screw up the hashmap's
// internal state.
for _ in 0..10 {
assert!(m.is_empty());
for i in 1..1001 {
assert!(m.insert(i, i).is_none());
for j in 1..=i {
let r = m.get(&j);
assert_eq!(r, Some(&j));
}
for j in i + 1..1001 {
let r = m.get(&j);
assert_eq!(r, None);
}
}
for i in 1001..2001 {
assert!(!m.contains_key(&i));
}
// remove forwards
for i in 1..1001 {
assert!(m.remove(&i).is_some());
for j in 1..=i {
assert!(!m.contains_key(&j));
}
for j in i + 1..1001 {
assert!(m.contains_key(&j));
}
}
for i in 1..1001 {
assert!(!m.contains_key(&i));
}
for i in 1..1001 {
assert!(m.insert(i, i).is_none());
}
// remove backwards
for i in (1..1001).rev() {
assert!(m.remove(&i).is_some());
for j in i..1001 {
assert!(!m.contains_key(&j));
}
for j in 1..i {
assert!(m.contains_key(&j));
}
}
}
}
#[test]
fn test_find_mut() {
let mut m = HashMap::new();
assert!(m.insert(1, 12).is_none());
assert!(m.insert(2, 8).is_none());
assert!(m.insert(5, 14).is_none());
let new = 100;
match m.get_mut(&5) {
None => panic!(),
Some(x) => *x = new,
}
assert_eq!(m.get(&5), Some(&new));
}
#[test]
fn test_insert_overwrite() {
let mut m = HashMap::new();
assert!(m.insert(1, 2).is_none());
assert_eq!(*m.get(&1).unwrap(), 2);
assert!(!m.insert(1, 3).is_none());
assert_eq!(*m.get(&1).unwrap(), 3);
}
#[test]
fn test_insert_conflicts() {
let mut m = HashMap::with_capacity(4);
assert!(m.insert(1, 2).is_none());
assert!(m.insert(5, 3).is_none());
assert!(m.insert(9, 4).is_none());
assert_eq!(*m.get(&9).unwrap(), 4);
assert_eq!(*m.get(&5).unwrap(), 3);
assert_eq!(*m.get(&1).unwrap(), 2);
}
#[test]
fn test_conflict_remove() {
let mut m = HashMap::with_capacity(4);
assert!(m.insert(1, 2).is_none());
assert_eq!(*m.get(&1).unwrap(), 2);
assert!(m.insert(5, 3).is_none());
assert_eq!(*m.get(&1).unwrap(), 2);
assert_eq!(*m.get(&5).unwrap(), 3);
assert!(m.insert(9, 4).is_none());
assert_eq!(*m.get(&1).unwrap(), 2);
assert_eq!(*m.get(&5).unwrap(), 3);
assert_eq!(*m.get(&9).unwrap(), 4);
assert!(m.remove(&1).is_some());
assert_eq!(*m.get(&9).unwrap(), 4);
assert_eq!(*m.get(&5).unwrap(), 3);
}
#[test]
fn test_is_empty() {
let mut m = HashMap::with_capacity(4);
assert!(m.insert(1, 2).is_none());
assert!(!m.is_empty());
assert!(m.remove(&1).is_some());
assert!(m.is_empty());
}
#[test]
fn test_remove() {
let mut m = HashMap::new();
m.insert(1, 2);
assert_eq!(m.remove(&1), Some(2));
assert_eq!(m.remove(&1), None);
}
#[test]
fn test_remove_entry() {
let mut m = HashMap::new();
m.insert(1, 2);
assert_eq!(m.remove_entry(&1), Some((1, 2)));
assert_eq!(m.remove(&1), None);
}
#[test]
fn test_iterate() {
let mut m = HashMap::with_capacity(4);
for i in 0..32 {
assert!(m.insert(i, i * 2).is_none());
}
assert_eq!(m.len(), 32);
let mut observed: u32 = 0;
for (k, v) in &m {
assert_eq!(*v, *k * 2);
observed |= 1 << *k;
}
assert_eq!(observed, 0xFFFF_FFFF);
}
#[test]
fn test_keys() {
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: HashMap<_, _> = vec.into_iter().collect();
let keys: Vec<_> = map.keys().cloned().collect();
assert_eq!(keys.len(), 3);
assert!(keys.contains(&1));
assert!(keys.contains(&2));
assert!(keys.contains(&3));
}
#[test]
fn test_values() {
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: HashMap<_, _> = vec.into_iter().collect();
let values: Vec<_> = map.values().cloned().collect();
assert_eq!(values.len(), 3);
assert!(values.contains(&'a'));
assert!(values.contains(&'b'));
assert!(values.contains(&'c'));
}
#[test]
fn test_values_mut() {
let vec = vec![(1, 1), (2, 2), (3, 3)];
let mut map: HashMap<_, _> = vec.into_iter().collect();
for value in map.values_mut() {
*value = (*value) * 2
}
let values: Vec<_> = map.values().cloned().collect();
assert_eq!(values.len(), 3);
assert!(values.contains(&2));
assert!(values.contains(&4));
assert!(values.contains(&6));
}
#[test]
fn test_into_keys() {
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: HashMap<_, _> = vec.into_iter().collect();
let keys: Vec<_> = map.into_keys().collect();
assert_eq!(keys.len(), 3);
assert!(keys.contains(&1));
assert!(keys.contains(&2));
assert!(keys.contains(&3));
}
#[test]
fn test_into_values() {
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: HashMap<_, _> = vec.into_iter().collect();
let values: Vec<_> = map.into_values().collect();
assert_eq!(values.len(), 3);
assert!(values.contains(&'a'));
assert!(values.contains(&'b'));
assert!(values.contains(&'c'));
}
#[test]
fn test_find() {
let mut m = HashMap::new();
assert!(m.get(&1).is_none());
m.insert(1, 2);
match m.get(&1) {
None => panic!(),
Some(v) => assert_eq!(*v, 2),
}
}
#[test]
fn test_eq() {
let mut m1 = HashMap::new();
m1.insert(1, 2);
m1.insert(2, 3);
m1.insert(3, 4);
let mut m2 = HashMap::new();
m2.insert(1, 2);
m2.insert(2, 3);
assert!(m1 != m2);
m2.insert(3, 4);
assert_eq!(m1, m2);
}
#[test]
fn test_show() {
let mut map = HashMap::new();
let empty: HashMap<i32, i32> = HashMap::new();
map.insert(1, 2);
map.insert(3, 4);
let map_str = format!("{:?}", map);
assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}");
assert_eq!(format!("{:?}", empty), "{}");
}
#[test]
fn test_reserve_shrink_to_fit() {
let mut m = HashMap::new();
m.insert(0, 0);
m.remove(&0);
assert!(m.capacity() >= m.len());
for i in 0..128 {
m.insert(i, i);
}
m.reserve(256);
let usable_cap = m.capacity();
for i in 128..(128 + 256) {
m.insert(i, i);
assert_eq!(m.capacity(), usable_cap);
}
for i in 100..(128 + 256) {
assert_eq!(m.remove(&i), Some(i));
}
m.shrink_to_fit();
assert_eq!(m.len(), 100);
assert!(!m.is_empty());
assert!(m.capacity() >= m.len());
for i in 0..100 {
assert_eq!(m.remove(&i), Some(i));
}
m.shrink_to_fit();
m.insert(0, 0);
assert_eq!(m.len(), 1);
assert!(m.capacity() >= m.len());
assert_eq!(m.remove(&0), Some(0));
}
#[test]
fn test_from_iter() {
let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let map: HashMap<_, _> = xs.iter().cloned().collect();
for &(k, v) in &xs {
assert_eq!(map.get(&k), Some(&v));
}
assert_eq!(map.iter().len(), xs.len() - 1);
}
#[test]
fn test_size_hint() {
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let map: HashMap<_, _> = xs.iter().cloned().collect();
let mut iter = map.iter();
for _ in iter.by_ref().take(3) {}
assert_eq!(iter.size_hint(), (3, Some(3)));
}
#[test]
fn test_iter_len() {
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let map: HashMap<_, _> = xs.iter().cloned().collect();
let mut iter = map.iter();
for _ in iter.by_ref().take(3) {}
assert_eq!(iter.len(), 3);
}
#[test]
fn test_mut_size_hint() {
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let mut map: HashMap<_, _> = xs.iter().cloned().collect();
let mut iter = map.iter_mut();
for _ in iter.by_ref().take(3) {}
assert_eq!(iter.size_hint(), (3, Some(3)));
}
#[test]
fn test_iter_mut_len() {
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let mut map: HashMap<_, _> = xs.iter().cloned().collect();
let mut iter = map.iter_mut();
for _ in iter.by_ref().take(3) {}
assert_eq!(iter.len(), 3);
}
#[test]
fn test_index() {
let mut map = HashMap::new();
map.insert(1, 2);
map.insert(2, 1);
map.insert(3, 4);
assert_eq!(map[&2], 1);
}
#[test]
#[should_panic]
fn test_index_nonexistent() {
let mut map = HashMap::new();
map.insert(1, 2);
map.insert(2, 1);
map.insert(3, 4);
map[&4];
}
#[test]
fn test_entry() {
let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
let mut map: HashMap<_, _> = xs.iter().cloned().collect();
// Existing key (insert)
match map.entry(1) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
assert_eq!(view.get(), &10);
assert_eq!(view.insert(100), 10);
}
}
assert_eq!(map.get(&1).unwrap(), &100);
assert_eq!(map.len(), 6);
// Existing key (update)
match map.entry(2) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
let v = view.get_mut();
let new_v = (*v) * 10;
*v = new_v;
}
}
assert_eq!(map.get(&2).unwrap(), &200);
assert_eq!(map.len(), 6);
// Existing key (take)
match map.entry(3) {
Vacant(_) => unreachable!(),
Occupied(view) => {
assert_eq!(view.remove(), 30);
}
}
assert_eq!(map.get(&3), None);
assert_eq!(map.len(), 5);
// Inexistent key (insert)
match map.entry(10) {
Occupied(_) => unreachable!(),
Vacant(view) => {
assert_eq!(*view.insert(1000), 1000);
}
}
assert_eq!(map.get(&10).unwrap(), &1000);
assert_eq!(map.len(), 6);
}
#[test]
fn test_entry_take_doesnt_corrupt() {
#![allow(deprecated)] //rand
// Test for #19292
fn check(m: &HashMap<i32, ()>) {
for k in m.keys() {
assert!(m.contains_key(k), "{} is in keys() but not in the map?", k);
}
}
let mut m = HashMap::new();
let mut rng = thread_rng();
// Populate the map with some items.
for _ in 0..50 {
let x = rng.gen_range(-10, 10);
m.insert(x, ());
}
for _ in 0..1000 {
let x = rng.gen_range(-10, 10);
match m.entry(x) {
Vacant(_) => {}
Occupied(e) => {
e.remove();
}
}
check(&m);
}
}
#[test]
fn test_extend_ref() {
let mut a = HashMap::new();
a.insert(1, "one");
let mut b = HashMap::new();
b.insert(2, "two");
b.insert(3, "three");
a.extend(&b);
assert_eq!(a.len(), 3);
assert_eq!(a[&1], "one");
assert_eq!(a[&2], "two");
assert_eq!(a[&3], "three");
}
#[test]
fn test_capacity_not_less_than_len() {
let mut a = HashMap::new();
let mut item = 0;
for _ in 0..116 {
a.insert(item, 0);
item += 1;
}
assert!(a.capacity() > a.len());
let free = a.capacity() - a.len();
for _ in 0..free {
a.insert(item, 0);
item += 1;
}
assert_eq!(a.len(), a.capacity());
// Insert at capacity should cause allocation.
a.insert(item, 0);
assert!(a.capacity() > a.len());
}
#[test]
fn test_occupied_entry_key() {
let mut a = HashMap::new();
let key = "hello there";
let value = "value goes here";
assert!(a.is_empty());
a.insert(key.clone(), value.clone());
assert_eq!(a.len(), 1);
assert_eq!(a[key], value);
match a.entry(key.clone()) {
Vacant(_) => panic!(),
Occupied(e) => assert_eq!(key, *e.key()),
}
assert_eq!(a.len(), 1);
assert_eq!(a[key], value);
}
#[test]
fn test_vacant_entry_key() {
let mut a = HashMap::new();
let key = "hello there";
let value = "value goes here";
assert!(a.is_empty());
match a.entry(key.clone()) {
Occupied(_) => panic!(),
Vacant(e) => {
assert_eq!(key, *e.key());
e.insert(value.clone());
}
}
assert_eq!(a.len(), 1);
assert_eq!(a[key], value);
}
#[test]
fn test_retain() {
let mut map: HashMap<i32, i32> = (0..100).map(|x| (x, x * 10)).collect();
map.retain(|&k, _| k % 2 == 0);
assert_eq!(map.len(), 50);
assert_eq!(map[&2], 20);
assert_eq!(map[&4], 40);
assert_eq!(map[&6], 60);
}
#[test]
fn test_try_reserve() {
let mut empty_bytes: HashMap<u8, u8> = HashMap::new();
const MAX_USIZE: usize = usize::MAX;
if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) {
} else {
panic!("usize::MAX should trigger an overflow!");
}
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) {
} else {
panic!("usize::MAX / 8 should trigger an OOM!")
}
}
#[test]
fn test_raw_entry() {
use super::RawEntryMut::{Occupied, Vacant};
let xs = [(1i32, 10i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
let mut map: HashMap<_, _> = xs.iter().cloned().collect();
let compute_hash = |map: &HashMap<i32, i32>, k: i32| -> u64 {
use core::hash::{BuildHasher, Hash, Hasher};
let mut hasher = map.hasher().build_hasher();
k.hash(&mut hasher);
hasher.finish()
};
// Existing key (insert)
match map.raw_entry_mut().from_key(&1) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
assert_eq!(view.get(), &10);
assert_eq!(view.insert(100), 10);
}
}
let hash1 = compute_hash(&map, 1);
assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100));
assert_eq!(map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), (&1, &100));
assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), (&1, &100));
assert_eq!(map.len(), 6);
// Existing key (update)
match map.raw_entry_mut().from_key(&2) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
let v = view.get_mut();
let new_v = (*v) * 10;
*v = new_v;
}
}
let hash2 = compute_hash(&map, 2);
assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200));
assert_eq!(map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), (&2, &200));
assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), (&2, &200));
assert_eq!(map.len(), 6);
// Existing key (take)
let hash3 = compute_hash(&map, 3);
match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) {
Vacant(_) => unreachable!(),
Occupied(view) => {
assert_eq!(view.remove_entry(), (3, 30));
}
}
assert_eq!(map.raw_entry().from_key(&3), None);
assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None);
assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None);
assert_eq!(map.len(), 5);
// Nonexistent key (insert)
match map.raw_entry_mut().from_key(&10) {
Occupied(_) => unreachable!(),
Vacant(view) => {
assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000));
}
}
assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000));
assert_eq!(map.len(), 6);
// Ensure all lookup methods produce equivalent results.
for k in 0..12 {
let hash = compute_hash(&map, k);
let v = map.get(&k).cloned();
let kv = v.as_ref().map(|v| (&k, v));
assert_eq!(map.raw_entry().from_key(&k), kv);
assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv);
assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv);
match map.raw_entry_mut().from_key(&k) {
Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
Vacant(_) => assert_eq!(v, None),
}
match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) {
Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
Vacant(_) => assert_eq!(v, None),
}
match map.raw_entry_mut().from_hash(hash, |q| *q == k) {
Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
Vacant(_) => assert_eq!(v, None),
}
}
}
}

View file

@ -0,0 +1,926 @@
use super::Entry::{Occupied, Vacant};
use super::HashMap;
use super::RandomState;
use crate::cell::RefCell;
use rand::{thread_rng, Rng};
use realstd::collections::TryReserveError::*;
// https://github.com/rust-lang/rust/issues/62301
fn _assert_hashmap_is_unwind_safe() {
fn assert_unwind_safe<T: crate::panic::UnwindSafe>() {}
assert_unwind_safe::<HashMap<(), crate::cell::UnsafeCell<()>>>();
}
#[test]
fn test_zero_capacities() {
type HM = HashMap<i32, i32>;
let m = HM::new();
assert_eq!(m.capacity(), 0);
let m = HM::default();
assert_eq!(m.capacity(), 0);
let m = HM::with_hasher(RandomState::new());
assert_eq!(m.capacity(), 0);
let m = HM::with_capacity(0);
assert_eq!(m.capacity(), 0);
let m = HM::with_capacity_and_hasher(0, RandomState::new());
assert_eq!(m.capacity(), 0);
let mut m = HM::new();
m.insert(1, 1);
m.insert(2, 2);
m.remove(&1);
m.remove(&2);
m.shrink_to_fit();
assert_eq!(m.capacity(), 0);
let mut m = HM::new();
m.reserve(0);
assert_eq!(m.capacity(), 0);
}
#[test]
fn test_create_capacity_zero() {
let mut m = HashMap::with_capacity(0);
assert!(m.insert(1, 1).is_none());
assert!(m.contains_key(&1));
assert!(!m.contains_key(&0));
}
#[test]
fn test_insert() {
let mut m = HashMap::new();
assert_eq!(m.len(), 0);
assert!(m.insert(1, 2).is_none());
assert_eq!(m.len(), 1);
assert!(m.insert(2, 4).is_none());
assert_eq!(m.len(), 2);
assert_eq!(*m.get(&1).unwrap(), 2);
assert_eq!(*m.get(&2).unwrap(), 4);
}
#[test]
fn test_clone() {
let mut m = HashMap::new();
assert_eq!(m.len(), 0);
assert!(m.insert(1, 2).is_none());
assert_eq!(m.len(), 1);
assert!(m.insert(2, 4).is_none());
assert_eq!(m.len(), 2);
let m2 = m.clone();
assert_eq!(*m2.get(&1).unwrap(), 2);
assert_eq!(*m2.get(&2).unwrap(), 4);
assert_eq!(m2.len(), 2);
}
thread_local! { static DROP_VECTOR: RefCell<Vec<i32>> = RefCell::new(Vec::new()) }
#[derive(Hash, PartialEq, Eq)]
struct Droppable {
k: usize,
}
impl Droppable {
fn new(k: usize) -> Droppable {
DROP_VECTOR.with(|slot| {
slot.borrow_mut()[k] += 1;
});
Droppable { k }
}
}
impl Drop for Droppable {
fn drop(&mut self) {
DROP_VECTOR.with(|slot| {
slot.borrow_mut()[self.k] -= 1;
});
}
}
impl Clone for Droppable {
fn clone(&self) -> Droppable {
Droppable::new(self.k)
}
}
#[test]
fn test_drops() {
DROP_VECTOR.with(|slot| {
*slot.borrow_mut() = vec![0; 200];
});
{
let mut m = HashMap::new();
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 0);
}
});
for i in 0..100 {
let d1 = Droppable::new(i);
let d2 = Droppable::new(i + 100);
m.insert(d1, d2);
}
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 1);
}
});
for i in 0..50 {
let k = Droppable::new(i);
let v = m.remove(&k);
assert!(v.is_some());
DROP_VECTOR.with(|v| {
assert_eq!(v.borrow()[i], 1);
assert_eq!(v.borrow()[i + 100], 1);
});
}
DROP_VECTOR.with(|v| {
for i in 0..50 {
assert_eq!(v.borrow()[i], 0);
assert_eq!(v.borrow()[i + 100], 0);
}
for i in 50..100 {
assert_eq!(v.borrow()[i], 1);
assert_eq!(v.borrow()[i + 100], 1);
}
});
}
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 0);
}
});
}
#[test]
fn test_into_iter_drops() {
DROP_VECTOR.with(|v| {
*v.borrow_mut() = vec![0; 200];
});
let hm = {
let mut hm = HashMap::new();
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 0);
}
});
for i in 0..100 {
let d1 = Droppable::new(i);
let d2 = Droppable::new(i + 100);
hm.insert(d1, d2);
}
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 1);
}
});
hm
};
// By the way, ensure that cloning doesn't screw up the dropping.
drop(hm.clone());
{
let mut half = hm.into_iter().take(50);
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 1);
}
});
for _ in half.by_ref() {}
DROP_VECTOR.with(|v| {
let nk = (0..100).filter(|&i| v.borrow()[i] == 1).count();
let nv = (0..100).filter(|&i| v.borrow()[i + 100] == 1).count();
assert_eq!(nk, 50);
assert_eq!(nv, 50);
});
};
DROP_VECTOR.with(|v| {
for i in 0..200 {
assert_eq!(v.borrow()[i], 0);
}
});
}
#[test]
fn test_empty_remove() {
let mut m: HashMap<i32, bool> = HashMap::new();
assert_eq!(m.remove(&0), None);
}
#[test]
fn test_empty_entry() {
let mut m: HashMap<i32, bool> = HashMap::new();
match m.entry(0) {
Occupied(_) => panic!(),
Vacant(_) => {}
}
assert!(*m.entry(0).or_insert(true));
assert_eq!(m.len(), 1);
}
#[test]
fn test_empty_iter() {
let mut m: HashMap<i32, bool> = HashMap::new();
assert_eq!(m.drain().next(), None);
assert_eq!(m.keys().next(), None);
assert_eq!(m.values().next(), None);
assert_eq!(m.values_mut().next(), None);
assert_eq!(m.iter().next(), None);
assert_eq!(m.iter_mut().next(), None);
assert_eq!(m.len(), 0);
assert!(m.is_empty());
assert_eq!(m.into_iter().next(), None);
}
#[test]
fn test_lots_of_insertions() {
let mut m = HashMap::new();
// Try this a few times to make sure we never screw up the hashmap's
// internal state.
for _ in 0..10 {
assert!(m.is_empty());
for i in 1..1001 {
assert!(m.insert(i, i).is_none());
for j in 1..=i {
let r = m.get(&j);
assert_eq!(r, Some(&j));
}
for j in i + 1..1001 {
let r = m.get(&j);
assert_eq!(r, None);
}
}
for i in 1001..2001 {
assert!(!m.contains_key(&i));
}
// remove forwards
for i in 1..1001 {
assert!(m.remove(&i).is_some());
for j in 1..=i {
assert!(!m.contains_key(&j));
}
for j in i + 1..1001 {
assert!(m.contains_key(&j));
}
}
for i in 1..1001 {
assert!(!m.contains_key(&i));
}
for i in 1..1001 {
assert!(m.insert(i, i).is_none());
}
// remove backwards
for i in (1..1001).rev() {
assert!(m.remove(&i).is_some());
for j in i..1001 {
assert!(!m.contains_key(&j));
}
for j in 1..i {
assert!(m.contains_key(&j));
}
}
}
}
#[test]
fn test_find_mut() {
let mut m = HashMap::new();
assert!(m.insert(1, 12).is_none());
assert!(m.insert(2, 8).is_none());
assert!(m.insert(5, 14).is_none());
let new = 100;
match m.get_mut(&5) {
None => panic!(),
Some(x) => *x = new,
}
assert_eq!(m.get(&5), Some(&new));
}
#[test]
fn test_insert_overwrite() {
let mut m = HashMap::new();
assert!(m.insert(1, 2).is_none());
assert_eq!(*m.get(&1).unwrap(), 2);
assert!(!m.insert(1, 3).is_none());
assert_eq!(*m.get(&1).unwrap(), 3);
}
#[test]
fn test_insert_conflicts() {
let mut m = HashMap::with_capacity(4);
assert!(m.insert(1, 2).is_none());
assert!(m.insert(5, 3).is_none());
assert!(m.insert(9, 4).is_none());
assert_eq!(*m.get(&9).unwrap(), 4);
assert_eq!(*m.get(&5).unwrap(), 3);
assert_eq!(*m.get(&1).unwrap(), 2);
}
#[test]
fn test_conflict_remove() {
let mut m = HashMap::with_capacity(4);
assert!(m.insert(1, 2).is_none());
assert_eq!(*m.get(&1).unwrap(), 2);
assert!(m.insert(5, 3).is_none());
assert_eq!(*m.get(&1).unwrap(), 2);
assert_eq!(*m.get(&5).unwrap(), 3);
assert!(m.insert(9, 4).is_none());
assert_eq!(*m.get(&1).unwrap(), 2);
assert_eq!(*m.get(&5).unwrap(), 3);
assert_eq!(*m.get(&9).unwrap(), 4);
assert!(m.remove(&1).is_some());
assert_eq!(*m.get(&9).unwrap(), 4);
assert_eq!(*m.get(&5).unwrap(), 3);
}
#[test]
fn test_is_empty() {
let mut m = HashMap::with_capacity(4);
assert!(m.insert(1, 2).is_none());
assert!(!m.is_empty());
assert!(m.remove(&1).is_some());
assert!(m.is_empty());
}
#[test]
fn test_remove() {
let mut m = HashMap::new();
m.insert(1, 2);
assert_eq!(m.remove(&1), Some(2));
assert_eq!(m.remove(&1), None);
}
#[test]
fn test_remove_entry() {
let mut m = HashMap::new();
m.insert(1, 2);
assert_eq!(m.remove_entry(&1), Some((1, 2)));
assert_eq!(m.remove(&1), None);
}
#[test]
fn test_iterate() {
let mut m = HashMap::with_capacity(4);
for i in 0..32 {
assert!(m.insert(i, i * 2).is_none());
}
assert_eq!(m.len(), 32);
let mut observed: u32 = 0;
for (k, v) in &m {
assert_eq!(*v, *k * 2);
observed |= 1 << *k;
}
assert_eq!(observed, 0xFFFF_FFFF);
}
#[test]
fn test_keys() {
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: HashMap<_, _> = vec.into_iter().collect();
let keys: Vec<_> = map.keys().cloned().collect();
assert_eq!(keys.len(), 3);
assert!(keys.contains(&1));
assert!(keys.contains(&2));
assert!(keys.contains(&3));
}
#[test]
fn test_values() {
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: HashMap<_, _> = vec.into_iter().collect();
let values: Vec<_> = map.values().cloned().collect();
assert_eq!(values.len(), 3);
assert!(values.contains(&'a'));
assert!(values.contains(&'b'));
assert!(values.contains(&'c'));
}
#[test]
fn test_values_mut() {
let vec = vec![(1, 1), (2, 2), (3, 3)];
let mut map: HashMap<_, _> = vec.into_iter().collect();
for value in map.values_mut() {
*value = (*value) * 2
}
let values: Vec<_> = map.values().cloned().collect();
assert_eq!(values.len(), 3);
assert!(values.contains(&2));
assert!(values.contains(&4));
assert!(values.contains(&6));
}
#[test]
fn test_into_keys() {
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: HashMap<_, _> = vec.into_iter().collect();
let keys: Vec<_> = map.into_keys().collect();
assert_eq!(keys.len(), 3);
assert!(keys.contains(&1));
assert!(keys.contains(&2));
assert!(keys.contains(&3));
}
#[test]
fn test_into_values() {
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: HashMap<_, _> = vec.into_iter().collect();
let values: Vec<_> = map.into_values().collect();
assert_eq!(values.len(), 3);
assert!(values.contains(&'a'));
assert!(values.contains(&'b'));
assert!(values.contains(&'c'));
}
#[test]
fn test_find() {
let mut m = HashMap::new();
assert!(m.get(&1).is_none());
m.insert(1, 2);
match m.get(&1) {
None => panic!(),
Some(v) => assert_eq!(*v, 2),
}
}
#[test]
fn test_eq() {
let mut m1 = HashMap::new();
m1.insert(1, 2);
m1.insert(2, 3);
m1.insert(3, 4);
let mut m2 = HashMap::new();
m2.insert(1, 2);
m2.insert(2, 3);
assert!(m1 != m2);
m2.insert(3, 4);
assert_eq!(m1, m2);
}
#[test]
fn test_show() {
let mut map = HashMap::new();
let empty: HashMap<i32, i32> = HashMap::new();
map.insert(1, 2);
map.insert(3, 4);
let map_str = format!("{:?}", map);
assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}");
assert_eq!(format!("{:?}", empty), "{}");
}
#[test]
fn test_reserve_shrink_to_fit() {
let mut m = HashMap::new();
m.insert(0, 0);
m.remove(&0);
assert!(m.capacity() >= m.len());
for i in 0..128 {
m.insert(i, i);
}
m.reserve(256);
let usable_cap = m.capacity();
for i in 128..(128 + 256) {
m.insert(i, i);
assert_eq!(m.capacity(), usable_cap);
}
for i in 100..(128 + 256) {
assert_eq!(m.remove(&i), Some(i));
}
m.shrink_to_fit();
assert_eq!(m.len(), 100);
assert!(!m.is_empty());
assert!(m.capacity() >= m.len());
for i in 0..100 {
assert_eq!(m.remove(&i), Some(i));
}
m.shrink_to_fit();
m.insert(0, 0);
assert_eq!(m.len(), 1);
assert!(m.capacity() >= m.len());
assert_eq!(m.remove(&0), Some(0));
}
#[test]
fn test_from_iter() {
let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let map: HashMap<_, _> = xs.iter().cloned().collect();
for &(k, v) in &xs {
assert_eq!(map.get(&k), Some(&v));
}
assert_eq!(map.iter().len(), xs.len() - 1);
}
#[test]
fn test_size_hint() {
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let map: HashMap<_, _> = xs.iter().cloned().collect();
let mut iter = map.iter();
for _ in iter.by_ref().take(3) {}
assert_eq!(iter.size_hint(), (3, Some(3)));
}
#[test]
fn test_iter_len() {
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let map: HashMap<_, _> = xs.iter().cloned().collect();
let mut iter = map.iter();
for _ in iter.by_ref().take(3) {}
assert_eq!(iter.len(), 3);
}
#[test]
fn test_mut_size_hint() {
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let mut map: HashMap<_, _> = xs.iter().cloned().collect();
let mut iter = map.iter_mut();
for _ in iter.by_ref().take(3) {}
assert_eq!(iter.size_hint(), (3, Some(3)));
}
#[test]
fn test_iter_mut_len() {
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let mut map: HashMap<_, _> = xs.iter().cloned().collect();
let mut iter = map.iter_mut();
for _ in iter.by_ref().take(3) {}
assert_eq!(iter.len(), 3);
}
#[test]
fn test_index() {
let mut map = HashMap::new();
map.insert(1, 2);
map.insert(2, 1);
map.insert(3, 4);
assert_eq!(map[&2], 1);
}
#[test]
#[should_panic]
fn test_index_nonexistent() {
let mut map = HashMap::new();
map.insert(1, 2);
map.insert(2, 1);
map.insert(3, 4);
map[&4];
}
#[test]
fn test_entry() {
let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
let mut map: HashMap<_, _> = xs.iter().cloned().collect();
// Existing key (insert)
match map.entry(1) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
assert_eq!(view.get(), &10);
assert_eq!(view.insert(100), 10);
}
}
assert_eq!(map.get(&1).unwrap(), &100);
assert_eq!(map.len(), 6);
// Existing key (update)
match map.entry(2) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
let v = view.get_mut();
let new_v = (*v) * 10;
*v = new_v;
}
}
assert_eq!(map.get(&2).unwrap(), &200);
assert_eq!(map.len(), 6);
// Existing key (take)
match map.entry(3) {
Vacant(_) => unreachable!(),
Occupied(view) => {
assert_eq!(view.remove(), 30);
}
}
assert_eq!(map.get(&3), None);
assert_eq!(map.len(), 5);
// Inexistent key (insert)
match map.entry(10) {
Occupied(_) => unreachable!(),
Vacant(view) => {
assert_eq!(*view.insert(1000), 1000);
}
}
assert_eq!(map.get(&10).unwrap(), &1000);
assert_eq!(map.len(), 6);
}
#[test]
fn test_entry_take_doesnt_corrupt() {
#![allow(deprecated)] //rand
// Test for #19292
fn check(m: &HashMap<i32, ()>) {
for k in m.keys() {
assert!(m.contains_key(k), "{} is in keys() but not in the map?", k);
}
}
let mut m = HashMap::new();
let mut rng = thread_rng();
// Populate the map with some items.
for _ in 0..50 {
let x = rng.gen_range(-10, 10);
m.insert(x, ());
}
for _ in 0..1000 {
let x = rng.gen_range(-10, 10);
match m.entry(x) {
Vacant(_) => {}
Occupied(e) => {
e.remove();
}
}
check(&m);
}
}
#[test]
fn test_extend_ref() {
let mut a = HashMap::new();
a.insert(1, "one");
let mut b = HashMap::new();
b.insert(2, "two");
b.insert(3, "three");
a.extend(&b);
assert_eq!(a.len(), 3);
assert_eq!(a[&1], "one");
assert_eq!(a[&2], "two");
assert_eq!(a[&3], "three");
}
#[test]
fn test_capacity_not_less_than_len() {
let mut a = HashMap::new();
let mut item = 0;
for _ in 0..116 {
a.insert(item, 0);
item += 1;
}
assert!(a.capacity() > a.len());
let free = a.capacity() - a.len();
for _ in 0..free {
a.insert(item, 0);
item += 1;
}
assert_eq!(a.len(), a.capacity());
// Insert at capacity should cause allocation.
a.insert(item, 0);
assert!(a.capacity() > a.len());
}
#[test]
fn test_occupied_entry_key() {
let mut a = HashMap::new();
let key = "hello there";
let value = "value goes here";
assert!(a.is_empty());
a.insert(key.clone(), value.clone());
assert_eq!(a.len(), 1);
assert_eq!(a[key], value);
match a.entry(key.clone()) {
Vacant(_) => panic!(),
Occupied(e) => assert_eq!(key, *e.key()),
}
assert_eq!(a.len(), 1);
assert_eq!(a[key], value);
}
#[test]
fn test_vacant_entry_key() {
let mut a = HashMap::new();
let key = "hello there";
let value = "value goes here";
assert!(a.is_empty());
match a.entry(key.clone()) {
Occupied(_) => panic!(),
Vacant(e) => {
assert_eq!(key, *e.key());
e.insert(value.clone());
}
}
assert_eq!(a.len(), 1);
assert_eq!(a[key], value);
}
#[test]
fn test_retain() {
let mut map: HashMap<i32, i32> = (0..100).map(|x| (x, x * 10)).collect();
map.retain(|&k, _| k % 2 == 0);
assert_eq!(map.len(), 50);
assert_eq!(map[&2], 20);
assert_eq!(map[&4], 40);
assert_eq!(map[&6], 60);
}
#[test]
fn test_try_reserve() {
let mut empty_bytes: HashMap<u8, u8> = HashMap::new();
const MAX_USIZE: usize = usize::MAX;
if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) {
} else {
panic!("usize::MAX should trigger an overflow!");
}
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) {
} else {
panic!("usize::MAX / 8 should trigger an OOM!")
}
}
#[test]
fn test_raw_entry() {
use super::RawEntryMut::{Occupied, Vacant};
let xs = [(1i32, 10i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
let mut map: HashMap<_, _> = xs.iter().cloned().collect();
let compute_hash = |map: &HashMap<i32, i32>, k: i32| -> u64 {
use core::hash::{BuildHasher, Hash, Hasher};
let mut hasher = map.hasher().build_hasher();
k.hash(&mut hasher);
hasher.finish()
};
// Existing key (insert)
match map.raw_entry_mut().from_key(&1) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
assert_eq!(view.get(), &10);
assert_eq!(view.insert(100), 10);
}
}
let hash1 = compute_hash(&map, 1);
assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100));
assert_eq!(map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), (&1, &100));
assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), (&1, &100));
assert_eq!(map.len(), 6);
// Existing key (update)
match map.raw_entry_mut().from_key(&2) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
let v = view.get_mut();
let new_v = (*v) * 10;
*v = new_v;
}
}
let hash2 = compute_hash(&map, 2);
assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200));
assert_eq!(map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), (&2, &200));
assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), (&2, &200));
assert_eq!(map.len(), 6);
// Existing key (take)
let hash3 = compute_hash(&map, 3);
match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) {
Vacant(_) => unreachable!(),
Occupied(view) => {
assert_eq!(view.remove_entry(), (3, 30));
}
}
assert_eq!(map.raw_entry().from_key(&3), None);
assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None);
assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None);
assert_eq!(map.len(), 5);
// Nonexistent key (insert)
match map.raw_entry_mut().from_key(&10) {
Occupied(_) => unreachable!(),
Vacant(view) => {
assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000));
}
}
assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000));
assert_eq!(map.len(), 6);
// Ensure all lookup methods produce equivalent results.
for k in 0..12 {
let hash = compute_hash(&map, k);
let v = map.get(&k).cloned();
let kv = v.as_ref().map(|v| (&k, v));
assert_eq!(map.raw_entry().from_key(&k), kv);
assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv);
assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv);
match map.raw_entry_mut().from_key(&k) {
Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
Vacant(_) => assert_eq!(v, None),
}
match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) {
Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
Vacant(_) => assert_eq!(v, None),
}
match map.raw_entry_mut().from_hash(hash, |q| *q == k) {
Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
Vacant(_) => assert_eq!(v, None),
}
}
}

View file

@ -1,3 +1,6 @@
#[cfg(test)]
mod tests;
use crate::borrow::Borrow;
use crate::collections::TryReserveError;
use crate::fmt;
@ -1579,422 +1582,3 @@ fn assert_covariance() {
d
}
}
#[cfg(test)]
mod test_set {
use super::super::map::RandomState;
use super::HashSet;
#[test]
fn test_zero_capacities() {
type HS = HashSet<i32>;
let s = HS::new();
assert_eq!(s.capacity(), 0);
let s = HS::default();
assert_eq!(s.capacity(), 0);
let s = HS::with_hasher(RandomState::new());
assert_eq!(s.capacity(), 0);
let s = HS::with_capacity(0);
assert_eq!(s.capacity(), 0);
let s = HS::with_capacity_and_hasher(0, RandomState::new());
assert_eq!(s.capacity(), 0);
let mut s = HS::new();
s.insert(1);
s.insert(2);
s.remove(&1);
s.remove(&2);
s.shrink_to_fit();
assert_eq!(s.capacity(), 0);
let mut s = HS::new();
s.reserve(0);
assert_eq!(s.capacity(), 0);
}
#[test]
fn test_disjoint() {
let mut xs = HashSet::new();
let mut ys = HashSet::new();
assert!(xs.is_disjoint(&ys));
assert!(ys.is_disjoint(&xs));
assert!(xs.insert(5));
assert!(ys.insert(11));
assert!(xs.is_disjoint(&ys));
assert!(ys.is_disjoint(&xs));
assert!(xs.insert(7));
assert!(xs.insert(19));
assert!(xs.insert(4));
assert!(ys.insert(2));
assert!(ys.insert(-11));
assert!(xs.is_disjoint(&ys));
assert!(ys.is_disjoint(&xs));
assert!(ys.insert(7));
assert!(!xs.is_disjoint(&ys));
assert!(!ys.is_disjoint(&xs));
}
#[test]
fn test_subset_and_superset() {
let mut a = HashSet::new();
assert!(a.insert(0));
assert!(a.insert(5));
assert!(a.insert(11));
assert!(a.insert(7));
let mut b = HashSet::new();
assert!(b.insert(0));
assert!(b.insert(7));
assert!(b.insert(19));
assert!(b.insert(250));
assert!(b.insert(11));
assert!(b.insert(200));
assert!(!a.is_subset(&b));
assert!(!a.is_superset(&b));
assert!(!b.is_subset(&a));
assert!(!b.is_superset(&a));
assert!(b.insert(5));
assert!(a.is_subset(&b));
assert!(!a.is_superset(&b));
assert!(!b.is_subset(&a));
assert!(b.is_superset(&a));
}
#[test]
fn test_iterate() {
let mut a = HashSet::new();
for i in 0..32 {
assert!(a.insert(i));
}
let mut observed: u32 = 0;
for k in &a {
observed |= 1 << *k;
}
assert_eq!(observed, 0xFFFF_FFFF);
}
#[test]
fn test_intersection() {
let mut a = HashSet::new();
let mut b = HashSet::new();
assert!(a.intersection(&b).next().is_none());
assert!(a.insert(11));
assert!(a.insert(1));
assert!(a.insert(3));
assert!(a.insert(77));
assert!(a.insert(103));
assert!(a.insert(5));
assert!(a.insert(-5));
assert!(b.insert(2));
assert!(b.insert(11));
assert!(b.insert(77));
assert!(b.insert(-9));
assert!(b.insert(-42));
assert!(b.insert(5));
assert!(b.insert(3));
let mut i = 0;
let expected = [3, 5, 11, 77];
for x in a.intersection(&b) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
assert!(a.insert(9)); // make a bigger than b
i = 0;
for x in a.intersection(&b) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
i = 0;
for x in b.intersection(&a) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
}
#[test]
fn test_difference() {
let mut a = HashSet::new();
let mut b = HashSet::new();
assert!(a.insert(1));
assert!(a.insert(3));
assert!(a.insert(5));
assert!(a.insert(9));
assert!(a.insert(11));
assert!(b.insert(3));
assert!(b.insert(9));
let mut i = 0;
let expected = [1, 5, 11];
for x in a.difference(&b) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
}
#[test]
fn test_symmetric_difference() {
let mut a = HashSet::new();
let mut b = HashSet::new();
assert!(a.insert(1));
assert!(a.insert(3));
assert!(a.insert(5));
assert!(a.insert(9));
assert!(a.insert(11));
assert!(b.insert(-2));
assert!(b.insert(3));
assert!(b.insert(9));
assert!(b.insert(14));
assert!(b.insert(22));
let mut i = 0;
let expected = [-2, 1, 5, 11, 14, 22];
for x in a.symmetric_difference(&b) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
}
#[test]
fn test_union() {
let mut a = HashSet::new();
let mut b = HashSet::new();
assert!(a.union(&b).next().is_none());
assert!(b.union(&a).next().is_none());
assert!(a.insert(1));
assert!(a.insert(3));
assert!(a.insert(11));
assert!(a.insert(16));
assert!(a.insert(19));
assert!(a.insert(24));
assert!(b.insert(-2));
assert!(b.insert(1));
assert!(b.insert(5));
assert!(b.insert(9));
assert!(b.insert(13));
assert!(b.insert(19));
let mut i = 0;
let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24];
for x in a.union(&b) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
assert!(a.insert(9)); // make a bigger than b
assert!(a.insert(5));
i = 0;
for x in a.union(&b) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
i = 0;
for x in b.union(&a) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
}
#[test]
fn test_from_iter() {
let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9];
let set: HashSet<_> = xs.iter().cloned().collect();
for x in &xs {
assert!(set.contains(x));
}
assert_eq!(set.iter().len(), xs.len() - 1);
}
#[test]
fn test_move_iter() {
let hs = {
let mut hs = HashSet::new();
hs.insert('a');
hs.insert('b');
hs
};
let v = hs.into_iter().collect::<Vec<char>>();
assert!(v == ['a', 'b'] || v == ['b', 'a']);
}
#[test]
fn test_eq() {
// These constants once happened to expose a bug in insert().
// I'm keeping them around to prevent a regression.
let mut s1 = HashSet::new();
s1.insert(1);
s1.insert(2);
s1.insert(3);
let mut s2 = HashSet::new();
s2.insert(1);
s2.insert(2);
assert!(s1 != s2);
s2.insert(3);
assert_eq!(s1, s2);
}
#[test]
fn test_show() {
let mut set = HashSet::new();
let empty = HashSet::<i32>::new();
set.insert(1);
set.insert(2);
let set_str = format!("{:?}", set);
assert!(set_str == "{1, 2}" || set_str == "{2, 1}");
assert_eq!(format!("{:?}", empty), "{}");
}
#[test]
fn test_trivial_drain() {
let mut s = HashSet::<i32>::new();
for _ in s.drain() {}
assert!(s.is_empty());
drop(s);
let mut s = HashSet::<i32>::new();
drop(s.drain());
assert!(s.is_empty());
}
#[test]
fn test_drain() {
let mut s: HashSet<_> = (1..100).collect();
// try this a bunch of times to make sure we don't screw up internal state.
for _ in 0..20 {
assert_eq!(s.len(), 99);
{
let mut last_i = 0;
let mut d = s.drain();
for (i, x) in d.by_ref().take(50).enumerate() {
last_i = i;
assert!(x != 0);
}
assert_eq!(last_i, 49);
}
for _ in &s {
panic!("s should be empty!");
}
// reset to try again.
s.extend(1..100);
}
}
#[test]
fn test_replace() {
use crate::hash;
#[derive(Debug)]
struct Foo(&'static str, i32);
impl PartialEq for Foo {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Eq for Foo {}
impl hash::Hash for Foo {
fn hash<H: hash::Hasher>(&self, h: &mut H) {
self.0.hash(h);
}
}
let mut s = HashSet::new();
assert_eq!(s.replace(Foo("a", 1)), None);
assert_eq!(s.len(), 1);
assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1)));
assert_eq!(s.len(), 1);
let mut it = s.iter();
assert_eq!(it.next(), Some(&Foo("a", 2)));
assert_eq!(it.next(), None);
}
#[test]
fn test_extend_ref() {
let mut a = HashSet::new();
a.insert(1);
a.extend(&[2, 3, 4]);
assert_eq!(a.len(), 4);
assert!(a.contains(&1));
assert!(a.contains(&2));
assert!(a.contains(&3));
assert!(a.contains(&4));
let mut b = HashSet::new();
b.insert(5);
b.insert(6);
a.extend(&b);
assert_eq!(a.len(), 6);
assert!(a.contains(&1));
assert!(a.contains(&2));
assert!(a.contains(&3));
assert!(a.contains(&4));
assert!(a.contains(&5));
assert!(a.contains(&6));
}
#[test]
fn test_retain() {
let xs = [1, 2, 3, 4, 5, 6];
let mut set: HashSet<i32> = xs.iter().cloned().collect();
set.retain(|&k| k % 2 == 0);
assert_eq!(set.len(), 3);
assert!(set.contains(&2));
assert!(set.contains(&4));
assert!(set.contains(&6));
}
}

View file

@ -0,0 +1,415 @@
use super::super::map::RandomState;
use super::HashSet;
#[test]
fn test_zero_capacities() {
type HS = HashSet<i32>;
let s = HS::new();
assert_eq!(s.capacity(), 0);
let s = HS::default();
assert_eq!(s.capacity(), 0);
let s = HS::with_hasher(RandomState::new());
assert_eq!(s.capacity(), 0);
let s = HS::with_capacity(0);
assert_eq!(s.capacity(), 0);
let s = HS::with_capacity_and_hasher(0, RandomState::new());
assert_eq!(s.capacity(), 0);
let mut s = HS::new();
s.insert(1);
s.insert(2);
s.remove(&1);
s.remove(&2);
s.shrink_to_fit();
assert_eq!(s.capacity(), 0);
let mut s = HS::new();
s.reserve(0);
assert_eq!(s.capacity(), 0);
}
#[test]
fn test_disjoint() {
let mut xs = HashSet::new();
let mut ys = HashSet::new();
assert!(xs.is_disjoint(&ys));
assert!(ys.is_disjoint(&xs));
assert!(xs.insert(5));
assert!(ys.insert(11));
assert!(xs.is_disjoint(&ys));
assert!(ys.is_disjoint(&xs));
assert!(xs.insert(7));
assert!(xs.insert(19));
assert!(xs.insert(4));
assert!(ys.insert(2));
assert!(ys.insert(-11));
assert!(xs.is_disjoint(&ys));
assert!(ys.is_disjoint(&xs));
assert!(ys.insert(7));
assert!(!xs.is_disjoint(&ys));
assert!(!ys.is_disjoint(&xs));
}
#[test]
fn test_subset_and_superset() {
let mut a = HashSet::new();
assert!(a.insert(0));
assert!(a.insert(5));
assert!(a.insert(11));
assert!(a.insert(7));
let mut b = HashSet::new();
assert!(b.insert(0));
assert!(b.insert(7));
assert!(b.insert(19));
assert!(b.insert(250));
assert!(b.insert(11));
assert!(b.insert(200));
assert!(!a.is_subset(&b));
assert!(!a.is_superset(&b));
assert!(!b.is_subset(&a));
assert!(!b.is_superset(&a));
assert!(b.insert(5));
assert!(a.is_subset(&b));
assert!(!a.is_superset(&b));
assert!(!b.is_subset(&a));
assert!(b.is_superset(&a));
}
#[test]
fn test_iterate() {
let mut a = HashSet::new();
for i in 0..32 {
assert!(a.insert(i));
}
let mut observed: u32 = 0;
for k in &a {
observed |= 1 << *k;
}
assert_eq!(observed, 0xFFFF_FFFF);
}
#[test]
fn test_intersection() {
let mut a = HashSet::new();
let mut b = HashSet::new();
assert!(a.intersection(&b).next().is_none());
assert!(a.insert(11));
assert!(a.insert(1));
assert!(a.insert(3));
assert!(a.insert(77));
assert!(a.insert(103));
assert!(a.insert(5));
assert!(a.insert(-5));
assert!(b.insert(2));
assert!(b.insert(11));
assert!(b.insert(77));
assert!(b.insert(-9));
assert!(b.insert(-42));
assert!(b.insert(5));
assert!(b.insert(3));
let mut i = 0;
let expected = [3, 5, 11, 77];
for x in a.intersection(&b) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
assert!(a.insert(9)); // make a bigger than b
i = 0;
for x in a.intersection(&b) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
i = 0;
for x in b.intersection(&a) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
}
#[test]
fn test_difference() {
let mut a = HashSet::new();
let mut b = HashSet::new();
assert!(a.insert(1));
assert!(a.insert(3));
assert!(a.insert(5));
assert!(a.insert(9));
assert!(a.insert(11));
assert!(b.insert(3));
assert!(b.insert(9));
let mut i = 0;
let expected = [1, 5, 11];
for x in a.difference(&b) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
}
#[test]
fn test_symmetric_difference() {
let mut a = HashSet::new();
let mut b = HashSet::new();
assert!(a.insert(1));
assert!(a.insert(3));
assert!(a.insert(5));
assert!(a.insert(9));
assert!(a.insert(11));
assert!(b.insert(-2));
assert!(b.insert(3));
assert!(b.insert(9));
assert!(b.insert(14));
assert!(b.insert(22));
let mut i = 0;
let expected = [-2, 1, 5, 11, 14, 22];
for x in a.symmetric_difference(&b) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
}
#[test]
fn test_union() {
let mut a = HashSet::new();
let mut b = HashSet::new();
assert!(a.union(&b).next().is_none());
assert!(b.union(&a).next().is_none());
assert!(a.insert(1));
assert!(a.insert(3));
assert!(a.insert(11));
assert!(a.insert(16));
assert!(a.insert(19));
assert!(a.insert(24));
assert!(b.insert(-2));
assert!(b.insert(1));
assert!(b.insert(5));
assert!(b.insert(9));
assert!(b.insert(13));
assert!(b.insert(19));
let mut i = 0;
let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24];
for x in a.union(&b) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
assert!(a.insert(9)); // make a bigger than b
assert!(a.insert(5));
i = 0;
for x in a.union(&b) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
i = 0;
for x in b.union(&a) {
assert!(expected.contains(x));
i += 1
}
assert_eq!(i, expected.len());
}
#[test]
fn test_from_iter() {
let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9];
let set: HashSet<_> = xs.iter().cloned().collect();
for x in &xs {
assert!(set.contains(x));
}
assert_eq!(set.iter().len(), xs.len() - 1);
}
#[test]
fn test_move_iter() {
let hs = {
let mut hs = HashSet::new();
hs.insert('a');
hs.insert('b');
hs
};
let v = hs.into_iter().collect::<Vec<char>>();
assert!(v == ['a', 'b'] || v == ['b', 'a']);
}
#[test]
fn test_eq() {
// These constants once happened to expose a bug in insert().
// I'm keeping them around to prevent a regression.
let mut s1 = HashSet::new();
s1.insert(1);
s1.insert(2);
s1.insert(3);
let mut s2 = HashSet::new();
s2.insert(1);
s2.insert(2);
assert!(s1 != s2);
s2.insert(3);
assert_eq!(s1, s2);
}
#[test]
fn test_show() {
let mut set = HashSet::new();
let empty = HashSet::<i32>::new();
set.insert(1);
set.insert(2);
let set_str = format!("{:?}", set);
assert!(set_str == "{1, 2}" || set_str == "{2, 1}");
assert_eq!(format!("{:?}", empty), "{}");
}
#[test]
fn test_trivial_drain() {
let mut s = HashSet::<i32>::new();
for _ in s.drain() {}
assert!(s.is_empty());
drop(s);
let mut s = HashSet::<i32>::new();
drop(s.drain());
assert!(s.is_empty());
}
#[test]
fn test_drain() {
let mut s: HashSet<_> = (1..100).collect();
// try this a bunch of times to make sure we don't screw up internal state.
for _ in 0..20 {
assert_eq!(s.len(), 99);
{
let mut last_i = 0;
let mut d = s.drain();
for (i, x) in d.by_ref().take(50).enumerate() {
last_i = i;
assert!(x != 0);
}
assert_eq!(last_i, 49);
}
for _ in &s {
panic!("s should be empty!");
}
// reset to try again.
s.extend(1..100);
}
}
#[test]
fn test_replace() {
use crate::hash;
#[derive(Debug)]
struct Foo(&'static str, i32);
impl PartialEq for Foo {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Eq for Foo {}
impl hash::Hash for Foo {
fn hash<H: hash::Hasher>(&self, h: &mut H) {
self.0.hash(h);
}
}
let mut s = HashSet::new();
assert_eq!(s.replace(Foo("a", 1)), None);
assert_eq!(s.len(), 1);
assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1)));
assert_eq!(s.len(), 1);
let mut it = s.iter();
assert_eq!(it.next(), Some(&Foo("a", 2)));
assert_eq!(it.next(), None);
}
#[test]
fn test_extend_ref() {
let mut a = HashSet::new();
a.insert(1);
a.extend(&[2, 3, 4]);
assert_eq!(a.len(), 4);
assert!(a.contains(&1));
assert!(a.contains(&2));
assert!(a.contains(&3));
assert!(a.contains(&4));
let mut b = HashSet::new();
b.insert(5);
b.insert(6);
a.extend(&b);
assert_eq!(a.len(), 6);
assert!(a.contains(&1));
assert!(a.contains(&2));
assert!(a.contains(&3));
assert!(a.contains(&4));
assert!(a.contains(&5));
assert!(a.contains(&6));
}
#[test]
fn test_retain() {
let xs = [1, 2, 3, 4, 5, 6];
let mut set: HashSet<i32> = xs.iter().cloned().collect();
set.retain(|&k| k % 2 == 0);
assert_eq!(set.len(), 3);
assert!(set.contains(&2));
assert!(set.contains(&4));
assert!(set.contains(&6));
}

View file

@ -10,6 +10,9 @@
#![stable(feature = "env", since = "1.0.0")]
#[cfg(test)]
mod tests;
use crate::error::Error;
use crate::ffi::{OsStr, OsString};
use crate::fmt;
@ -944,112 +947,3 @@ pub mod consts {
#[stable(feature = "env", since = "1.0.0")]
pub const EXE_EXTENSION: &str = os::EXE_EXTENSION;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::path::Path;
#[test]
#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
fn test_self_exe_path() {
let path = current_exe();
assert!(path.is_ok());
let path = path.unwrap();
// Hard to test this function
assert!(path.is_absolute());
}
#[test]
fn test() {
assert!((!Path::new("test-path").is_absolute()));
#[cfg(not(target_env = "sgx"))]
current_dir().unwrap();
}
#[test]
#[cfg(windows)]
fn split_paths_windows() {
use crate::path::PathBuf;
fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
split_paths(unparsed).collect::<Vec<_>>()
== parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
}
assert!(check_parse("", &mut [""]));
assert!(check_parse(r#""""#, &mut [""]));
assert!(check_parse(";;", &mut ["", "", ""]));
assert!(check_parse(r"c:\", &mut [r"c:\"]));
assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
assert!(check_parse(r"c:\;c:\Program Files\", &mut [r"c:\", r"c:\Program Files\"]));
assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
assert!(check_parse(
r#"c:\;c:\"foo;bar"\;c:\baz"#,
&mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]
));
}
#[test]
#[cfg(unix)]
fn split_paths_unix() {
use crate::path::PathBuf;
fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
split_paths(unparsed).collect::<Vec<_>>()
== parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
}
assert!(check_parse("", &mut [""]));
assert!(check_parse("::", &mut ["", "", ""]));
assert!(check_parse("/", &mut ["/"]));
assert!(check_parse("/:", &mut ["/", ""]));
assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
}
#[test]
#[cfg(unix)]
fn join_paths_unix() {
use crate::ffi::OsStr;
fn test_eq(input: &[&str], output: &str) -> bool {
&*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output)
}
assert!(test_eq(&[], ""));
assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], "/bin:/usr/bin:/usr/local/bin"));
assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], ":/bin:::/usr/bin:"));
assert!(join_paths(["/te:st"].iter().cloned()).is_err());
}
#[test]
#[cfg(windows)]
fn join_paths_windows() {
use crate::ffi::OsStr;
fn test_eq(input: &[&str], output: &str) -> bool {
&*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output)
}
assert!(test_eq(&[], ""));
assert!(test_eq(&[r"c:\windows", r"c:\"], r"c:\windows;c:\"));
assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], r";c:\windows;;;c:\;"));
assert!(test_eq(&[r"c:\te;st", r"c:\"], r#""c:\te;st";c:\"#));
assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err());
}
#[test]
fn args_debug() {
assert_eq!(
format!("Args {{ inner: {:?} }}", args().collect::<Vec<_>>()),
format!("{:?}", args())
);
assert_eq!(
format!("ArgsOs {{ inner: {:?} }}", args_os().collect::<Vec<_>>()),
format!("{:?}", args_os())
);
}
}

102
library/std/src/env/tests.rs vendored Normal file
View file

@ -0,0 +1,102 @@
use super::*;
use crate::path::Path;
#[test]
#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
fn test_self_exe_path() {
let path = current_exe();
assert!(path.is_ok());
let path = path.unwrap();
// Hard to test this function
assert!(path.is_absolute());
}
#[test]
fn test() {
assert!((!Path::new("test-path").is_absolute()));
#[cfg(not(target_env = "sgx"))]
current_dir().unwrap();
}
#[test]
#[cfg(windows)]
fn split_paths_windows() {
use crate::path::PathBuf;
fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
split_paths(unparsed).collect::<Vec<_>>()
== parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
}
assert!(check_parse("", &mut [""]));
assert!(check_parse(r#""""#, &mut [""]));
assert!(check_parse(";;", &mut ["", "", ""]));
assert!(check_parse(r"c:\", &mut [r"c:\"]));
assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
assert!(check_parse(r"c:\;c:\Program Files\", &mut [r"c:\", r"c:\Program Files\"]));
assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#, &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
}
#[test]
#[cfg(unix)]
fn split_paths_unix() {
use crate::path::PathBuf;
fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
split_paths(unparsed).collect::<Vec<_>>()
== parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
}
assert!(check_parse("", &mut [""]));
assert!(check_parse("::", &mut ["", "", ""]));
assert!(check_parse("/", &mut ["/"]));
assert!(check_parse("/:", &mut ["/", ""]));
assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
}
#[test]
#[cfg(unix)]
fn join_paths_unix() {
use crate::ffi::OsStr;
fn test_eq(input: &[&str], output: &str) -> bool {
&*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output)
}
assert!(test_eq(&[], ""));
assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], "/bin:/usr/bin:/usr/local/bin"));
assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], ":/bin:::/usr/bin:"));
assert!(join_paths(["/te:st"].iter().cloned()).is_err());
}
#[test]
#[cfg(windows)]
fn join_paths_windows() {
use crate::ffi::OsStr;
fn test_eq(input: &[&str], output: &str) -> bool {
&*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output)
}
assert!(test_eq(&[], ""));
assert!(test_eq(&[r"c:\windows", r"c:\"], r"c:\windows;c:\"));
assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], r";c:\windows;;;c:\;"));
assert!(test_eq(&[r"c:\te;st", r"c:\"], r#""c:\te;st";c:\"#));
assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err());
}
#[test]
fn args_debug() {
assert_eq!(
format!("Args {{ inner: {:?} }}", args().collect::<Vec<_>>()),
format!("{:?}", args())
);
assert_eq!(
format!("ArgsOs {{ inner: {:?} }}", args_os().collect::<Vec<_>>()),
format!("{:?}", args_os())
);
}

View file

@ -13,6 +13,9 @@
// coherence challenge (e.g., specialization, neg impls, etc) we can
// reconsider what crate these items belong in.
#[cfg(test)]
mod tests;
use core::array;
use core::convert::Infallible;
@ -738,44 +741,3 @@ impl dyn Error + Send + Sync {
})
}
}
#[cfg(test)]
mod tests {
use super::Error;
use crate::fmt;
#[derive(Debug, PartialEq)]
struct A;
#[derive(Debug, PartialEq)]
struct B;
impl fmt::Display for A {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "A")
}
}
impl fmt::Display for B {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "B")
}
}
impl Error for A {}
impl Error for B {}
#[test]
fn downcasting() {
let mut a = A;
let a = &mut a as &mut (dyn Error + 'static);
assert_eq!(a.downcast_ref::<A>(), Some(&A));
assert_eq!(a.downcast_ref::<B>(), None);
assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
assert_eq!(a.downcast_mut::<B>(), None);
let a: Box<dyn Error> = Box::new(A);
match a.downcast::<B>() {
Ok(..) => panic!("expected error"),
Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
}
}
}

View file

@ -0,0 +1,37 @@
use super::Error;
use crate::fmt;
#[derive(Debug, PartialEq)]
struct A;
#[derive(Debug, PartialEq)]
struct B;
impl fmt::Display for A {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "A")
}
}
impl fmt::Display for B {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "B")
}
}
impl Error for A {}
impl Error for B {}
#[test]
fn downcasting() {
let mut a = A;
let a = &mut a as &mut (dyn Error + 'static);
assert_eq!(a.downcast_ref::<A>(), Some(&A));
assert_eq!(a.downcast_ref::<B>(), None);
assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
assert_eq!(a.downcast_mut::<B>(), None);
let a: Box<dyn Error> = Box::new(A);
match a.downcast::<B>() {
Ok(..) => panic!("expected error"),
Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
}
}

View file

@ -11,6 +11,9 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
#[cfg(test)]
mod tests;
#[cfg(not(test))]
use crate::intrinsics;
#[cfg(not(test))]
@ -909,766 +912,3 @@ impl f32 {
x
}
}
#[cfg(test)]
mod tests {
use crate::f32::consts;
use crate::num::FpCategory as Fp;
use crate::num::*;
#[test]
fn test_num_f32() {
test_num(10f32, 2f32);
}
#[test]
fn test_min_nan() {
assert_eq!(f32::NAN.min(2.0), 2.0);
assert_eq!(2.0f32.min(f32::NAN), 2.0);
}
#[test]
fn test_max_nan() {
assert_eq!(f32::NAN.max(2.0), 2.0);
assert_eq!(2.0f32.max(f32::NAN), 2.0);
}
#[test]
fn test_nan() {
let nan: f32 = f32::NAN;
assert!(nan.is_nan());
assert!(!nan.is_infinite());
assert!(!nan.is_finite());
assert!(!nan.is_normal());
assert!(nan.is_sign_positive());
assert!(!nan.is_sign_negative());
assert_eq!(Fp::Nan, nan.classify());
}
#[test]
fn test_infinity() {
let inf: f32 = f32::INFINITY;
assert!(inf.is_infinite());
assert!(!inf.is_finite());
assert!(inf.is_sign_positive());
assert!(!inf.is_sign_negative());
assert!(!inf.is_nan());
assert!(!inf.is_normal());
assert_eq!(Fp::Infinite, inf.classify());
}
#[test]
fn test_neg_infinity() {
let neg_inf: f32 = f32::NEG_INFINITY;
assert!(neg_inf.is_infinite());
assert!(!neg_inf.is_finite());
assert!(!neg_inf.is_sign_positive());
assert!(neg_inf.is_sign_negative());
assert!(!neg_inf.is_nan());
assert!(!neg_inf.is_normal());
assert_eq!(Fp::Infinite, neg_inf.classify());
}
#[test]
fn test_zero() {
let zero: f32 = 0.0f32;
assert_eq!(0.0, zero);
assert!(!zero.is_infinite());
assert!(zero.is_finite());
assert!(zero.is_sign_positive());
assert!(!zero.is_sign_negative());
assert!(!zero.is_nan());
assert!(!zero.is_normal());
assert_eq!(Fp::Zero, zero.classify());
}
#[test]
fn test_neg_zero() {
let neg_zero: f32 = -0.0;
assert_eq!(0.0, neg_zero);
assert!(!neg_zero.is_infinite());
assert!(neg_zero.is_finite());
assert!(!neg_zero.is_sign_positive());
assert!(neg_zero.is_sign_negative());
assert!(!neg_zero.is_nan());
assert!(!neg_zero.is_normal());
assert_eq!(Fp::Zero, neg_zero.classify());
}
#[test]
fn test_one() {
let one: f32 = 1.0f32;
assert_eq!(1.0, one);
assert!(!one.is_infinite());
assert!(one.is_finite());
assert!(one.is_sign_positive());
assert!(!one.is_sign_negative());
assert!(!one.is_nan());
assert!(one.is_normal());
assert_eq!(Fp::Normal, one.classify());
}
#[test]
fn test_is_nan() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert!(nan.is_nan());
assert!(!0.0f32.is_nan());
assert!(!5.3f32.is_nan());
assert!(!(-10.732f32).is_nan());
assert!(!inf.is_nan());
assert!(!neg_inf.is_nan());
}
#[test]
fn test_is_infinite() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert!(!nan.is_infinite());
assert!(inf.is_infinite());
assert!(neg_inf.is_infinite());
assert!(!0.0f32.is_infinite());
assert!(!42.8f32.is_infinite());
assert!(!(-109.2f32).is_infinite());
}
#[test]
fn test_is_finite() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert!(!nan.is_finite());
assert!(!inf.is_finite());
assert!(!neg_inf.is_finite());
assert!(0.0f32.is_finite());
assert!(42.8f32.is_finite());
assert!((-109.2f32).is_finite());
}
#[test]
fn test_is_normal() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
let zero: f32 = 0.0f32;
let neg_zero: f32 = -0.0;
assert!(!nan.is_normal());
assert!(!inf.is_normal());
assert!(!neg_inf.is_normal());
assert!(!zero.is_normal());
assert!(!neg_zero.is_normal());
assert!(1f32.is_normal());
assert!(1e-37f32.is_normal());
assert!(!1e-38f32.is_normal());
}
#[test]
fn test_classify() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
let zero: f32 = 0.0f32;
let neg_zero: f32 = -0.0;
assert_eq!(nan.classify(), Fp::Nan);
assert_eq!(inf.classify(), Fp::Infinite);
assert_eq!(neg_inf.classify(), Fp::Infinite);
assert_eq!(zero.classify(), Fp::Zero);
assert_eq!(neg_zero.classify(), Fp::Zero);
assert_eq!(1f32.classify(), Fp::Normal);
assert_eq!(1e-37f32.classify(), Fp::Normal);
assert_eq!(1e-38f32.classify(), Fp::Subnormal);
}
#[test]
fn test_floor() {
assert_approx_eq!(1.0f32.floor(), 1.0f32);
assert_approx_eq!(1.3f32.floor(), 1.0f32);
assert_approx_eq!(1.5f32.floor(), 1.0f32);
assert_approx_eq!(1.7f32.floor(), 1.0f32);
assert_approx_eq!(0.0f32.floor(), 0.0f32);
assert_approx_eq!((-0.0f32).floor(), -0.0f32);
assert_approx_eq!((-1.0f32).floor(), -1.0f32);
assert_approx_eq!((-1.3f32).floor(), -2.0f32);
assert_approx_eq!((-1.5f32).floor(), -2.0f32);
assert_approx_eq!((-1.7f32).floor(), -2.0f32);
}
#[test]
fn test_ceil() {
assert_approx_eq!(1.0f32.ceil(), 1.0f32);
assert_approx_eq!(1.3f32.ceil(), 2.0f32);
assert_approx_eq!(1.5f32.ceil(), 2.0f32);
assert_approx_eq!(1.7f32.ceil(), 2.0f32);
assert_approx_eq!(0.0f32.ceil(), 0.0f32);
assert_approx_eq!((-0.0f32).ceil(), -0.0f32);
assert_approx_eq!((-1.0f32).ceil(), -1.0f32);
assert_approx_eq!((-1.3f32).ceil(), -1.0f32);
assert_approx_eq!((-1.5f32).ceil(), -1.0f32);
assert_approx_eq!((-1.7f32).ceil(), -1.0f32);
}
#[test]
fn test_round() {
assert_approx_eq!(1.0f32.round(), 1.0f32);
assert_approx_eq!(1.3f32.round(), 1.0f32);
assert_approx_eq!(1.5f32.round(), 2.0f32);
assert_approx_eq!(1.7f32.round(), 2.0f32);
assert_approx_eq!(0.0f32.round(), 0.0f32);
assert_approx_eq!((-0.0f32).round(), -0.0f32);
assert_approx_eq!((-1.0f32).round(), -1.0f32);
assert_approx_eq!((-1.3f32).round(), -1.0f32);
assert_approx_eq!((-1.5f32).round(), -2.0f32);
assert_approx_eq!((-1.7f32).round(), -2.0f32);
}
#[test]
fn test_trunc() {
assert_approx_eq!(1.0f32.trunc(), 1.0f32);
assert_approx_eq!(1.3f32.trunc(), 1.0f32);
assert_approx_eq!(1.5f32.trunc(), 1.0f32);
assert_approx_eq!(1.7f32.trunc(), 1.0f32);
assert_approx_eq!(0.0f32.trunc(), 0.0f32);
assert_approx_eq!((-0.0f32).trunc(), -0.0f32);
assert_approx_eq!((-1.0f32).trunc(), -1.0f32);
assert_approx_eq!((-1.3f32).trunc(), -1.0f32);
assert_approx_eq!((-1.5f32).trunc(), -1.0f32);
assert_approx_eq!((-1.7f32).trunc(), -1.0f32);
}
#[test]
fn test_fract() {
assert_approx_eq!(1.0f32.fract(), 0.0f32);
assert_approx_eq!(1.3f32.fract(), 0.3f32);
assert_approx_eq!(1.5f32.fract(), 0.5f32);
assert_approx_eq!(1.7f32.fract(), 0.7f32);
assert_approx_eq!(0.0f32.fract(), 0.0f32);
assert_approx_eq!((-0.0f32).fract(), -0.0f32);
assert_approx_eq!((-1.0f32).fract(), -0.0f32);
assert_approx_eq!((-1.3f32).fract(), -0.3f32);
assert_approx_eq!((-1.5f32).fract(), -0.5f32);
assert_approx_eq!((-1.7f32).fract(), -0.7f32);
}
#[test]
fn test_abs() {
assert_eq!(f32::INFINITY.abs(), f32::INFINITY);
assert_eq!(1f32.abs(), 1f32);
assert_eq!(0f32.abs(), 0f32);
assert_eq!((-0f32).abs(), 0f32);
assert_eq!((-1f32).abs(), 1f32);
assert_eq!(f32::NEG_INFINITY.abs(), f32::INFINITY);
assert_eq!((1f32 / f32::NEG_INFINITY).abs(), 0f32);
assert!(f32::NAN.abs().is_nan());
}
#[test]
fn test_signum() {
assert_eq!(f32::INFINITY.signum(), 1f32);
assert_eq!(1f32.signum(), 1f32);
assert_eq!(0f32.signum(), 1f32);
assert_eq!((-0f32).signum(), -1f32);
assert_eq!((-1f32).signum(), -1f32);
assert_eq!(f32::NEG_INFINITY.signum(), -1f32);
assert_eq!((1f32 / f32::NEG_INFINITY).signum(), -1f32);
assert!(f32::NAN.signum().is_nan());
}
#[test]
fn test_is_sign_positive() {
assert!(f32::INFINITY.is_sign_positive());
assert!(1f32.is_sign_positive());
assert!(0f32.is_sign_positive());
assert!(!(-0f32).is_sign_positive());
assert!(!(-1f32).is_sign_positive());
assert!(!f32::NEG_INFINITY.is_sign_positive());
assert!(!(1f32 / f32::NEG_INFINITY).is_sign_positive());
assert!(f32::NAN.is_sign_positive());
assert!(!(-f32::NAN).is_sign_positive());
}
#[test]
fn test_is_sign_negative() {
assert!(!f32::INFINITY.is_sign_negative());
assert!(!1f32.is_sign_negative());
assert!(!0f32.is_sign_negative());
assert!((-0f32).is_sign_negative());
assert!((-1f32).is_sign_negative());
assert!(f32::NEG_INFINITY.is_sign_negative());
assert!((1f32 / f32::NEG_INFINITY).is_sign_negative());
assert!(!f32::NAN.is_sign_negative());
assert!((-f32::NAN).is_sign_negative());
}
#[test]
fn test_mul_add() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05);
assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65);
assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2);
assert_approx_eq!(3.4f32.mul_add(-0.0, 5.6), 5.6);
assert!(nan.mul_add(7.8, 9.0).is_nan());
assert_eq!(inf.mul_add(7.8, 9.0), inf);
assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
assert_eq!(8.9f32.mul_add(inf, 3.2), inf);
assert_eq!((-3.2f32).mul_add(2.4, neg_inf), neg_inf);
}
#[test]
fn test_recip() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(1.0f32.recip(), 1.0);
assert_eq!(2.0f32.recip(), 0.5);
assert_eq!((-0.4f32).recip(), -2.5);
assert_eq!(0.0f32.recip(), inf);
assert!(nan.recip().is_nan());
assert_eq!(inf.recip(), 0.0);
assert_eq!(neg_inf.recip(), 0.0);
}
#[test]
fn test_powi() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(1.0f32.powi(1), 1.0);
assert_approx_eq!((-3.1f32).powi(2), 9.61);
assert_approx_eq!(5.9f32.powi(-2), 0.028727);
assert_eq!(8.3f32.powi(0), 1.0);
assert!(nan.powi(2).is_nan());
assert_eq!(inf.powi(3), inf);
assert_eq!(neg_inf.powi(2), inf);
}
#[test]
fn test_powf() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(1.0f32.powf(1.0), 1.0);
assert_approx_eq!(3.4f32.powf(4.5), 246.408218);
assert_approx_eq!(2.7f32.powf(-3.2), 0.041652);
assert_approx_eq!((-3.1f32).powf(2.0), 9.61);
assert_approx_eq!(5.9f32.powf(-2.0), 0.028727);
assert_eq!(8.3f32.powf(0.0), 1.0);
assert!(nan.powf(2.0).is_nan());
assert_eq!(inf.powf(2.0), inf);
assert_eq!(neg_inf.powf(3.0), neg_inf);
}
#[test]
fn test_sqrt_domain() {
assert!(f32::NAN.sqrt().is_nan());
assert!(f32::NEG_INFINITY.sqrt().is_nan());
assert!((-1.0f32).sqrt().is_nan());
assert_eq!((-0.0f32).sqrt(), -0.0);
assert_eq!(0.0f32.sqrt(), 0.0);
assert_eq!(1.0f32.sqrt(), 1.0);
assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY);
}
#[test]
fn test_exp() {
assert_eq!(1.0, 0.0f32.exp());
assert_approx_eq!(2.718282, 1.0f32.exp());
assert_approx_eq!(148.413162, 5.0f32.exp());
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
let nan: f32 = f32::NAN;
assert_eq!(inf, inf.exp());
assert_eq!(0.0, neg_inf.exp());
assert!(nan.exp().is_nan());
}
#[test]
fn test_exp2() {
assert_eq!(32.0, 5.0f32.exp2());
assert_eq!(1.0, 0.0f32.exp2());
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
let nan: f32 = f32::NAN;
assert_eq!(inf, inf.exp2());
assert_eq!(0.0, neg_inf.exp2());
assert!(nan.exp2().is_nan());
}
#[test]
fn test_ln() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_approx_eq!(1.0f32.exp().ln(), 1.0);
assert!(nan.ln().is_nan());
assert_eq!(inf.ln(), inf);
assert!(neg_inf.ln().is_nan());
assert!((-2.3f32).ln().is_nan());
assert_eq!((-0.0f32).ln(), neg_inf);
assert_eq!(0.0f32.ln(), neg_inf);
assert_approx_eq!(4.0f32.ln(), 1.386294);
}
#[test]
fn test_log() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(10.0f32.log(10.0), 1.0);
assert_approx_eq!(2.3f32.log(3.5), 0.664858);
assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0);
assert!(1.0f32.log(1.0).is_nan());
assert!(1.0f32.log(-13.9).is_nan());
assert!(nan.log(2.3).is_nan());
assert_eq!(inf.log(10.0), inf);
assert!(neg_inf.log(8.8).is_nan());
assert!((-2.3f32).log(0.1).is_nan());
assert_eq!((-0.0f32).log(2.0), neg_inf);
assert_eq!(0.0f32.log(7.0), neg_inf);
}
#[test]
fn test_log2() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_approx_eq!(10.0f32.log2(), 3.321928);
assert_approx_eq!(2.3f32.log2(), 1.201634);
assert_approx_eq!(1.0f32.exp().log2(), 1.442695);
assert!(nan.log2().is_nan());
assert_eq!(inf.log2(), inf);
assert!(neg_inf.log2().is_nan());
assert!((-2.3f32).log2().is_nan());
assert_eq!((-0.0f32).log2(), neg_inf);
assert_eq!(0.0f32.log2(), neg_inf);
}
#[test]
fn test_log10() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(10.0f32.log10(), 1.0);
assert_approx_eq!(2.3f32.log10(), 0.361728);
assert_approx_eq!(1.0f32.exp().log10(), 0.434294);
assert_eq!(1.0f32.log10(), 0.0);
assert!(nan.log10().is_nan());
assert_eq!(inf.log10(), inf);
assert!(neg_inf.log10().is_nan());
assert!((-2.3f32).log10().is_nan());
assert_eq!((-0.0f32).log10(), neg_inf);
assert_eq!(0.0f32.log10(), neg_inf);
}
#[test]
fn test_to_degrees() {
let pi: f32 = consts::PI;
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(0.0f32.to_degrees(), 0.0);
assert_approx_eq!((-5.8f32).to_degrees(), -332.315521);
assert_eq!(pi.to_degrees(), 180.0);
assert!(nan.to_degrees().is_nan());
assert_eq!(inf.to_degrees(), inf);
assert_eq!(neg_inf.to_degrees(), neg_inf);
assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703);
}
#[test]
fn test_to_radians() {
let pi: f32 = consts::PI;
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(0.0f32.to_radians(), 0.0);
assert_approx_eq!(154.6f32.to_radians(), 2.698279);
assert_approx_eq!((-332.31f32).to_radians(), -5.799903);
assert_eq!(180.0f32.to_radians(), pi);
assert!(nan.to_radians().is_nan());
assert_eq!(inf.to_radians(), inf);
assert_eq!(neg_inf.to_radians(), neg_inf);
}
#[test]
fn test_asinh() {
assert_eq!(0.0f32.asinh(), 0.0f32);
assert_eq!((-0.0f32).asinh(), -0.0f32);
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
let nan: f32 = f32::NAN;
assert_eq!(inf.asinh(), inf);
assert_eq!(neg_inf.asinh(), neg_inf);
assert!(nan.asinh().is_nan());
assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271
assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
// regression test for the catastrophic cancellation fixed in 72486
assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32);
}
#[test]
fn test_acosh() {
assert_eq!(1.0f32.acosh(), 0.0f32);
assert!(0.999f32.acosh().is_nan());
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
let nan: f32 = f32::NAN;
assert_eq!(inf.acosh(), inf);
assert!(neg_inf.acosh().is_nan());
assert!(nan.acosh().is_nan());
assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32);
assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32);
}
#[test]
fn test_atanh() {
assert_eq!(0.0f32.atanh(), 0.0f32);
assert_eq!((-0.0f32).atanh(), -0.0f32);
let inf32: f32 = f32::INFINITY;
let neg_inf32: f32 = f32::NEG_INFINITY;
assert_eq!(1.0f32.atanh(), inf32);
assert_eq!((-1.0f32).atanh(), neg_inf32);
assert!(2f64.atanh().atanh().is_nan());
assert!((-2f64).atanh().atanh().is_nan());
let inf64: f32 = f32::INFINITY;
let neg_inf64: f32 = f32::NEG_INFINITY;
let nan32: f32 = f32::NAN;
assert!(inf64.atanh().is_nan());
assert!(neg_inf64.atanh().is_nan());
assert!(nan32.atanh().is_nan());
assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32);
assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32);
}
#[test]
fn test_real_consts() {
use super::consts;
let pi: f32 = consts::PI;
let frac_pi_2: f32 = consts::FRAC_PI_2;
let frac_pi_3: f32 = consts::FRAC_PI_3;
let frac_pi_4: f32 = consts::FRAC_PI_4;
let frac_pi_6: f32 = consts::FRAC_PI_6;
let frac_pi_8: f32 = consts::FRAC_PI_8;
let frac_1_pi: f32 = consts::FRAC_1_PI;
let frac_2_pi: f32 = consts::FRAC_2_PI;
let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI;
let sqrt2: f32 = consts::SQRT_2;
let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2;
let e: f32 = consts::E;
let log2_e: f32 = consts::LOG2_E;
let log10_e: f32 = consts::LOG10_E;
let ln_2: f32 = consts::LN_2;
let ln_10: f32 = consts::LN_10;
assert_approx_eq!(frac_pi_2, pi / 2f32);
assert_approx_eq!(frac_pi_3, pi / 3f32);
assert_approx_eq!(frac_pi_4, pi / 4f32);
assert_approx_eq!(frac_pi_6, pi / 6f32);
assert_approx_eq!(frac_pi_8, pi / 8f32);
assert_approx_eq!(frac_1_pi, 1f32 / pi);
assert_approx_eq!(frac_2_pi, 2f32 / pi);
assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt());
assert_approx_eq!(sqrt2, 2f32.sqrt());
assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt());
assert_approx_eq!(log2_e, e.log2());
assert_approx_eq!(log10_e, e.log10());
assert_approx_eq!(ln_2, 2f32.ln());
assert_approx_eq!(ln_10, 10f32.ln());
}
#[test]
fn test_float_bits_conv() {
assert_eq!((1f32).to_bits(), 0x3f800000);
assert_eq!((12.5f32).to_bits(), 0x41480000);
assert_eq!((1337f32).to_bits(), 0x44a72000);
assert_eq!((-14.25f32).to_bits(), 0xc1640000);
assert_approx_eq!(f32::from_bits(0x3f800000), 1.0);
assert_approx_eq!(f32::from_bits(0x41480000), 12.5);
assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0);
assert_approx_eq!(f32::from_bits(0xc1640000), -14.25);
// Check that NaNs roundtrip their bits regardless of signaling-ness
// 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA;
let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555;
assert!(f32::from_bits(masked_nan1).is_nan());
assert!(f32::from_bits(masked_nan2).is_nan());
assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1);
assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2);
}
#[test]
#[should_panic]
fn test_clamp_min_greater_than_max() {
let _ = 1.0f32.clamp(3.0, 1.0);
}
#[test]
#[should_panic]
fn test_clamp_min_is_nan() {
let _ = 1.0f32.clamp(f32::NAN, 1.0);
}
#[test]
#[should_panic]
fn test_clamp_max_is_nan() {
let _ = 1.0f32.clamp(3.0, f32::NAN);
}
#[test]
fn test_total_cmp() {
use core::cmp::Ordering;
fn quiet_bit_mask() -> u32 {
1 << (f32::MANTISSA_DIGITS - 2)
}
fn min_subnorm() -> f32 {
f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0)
}
fn max_subnorm() -> f32 {
f32::MIN_POSITIVE - min_subnorm()
}
fn q_nan() -> f32 {
f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask())
}
fn s_nan() -> f32 {
f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42)
}
assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan()));
assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5));
assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0));
assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5));
assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5));
assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0));
assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0));
assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm()));
assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm()));
assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5));
assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0));
assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5));
assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5));
assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX));
assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan()));
assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0));
assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5));
assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0));
assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5));
assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5));
assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX));
assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan()));
assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan()));
assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan()));
assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan()));
assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5));
assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5));
assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0));
assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5));
assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0));
assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0));
assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm()));
assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm()));
assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5));
assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0));
assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5));
assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5));
assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX));
assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
}
}

View file

@ -0,0 +1,759 @@
use crate::f32::consts;
use crate::num::FpCategory as Fp;
use crate::num::*;
#[test]
fn test_num_f32() {
test_num(10f32, 2f32);
}
#[test]
fn test_min_nan() {
assert_eq!(f32::NAN.min(2.0), 2.0);
assert_eq!(2.0f32.min(f32::NAN), 2.0);
}
#[test]
fn test_max_nan() {
assert_eq!(f32::NAN.max(2.0), 2.0);
assert_eq!(2.0f32.max(f32::NAN), 2.0);
}
#[test]
fn test_nan() {
let nan: f32 = f32::NAN;
assert!(nan.is_nan());
assert!(!nan.is_infinite());
assert!(!nan.is_finite());
assert!(!nan.is_normal());
assert!(nan.is_sign_positive());
assert!(!nan.is_sign_negative());
assert_eq!(Fp::Nan, nan.classify());
}
#[test]
fn test_infinity() {
let inf: f32 = f32::INFINITY;
assert!(inf.is_infinite());
assert!(!inf.is_finite());
assert!(inf.is_sign_positive());
assert!(!inf.is_sign_negative());
assert!(!inf.is_nan());
assert!(!inf.is_normal());
assert_eq!(Fp::Infinite, inf.classify());
}
#[test]
fn test_neg_infinity() {
let neg_inf: f32 = f32::NEG_INFINITY;
assert!(neg_inf.is_infinite());
assert!(!neg_inf.is_finite());
assert!(!neg_inf.is_sign_positive());
assert!(neg_inf.is_sign_negative());
assert!(!neg_inf.is_nan());
assert!(!neg_inf.is_normal());
assert_eq!(Fp::Infinite, neg_inf.classify());
}
#[test]
fn test_zero() {
let zero: f32 = 0.0f32;
assert_eq!(0.0, zero);
assert!(!zero.is_infinite());
assert!(zero.is_finite());
assert!(zero.is_sign_positive());
assert!(!zero.is_sign_negative());
assert!(!zero.is_nan());
assert!(!zero.is_normal());
assert_eq!(Fp::Zero, zero.classify());
}
#[test]
fn test_neg_zero() {
let neg_zero: f32 = -0.0;
assert_eq!(0.0, neg_zero);
assert!(!neg_zero.is_infinite());
assert!(neg_zero.is_finite());
assert!(!neg_zero.is_sign_positive());
assert!(neg_zero.is_sign_negative());
assert!(!neg_zero.is_nan());
assert!(!neg_zero.is_normal());
assert_eq!(Fp::Zero, neg_zero.classify());
}
#[test]
fn test_one() {
let one: f32 = 1.0f32;
assert_eq!(1.0, one);
assert!(!one.is_infinite());
assert!(one.is_finite());
assert!(one.is_sign_positive());
assert!(!one.is_sign_negative());
assert!(!one.is_nan());
assert!(one.is_normal());
assert_eq!(Fp::Normal, one.classify());
}
#[test]
fn test_is_nan() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert!(nan.is_nan());
assert!(!0.0f32.is_nan());
assert!(!5.3f32.is_nan());
assert!(!(-10.732f32).is_nan());
assert!(!inf.is_nan());
assert!(!neg_inf.is_nan());
}
#[test]
fn test_is_infinite() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert!(!nan.is_infinite());
assert!(inf.is_infinite());
assert!(neg_inf.is_infinite());
assert!(!0.0f32.is_infinite());
assert!(!42.8f32.is_infinite());
assert!(!(-109.2f32).is_infinite());
}
#[test]
fn test_is_finite() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert!(!nan.is_finite());
assert!(!inf.is_finite());
assert!(!neg_inf.is_finite());
assert!(0.0f32.is_finite());
assert!(42.8f32.is_finite());
assert!((-109.2f32).is_finite());
}
#[test]
fn test_is_normal() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
let zero: f32 = 0.0f32;
let neg_zero: f32 = -0.0;
assert!(!nan.is_normal());
assert!(!inf.is_normal());
assert!(!neg_inf.is_normal());
assert!(!zero.is_normal());
assert!(!neg_zero.is_normal());
assert!(1f32.is_normal());
assert!(1e-37f32.is_normal());
assert!(!1e-38f32.is_normal());
}
#[test]
fn test_classify() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
let zero: f32 = 0.0f32;
let neg_zero: f32 = -0.0;
assert_eq!(nan.classify(), Fp::Nan);
assert_eq!(inf.classify(), Fp::Infinite);
assert_eq!(neg_inf.classify(), Fp::Infinite);
assert_eq!(zero.classify(), Fp::Zero);
assert_eq!(neg_zero.classify(), Fp::Zero);
assert_eq!(1f32.classify(), Fp::Normal);
assert_eq!(1e-37f32.classify(), Fp::Normal);
assert_eq!(1e-38f32.classify(), Fp::Subnormal);
}
#[test]
fn test_floor() {
assert_approx_eq!(1.0f32.floor(), 1.0f32);
assert_approx_eq!(1.3f32.floor(), 1.0f32);
assert_approx_eq!(1.5f32.floor(), 1.0f32);
assert_approx_eq!(1.7f32.floor(), 1.0f32);
assert_approx_eq!(0.0f32.floor(), 0.0f32);
assert_approx_eq!((-0.0f32).floor(), -0.0f32);
assert_approx_eq!((-1.0f32).floor(), -1.0f32);
assert_approx_eq!((-1.3f32).floor(), -2.0f32);
assert_approx_eq!((-1.5f32).floor(), -2.0f32);
assert_approx_eq!((-1.7f32).floor(), -2.0f32);
}
#[test]
fn test_ceil() {
assert_approx_eq!(1.0f32.ceil(), 1.0f32);
assert_approx_eq!(1.3f32.ceil(), 2.0f32);
assert_approx_eq!(1.5f32.ceil(), 2.0f32);
assert_approx_eq!(1.7f32.ceil(), 2.0f32);
assert_approx_eq!(0.0f32.ceil(), 0.0f32);
assert_approx_eq!((-0.0f32).ceil(), -0.0f32);
assert_approx_eq!((-1.0f32).ceil(), -1.0f32);
assert_approx_eq!((-1.3f32).ceil(), -1.0f32);
assert_approx_eq!((-1.5f32).ceil(), -1.0f32);
assert_approx_eq!((-1.7f32).ceil(), -1.0f32);
}
#[test]
fn test_round() {
assert_approx_eq!(1.0f32.round(), 1.0f32);
assert_approx_eq!(1.3f32.round(), 1.0f32);
assert_approx_eq!(1.5f32.round(), 2.0f32);
assert_approx_eq!(1.7f32.round(), 2.0f32);
assert_approx_eq!(0.0f32.round(), 0.0f32);
assert_approx_eq!((-0.0f32).round(), -0.0f32);
assert_approx_eq!((-1.0f32).round(), -1.0f32);
assert_approx_eq!((-1.3f32).round(), -1.0f32);
assert_approx_eq!((-1.5f32).round(), -2.0f32);
assert_approx_eq!((-1.7f32).round(), -2.0f32);
}
#[test]
fn test_trunc() {
assert_approx_eq!(1.0f32.trunc(), 1.0f32);
assert_approx_eq!(1.3f32.trunc(), 1.0f32);
assert_approx_eq!(1.5f32.trunc(), 1.0f32);
assert_approx_eq!(1.7f32.trunc(), 1.0f32);
assert_approx_eq!(0.0f32.trunc(), 0.0f32);
assert_approx_eq!((-0.0f32).trunc(), -0.0f32);
assert_approx_eq!((-1.0f32).trunc(), -1.0f32);
assert_approx_eq!((-1.3f32).trunc(), -1.0f32);
assert_approx_eq!((-1.5f32).trunc(), -1.0f32);
assert_approx_eq!((-1.7f32).trunc(), -1.0f32);
}
#[test]
fn test_fract() {
assert_approx_eq!(1.0f32.fract(), 0.0f32);
assert_approx_eq!(1.3f32.fract(), 0.3f32);
assert_approx_eq!(1.5f32.fract(), 0.5f32);
assert_approx_eq!(1.7f32.fract(), 0.7f32);
assert_approx_eq!(0.0f32.fract(), 0.0f32);
assert_approx_eq!((-0.0f32).fract(), -0.0f32);
assert_approx_eq!((-1.0f32).fract(), -0.0f32);
assert_approx_eq!((-1.3f32).fract(), -0.3f32);
assert_approx_eq!((-1.5f32).fract(), -0.5f32);
assert_approx_eq!((-1.7f32).fract(), -0.7f32);
}
#[test]
fn test_abs() {
assert_eq!(f32::INFINITY.abs(), f32::INFINITY);
assert_eq!(1f32.abs(), 1f32);
assert_eq!(0f32.abs(), 0f32);
assert_eq!((-0f32).abs(), 0f32);
assert_eq!((-1f32).abs(), 1f32);
assert_eq!(f32::NEG_INFINITY.abs(), f32::INFINITY);
assert_eq!((1f32 / f32::NEG_INFINITY).abs(), 0f32);
assert!(f32::NAN.abs().is_nan());
}
#[test]
fn test_signum() {
assert_eq!(f32::INFINITY.signum(), 1f32);
assert_eq!(1f32.signum(), 1f32);
assert_eq!(0f32.signum(), 1f32);
assert_eq!((-0f32).signum(), -1f32);
assert_eq!((-1f32).signum(), -1f32);
assert_eq!(f32::NEG_INFINITY.signum(), -1f32);
assert_eq!((1f32 / f32::NEG_INFINITY).signum(), -1f32);
assert!(f32::NAN.signum().is_nan());
}
#[test]
fn test_is_sign_positive() {
assert!(f32::INFINITY.is_sign_positive());
assert!(1f32.is_sign_positive());
assert!(0f32.is_sign_positive());
assert!(!(-0f32).is_sign_positive());
assert!(!(-1f32).is_sign_positive());
assert!(!f32::NEG_INFINITY.is_sign_positive());
assert!(!(1f32 / f32::NEG_INFINITY).is_sign_positive());
assert!(f32::NAN.is_sign_positive());
assert!(!(-f32::NAN).is_sign_positive());
}
#[test]
fn test_is_sign_negative() {
assert!(!f32::INFINITY.is_sign_negative());
assert!(!1f32.is_sign_negative());
assert!(!0f32.is_sign_negative());
assert!((-0f32).is_sign_negative());
assert!((-1f32).is_sign_negative());
assert!(f32::NEG_INFINITY.is_sign_negative());
assert!((1f32 / f32::NEG_INFINITY).is_sign_negative());
assert!(!f32::NAN.is_sign_negative());
assert!((-f32::NAN).is_sign_negative());
}
#[test]
fn test_mul_add() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05);
assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65);
assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2);
assert_approx_eq!(3.4f32.mul_add(-0.0, 5.6), 5.6);
assert!(nan.mul_add(7.8, 9.0).is_nan());
assert_eq!(inf.mul_add(7.8, 9.0), inf);
assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
assert_eq!(8.9f32.mul_add(inf, 3.2), inf);
assert_eq!((-3.2f32).mul_add(2.4, neg_inf), neg_inf);
}
#[test]
fn test_recip() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(1.0f32.recip(), 1.0);
assert_eq!(2.0f32.recip(), 0.5);
assert_eq!((-0.4f32).recip(), -2.5);
assert_eq!(0.0f32.recip(), inf);
assert!(nan.recip().is_nan());
assert_eq!(inf.recip(), 0.0);
assert_eq!(neg_inf.recip(), 0.0);
}
#[test]
fn test_powi() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(1.0f32.powi(1), 1.0);
assert_approx_eq!((-3.1f32).powi(2), 9.61);
assert_approx_eq!(5.9f32.powi(-2), 0.028727);
assert_eq!(8.3f32.powi(0), 1.0);
assert!(nan.powi(2).is_nan());
assert_eq!(inf.powi(3), inf);
assert_eq!(neg_inf.powi(2), inf);
}
#[test]
fn test_powf() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(1.0f32.powf(1.0), 1.0);
assert_approx_eq!(3.4f32.powf(4.5), 246.408218);
assert_approx_eq!(2.7f32.powf(-3.2), 0.041652);
assert_approx_eq!((-3.1f32).powf(2.0), 9.61);
assert_approx_eq!(5.9f32.powf(-2.0), 0.028727);
assert_eq!(8.3f32.powf(0.0), 1.0);
assert!(nan.powf(2.0).is_nan());
assert_eq!(inf.powf(2.0), inf);
assert_eq!(neg_inf.powf(3.0), neg_inf);
}
#[test]
fn test_sqrt_domain() {
assert!(f32::NAN.sqrt().is_nan());
assert!(f32::NEG_INFINITY.sqrt().is_nan());
assert!((-1.0f32).sqrt().is_nan());
assert_eq!((-0.0f32).sqrt(), -0.0);
assert_eq!(0.0f32.sqrt(), 0.0);
assert_eq!(1.0f32.sqrt(), 1.0);
assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY);
}
#[test]
fn test_exp() {
assert_eq!(1.0, 0.0f32.exp());
assert_approx_eq!(2.718282, 1.0f32.exp());
assert_approx_eq!(148.413162, 5.0f32.exp());
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
let nan: f32 = f32::NAN;
assert_eq!(inf, inf.exp());
assert_eq!(0.0, neg_inf.exp());
assert!(nan.exp().is_nan());
}
#[test]
fn test_exp2() {
assert_eq!(32.0, 5.0f32.exp2());
assert_eq!(1.0, 0.0f32.exp2());
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
let nan: f32 = f32::NAN;
assert_eq!(inf, inf.exp2());
assert_eq!(0.0, neg_inf.exp2());
assert!(nan.exp2().is_nan());
}
#[test]
fn test_ln() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_approx_eq!(1.0f32.exp().ln(), 1.0);
assert!(nan.ln().is_nan());
assert_eq!(inf.ln(), inf);
assert!(neg_inf.ln().is_nan());
assert!((-2.3f32).ln().is_nan());
assert_eq!((-0.0f32).ln(), neg_inf);
assert_eq!(0.0f32.ln(), neg_inf);
assert_approx_eq!(4.0f32.ln(), 1.386294);
}
#[test]
fn test_log() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(10.0f32.log(10.0), 1.0);
assert_approx_eq!(2.3f32.log(3.5), 0.664858);
assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0);
assert!(1.0f32.log(1.0).is_nan());
assert!(1.0f32.log(-13.9).is_nan());
assert!(nan.log(2.3).is_nan());
assert_eq!(inf.log(10.0), inf);
assert!(neg_inf.log(8.8).is_nan());
assert!((-2.3f32).log(0.1).is_nan());
assert_eq!((-0.0f32).log(2.0), neg_inf);
assert_eq!(0.0f32.log(7.0), neg_inf);
}
#[test]
fn test_log2() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_approx_eq!(10.0f32.log2(), 3.321928);
assert_approx_eq!(2.3f32.log2(), 1.201634);
assert_approx_eq!(1.0f32.exp().log2(), 1.442695);
assert!(nan.log2().is_nan());
assert_eq!(inf.log2(), inf);
assert!(neg_inf.log2().is_nan());
assert!((-2.3f32).log2().is_nan());
assert_eq!((-0.0f32).log2(), neg_inf);
assert_eq!(0.0f32.log2(), neg_inf);
}
#[test]
fn test_log10() {
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(10.0f32.log10(), 1.0);
assert_approx_eq!(2.3f32.log10(), 0.361728);
assert_approx_eq!(1.0f32.exp().log10(), 0.434294);
assert_eq!(1.0f32.log10(), 0.0);
assert!(nan.log10().is_nan());
assert_eq!(inf.log10(), inf);
assert!(neg_inf.log10().is_nan());
assert!((-2.3f32).log10().is_nan());
assert_eq!((-0.0f32).log10(), neg_inf);
assert_eq!(0.0f32.log10(), neg_inf);
}
#[test]
fn test_to_degrees() {
let pi: f32 = consts::PI;
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(0.0f32.to_degrees(), 0.0);
assert_approx_eq!((-5.8f32).to_degrees(), -332.315521);
assert_eq!(pi.to_degrees(), 180.0);
assert!(nan.to_degrees().is_nan());
assert_eq!(inf.to_degrees(), inf);
assert_eq!(neg_inf.to_degrees(), neg_inf);
assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703);
}
#[test]
fn test_to_radians() {
let pi: f32 = consts::PI;
let nan: f32 = f32::NAN;
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
assert_eq!(0.0f32.to_radians(), 0.0);
assert_approx_eq!(154.6f32.to_radians(), 2.698279);
assert_approx_eq!((-332.31f32).to_radians(), -5.799903);
assert_eq!(180.0f32.to_radians(), pi);
assert!(nan.to_radians().is_nan());
assert_eq!(inf.to_radians(), inf);
assert_eq!(neg_inf.to_radians(), neg_inf);
}
#[test]
fn test_asinh() {
assert_eq!(0.0f32.asinh(), 0.0f32);
assert_eq!((-0.0f32).asinh(), -0.0f32);
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
let nan: f32 = f32::NAN;
assert_eq!(inf.asinh(), inf);
assert_eq!(neg_inf.asinh(), neg_inf);
assert!(nan.asinh().is_nan());
assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271
assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
// regression test for the catastrophic cancellation fixed in 72486
assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32);
}
#[test]
fn test_acosh() {
assert_eq!(1.0f32.acosh(), 0.0f32);
assert!(0.999f32.acosh().is_nan());
let inf: f32 = f32::INFINITY;
let neg_inf: f32 = f32::NEG_INFINITY;
let nan: f32 = f32::NAN;
assert_eq!(inf.acosh(), inf);
assert!(neg_inf.acosh().is_nan());
assert!(nan.acosh().is_nan());
assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32);
assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32);
}
#[test]
fn test_atanh() {
assert_eq!(0.0f32.atanh(), 0.0f32);
assert_eq!((-0.0f32).atanh(), -0.0f32);
let inf32: f32 = f32::INFINITY;
let neg_inf32: f32 = f32::NEG_INFINITY;
assert_eq!(1.0f32.atanh(), inf32);
assert_eq!((-1.0f32).atanh(), neg_inf32);
assert!(2f64.atanh().atanh().is_nan());
assert!((-2f64).atanh().atanh().is_nan());
let inf64: f32 = f32::INFINITY;
let neg_inf64: f32 = f32::NEG_INFINITY;
let nan32: f32 = f32::NAN;
assert!(inf64.atanh().is_nan());
assert!(neg_inf64.atanh().is_nan());
assert!(nan32.atanh().is_nan());
assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32);
assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32);
}
#[test]
fn test_real_consts() {
use super::consts;
let pi: f32 = consts::PI;
let frac_pi_2: f32 = consts::FRAC_PI_2;
let frac_pi_3: f32 = consts::FRAC_PI_3;
let frac_pi_4: f32 = consts::FRAC_PI_4;
let frac_pi_6: f32 = consts::FRAC_PI_6;
let frac_pi_8: f32 = consts::FRAC_PI_8;
let frac_1_pi: f32 = consts::FRAC_1_PI;
let frac_2_pi: f32 = consts::FRAC_2_PI;
let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI;
let sqrt2: f32 = consts::SQRT_2;
let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2;
let e: f32 = consts::E;
let log2_e: f32 = consts::LOG2_E;
let log10_e: f32 = consts::LOG10_E;
let ln_2: f32 = consts::LN_2;
let ln_10: f32 = consts::LN_10;
assert_approx_eq!(frac_pi_2, pi / 2f32);
assert_approx_eq!(frac_pi_3, pi / 3f32);
assert_approx_eq!(frac_pi_4, pi / 4f32);
assert_approx_eq!(frac_pi_6, pi / 6f32);
assert_approx_eq!(frac_pi_8, pi / 8f32);
assert_approx_eq!(frac_1_pi, 1f32 / pi);
assert_approx_eq!(frac_2_pi, 2f32 / pi);
assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt());
assert_approx_eq!(sqrt2, 2f32.sqrt());
assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt());
assert_approx_eq!(log2_e, e.log2());
assert_approx_eq!(log10_e, e.log10());
assert_approx_eq!(ln_2, 2f32.ln());
assert_approx_eq!(ln_10, 10f32.ln());
}
#[test]
fn test_float_bits_conv() {
assert_eq!((1f32).to_bits(), 0x3f800000);
assert_eq!((12.5f32).to_bits(), 0x41480000);
assert_eq!((1337f32).to_bits(), 0x44a72000);
assert_eq!((-14.25f32).to_bits(), 0xc1640000);
assert_approx_eq!(f32::from_bits(0x3f800000), 1.0);
assert_approx_eq!(f32::from_bits(0x41480000), 12.5);
assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0);
assert_approx_eq!(f32::from_bits(0xc1640000), -14.25);
// Check that NaNs roundtrip their bits regardless of signaling-ness
// 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA;
let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555;
assert!(f32::from_bits(masked_nan1).is_nan());
assert!(f32::from_bits(masked_nan2).is_nan());
assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1);
assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2);
}
#[test]
#[should_panic]
fn test_clamp_min_greater_than_max() {
let _ = 1.0f32.clamp(3.0, 1.0);
}
#[test]
#[should_panic]
fn test_clamp_min_is_nan() {
let _ = 1.0f32.clamp(f32::NAN, 1.0);
}
#[test]
#[should_panic]
fn test_clamp_max_is_nan() {
let _ = 1.0f32.clamp(3.0, f32::NAN);
}
#[test]
fn test_total_cmp() {
use core::cmp::Ordering;
fn quiet_bit_mask() -> u32 {
1 << (f32::MANTISSA_DIGITS - 2)
}
fn min_subnorm() -> f32 {
f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0)
}
fn max_subnorm() -> f32 {
f32::MIN_POSITIVE - min_subnorm()
}
fn q_nan() -> f32 {
f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask())
}
fn s_nan() -> f32 {
f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42)
}
assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan()));
assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5));
assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0));
assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5));
assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5));
assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0));
assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0));
assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm()));
assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm()));
assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5));
assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0));
assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5));
assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5));
assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX));
assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan()));
assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0));
assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5));
assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0));
assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5));
assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5));
assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX));
assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan()));
assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan()));
assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan()));
assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan()));
assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5));
assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5));
assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0));
assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5));
assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0));
assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0));
assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm()));
assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm()));
assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5));
assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0));
assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5));
assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5));
assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX));
assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
}

View file

@ -11,6 +11,9 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
#[cfg(test)]
mod tests;
#[cfg(not(test))]
use crate::intrinsics;
#[cfg(not(test))]
@ -936,762 +939,3 @@ impl f64 {
}
}
}
#[cfg(test)]
mod tests {
use crate::f64::consts;
use crate::num::FpCategory as Fp;
use crate::num::*;
#[test]
fn test_num_f64() {
test_num(10f64, 2f64);
}
#[test]
fn test_min_nan() {
assert_eq!(f64::NAN.min(2.0), 2.0);
assert_eq!(2.0f64.min(f64::NAN), 2.0);
}
#[test]
fn test_max_nan() {
assert_eq!(f64::NAN.max(2.0), 2.0);
assert_eq!(2.0f64.max(f64::NAN), 2.0);
}
#[test]
fn test_nan() {
let nan: f64 = f64::NAN;
assert!(nan.is_nan());
assert!(!nan.is_infinite());
assert!(!nan.is_finite());
assert!(!nan.is_normal());
assert!(nan.is_sign_positive());
assert!(!nan.is_sign_negative());
assert_eq!(Fp::Nan, nan.classify());
}
#[test]
fn test_infinity() {
let inf: f64 = f64::INFINITY;
assert!(inf.is_infinite());
assert!(!inf.is_finite());
assert!(inf.is_sign_positive());
assert!(!inf.is_sign_negative());
assert!(!inf.is_nan());
assert!(!inf.is_normal());
assert_eq!(Fp::Infinite, inf.classify());
}
#[test]
fn test_neg_infinity() {
let neg_inf: f64 = f64::NEG_INFINITY;
assert!(neg_inf.is_infinite());
assert!(!neg_inf.is_finite());
assert!(!neg_inf.is_sign_positive());
assert!(neg_inf.is_sign_negative());
assert!(!neg_inf.is_nan());
assert!(!neg_inf.is_normal());
assert_eq!(Fp::Infinite, neg_inf.classify());
}
#[test]
fn test_zero() {
let zero: f64 = 0.0f64;
assert_eq!(0.0, zero);
assert!(!zero.is_infinite());
assert!(zero.is_finite());
assert!(zero.is_sign_positive());
assert!(!zero.is_sign_negative());
assert!(!zero.is_nan());
assert!(!zero.is_normal());
assert_eq!(Fp::Zero, zero.classify());
}
#[test]
fn test_neg_zero() {
let neg_zero: f64 = -0.0;
assert_eq!(0.0, neg_zero);
assert!(!neg_zero.is_infinite());
assert!(neg_zero.is_finite());
assert!(!neg_zero.is_sign_positive());
assert!(neg_zero.is_sign_negative());
assert!(!neg_zero.is_nan());
assert!(!neg_zero.is_normal());
assert_eq!(Fp::Zero, neg_zero.classify());
}
#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
#[test]
fn test_one() {
let one: f64 = 1.0f64;
assert_eq!(1.0, one);
assert!(!one.is_infinite());
assert!(one.is_finite());
assert!(one.is_sign_positive());
assert!(!one.is_sign_negative());
assert!(!one.is_nan());
assert!(one.is_normal());
assert_eq!(Fp::Normal, one.classify());
}
#[test]
fn test_is_nan() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert!(nan.is_nan());
assert!(!0.0f64.is_nan());
assert!(!5.3f64.is_nan());
assert!(!(-10.732f64).is_nan());
assert!(!inf.is_nan());
assert!(!neg_inf.is_nan());
}
#[test]
fn test_is_infinite() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert!(!nan.is_infinite());
assert!(inf.is_infinite());
assert!(neg_inf.is_infinite());
assert!(!0.0f64.is_infinite());
assert!(!42.8f64.is_infinite());
assert!(!(-109.2f64).is_infinite());
}
#[test]
fn test_is_finite() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert!(!nan.is_finite());
assert!(!inf.is_finite());
assert!(!neg_inf.is_finite());
assert!(0.0f64.is_finite());
assert!(42.8f64.is_finite());
assert!((-109.2f64).is_finite());
}
#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
#[test]
fn test_is_normal() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let zero: f64 = 0.0f64;
let neg_zero: f64 = -0.0;
assert!(!nan.is_normal());
assert!(!inf.is_normal());
assert!(!neg_inf.is_normal());
assert!(!zero.is_normal());
assert!(!neg_zero.is_normal());
assert!(1f64.is_normal());
assert!(1e-307f64.is_normal());
assert!(!1e-308f64.is_normal());
}
#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
#[test]
fn test_classify() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let zero: f64 = 0.0f64;
let neg_zero: f64 = -0.0;
assert_eq!(nan.classify(), Fp::Nan);
assert_eq!(inf.classify(), Fp::Infinite);
assert_eq!(neg_inf.classify(), Fp::Infinite);
assert_eq!(zero.classify(), Fp::Zero);
assert_eq!(neg_zero.classify(), Fp::Zero);
assert_eq!(1e-307f64.classify(), Fp::Normal);
assert_eq!(1e-308f64.classify(), Fp::Subnormal);
}
#[test]
fn test_floor() {
assert_approx_eq!(1.0f64.floor(), 1.0f64);
assert_approx_eq!(1.3f64.floor(), 1.0f64);
assert_approx_eq!(1.5f64.floor(), 1.0f64);
assert_approx_eq!(1.7f64.floor(), 1.0f64);
assert_approx_eq!(0.0f64.floor(), 0.0f64);
assert_approx_eq!((-0.0f64).floor(), -0.0f64);
assert_approx_eq!((-1.0f64).floor(), -1.0f64);
assert_approx_eq!((-1.3f64).floor(), -2.0f64);
assert_approx_eq!((-1.5f64).floor(), -2.0f64);
assert_approx_eq!((-1.7f64).floor(), -2.0f64);
}
#[test]
fn test_ceil() {
assert_approx_eq!(1.0f64.ceil(), 1.0f64);
assert_approx_eq!(1.3f64.ceil(), 2.0f64);
assert_approx_eq!(1.5f64.ceil(), 2.0f64);
assert_approx_eq!(1.7f64.ceil(), 2.0f64);
assert_approx_eq!(0.0f64.ceil(), 0.0f64);
assert_approx_eq!((-0.0f64).ceil(), -0.0f64);
assert_approx_eq!((-1.0f64).ceil(), -1.0f64);
assert_approx_eq!((-1.3f64).ceil(), -1.0f64);
assert_approx_eq!((-1.5f64).ceil(), -1.0f64);
assert_approx_eq!((-1.7f64).ceil(), -1.0f64);
}
#[test]
fn test_round() {
assert_approx_eq!(1.0f64.round(), 1.0f64);
assert_approx_eq!(1.3f64.round(), 1.0f64);
assert_approx_eq!(1.5f64.round(), 2.0f64);
assert_approx_eq!(1.7f64.round(), 2.0f64);
assert_approx_eq!(0.0f64.round(), 0.0f64);
assert_approx_eq!((-0.0f64).round(), -0.0f64);
assert_approx_eq!((-1.0f64).round(), -1.0f64);
assert_approx_eq!((-1.3f64).round(), -1.0f64);
assert_approx_eq!((-1.5f64).round(), -2.0f64);
assert_approx_eq!((-1.7f64).round(), -2.0f64);
}
#[test]
fn test_trunc() {
assert_approx_eq!(1.0f64.trunc(), 1.0f64);
assert_approx_eq!(1.3f64.trunc(), 1.0f64);
assert_approx_eq!(1.5f64.trunc(), 1.0f64);
assert_approx_eq!(1.7f64.trunc(), 1.0f64);
assert_approx_eq!(0.0f64.trunc(), 0.0f64);
assert_approx_eq!((-0.0f64).trunc(), -0.0f64);
assert_approx_eq!((-1.0f64).trunc(), -1.0f64);
assert_approx_eq!((-1.3f64).trunc(), -1.0f64);
assert_approx_eq!((-1.5f64).trunc(), -1.0f64);
assert_approx_eq!((-1.7f64).trunc(), -1.0f64);
}
#[test]
fn test_fract() {
assert_approx_eq!(1.0f64.fract(), 0.0f64);
assert_approx_eq!(1.3f64.fract(), 0.3f64);
assert_approx_eq!(1.5f64.fract(), 0.5f64);
assert_approx_eq!(1.7f64.fract(), 0.7f64);
assert_approx_eq!(0.0f64.fract(), 0.0f64);
assert_approx_eq!((-0.0f64).fract(), -0.0f64);
assert_approx_eq!((-1.0f64).fract(), -0.0f64);
assert_approx_eq!((-1.3f64).fract(), -0.3f64);
assert_approx_eq!((-1.5f64).fract(), -0.5f64);
assert_approx_eq!((-1.7f64).fract(), -0.7f64);
}
#[test]
fn test_abs() {
assert_eq!(f64::INFINITY.abs(), f64::INFINITY);
assert_eq!(1f64.abs(), 1f64);
assert_eq!(0f64.abs(), 0f64);
assert_eq!((-0f64).abs(), 0f64);
assert_eq!((-1f64).abs(), 1f64);
assert_eq!(f64::NEG_INFINITY.abs(), f64::INFINITY);
assert_eq!((1f64 / f64::NEG_INFINITY).abs(), 0f64);
assert!(f64::NAN.abs().is_nan());
}
#[test]
fn test_signum() {
assert_eq!(f64::INFINITY.signum(), 1f64);
assert_eq!(1f64.signum(), 1f64);
assert_eq!(0f64.signum(), 1f64);
assert_eq!((-0f64).signum(), -1f64);
assert_eq!((-1f64).signum(), -1f64);
assert_eq!(f64::NEG_INFINITY.signum(), -1f64);
assert_eq!((1f64 / f64::NEG_INFINITY).signum(), -1f64);
assert!(f64::NAN.signum().is_nan());
}
#[test]
fn test_is_sign_positive() {
assert!(f64::INFINITY.is_sign_positive());
assert!(1f64.is_sign_positive());
assert!(0f64.is_sign_positive());
assert!(!(-0f64).is_sign_positive());
assert!(!(-1f64).is_sign_positive());
assert!(!f64::NEG_INFINITY.is_sign_positive());
assert!(!(1f64 / f64::NEG_INFINITY).is_sign_positive());
assert!(f64::NAN.is_sign_positive());
assert!(!(-f64::NAN).is_sign_positive());
}
#[test]
fn test_is_sign_negative() {
assert!(!f64::INFINITY.is_sign_negative());
assert!(!1f64.is_sign_negative());
assert!(!0f64.is_sign_negative());
assert!((-0f64).is_sign_negative());
assert!((-1f64).is_sign_negative());
assert!(f64::NEG_INFINITY.is_sign_negative());
assert!((1f64 / f64::NEG_INFINITY).is_sign_negative());
assert!(!f64::NAN.is_sign_negative());
assert!((-f64::NAN).is_sign_negative());
}
#[test]
fn test_mul_add() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05);
assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65);
assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2);
assert_approx_eq!(3.4f64.mul_add(-0.0, 5.6), 5.6);
assert!(nan.mul_add(7.8, 9.0).is_nan());
assert_eq!(inf.mul_add(7.8, 9.0), inf);
assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
assert_eq!(8.9f64.mul_add(inf, 3.2), inf);
assert_eq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf);
}
#[test]
fn test_recip() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(1.0f64.recip(), 1.0);
assert_eq!(2.0f64.recip(), 0.5);
assert_eq!((-0.4f64).recip(), -2.5);
assert_eq!(0.0f64.recip(), inf);
assert!(nan.recip().is_nan());
assert_eq!(inf.recip(), 0.0);
assert_eq!(neg_inf.recip(), 0.0);
}
#[test]
fn test_powi() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(1.0f64.powi(1), 1.0);
assert_approx_eq!((-3.1f64).powi(2), 9.61);
assert_approx_eq!(5.9f64.powi(-2), 0.028727);
assert_eq!(8.3f64.powi(0), 1.0);
assert!(nan.powi(2).is_nan());
assert_eq!(inf.powi(3), inf);
assert_eq!(neg_inf.powi(2), inf);
}
#[test]
fn test_powf() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(1.0f64.powf(1.0), 1.0);
assert_approx_eq!(3.4f64.powf(4.5), 246.408183);
assert_approx_eq!(2.7f64.powf(-3.2), 0.041652);
assert_approx_eq!((-3.1f64).powf(2.0), 9.61);
assert_approx_eq!(5.9f64.powf(-2.0), 0.028727);
assert_eq!(8.3f64.powf(0.0), 1.0);
assert!(nan.powf(2.0).is_nan());
assert_eq!(inf.powf(2.0), inf);
assert_eq!(neg_inf.powf(3.0), neg_inf);
}
#[test]
fn test_sqrt_domain() {
assert!(f64::NAN.sqrt().is_nan());
assert!(f64::NEG_INFINITY.sqrt().is_nan());
assert!((-1.0f64).sqrt().is_nan());
assert_eq!((-0.0f64).sqrt(), -0.0);
assert_eq!(0.0f64.sqrt(), 0.0);
assert_eq!(1.0f64.sqrt(), 1.0);
assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY);
}
#[test]
fn test_exp() {
assert_eq!(1.0, 0.0f64.exp());
assert_approx_eq!(2.718282, 1.0f64.exp());
assert_approx_eq!(148.413159, 5.0f64.exp());
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let nan: f64 = f64::NAN;
assert_eq!(inf, inf.exp());
assert_eq!(0.0, neg_inf.exp());
assert!(nan.exp().is_nan());
}
#[test]
fn test_exp2() {
assert_eq!(32.0, 5.0f64.exp2());
assert_eq!(1.0, 0.0f64.exp2());
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let nan: f64 = f64::NAN;
assert_eq!(inf, inf.exp2());
assert_eq!(0.0, neg_inf.exp2());
assert!(nan.exp2().is_nan());
}
#[test]
fn test_ln() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_approx_eq!(1.0f64.exp().ln(), 1.0);
assert!(nan.ln().is_nan());
assert_eq!(inf.ln(), inf);
assert!(neg_inf.ln().is_nan());
assert!((-2.3f64).ln().is_nan());
assert_eq!((-0.0f64).ln(), neg_inf);
assert_eq!(0.0f64.ln(), neg_inf);
assert_approx_eq!(4.0f64.ln(), 1.386294);
}
#[test]
fn test_log() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(10.0f64.log(10.0), 1.0);
assert_approx_eq!(2.3f64.log(3.5), 0.664858);
assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0);
assert!(1.0f64.log(1.0).is_nan());
assert!(1.0f64.log(-13.9).is_nan());
assert!(nan.log(2.3).is_nan());
assert_eq!(inf.log(10.0), inf);
assert!(neg_inf.log(8.8).is_nan());
assert!((-2.3f64).log(0.1).is_nan());
assert_eq!((-0.0f64).log(2.0), neg_inf);
assert_eq!(0.0f64.log(7.0), neg_inf);
}
#[test]
fn test_log2() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_approx_eq!(10.0f64.log2(), 3.321928);
assert_approx_eq!(2.3f64.log2(), 1.201634);
assert_approx_eq!(1.0f64.exp().log2(), 1.442695);
assert!(nan.log2().is_nan());
assert_eq!(inf.log2(), inf);
assert!(neg_inf.log2().is_nan());
assert!((-2.3f64).log2().is_nan());
assert_eq!((-0.0f64).log2(), neg_inf);
assert_eq!(0.0f64.log2(), neg_inf);
}
#[test]
fn test_log10() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(10.0f64.log10(), 1.0);
assert_approx_eq!(2.3f64.log10(), 0.361728);
assert_approx_eq!(1.0f64.exp().log10(), 0.434294);
assert_eq!(1.0f64.log10(), 0.0);
assert!(nan.log10().is_nan());
assert_eq!(inf.log10(), inf);
assert!(neg_inf.log10().is_nan());
assert!((-2.3f64).log10().is_nan());
assert_eq!((-0.0f64).log10(), neg_inf);
assert_eq!(0.0f64.log10(), neg_inf);
}
#[test]
fn test_to_degrees() {
let pi: f64 = consts::PI;
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(0.0f64.to_degrees(), 0.0);
assert_approx_eq!((-5.8f64).to_degrees(), -332.315521);
assert_eq!(pi.to_degrees(), 180.0);
assert!(nan.to_degrees().is_nan());
assert_eq!(inf.to_degrees(), inf);
assert_eq!(neg_inf.to_degrees(), neg_inf);
}
#[test]
fn test_to_radians() {
let pi: f64 = consts::PI;
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(0.0f64.to_radians(), 0.0);
assert_approx_eq!(154.6f64.to_radians(), 2.698279);
assert_approx_eq!((-332.31f64).to_radians(), -5.799903);
assert_eq!(180.0f64.to_radians(), pi);
assert!(nan.to_radians().is_nan());
assert_eq!(inf.to_radians(), inf);
assert_eq!(neg_inf.to_radians(), neg_inf);
}
#[test]
fn test_asinh() {
assert_eq!(0.0f64.asinh(), 0.0f64);
assert_eq!((-0.0f64).asinh(), -0.0f64);
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let nan: f64 = f64::NAN;
assert_eq!(inf.asinh(), inf);
assert_eq!(neg_inf.asinh(), neg_inf);
assert!(nan.asinh().is_nan());
assert!((-0.0f64).asinh().is_sign_negative());
// issue 63271
assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
// regression test for the catastrophic cancellation fixed in 72486
assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083);
}
#[test]
fn test_acosh() {
assert_eq!(1.0f64.acosh(), 0.0f64);
assert!(0.999f64.acosh().is_nan());
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let nan: f64 = f64::NAN;
assert_eq!(inf.acosh(), inf);
assert!(neg_inf.acosh().is_nan());
assert!(nan.acosh().is_nan());
assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64);
assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64);
}
#[test]
fn test_atanh() {
assert_eq!(0.0f64.atanh(), 0.0f64);
assert_eq!((-0.0f64).atanh(), -0.0f64);
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let nan: f64 = f64::NAN;
assert_eq!(1.0f64.atanh(), inf);
assert_eq!((-1.0f64).atanh(), neg_inf);
assert!(2f64.atanh().atanh().is_nan());
assert!((-2f64).atanh().atanh().is_nan());
assert!(inf.atanh().is_nan());
assert!(neg_inf.atanh().is_nan());
assert!(nan.atanh().is_nan());
assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64);
}
#[test]
fn test_real_consts() {
use super::consts;
let pi: f64 = consts::PI;
let frac_pi_2: f64 = consts::FRAC_PI_2;
let frac_pi_3: f64 = consts::FRAC_PI_3;
let frac_pi_4: f64 = consts::FRAC_PI_4;
let frac_pi_6: f64 = consts::FRAC_PI_6;
let frac_pi_8: f64 = consts::FRAC_PI_8;
let frac_1_pi: f64 = consts::FRAC_1_PI;
let frac_2_pi: f64 = consts::FRAC_2_PI;
let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI;
let sqrt2: f64 = consts::SQRT_2;
let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2;
let e: f64 = consts::E;
let log2_e: f64 = consts::LOG2_E;
let log10_e: f64 = consts::LOG10_E;
let ln_2: f64 = consts::LN_2;
let ln_10: f64 = consts::LN_10;
assert_approx_eq!(frac_pi_2, pi / 2f64);
assert_approx_eq!(frac_pi_3, pi / 3f64);
assert_approx_eq!(frac_pi_4, pi / 4f64);
assert_approx_eq!(frac_pi_6, pi / 6f64);
assert_approx_eq!(frac_pi_8, pi / 8f64);
assert_approx_eq!(frac_1_pi, 1f64 / pi);
assert_approx_eq!(frac_2_pi, 2f64 / pi);
assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt());
assert_approx_eq!(sqrt2, 2f64.sqrt());
assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt());
assert_approx_eq!(log2_e, e.log2());
assert_approx_eq!(log10_e, e.log10());
assert_approx_eq!(ln_2, 2f64.ln());
assert_approx_eq!(ln_10, 10f64.ln());
}
#[test]
fn test_float_bits_conv() {
assert_eq!((1f64).to_bits(), 0x3ff0000000000000);
assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
assert_eq!((1337f64).to_bits(), 0x4094e40000000000);
assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000);
assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0);
assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5);
assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0);
assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25);
// Check that NaNs roundtrip their bits regardless of signaling-ness
// 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
assert!(f64::from_bits(masked_nan1).is_nan());
assert!(f64::from_bits(masked_nan2).is_nan());
assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1);
assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2);
}
#[test]
#[should_panic]
fn test_clamp_min_greater_than_max() {
let _ = 1.0f64.clamp(3.0, 1.0);
}
#[test]
#[should_panic]
fn test_clamp_min_is_nan() {
let _ = 1.0f64.clamp(f64::NAN, 1.0);
}
#[test]
#[should_panic]
fn test_clamp_max_is_nan() {
let _ = 1.0f64.clamp(3.0, f64::NAN);
}
#[test]
fn test_total_cmp() {
use core::cmp::Ordering;
fn quiet_bit_mask() -> u64 {
1 << (f64::MANTISSA_DIGITS - 2)
}
fn min_subnorm() -> f64 {
f64::MIN_POSITIVE / f64::powf(2.0, f64::MANTISSA_DIGITS as f64 - 1.0)
}
fn max_subnorm() -> f64 {
f64::MIN_POSITIVE - min_subnorm()
}
fn q_nan() -> f64 {
f64::from_bits(f64::NAN.to_bits() | quiet_bit_mask())
}
fn s_nan() -> f64 {
f64::from_bits((f64::NAN.to_bits() & !quiet_bit_mask()) + 42)
}
assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan()));
assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Equal, (-f64::INFINITY).total_cmp(&-f64::INFINITY));
assert_eq!(Ordering::Equal, (-f64::MAX).total_cmp(&-f64::MAX));
assert_eq!(Ordering::Equal, (-2.5_f64).total_cmp(&-2.5));
assert_eq!(Ordering::Equal, (-1.0_f64).total_cmp(&-1.0));
assert_eq!(Ordering::Equal, (-1.5_f64).total_cmp(&-1.5));
assert_eq!(Ordering::Equal, (-0.5_f64).total_cmp(&-0.5));
assert_eq!(Ordering::Equal, (-f64::MIN_POSITIVE).total_cmp(&-f64::MIN_POSITIVE));
assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Equal, (-0.0_f64).total_cmp(&-0.0));
assert_eq!(Ordering::Equal, 0.0_f64.total_cmp(&0.0));
assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm()));
assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm()));
assert_eq!(Ordering::Equal, f64::MIN_POSITIVE.total_cmp(&f64::MIN_POSITIVE));
assert_eq!(Ordering::Equal, 0.5_f64.total_cmp(&0.5));
assert_eq!(Ordering::Equal, 1.0_f64.total_cmp(&1.0));
assert_eq!(Ordering::Equal, 1.5_f64.total_cmp(&1.5));
assert_eq!(Ordering::Equal, 2.5_f64.total_cmp(&2.5));
assert_eq!(Ordering::Equal, f64::MAX.total_cmp(&f64::MAX));
assert_eq!(Ordering::Equal, f64::INFINITY.total_cmp(&f64::INFINITY));
assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan()));
assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY));
assert_eq!(Ordering::Less, (-f64::INFINITY).total_cmp(&-f64::MAX));
assert_eq!(Ordering::Less, (-f64::MAX).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-2.5_f64).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-1.5_f64).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-1.0_f64).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-0.5_f64).total_cmp(&-f64::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-f64::MIN_POSITIVE).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-0.0_f64).total_cmp(&0.0));
assert_eq!(Ordering::Less, 0.0_f64.total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f64::MIN_POSITIVE));
assert_eq!(Ordering::Less, f64::MIN_POSITIVE.total_cmp(&0.5));
assert_eq!(Ordering::Less, 0.5_f64.total_cmp(&1.0));
assert_eq!(Ordering::Less, 1.0_f64.total_cmp(&1.5));
assert_eq!(Ordering::Less, 1.5_f64.total_cmp(&2.5));
assert_eq!(Ordering::Less, 2.5_f64.total_cmp(&f64::MAX));
assert_eq!(Ordering::Less, f64::MAX.total_cmp(&f64::INFINITY));
assert_eq!(Ordering::Less, f64::INFINITY.total_cmp(&s_nan()));
assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan()));
assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan()));
assert_eq!(Ordering::Greater, (-f64::INFINITY).total_cmp(&-s_nan()));
assert_eq!(Ordering::Greater, (-f64::MAX).total_cmp(&-f64::INFINITY));
assert_eq!(Ordering::Greater, (-2.5_f64).total_cmp(&-f64::MAX));
assert_eq!(Ordering::Greater, (-1.5_f64).total_cmp(&-2.5));
assert_eq!(Ordering::Greater, (-1.0_f64).total_cmp(&-1.5));
assert_eq!(Ordering::Greater, (-0.5_f64).total_cmp(&-1.0));
assert_eq!(Ordering::Greater, (-f64::MIN_POSITIVE).total_cmp(&-0.5));
assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f64::MIN_POSITIVE));
assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Greater, (-0.0_f64).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Greater, 0.0_f64.total_cmp(&-0.0));
assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0));
assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm()));
assert_eq!(Ordering::Greater, f64::MIN_POSITIVE.total_cmp(&max_subnorm()));
assert_eq!(Ordering::Greater, 0.5_f64.total_cmp(&f64::MIN_POSITIVE));
assert_eq!(Ordering::Greater, 1.0_f64.total_cmp(&0.5));
assert_eq!(Ordering::Greater, 1.5_f64.total_cmp(&1.0));
assert_eq!(Ordering::Greater, 2.5_f64.total_cmp(&1.5));
assert_eq!(Ordering::Greater, f64::MAX.total_cmp(&2.5));
assert_eq!(Ordering::Greater, f64::INFINITY.total_cmp(&f64::MAX));
assert_eq!(Ordering::Greater, s_nan().total_cmp(&f64::INFINITY));
assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::INFINITY));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MAX));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MAX));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::INFINITY));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MAX));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MAX));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
}
}

View file

@ -0,0 +1,755 @@
use crate::f64::consts;
use crate::num::FpCategory as Fp;
use crate::num::*;
#[test]
fn test_num_f64() {
test_num(10f64, 2f64);
}
#[test]
fn test_min_nan() {
assert_eq!(f64::NAN.min(2.0), 2.0);
assert_eq!(2.0f64.min(f64::NAN), 2.0);
}
#[test]
fn test_max_nan() {
assert_eq!(f64::NAN.max(2.0), 2.0);
assert_eq!(2.0f64.max(f64::NAN), 2.0);
}
#[test]
fn test_nan() {
let nan: f64 = f64::NAN;
assert!(nan.is_nan());
assert!(!nan.is_infinite());
assert!(!nan.is_finite());
assert!(!nan.is_normal());
assert!(nan.is_sign_positive());
assert!(!nan.is_sign_negative());
assert_eq!(Fp::Nan, nan.classify());
}
#[test]
fn test_infinity() {
let inf: f64 = f64::INFINITY;
assert!(inf.is_infinite());
assert!(!inf.is_finite());
assert!(inf.is_sign_positive());
assert!(!inf.is_sign_negative());
assert!(!inf.is_nan());
assert!(!inf.is_normal());
assert_eq!(Fp::Infinite, inf.classify());
}
#[test]
fn test_neg_infinity() {
let neg_inf: f64 = f64::NEG_INFINITY;
assert!(neg_inf.is_infinite());
assert!(!neg_inf.is_finite());
assert!(!neg_inf.is_sign_positive());
assert!(neg_inf.is_sign_negative());
assert!(!neg_inf.is_nan());
assert!(!neg_inf.is_normal());
assert_eq!(Fp::Infinite, neg_inf.classify());
}
#[test]
fn test_zero() {
let zero: f64 = 0.0f64;
assert_eq!(0.0, zero);
assert!(!zero.is_infinite());
assert!(zero.is_finite());
assert!(zero.is_sign_positive());
assert!(!zero.is_sign_negative());
assert!(!zero.is_nan());
assert!(!zero.is_normal());
assert_eq!(Fp::Zero, zero.classify());
}
#[test]
fn test_neg_zero() {
let neg_zero: f64 = -0.0;
assert_eq!(0.0, neg_zero);
assert!(!neg_zero.is_infinite());
assert!(neg_zero.is_finite());
assert!(!neg_zero.is_sign_positive());
assert!(neg_zero.is_sign_negative());
assert!(!neg_zero.is_nan());
assert!(!neg_zero.is_normal());
assert_eq!(Fp::Zero, neg_zero.classify());
}
#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
#[test]
fn test_one() {
let one: f64 = 1.0f64;
assert_eq!(1.0, one);
assert!(!one.is_infinite());
assert!(one.is_finite());
assert!(one.is_sign_positive());
assert!(!one.is_sign_negative());
assert!(!one.is_nan());
assert!(one.is_normal());
assert_eq!(Fp::Normal, one.classify());
}
#[test]
fn test_is_nan() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert!(nan.is_nan());
assert!(!0.0f64.is_nan());
assert!(!5.3f64.is_nan());
assert!(!(-10.732f64).is_nan());
assert!(!inf.is_nan());
assert!(!neg_inf.is_nan());
}
#[test]
fn test_is_infinite() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert!(!nan.is_infinite());
assert!(inf.is_infinite());
assert!(neg_inf.is_infinite());
assert!(!0.0f64.is_infinite());
assert!(!42.8f64.is_infinite());
assert!(!(-109.2f64).is_infinite());
}
#[test]
fn test_is_finite() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert!(!nan.is_finite());
assert!(!inf.is_finite());
assert!(!neg_inf.is_finite());
assert!(0.0f64.is_finite());
assert!(42.8f64.is_finite());
assert!((-109.2f64).is_finite());
}
#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
#[test]
fn test_is_normal() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let zero: f64 = 0.0f64;
let neg_zero: f64 = -0.0;
assert!(!nan.is_normal());
assert!(!inf.is_normal());
assert!(!neg_inf.is_normal());
assert!(!zero.is_normal());
assert!(!neg_zero.is_normal());
assert!(1f64.is_normal());
assert!(1e-307f64.is_normal());
assert!(!1e-308f64.is_normal());
}
#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
#[test]
fn test_classify() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let zero: f64 = 0.0f64;
let neg_zero: f64 = -0.0;
assert_eq!(nan.classify(), Fp::Nan);
assert_eq!(inf.classify(), Fp::Infinite);
assert_eq!(neg_inf.classify(), Fp::Infinite);
assert_eq!(zero.classify(), Fp::Zero);
assert_eq!(neg_zero.classify(), Fp::Zero);
assert_eq!(1e-307f64.classify(), Fp::Normal);
assert_eq!(1e-308f64.classify(), Fp::Subnormal);
}
#[test]
fn test_floor() {
assert_approx_eq!(1.0f64.floor(), 1.0f64);
assert_approx_eq!(1.3f64.floor(), 1.0f64);
assert_approx_eq!(1.5f64.floor(), 1.0f64);
assert_approx_eq!(1.7f64.floor(), 1.0f64);
assert_approx_eq!(0.0f64.floor(), 0.0f64);
assert_approx_eq!((-0.0f64).floor(), -0.0f64);
assert_approx_eq!((-1.0f64).floor(), -1.0f64);
assert_approx_eq!((-1.3f64).floor(), -2.0f64);
assert_approx_eq!((-1.5f64).floor(), -2.0f64);
assert_approx_eq!((-1.7f64).floor(), -2.0f64);
}
#[test]
fn test_ceil() {
assert_approx_eq!(1.0f64.ceil(), 1.0f64);
assert_approx_eq!(1.3f64.ceil(), 2.0f64);
assert_approx_eq!(1.5f64.ceil(), 2.0f64);
assert_approx_eq!(1.7f64.ceil(), 2.0f64);
assert_approx_eq!(0.0f64.ceil(), 0.0f64);
assert_approx_eq!((-0.0f64).ceil(), -0.0f64);
assert_approx_eq!((-1.0f64).ceil(), -1.0f64);
assert_approx_eq!((-1.3f64).ceil(), -1.0f64);
assert_approx_eq!((-1.5f64).ceil(), -1.0f64);
assert_approx_eq!((-1.7f64).ceil(), -1.0f64);
}
#[test]
fn test_round() {
assert_approx_eq!(1.0f64.round(), 1.0f64);
assert_approx_eq!(1.3f64.round(), 1.0f64);
assert_approx_eq!(1.5f64.round(), 2.0f64);
assert_approx_eq!(1.7f64.round(), 2.0f64);
assert_approx_eq!(0.0f64.round(), 0.0f64);
assert_approx_eq!((-0.0f64).round(), -0.0f64);
assert_approx_eq!((-1.0f64).round(), -1.0f64);
assert_approx_eq!((-1.3f64).round(), -1.0f64);
assert_approx_eq!((-1.5f64).round(), -2.0f64);
assert_approx_eq!((-1.7f64).round(), -2.0f64);
}
#[test]
fn test_trunc() {
assert_approx_eq!(1.0f64.trunc(), 1.0f64);
assert_approx_eq!(1.3f64.trunc(), 1.0f64);
assert_approx_eq!(1.5f64.trunc(), 1.0f64);
assert_approx_eq!(1.7f64.trunc(), 1.0f64);
assert_approx_eq!(0.0f64.trunc(), 0.0f64);
assert_approx_eq!((-0.0f64).trunc(), -0.0f64);
assert_approx_eq!((-1.0f64).trunc(), -1.0f64);
assert_approx_eq!((-1.3f64).trunc(), -1.0f64);
assert_approx_eq!((-1.5f64).trunc(), -1.0f64);
assert_approx_eq!((-1.7f64).trunc(), -1.0f64);
}
#[test]
fn test_fract() {
assert_approx_eq!(1.0f64.fract(), 0.0f64);
assert_approx_eq!(1.3f64.fract(), 0.3f64);
assert_approx_eq!(1.5f64.fract(), 0.5f64);
assert_approx_eq!(1.7f64.fract(), 0.7f64);
assert_approx_eq!(0.0f64.fract(), 0.0f64);
assert_approx_eq!((-0.0f64).fract(), -0.0f64);
assert_approx_eq!((-1.0f64).fract(), -0.0f64);
assert_approx_eq!((-1.3f64).fract(), -0.3f64);
assert_approx_eq!((-1.5f64).fract(), -0.5f64);
assert_approx_eq!((-1.7f64).fract(), -0.7f64);
}
#[test]
fn test_abs() {
assert_eq!(f64::INFINITY.abs(), f64::INFINITY);
assert_eq!(1f64.abs(), 1f64);
assert_eq!(0f64.abs(), 0f64);
assert_eq!((-0f64).abs(), 0f64);
assert_eq!((-1f64).abs(), 1f64);
assert_eq!(f64::NEG_INFINITY.abs(), f64::INFINITY);
assert_eq!((1f64 / f64::NEG_INFINITY).abs(), 0f64);
assert!(f64::NAN.abs().is_nan());
}
#[test]
fn test_signum() {
assert_eq!(f64::INFINITY.signum(), 1f64);
assert_eq!(1f64.signum(), 1f64);
assert_eq!(0f64.signum(), 1f64);
assert_eq!((-0f64).signum(), -1f64);
assert_eq!((-1f64).signum(), -1f64);
assert_eq!(f64::NEG_INFINITY.signum(), -1f64);
assert_eq!((1f64 / f64::NEG_INFINITY).signum(), -1f64);
assert!(f64::NAN.signum().is_nan());
}
#[test]
fn test_is_sign_positive() {
assert!(f64::INFINITY.is_sign_positive());
assert!(1f64.is_sign_positive());
assert!(0f64.is_sign_positive());
assert!(!(-0f64).is_sign_positive());
assert!(!(-1f64).is_sign_positive());
assert!(!f64::NEG_INFINITY.is_sign_positive());
assert!(!(1f64 / f64::NEG_INFINITY).is_sign_positive());
assert!(f64::NAN.is_sign_positive());
assert!(!(-f64::NAN).is_sign_positive());
}
#[test]
fn test_is_sign_negative() {
assert!(!f64::INFINITY.is_sign_negative());
assert!(!1f64.is_sign_negative());
assert!(!0f64.is_sign_negative());
assert!((-0f64).is_sign_negative());
assert!((-1f64).is_sign_negative());
assert!(f64::NEG_INFINITY.is_sign_negative());
assert!((1f64 / f64::NEG_INFINITY).is_sign_negative());
assert!(!f64::NAN.is_sign_negative());
assert!((-f64::NAN).is_sign_negative());
}
#[test]
fn test_mul_add() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05);
assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65);
assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2);
assert_approx_eq!(3.4f64.mul_add(-0.0, 5.6), 5.6);
assert!(nan.mul_add(7.8, 9.0).is_nan());
assert_eq!(inf.mul_add(7.8, 9.0), inf);
assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
assert_eq!(8.9f64.mul_add(inf, 3.2), inf);
assert_eq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf);
}
#[test]
fn test_recip() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(1.0f64.recip(), 1.0);
assert_eq!(2.0f64.recip(), 0.5);
assert_eq!((-0.4f64).recip(), -2.5);
assert_eq!(0.0f64.recip(), inf);
assert!(nan.recip().is_nan());
assert_eq!(inf.recip(), 0.0);
assert_eq!(neg_inf.recip(), 0.0);
}
#[test]
fn test_powi() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(1.0f64.powi(1), 1.0);
assert_approx_eq!((-3.1f64).powi(2), 9.61);
assert_approx_eq!(5.9f64.powi(-2), 0.028727);
assert_eq!(8.3f64.powi(0), 1.0);
assert!(nan.powi(2).is_nan());
assert_eq!(inf.powi(3), inf);
assert_eq!(neg_inf.powi(2), inf);
}
#[test]
fn test_powf() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(1.0f64.powf(1.0), 1.0);
assert_approx_eq!(3.4f64.powf(4.5), 246.408183);
assert_approx_eq!(2.7f64.powf(-3.2), 0.041652);
assert_approx_eq!((-3.1f64).powf(2.0), 9.61);
assert_approx_eq!(5.9f64.powf(-2.0), 0.028727);
assert_eq!(8.3f64.powf(0.0), 1.0);
assert!(nan.powf(2.0).is_nan());
assert_eq!(inf.powf(2.0), inf);
assert_eq!(neg_inf.powf(3.0), neg_inf);
}
#[test]
fn test_sqrt_domain() {
assert!(f64::NAN.sqrt().is_nan());
assert!(f64::NEG_INFINITY.sqrt().is_nan());
assert!((-1.0f64).sqrt().is_nan());
assert_eq!((-0.0f64).sqrt(), -0.0);
assert_eq!(0.0f64.sqrt(), 0.0);
assert_eq!(1.0f64.sqrt(), 1.0);
assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY);
}
#[test]
fn test_exp() {
assert_eq!(1.0, 0.0f64.exp());
assert_approx_eq!(2.718282, 1.0f64.exp());
assert_approx_eq!(148.413159, 5.0f64.exp());
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let nan: f64 = f64::NAN;
assert_eq!(inf, inf.exp());
assert_eq!(0.0, neg_inf.exp());
assert!(nan.exp().is_nan());
}
#[test]
fn test_exp2() {
assert_eq!(32.0, 5.0f64.exp2());
assert_eq!(1.0, 0.0f64.exp2());
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let nan: f64 = f64::NAN;
assert_eq!(inf, inf.exp2());
assert_eq!(0.0, neg_inf.exp2());
assert!(nan.exp2().is_nan());
}
#[test]
fn test_ln() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_approx_eq!(1.0f64.exp().ln(), 1.0);
assert!(nan.ln().is_nan());
assert_eq!(inf.ln(), inf);
assert!(neg_inf.ln().is_nan());
assert!((-2.3f64).ln().is_nan());
assert_eq!((-0.0f64).ln(), neg_inf);
assert_eq!(0.0f64.ln(), neg_inf);
assert_approx_eq!(4.0f64.ln(), 1.386294);
}
#[test]
fn test_log() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(10.0f64.log(10.0), 1.0);
assert_approx_eq!(2.3f64.log(3.5), 0.664858);
assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0);
assert!(1.0f64.log(1.0).is_nan());
assert!(1.0f64.log(-13.9).is_nan());
assert!(nan.log(2.3).is_nan());
assert_eq!(inf.log(10.0), inf);
assert!(neg_inf.log(8.8).is_nan());
assert!((-2.3f64).log(0.1).is_nan());
assert_eq!((-0.0f64).log(2.0), neg_inf);
assert_eq!(0.0f64.log(7.0), neg_inf);
}
#[test]
fn test_log2() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_approx_eq!(10.0f64.log2(), 3.321928);
assert_approx_eq!(2.3f64.log2(), 1.201634);
assert_approx_eq!(1.0f64.exp().log2(), 1.442695);
assert!(nan.log2().is_nan());
assert_eq!(inf.log2(), inf);
assert!(neg_inf.log2().is_nan());
assert!((-2.3f64).log2().is_nan());
assert_eq!((-0.0f64).log2(), neg_inf);
assert_eq!(0.0f64.log2(), neg_inf);
}
#[test]
fn test_log10() {
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(10.0f64.log10(), 1.0);
assert_approx_eq!(2.3f64.log10(), 0.361728);
assert_approx_eq!(1.0f64.exp().log10(), 0.434294);
assert_eq!(1.0f64.log10(), 0.0);
assert!(nan.log10().is_nan());
assert_eq!(inf.log10(), inf);
assert!(neg_inf.log10().is_nan());
assert!((-2.3f64).log10().is_nan());
assert_eq!((-0.0f64).log10(), neg_inf);
assert_eq!(0.0f64.log10(), neg_inf);
}
#[test]
fn test_to_degrees() {
let pi: f64 = consts::PI;
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(0.0f64.to_degrees(), 0.0);
assert_approx_eq!((-5.8f64).to_degrees(), -332.315521);
assert_eq!(pi.to_degrees(), 180.0);
assert!(nan.to_degrees().is_nan());
assert_eq!(inf.to_degrees(), inf);
assert_eq!(neg_inf.to_degrees(), neg_inf);
}
#[test]
fn test_to_radians() {
let pi: f64 = consts::PI;
let nan: f64 = f64::NAN;
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
assert_eq!(0.0f64.to_radians(), 0.0);
assert_approx_eq!(154.6f64.to_radians(), 2.698279);
assert_approx_eq!((-332.31f64).to_radians(), -5.799903);
assert_eq!(180.0f64.to_radians(), pi);
assert!(nan.to_radians().is_nan());
assert_eq!(inf.to_radians(), inf);
assert_eq!(neg_inf.to_radians(), neg_inf);
}
#[test]
fn test_asinh() {
assert_eq!(0.0f64.asinh(), 0.0f64);
assert_eq!((-0.0f64).asinh(), -0.0f64);
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let nan: f64 = f64::NAN;
assert_eq!(inf.asinh(), inf);
assert_eq!(neg_inf.asinh(), neg_inf);
assert!(nan.asinh().is_nan());
assert!((-0.0f64).asinh().is_sign_negative());
// issue 63271
assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
// regression test for the catastrophic cancellation fixed in 72486
assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083);
}
#[test]
fn test_acosh() {
assert_eq!(1.0f64.acosh(), 0.0f64);
assert!(0.999f64.acosh().is_nan());
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let nan: f64 = f64::NAN;
assert_eq!(inf.acosh(), inf);
assert!(neg_inf.acosh().is_nan());
assert!(nan.acosh().is_nan());
assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64);
assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64);
}
#[test]
fn test_atanh() {
assert_eq!(0.0f64.atanh(), 0.0f64);
assert_eq!((-0.0f64).atanh(), -0.0f64);
let inf: f64 = f64::INFINITY;
let neg_inf: f64 = f64::NEG_INFINITY;
let nan: f64 = f64::NAN;
assert_eq!(1.0f64.atanh(), inf);
assert_eq!((-1.0f64).atanh(), neg_inf);
assert!(2f64.atanh().atanh().is_nan());
assert!((-2f64).atanh().atanh().is_nan());
assert!(inf.atanh().is_nan());
assert!(neg_inf.atanh().is_nan());
assert!(nan.atanh().is_nan());
assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64);
}
#[test]
fn test_real_consts() {
use super::consts;
let pi: f64 = consts::PI;
let frac_pi_2: f64 = consts::FRAC_PI_2;
let frac_pi_3: f64 = consts::FRAC_PI_3;
let frac_pi_4: f64 = consts::FRAC_PI_4;
let frac_pi_6: f64 = consts::FRAC_PI_6;
let frac_pi_8: f64 = consts::FRAC_PI_8;
let frac_1_pi: f64 = consts::FRAC_1_PI;
let frac_2_pi: f64 = consts::FRAC_2_PI;
let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI;
let sqrt2: f64 = consts::SQRT_2;
let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2;
let e: f64 = consts::E;
let log2_e: f64 = consts::LOG2_E;
let log10_e: f64 = consts::LOG10_E;
let ln_2: f64 = consts::LN_2;
let ln_10: f64 = consts::LN_10;
assert_approx_eq!(frac_pi_2, pi / 2f64);
assert_approx_eq!(frac_pi_3, pi / 3f64);
assert_approx_eq!(frac_pi_4, pi / 4f64);
assert_approx_eq!(frac_pi_6, pi / 6f64);
assert_approx_eq!(frac_pi_8, pi / 8f64);
assert_approx_eq!(frac_1_pi, 1f64 / pi);
assert_approx_eq!(frac_2_pi, 2f64 / pi);
assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt());
assert_approx_eq!(sqrt2, 2f64.sqrt());
assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt());
assert_approx_eq!(log2_e, e.log2());
assert_approx_eq!(log10_e, e.log10());
assert_approx_eq!(ln_2, 2f64.ln());
assert_approx_eq!(ln_10, 10f64.ln());
}
#[test]
fn test_float_bits_conv() {
assert_eq!((1f64).to_bits(), 0x3ff0000000000000);
assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
assert_eq!((1337f64).to_bits(), 0x4094e40000000000);
assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000);
assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0);
assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5);
assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0);
assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25);
// Check that NaNs roundtrip their bits regardless of signaling-ness
// 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
assert!(f64::from_bits(masked_nan1).is_nan());
assert!(f64::from_bits(masked_nan2).is_nan());
assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1);
assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2);
}
#[test]
#[should_panic]
fn test_clamp_min_greater_than_max() {
let _ = 1.0f64.clamp(3.0, 1.0);
}
#[test]
#[should_panic]
fn test_clamp_min_is_nan() {
let _ = 1.0f64.clamp(f64::NAN, 1.0);
}
#[test]
#[should_panic]
fn test_clamp_max_is_nan() {
let _ = 1.0f64.clamp(3.0, f64::NAN);
}
#[test]
fn test_total_cmp() {
use core::cmp::Ordering;
fn quiet_bit_mask() -> u64 {
1 << (f64::MANTISSA_DIGITS - 2)
}
fn min_subnorm() -> f64 {
f64::MIN_POSITIVE / f64::powf(2.0, f64::MANTISSA_DIGITS as f64 - 1.0)
}
fn max_subnorm() -> f64 {
f64::MIN_POSITIVE - min_subnorm()
}
fn q_nan() -> f64 {
f64::from_bits(f64::NAN.to_bits() | quiet_bit_mask())
}
fn s_nan() -> f64 {
f64::from_bits((f64::NAN.to_bits() & !quiet_bit_mask()) + 42)
}
assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan()));
assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Equal, (-f64::INFINITY).total_cmp(&-f64::INFINITY));
assert_eq!(Ordering::Equal, (-f64::MAX).total_cmp(&-f64::MAX));
assert_eq!(Ordering::Equal, (-2.5_f64).total_cmp(&-2.5));
assert_eq!(Ordering::Equal, (-1.0_f64).total_cmp(&-1.0));
assert_eq!(Ordering::Equal, (-1.5_f64).total_cmp(&-1.5));
assert_eq!(Ordering::Equal, (-0.5_f64).total_cmp(&-0.5));
assert_eq!(Ordering::Equal, (-f64::MIN_POSITIVE).total_cmp(&-f64::MIN_POSITIVE));
assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Equal, (-0.0_f64).total_cmp(&-0.0));
assert_eq!(Ordering::Equal, 0.0_f64.total_cmp(&0.0));
assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm()));
assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm()));
assert_eq!(Ordering::Equal, f64::MIN_POSITIVE.total_cmp(&f64::MIN_POSITIVE));
assert_eq!(Ordering::Equal, 0.5_f64.total_cmp(&0.5));
assert_eq!(Ordering::Equal, 1.0_f64.total_cmp(&1.0));
assert_eq!(Ordering::Equal, 1.5_f64.total_cmp(&1.5));
assert_eq!(Ordering::Equal, 2.5_f64.total_cmp(&2.5));
assert_eq!(Ordering::Equal, f64::MAX.total_cmp(&f64::MAX));
assert_eq!(Ordering::Equal, f64::INFINITY.total_cmp(&f64::INFINITY));
assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan()));
assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY));
assert_eq!(Ordering::Less, (-f64::INFINITY).total_cmp(&-f64::MAX));
assert_eq!(Ordering::Less, (-f64::MAX).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-2.5_f64).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-1.5_f64).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-1.0_f64).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-0.5_f64).total_cmp(&-f64::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-f64::MIN_POSITIVE).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-0.0_f64).total_cmp(&0.0));
assert_eq!(Ordering::Less, 0.0_f64.total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f64::MIN_POSITIVE));
assert_eq!(Ordering::Less, f64::MIN_POSITIVE.total_cmp(&0.5));
assert_eq!(Ordering::Less, 0.5_f64.total_cmp(&1.0));
assert_eq!(Ordering::Less, 1.0_f64.total_cmp(&1.5));
assert_eq!(Ordering::Less, 1.5_f64.total_cmp(&2.5));
assert_eq!(Ordering::Less, 2.5_f64.total_cmp(&f64::MAX));
assert_eq!(Ordering::Less, f64::MAX.total_cmp(&f64::INFINITY));
assert_eq!(Ordering::Less, f64::INFINITY.total_cmp(&s_nan()));
assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan()));
assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan()));
assert_eq!(Ordering::Greater, (-f64::INFINITY).total_cmp(&-s_nan()));
assert_eq!(Ordering::Greater, (-f64::MAX).total_cmp(&-f64::INFINITY));
assert_eq!(Ordering::Greater, (-2.5_f64).total_cmp(&-f64::MAX));
assert_eq!(Ordering::Greater, (-1.5_f64).total_cmp(&-2.5));
assert_eq!(Ordering::Greater, (-1.0_f64).total_cmp(&-1.5));
assert_eq!(Ordering::Greater, (-0.5_f64).total_cmp(&-1.0));
assert_eq!(Ordering::Greater, (-f64::MIN_POSITIVE).total_cmp(&-0.5));
assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f64::MIN_POSITIVE));
assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Greater, (-0.0_f64).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Greater, 0.0_f64.total_cmp(&-0.0));
assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0));
assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm()));
assert_eq!(Ordering::Greater, f64::MIN_POSITIVE.total_cmp(&max_subnorm()));
assert_eq!(Ordering::Greater, 0.5_f64.total_cmp(&f64::MIN_POSITIVE));
assert_eq!(Ordering::Greater, 1.0_f64.total_cmp(&0.5));
assert_eq!(Ordering::Greater, 1.5_f64.total_cmp(&1.0));
assert_eq!(Ordering::Greater, 2.5_f64.total_cmp(&1.5));
assert_eq!(Ordering::Greater, f64::MAX.total_cmp(&2.5));
assert_eq!(Ordering::Greater, f64::INFINITY.total_cmp(&f64::MAX));
assert_eq!(Ordering::Greater, s_nan().total_cmp(&f64::INFINITY));
assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::INFINITY));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MAX));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MAX));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::INFINITY));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MAX));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MAX));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
}

View file

@ -1,4 +1,8 @@
#![deny(unsafe_op_in_unsafe_fn)]
#[cfg(test)]
mod tests;
use crate::ascii;
use crate::borrow::{Borrow, Cow};
use crate::cmp::Ordering;
@ -1522,202 +1526,3 @@ impl AsRef<CStr> for CString {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::borrow::Cow::{Borrowed, Owned};
use crate::collections::hash_map::DefaultHasher;
use crate::hash::{Hash, Hasher};
use crate::os::raw::c_char;
use crate::rc::Rc;
use crate::sync::Arc;
#[test]
fn c_to_rust() {
let data = b"123\0";
let ptr = data.as_ptr() as *const c_char;
unsafe {
assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123");
assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0");
}
}
#[test]
fn simple() {
let s = CString::new("1234").unwrap();
assert_eq!(s.as_bytes(), b"1234");
assert_eq!(s.as_bytes_with_nul(), b"1234\0");
}
#[test]
fn build_with_zero1() {
assert!(CString::new(&b"\0"[..]).is_err());
}
#[test]
fn build_with_zero2() {
assert!(CString::new(vec![0]).is_err());
}
#[test]
fn build_with_zero3() {
unsafe {
let s = CString::from_vec_unchecked(vec![0]);
assert_eq!(s.as_bytes(), b"\0");
}
}
#[test]
fn formatted() {
let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
}
#[test]
fn borrowed() {
unsafe {
let s = CStr::from_ptr(b"12\0".as_ptr() as *const _);
assert_eq!(s.to_bytes(), b"12");
assert_eq!(s.to_bytes_with_nul(), b"12\0");
}
}
#[test]
fn to_str() {
let data = b"123\xE2\x80\xA6\0";
let ptr = data.as_ptr() as *const c_char;
unsafe {
assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
}
let data = b"123\xE2\0";
let ptr = data.as_ptr() as *const c_char;
unsafe {
assert!(CStr::from_ptr(ptr).to_str().is_err());
assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::<str>(format!("123\u{FFFD}")));
}
}
#[test]
fn to_owned() {
let data = b"123\0";
let ptr = data.as_ptr() as *const c_char;
let owned = unsafe { CStr::from_ptr(ptr).to_owned() };
assert_eq!(owned.as_bytes_with_nul(), data);
}
#[test]
fn equal_hash() {
let data = b"123\xE2\xFA\xA6\0";
let ptr = data.as_ptr() as *const c_char;
let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) };
let mut s = DefaultHasher::new();
cstr.hash(&mut s);
let cstr_hash = s.finish();
let mut s = DefaultHasher::new();
CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s);
let cstring_hash = s.finish();
assert_eq!(cstr_hash, cstring_hash);
}
#[test]
fn from_bytes_with_nul() {
let data = b"123\0";
let cstr = CStr::from_bytes_with_nul(data);
assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..]));
let cstr = CStr::from_bytes_with_nul(data);
assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..]));
unsafe {
let cstr = CStr::from_bytes_with_nul(data);
let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data);
assert_eq!(cstr, Ok(cstr_unchecked));
}
}
#[test]
fn from_bytes_with_nul_unterminated() {
let data = b"123";
let cstr = CStr::from_bytes_with_nul(data);
assert!(cstr.is_err());
}
#[test]
fn from_bytes_with_nul_interior() {
let data = b"1\023\0";
let cstr = CStr::from_bytes_with_nul(data);
assert!(cstr.is_err());
}
#[test]
fn into_boxed() {
let orig: &[u8] = b"Hello, world!\0";
let cstr = CStr::from_bytes_with_nul(orig).unwrap();
let boxed: Box<CStr> = Box::from(cstr);
let cstring = cstr.to_owned().into_boxed_c_str().into_c_string();
assert_eq!(cstr, &*boxed);
assert_eq!(&*boxed, &*cstring);
assert_eq!(&*cstring, cstr);
}
#[test]
fn boxed_default() {
let boxed = <Box<CStr>>::default();
assert_eq!(boxed.to_bytes_with_nul(), &[0]);
}
#[test]
fn test_c_str_clone_into() {
let mut c_string = CString::new("lorem").unwrap();
let c_ptr = c_string.as_ptr();
let c_str = CStr::from_bytes_with_nul(b"ipsum\0").unwrap();
c_str.clone_into(&mut c_string);
assert_eq!(c_str, c_string.as_c_str());
// The exact same size shouldn't have needed to move its allocation
assert_eq!(c_ptr, c_string.as_ptr());
}
#[test]
fn into_rc() {
let orig: &[u8] = b"Hello, world!\0";
let cstr = CStr::from_bytes_with_nul(orig).unwrap();
let rc: Rc<CStr> = Rc::from(cstr);
let arc: Arc<CStr> = Arc::from(cstr);
assert_eq!(&*rc, cstr);
assert_eq!(&*arc, cstr);
let rc2: Rc<CStr> = Rc::from(cstr.to_owned());
let arc2: Arc<CStr> = Arc::from(cstr.to_owned());
assert_eq!(&*rc2, cstr);
assert_eq!(&*arc2, cstr);
}
#[test]
fn cstr_const_constructor() {
const CSTR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello, world!\0") };
assert_eq!(CSTR.to_str().unwrap(), "Hello, world!");
}
#[test]
fn cstr_index_from() {
let original = b"Hello, world!\0";
let cstr = CStr::from_bytes_with_nul(original).unwrap();
let result = CStr::from_bytes_with_nul(&original[7..]).unwrap();
assert_eq!(&cstr[7..], result);
}
#[test]
#[should_panic]
fn cstr_index_from_empty() {
let original = b"Hello, world!\0";
let cstr = CStr::from_bytes_with_nul(original).unwrap();
let _ = &cstr[original.len()..];
}
}

View file

@ -0,0 +1,195 @@
use super::*;
use crate::borrow::Cow::{Borrowed, Owned};
use crate::collections::hash_map::DefaultHasher;
use crate::hash::{Hash, Hasher};
use crate::os::raw::c_char;
use crate::rc::Rc;
use crate::sync::Arc;
#[test]
fn c_to_rust() {
let data = b"123\0";
let ptr = data.as_ptr() as *const c_char;
unsafe {
assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123");
assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0");
}
}
#[test]
fn simple() {
let s = CString::new("1234").unwrap();
assert_eq!(s.as_bytes(), b"1234");
assert_eq!(s.as_bytes_with_nul(), b"1234\0");
}
#[test]
fn build_with_zero1() {
assert!(CString::new(&b"\0"[..]).is_err());
}
#[test]
fn build_with_zero2() {
assert!(CString::new(vec![0]).is_err());
}
#[test]
fn build_with_zero3() {
unsafe {
let s = CString::from_vec_unchecked(vec![0]);
assert_eq!(s.as_bytes(), b"\0");
}
}
#[test]
fn formatted() {
let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
}
#[test]
fn borrowed() {
unsafe {
let s = CStr::from_ptr(b"12\0".as_ptr() as *const _);
assert_eq!(s.to_bytes(), b"12");
assert_eq!(s.to_bytes_with_nul(), b"12\0");
}
}
#[test]
fn to_str() {
let data = b"123\xE2\x80\xA6\0";
let ptr = data.as_ptr() as *const c_char;
unsafe {
assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
}
let data = b"123\xE2\0";
let ptr = data.as_ptr() as *const c_char;
unsafe {
assert!(CStr::from_ptr(ptr).to_str().is_err());
assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::<str>(format!("123\u{FFFD}")));
}
}
#[test]
fn to_owned() {
let data = b"123\0";
let ptr = data.as_ptr() as *const c_char;
let owned = unsafe { CStr::from_ptr(ptr).to_owned() };
assert_eq!(owned.as_bytes_with_nul(), data);
}
#[test]
fn equal_hash() {
let data = b"123\xE2\xFA\xA6\0";
let ptr = data.as_ptr() as *const c_char;
let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) };
let mut s = DefaultHasher::new();
cstr.hash(&mut s);
let cstr_hash = s.finish();
let mut s = DefaultHasher::new();
CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s);
let cstring_hash = s.finish();
assert_eq!(cstr_hash, cstring_hash);
}
#[test]
fn from_bytes_with_nul() {
let data = b"123\0";
let cstr = CStr::from_bytes_with_nul(data);
assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..]));
let cstr = CStr::from_bytes_with_nul(data);
assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..]));
unsafe {
let cstr = CStr::from_bytes_with_nul(data);
let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data);
assert_eq!(cstr, Ok(cstr_unchecked));
}
}
#[test]
fn from_bytes_with_nul_unterminated() {
let data = b"123";
let cstr = CStr::from_bytes_with_nul(data);
assert!(cstr.is_err());
}
#[test]
fn from_bytes_with_nul_interior() {
let data = b"1\023\0";
let cstr = CStr::from_bytes_with_nul(data);
assert!(cstr.is_err());
}
#[test]
fn into_boxed() {
let orig: &[u8] = b"Hello, world!\0";
let cstr = CStr::from_bytes_with_nul(orig).unwrap();
let boxed: Box<CStr> = Box::from(cstr);
let cstring = cstr.to_owned().into_boxed_c_str().into_c_string();
assert_eq!(cstr, &*boxed);
assert_eq!(&*boxed, &*cstring);
assert_eq!(&*cstring, cstr);
}
#[test]
fn boxed_default() {
let boxed = <Box<CStr>>::default();
assert_eq!(boxed.to_bytes_with_nul(), &[0]);
}
#[test]
fn test_c_str_clone_into() {
let mut c_string = CString::new("lorem").unwrap();
let c_ptr = c_string.as_ptr();
let c_str = CStr::from_bytes_with_nul(b"ipsum\0").unwrap();
c_str.clone_into(&mut c_string);
assert_eq!(c_str, c_string.as_c_str());
// The exact same size shouldn't have needed to move its allocation
assert_eq!(c_ptr, c_string.as_ptr());
}
#[test]
fn into_rc() {
let orig: &[u8] = b"Hello, world!\0";
let cstr = CStr::from_bytes_with_nul(orig).unwrap();
let rc: Rc<CStr> = Rc::from(cstr);
let arc: Arc<CStr> = Arc::from(cstr);
assert_eq!(&*rc, cstr);
assert_eq!(&*arc, cstr);
let rc2: Rc<CStr> = Rc::from(cstr.to_owned());
let arc2: Arc<CStr> = Arc::from(cstr.to_owned());
assert_eq!(&*rc2, cstr);
assert_eq!(&*arc2, cstr);
}
#[test]
fn cstr_const_constructor() {
const CSTR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello, world!\0") };
assert_eq!(CSTR.to_str().unwrap(), "Hello, world!");
}
#[test]
fn cstr_index_from() {
let original = b"Hello, world!\0";
let cstr = CStr::from_bytes_with_nul(original).unwrap();
let result = CStr::from_bytes_with_nul(&original[7..]).unwrap();
assert_eq!(&cstr[7..], result);
}
#[test]
#[should_panic]
fn cstr_index_from_empty() {
let original = b"Hello, world!\0";
let cstr = CStr::from_bytes_with_nul(original).unwrap();
let _ = &cstr[original.len()..];
}

View file

@ -1,3 +1,6 @@
#[cfg(test)]
mod tests;
use crate::borrow::{Borrow, Cow};
use crate::cmp;
use crate::fmt;
@ -1145,172 +1148,3 @@ impl FromStr for OsString {
Ok(OsString::from(s))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::sys_common::{AsInner, IntoInner};
use crate::rc::Rc;
use crate::sync::Arc;
#[test]
fn test_os_string_with_capacity() {
let os_string = OsString::with_capacity(0);
assert_eq!(0, os_string.inner.into_inner().capacity());
let os_string = OsString::with_capacity(10);
assert_eq!(10, os_string.inner.into_inner().capacity());
let mut os_string = OsString::with_capacity(0);
os_string.push("abc");
assert!(os_string.inner.into_inner().capacity() >= 3);
}
#[test]
fn test_os_string_clear() {
let mut os_string = OsString::from("abc");
assert_eq!(3, os_string.inner.as_inner().len());
os_string.clear();
assert_eq!(&os_string, "");
assert_eq!(0, os_string.inner.as_inner().len());
}
#[test]
fn test_os_string_capacity() {
let os_string = OsString::with_capacity(0);
assert_eq!(0, os_string.capacity());
let os_string = OsString::with_capacity(10);
assert_eq!(10, os_string.capacity());
let mut os_string = OsString::with_capacity(0);
os_string.push("abc");
assert!(os_string.capacity() >= 3);
}
#[test]
fn test_os_string_reserve() {
let mut os_string = OsString::new();
assert_eq!(os_string.capacity(), 0);
os_string.reserve(2);
assert!(os_string.capacity() >= 2);
for _ in 0..16 {
os_string.push("a");
}
assert!(os_string.capacity() >= 16);
os_string.reserve(16);
assert!(os_string.capacity() >= 32);
os_string.push("a");
os_string.reserve(16);
assert!(os_string.capacity() >= 33)
}
#[test]
fn test_os_string_reserve_exact() {
let mut os_string = OsString::new();
assert_eq!(os_string.capacity(), 0);
os_string.reserve_exact(2);
assert!(os_string.capacity() >= 2);
for _ in 0..16 {
os_string.push("a");
}
assert!(os_string.capacity() >= 16);
os_string.reserve_exact(16);
assert!(os_string.capacity() >= 32);
os_string.push("a");
os_string.reserve_exact(16);
assert!(os_string.capacity() >= 33)
}
#[test]
fn test_os_string_default() {
let os_string: OsString = Default::default();
assert_eq!("", &os_string);
}
#[test]
fn test_os_str_is_empty() {
let mut os_string = OsString::new();
assert!(os_string.is_empty());
os_string.push("abc");
assert!(!os_string.is_empty());
os_string.clear();
assert!(os_string.is_empty());
}
#[test]
fn test_os_str_len() {
let mut os_string = OsString::new();
assert_eq!(0, os_string.len());
os_string.push("abc");
assert_eq!(3, os_string.len());
os_string.clear();
assert_eq!(0, os_string.len());
}
#[test]
fn test_os_str_default() {
let os_str: &OsStr = Default::default();
assert_eq!("", os_str);
}
#[test]
fn into_boxed() {
let orig = "Hello, world!";
let os_str = OsStr::new(orig);
let boxed: Box<OsStr> = Box::from(os_str);
let os_string = os_str.to_owned().into_boxed_os_str().into_os_string();
assert_eq!(os_str, &*boxed);
assert_eq!(&*boxed, &*os_string);
assert_eq!(&*os_string, os_str);
}
#[test]
fn boxed_default() {
let boxed = <Box<OsStr>>::default();
assert!(boxed.is_empty());
}
#[test]
fn test_os_str_clone_into() {
let mut os_string = OsString::with_capacity(123);
os_string.push("hello");
let os_str = OsStr::new("bonjour");
os_str.clone_into(&mut os_string);
assert_eq!(os_str, os_string);
assert!(os_string.capacity() >= 123);
}
#[test]
fn into_rc() {
let orig = "Hello, world!";
let os_str = OsStr::new(orig);
let rc: Rc<OsStr> = Rc::from(os_str);
let arc: Arc<OsStr> = Arc::from(os_str);
assert_eq!(&*rc, os_str);
assert_eq!(&*arc, os_str);
let rc2: Rc<OsStr> = Rc::from(os_str.to_owned());
let arc2: Arc<OsStr> = Arc::from(os_str.to_owned());
assert_eq!(&*rc2, os_str);
assert_eq!(&*arc2, os_str);
}
}

View file

@ -0,0 +1,165 @@
use super::*;
use crate::sys_common::{AsInner, IntoInner};
use crate::rc::Rc;
use crate::sync::Arc;
#[test]
fn test_os_string_with_capacity() {
let os_string = OsString::with_capacity(0);
assert_eq!(0, os_string.inner.into_inner().capacity());
let os_string = OsString::with_capacity(10);
assert_eq!(10, os_string.inner.into_inner().capacity());
let mut os_string = OsString::with_capacity(0);
os_string.push("abc");
assert!(os_string.inner.into_inner().capacity() >= 3);
}
#[test]
fn test_os_string_clear() {
let mut os_string = OsString::from("abc");
assert_eq!(3, os_string.inner.as_inner().len());
os_string.clear();
assert_eq!(&os_string, "");
assert_eq!(0, os_string.inner.as_inner().len());
}
#[test]
fn test_os_string_capacity() {
let os_string = OsString::with_capacity(0);
assert_eq!(0, os_string.capacity());
let os_string = OsString::with_capacity(10);
assert_eq!(10, os_string.capacity());
let mut os_string = OsString::with_capacity(0);
os_string.push("abc");
assert!(os_string.capacity() >= 3);
}
#[test]
fn test_os_string_reserve() {
let mut os_string = OsString::new();
assert_eq!(os_string.capacity(), 0);
os_string.reserve(2);
assert!(os_string.capacity() >= 2);
for _ in 0..16 {
os_string.push("a");
}
assert!(os_string.capacity() >= 16);
os_string.reserve(16);
assert!(os_string.capacity() >= 32);
os_string.push("a");
os_string.reserve(16);
assert!(os_string.capacity() >= 33)
}
#[test]
fn test_os_string_reserve_exact() {
let mut os_string = OsString::new();
assert_eq!(os_string.capacity(), 0);
os_string.reserve_exact(2);
assert!(os_string.capacity() >= 2);
for _ in 0..16 {
os_string.push("a");
}
assert!(os_string.capacity() >= 16);
os_string.reserve_exact(16);
assert!(os_string.capacity() >= 32);
os_string.push("a");
os_string.reserve_exact(16);
assert!(os_string.capacity() >= 33)
}
#[test]
fn test_os_string_default() {
let os_string: OsString = Default::default();
assert_eq!("", &os_string);
}
#[test]
fn test_os_str_is_empty() {
let mut os_string = OsString::new();
assert!(os_string.is_empty());
os_string.push("abc");
assert!(!os_string.is_empty());
os_string.clear();
assert!(os_string.is_empty());
}
#[test]
fn test_os_str_len() {
let mut os_string = OsString::new();
assert_eq!(0, os_string.len());
os_string.push("abc");
assert_eq!(3, os_string.len());
os_string.clear();
assert_eq!(0, os_string.len());
}
#[test]
fn test_os_str_default() {
let os_str: &OsStr = Default::default();
assert_eq!("", os_str);
}
#[test]
fn into_boxed() {
let orig = "Hello, world!";
let os_str = OsStr::new(orig);
let boxed: Box<OsStr> = Box::from(os_str);
let os_string = os_str.to_owned().into_boxed_os_str().into_os_string();
assert_eq!(os_str, &*boxed);
assert_eq!(&*boxed, &*os_string);
assert_eq!(&*os_string, os_str);
}
#[test]
fn boxed_default() {
let boxed = <Box<OsStr>>::default();
assert!(boxed.is_empty());
}
#[test]
fn test_os_str_clone_into() {
let mut os_string = OsString::with_capacity(123);
os_string.push("hello");
let os_str = OsStr::new("bonjour");
os_str.clone_into(&mut os_string);
assert_eq!(os_str, os_string);
assert!(os_string.capacity() >= 123);
}
#[test]
fn into_rc() {
let orig = "Hello, world!";
let os_str = OsStr::new(orig);
let rc: Rc<OsStr> = Rc::from(os_str);
let arc: Arc<OsStr> = Arc::from(os_str);
assert_eq!(&*rc, os_str);
assert_eq!(&*arc, os_str);
let rc2: Rc<OsStr> = Rc::from(os_str.to_owned());
let arc2: Arc<OsStr> = Arc::from(os_str.to_owned());
assert_eq!(&*rc2, os_str);
assert_eq!(&*arc2, os_str);
}

File diff suppressed because it is too large Load diff

1339
library/std/src/fs/tests.rs Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,8 @@
//! Buffering wrappers for I/O traits
#[cfg(test)]
mod tests;
use crate::io::prelude::*;
use crate::cmp;
@ -1388,923 +1391,3 @@ where
.finish()
}
}
#[cfg(test)]
mod tests {
use crate::io::prelude::*;
use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom};
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::thread;
/// A dummy reader intended at testing short-reads propagation.
pub struct ShortReader {
lengths: Vec<usize>,
}
// FIXME: rustfmt and tidy disagree about the correct formatting of this
// function. This leads to issues for users with editors configured to
// rustfmt-on-save.
impl Read for ShortReader {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) }
}
}
#[test]
fn test_buffered_reader() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, inner);
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 3);
assert_eq!(buf, [5, 6, 7]);
assert_eq!(reader.buffer(), []);
let mut buf = [0, 0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 2);
assert_eq!(buf, [0, 1]);
assert_eq!(reader.buffer(), []);
let mut buf = [0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 1);
assert_eq!(buf, [2]);
assert_eq!(reader.buffer(), [3]);
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 1);
assert_eq!(buf, [3, 0, 0]);
assert_eq!(reader.buffer(), []);
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 1);
assert_eq!(buf, [4, 0, 0]);
assert_eq!(reader.buffer(), []);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_buffered_reader_seek() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3));
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3));
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4));
assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..]));
reader.consume(1);
assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3));
}
#[test]
fn test_buffered_reader_seek_relative() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
assert!(reader.seek_relative(3).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert!(reader.seek_relative(0).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert!(reader.seek_relative(1).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[1][..]));
assert!(reader.seek_relative(-1).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert!(reader.seek_relative(2).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..]));
}
#[test]
fn test_buffered_reader_invalidated_after_read() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner));
assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..]));
reader.consume(3);
let mut buffer = [0, 0, 0, 0, 0];
assert_eq!(reader.read(&mut buffer).ok(), Some(5));
assert_eq!(buffer, [0, 1, 2, 3, 4]);
assert!(reader.seek_relative(-2).is_ok());
let mut buffer = [0, 0];
assert_eq!(reader.read(&mut buffer).ok(), Some(2));
assert_eq!(buffer, [3, 4]);
}
#[test]
fn test_buffered_reader_invalidated_after_seek() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner));
assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..]));
reader.consume(3);
assert!(reader.seek(SeekFrom::Current(5)).is_ok());
assert!(reader.seek_relative(-2).is_ok());
let mut buffer = [0, 0];
assert_eq!(reader.read(&mut buffer).ok(), Some(2));
assert_eq!(buffer, [3, 4]);
}
#[test]
fn test_buffered_reader_seek_underflow() {
// gimmick reader that yields its position modulo 256 for each byte
struct PositionReader {
pos: u64,
}
impl Read for PositionReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let len = buf.len();
for x in buf {
*x = self.pos as u8;
self.pos = self.pos.wrapping_add(1);
}
Ok(len)
}
}
impl Seek for PositionReader {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
match pos {
SeekFrom::Start(n) => {
self.pos = n;
}
SeekFrom::Current(n) => {
self.pos = self.pos.wrapping_add(n as u64);
}
SeekFrom::End(n) => {
self.pos = u64::MAX.wrapping_add(n as u64);
}
}
Ok(self.pos)
}
}
let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 });
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..]));
assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::MAX - 5));
assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
// the following seek will require two underlying seeks
let expected = 9223372036854775802;
assert_eq!(reader.seek(SeekFrom::Current(i64::MIN)).ok(), Some(expected));
assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
// seeking to 0 should empty the buffer.
assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected));
assert_eq!(reader.get_ref().pos, expected);
}
#[test]
fn test_buffered_reader_seek_underflow_discard_buffer_between_seeks() {
// gimmick reader that returns Err after first seek
struct ErrAfterFirstSeekReader {
first_seek: bool,
}
impl Read for ErrAfterFirstSeekReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
for x in &mut *buf {
*x = 0;
}
Ok(buf.len())
}
}
impl Seek for ErrAfterFirstSeekReader {
fn seek(&mut self, _: SeekFrom) -> io::Result<u64> {
if self.first_seek {
self.first_seek = false;
Ok(0)
} else {
Err(io::Error::new(io::ErrorKind::Other, "oh no!"))
}
}
}
let mut reader = BufReader::with_capacity(5, ErrAfterFirstSeekReader { first_seek: true });
assert_eq!(reader.fill_buf().ok(), Some(&[0, 0, 0, 0, 0][..]));
// The following seek will require two underlying seeks. The first will
// succeed but the second will fail. This should still invalidate the
// buffer.
assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err());
assert_eq!(reader.buffer().len(), 0);
}
#[test]
fn test_buffered_writer() {
let inner = Vec::new();
let mut writer = BufWriter::with_capacity(2, inner);
writer.write(&[0, 1]).unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[2]).unwrap();
assert_eq!(writer.buffer(), [2]);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[3]).unwrap();
assert_eq!(writer.buffer(), [2, 3]);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.flush().unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
writer.write(&[4]).unwrap();
writer.write(&[5]).unwrap();
assert_eq!(writer.buffer(), [4, 5]);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
writer.write(&[6]).unwrap();
assert_eq!(writer.buffer(), [6]);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]);
writer.write(&[7, 8]).unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]);
writer.write(&[9, 10, 11]).unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
writer.flush().unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
}
#[test]
fn test_buffered_writer_inner_flushes() {
let mut w = BufWriter::with_capacity(3, Vec::new());
w.write(&[0, 1]).unwrap();
assert_eq!(*w.get_ref(), []);
let w = w.into_inner().unwrap();
assert_eq!(w, [0, 1]);
}
#[test]
fn test_buffered_writer_seek() {
let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new()));
w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap();
w.write_all(&[6, 7]).unwrap();
assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8));
assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]);
assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2));
w.write_all(&[8, 9]).unwrap();
assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]);
}
#[test]
fn test_read_until() {
let inner: &[u8] = &[0, 1, 2, 1, 0];
let mut reader = BufReader::with_capacity(2, inner);
let mut v = Vec::new();
reader.read_until(0, &mut v).unwrap();
assert_eq!(v, [0]);
v.truncate(0);
reader.read_until(2, &mut v).unwrap();
assert_eq!(v, [1, 2]);
v.truncate(0);
reader.read_until(1, &mut v).unwrap();
assert_eq!(v, [1]);
v.truncate(0);
reader.read_until(8, &mut v).unwrap();
assert_eq!(v, [0]);
v.truncate(0);
reader.read_until(9, &mut v).unwrap();
assert_eq!(v, []);
}
#[test]
fn test_line_buffer() {
let mut writer = LineWriter::new(Vec::new());
writer.write(&[0]).unwrap();
assert_eq!(*writer.get_ref(), []);
writer.write(&[1]).unwrap();
assert_eq!(*writer.get_ref(), []);
writer.flush().unwrap();
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']);
writer.flush().unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]);
writer.write(&[3, b'\n']).unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']);
}
#[test]
fn test_read_line() {
let in_buf: &[u8] = b"a\nb\nc";
let mut reader = BufReader::with_capacity(2, in_buf);
let mut s = String::new();
reader.read_line(&mut s).unwrap();
assert_eq!(s, "a\n");
s.truncate(0);
reader.read_line(&mut s).unwrap();
assert_eq!(s, "b\n");
s.truncate(0);
reader.read_line(&mut s).unwrap();
assert_eq!(s, "c");
s.truncate(0);
reader.read_line(&mut s).unwrap();
assert_eq!(s, "");
}
#[test]
fn test_lines() {
let in_buf: &[u8] = b"a\nb\nc";
let reader = BufReader::with_capacity(2, in_buf);
let mut it = reader.lines();
assert_eq!(it.next().unwrap().unwrap(), "a".to_string());
assert_eq!(it.next().unwrap().unwrap(), "b".to_string());
assert_eq!(it.next().unwrap().unwrap(), "c".to_string());
assert!(it.next().is_none());
}
#[test]
fn test_short_reads() {
let inner = ShortReader { lengths: vec![0, 1, 2, 0, 1, 0] };
let mut reader = BufReader::new(inner);
let mut buf = [0, 0];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.read(&mut buf).unwrap(), 2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
#[should_panic]
fn dont_panic_in_drop_on_panicked_flush() {
struct FailFlushWriter;
impl Write for FailFlushWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Err(io::Error::last_os_error())
}
}
let writer = FailFlushWriter;
let _writer = BufWriter::new(writer);
// If writer panics *again* due to the flush error then the process will
// abort.
panic!();
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn panic_in_write_doesnt_flush_in_drop() {
static WRITES: AtomicUsize = AtomicUsize::new(0);
struct PanicWriter;
impl Write for PanicWriter {
fn write(&mut self, _: &[u8]) -> io::Result<usize> {
WRITES.fetch_add(1, Ordering::SeqCst);
panic!();
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
thread::spawn(|| {
let mut writer = BufWriter::new(PanicWriter);
let _ = writer.write(b"hello world");
let _ = writer.flush();
})
.join()
.unwrap_err();
assert_eq!(WRITES.load(Ordering::SeqCst), 1);
}
#[bench]
fn bench_buffered_reader(b: &mut test::Bencher) {
b.iter(|| BufReader::new(io::empty()));
}
#[bench]
fn bench_buffered_writer(b: &mut test::Bencher) {
b.iter(|| BufWriter::new(io::sink()));
}
/// A simple `Write` target, designed to be wrapped by `LineWriter` /
/// `BufWriter` / etc, that can have its `write` & `flush` behavior
/// configured
#[derive(Default, Clone)]
struct ProgrammableSink {
// Writes append to this slice
pub buffer: Vec<u8>,
// Flush sets this flag
pub flushed: bool,
// If true, writes will always be an error
pub always_write_error: bool,
// If true, flushes will always be an error
pub always_flush_error: bool,
// If set, only up to this number of bytes will be written in a single
// call to `write`
pub accept_prefix: Option<usize>,
// If set, counts down with each write, and writes return an error
// when it hits 0
pub max_writes: Option<usize>,
// If set, attempting to write when max_writes == Some(0) will be an
// error; otherwise, it will return Ok(0).
pub error_after_max_writes: bool,
}
impl Write for ProgrammableSink {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
if self.always_write_error {
return Err(io::Error::new(io::ErrorKind::Other, "test - always_write_error"));
}
match self.max_writes {
Some(0) if self.error_after_max_writes => {
return Err(io::Error::new(io::ErrorKind::Other, "test - max_writes"));
}
Some(0) => return Ok(0),
Some(ref mut count) => *count -= 1,
None => {}
}
let len = match self.accept_prefix {
None => data.len(),
Some(prefix) => data.len().min(prefix),
};
let data = &data[..len];
self.buffer.extend_from_slice(data);
Ok(len)
}
fn flush(&mut self) -> io::Result<()> {
if self.always_flush_error {
Err(io::Error::new(io::ErrorKind::Other, "test - always_flush_error"))
} else {
self.flushed = true;
Ok(())
}
}
}
/// Previously the `LineWriter` could successfully write some bytes but
/// then fail to report that it has done so. Additionally, an erroneous
/// flush after a successful write was permanently ignored.
///
/// Test that a line writer correctly reports the number of written bytes,
/// and that it attempts to flush buffered lines from previous writes
/// before processing new data
///
/// Regression test for #37807
#[test]
fn erroneous_flush_retried() {
let writer = ProgrammableSink {
// Only write up to 4 bytes at a time
accept_prefix: Some(4),
// Accept the first two writes, then error the others
max_writes: Some(2),
error_after_max_writes: true,
..Default::default()
};
// This should write the first 4 bytes. The rest will be buffered, out
// to the last newline.
let mut writer = LineWriter::new(writer);
assert_eq!(writer.write(b"a\nb\nc\nd\ne").unwrap(), 8);
// This write should attempt to flush "c\nd\n", then buffer "e". No
// errors should happen here because no further writes should be
// attempted against `writer`.
assert_eq!(writer.write(b"e").unwrap(), 1);
assert_eq!(&writer.get_ref().buffer, b"a\nb\nc\nd\n");
}
#[test]
fn line_vectored() {
let mut a = LineWriter::new(Vec::new());
assert_eq!(
a.write_vectored(&[
IoSlice::new(&[]),
IoSlice::new(b"\n"),
IoSlice::new(&[]),
IoSlice::new(b"a"),
])
.unwrap(),
2,
);
assert_eq!(a.get_ref(), b"\n");
assert_eq!(
a.write_vectored(&[
IoSlice::new(&[]),
IoSlice::new(b"b"),
IoSlice::new(&[]),
IoSlice::new(b"a"),
IoSlice::new(&[]),
IoSlice::new(b"c"),
])
.unwrap(),
3,
);
assert_eq!(a.get_ref(), b"\n");
a.flush().unwrap();
assert_eq!(a.get_ref(), b"\nabac");
assert_eq!(a.write_vectored(&[]).unwrap(), 0);
assert_eq!(
a.write_vectored(&[
IoSlice::new(&[]),
IoSlice::new(&[]),
IoSlice::new(&[]),
IoSlice::new(&[]),
])
.unwrap(),
0,
);
assert_eq!(a.write_vectored(&[IoSlice::new(b"a\nb"),]).unwrap(), 3);
assert_eq!(a.get_ref(), b"\nabaca\nb");
}
#[test]
fn line_vectored_partial_and_errors() {
use crate::collections::VecDeque;
enum Call {
Write { inputs: Vec<&'static [u8]>, output: io::Result<usize> },
Flush { output: io::Result<()> },
}
#[derive(Default)]
struct Writer {
calls: VecDeque<Call>,
}
impl Write for Writer {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.write_vectored(&[IoSlice::new(buf)])
}
fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> io::Result<usize> {
match self.calls.pop_front().expect("unexpected call to write") {
Call::Write { inputs, output } => {
assert_eq!(inputs, buf.iter().map(|b| &**b).collect::<Vec<_>>());
output
}
Call::Flush { .. } => panic!("unexpected call to write; expected a flush"),
}
}
fn is_write_vectored(&self) -> bool {
true
}
fn flush(&mut self) -> io::Result<()> {
match self.calls.pop_front().expect("Unexpected call to flush") {
Call::Flush { output } => output,
Call::Write { .. } => panic!("unexpected call to flush; expected a write"),
}
}
}
impl Drop for Writer {
fn drop(&mut self) {
if !thread::panicking() {
assert_eq!(self.calls.len(), 0);
}
}
}
// partial writes keep going
let mut a = LineWriter::new(Writer::default());
a.write_vectored(&[IoSlice::new(&[]), IoSlice::new(b"abc")]).unwrap();
a.get_mut().calls.push_back(Call::Write { inputs: vec![b"abc"], output: Ok(1) });
a.get_mut().calls.push_back(Call::Write { inputs: vec![b"bc"], output: Ok(2) });
a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\n"], output: Ok(2) });
a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\n")]).unwrap();
a.get_mut().calls.push_back(Call::Flush { output: Ok(()) });
a.flush().unwrap();
// erroneous writes stop and don't write more
a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\na"], output: Err(err()) });
a.get_mut().calls.push_back(Call::Flush { output: Ok(()) });
assert!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).is_err());
a.flush().unwrap();
fn err() -> io::Error {
io::Error::new(io::ErrorKind::Other, "x")
}
}
/// Test that, in cases where vectored writing is not enabled, the
/// LineWriter uses the normal `write` call, which more-correctly handles
/// partial lines
#[test]
fn line_vectored_ignored() {
let writer = ProgrammableSink::default();
let mut writer = LineWriter::new(writer);
let content = [
IoSlice::new(&[]),
IoSlice::new(b"Line 1\nLine"),
IoSlice::new(b" 2\nLine 3\nL"),
IoSlice::new(&[]),
IoSlice::new(&[]),
IoSlice::new(b"ine 4"),
IoSlice::new(b"\nLine 5\n"),
];
let count = writer.write_vectored(&content).unwrap();
assert_eq!(count, 11);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
let count = writer.write_vectored(&content[2..]).unwrap();
assert_eq!(count, 11);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
let count = writer.write_vectored(&content[5..]).unwrap();
assert_eq!(count, 5);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
let count = writer.write_vectored(&content[6..]).unwrap();
assert_eq!(count, 8);
assert_eq!(
writer.get_ref().buffer.as_slice(),
b"Line 1\nLine 2\nLine 3\nLine 4\nLine 5\n".as_ref()
);
}
/// Test that, given this input:
///
/// Line 1\n
/// Line 2\n
/// Line 3\n
/// Line 4
///
/// And given a result that only writes to midway through Line 2
///
/// That only up to the end of Line 3 is buffered
///
/// This behavior is desirable because it prevents flushing partial lines
#[test]
fn partial_write_buffers_line() {
let writer = ProgrammableSink { accept_prefix: Some(13), ..Default::default() };
let mut writer = LineWriter::new(writer);
assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3\nLine4").unwrap(), 21);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2");
assert_eq!(writer.write(b"Line 4").unwrap(), 6);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
}
/// Test that, given this input:
///
/// Line 1\n
/// Line 2\n
/// Line 3
///
/// And given that the full write of lines 1 and 2 was successful
/// That data up to Line 3 is buffered
#[test]
fn partial_line_buffered_after_line_write() {
let writer = ProgrammableSink::default();
let mut writer = LineWriter::new(writer);
assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3").unwrap(), 20);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\n");
assert!(writer.flush().is_ok());
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3");
}
/// Test that, given a partial line that exceeds the length of
/// LineBuffer's buffer (that is, without a trailing newline), that that
/// line is written to the inner writer
#[test]
fn long_line_flushed() {
let writer = ProgrammableSink::default();
let mut writer = LineWriter::with_capacity(5, writer);
assert_eq!(writer.write(b"0123456789").unwrap(), 10);
assert_eq!(&writer.get_ref().buffer, b"0123456789");
}
/// Test that, given a very long partial line *after* successfully
/// flushing a complete line, that that line is buffered unconditionally,
/// and no additional writes take place. This assures the property that
/// `write` should make at-most-one attempt to write new data.
#[test]
fn line_long_tail_not_flushed() {
let writer = ProgrammableSink::default();
let mut writer = LineWriter::with_capacity(5, writer);
// Assert that Line 1\n is flushed, and 01234 is buffered
assert_eq!(writer.write(b"Line 1\n0123456789").unwrap(), 12);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
// Because the buffer is full, this subsequent write will flush it
assert_eq!(writer.write(b"5").unwrap(), 1);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n01234");
}
/// Test that, if an attempt to pre-flush buffered data returns Ok(0),
/// this is propagated as an error.
#[test]
fn line_buffer_write0_error() {
let writer = ProgrammableSink {
// Accept one write, then return Ok(0) on subsequent ones
max_writes: Some(1),
..Default::default()
};
let mut writer = LineWriter::new(writer);
// This should write "Line 1\n" and buffer "Partial"
assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
// This will attempt to flush "partial", which will return Ok(0), which
// needs to be an error, because we've already informed the client
// that we accepted the write.
let err = writer.write(b" Line End\n").unwrap_err();
assert_eq!(err.kind(), ErrorKind::WriteZero);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
}
/// Test that, if a write returns Ok(0) after a successful pre-flush, this
/// is propagated as Ok(0)
#[test]
fn line_buffer_write0_normal() {
let writer = ProgrammableSink {
// Accept two writes, then return Ok(0) on subsequent ones
max_writes: Some(2),
..Default::default()
};
let mut writer = LineWriter::new(writer);
// This should write "Line 1\n" and buffer "Partial"
assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
// This will flush partial, which will succeed, but then return Ok(0)
// when flushing " Line End\n"
assert_eq!(writer.write(b" Line End\n").unwrap(), 0);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nPartial");
}
/// LineWriter has a custom `write_all`; make sure it works correctly
#[test]
fn line_write_all() {
let writer = ProgrammableSink {
// Only write 5 bytes at a time
accept_prefix: Some(5),
..Default::default()
};
let mut writer = LineWriter::new(writer);
writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial").unwrap();
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\nLine 4\n");
writer.write_all(b" Line 5\n").unwrap();
assert_eq!(
writer.get_ref().buffer.as_slice(),
b"Line 1\nLine 2\nLine 3\nLine 4\nPartial Line 5\n".as_ref(),
);
}
#[test]
fn line_write_all_error() {
let writer = ProgrammableSink {
// Only accept up to 3 writes of up to 5 bytes each
accept_prefix: Some(5),
max_writes: Some(3),
..Default::default()
};
let mut writer = LineWriter::new(writer);
let res = writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial");
assert!(res.is_err());
// An error from write_all leaves everything in an indeterminate state,
// so there's nothing else to test here
}
/// Under certain circumstances, the old implementation of LineWriter
/// would try to buffer "to the last newline" but be forced to buffer
/// less than that, leading to inappropriate partial line writes.
/// Regression test for that issue.
#[test]
fn partial_multiline_buffering() {
let writer = ProgrammableSink {
// Write only up to 5 bytes at a time
accept_prefix: Some(5),
..Default::default()
};
let mut writer = LineWriter::with_capacity(10, writer);
let content = b"AAAAABBBBB\nCCCCDDDDDD\nEEE";
// When content is written, LineWriter will try to write blocks A, B,
// C, and D. Only block A will succeed. Under the old behavior, LineWriter
// would then try to buffer B, C and D, but because its capacity is 10,
// it will only be able to buffer B and C. We don't want to buffer
// partial lines concurrent with whole lines, so the correct behavior
// is to buffer only block B (out to the newline)
assert_eq!(writer.write(content).unwrap(), 11);
assert_eq!(writer.get_ref().buffer, *b"AAAAA");
writer.flush().unwrap();
assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB\n");
}
/// Same as test_partial_multiline_buffering, but in the event NO full lines
/// fit in the buffer, just buffer as much as possible
#[test]
fn partial_multiline_buffering_without_full_line() {
let writer = ProgrammableSink {
// Write only up to 5 bytes at a time
accept_prefix: Some(5),
..Default::default()
};
let mut writer = LineWriter::with_capacity(5, writer);
let content = b"AAAAABBBBBBBBBB\nCCCCC\nDDDDD";
// When content is written, LineWriter will try to write blocks A, B,
// and C. Only block A will succeed. Under the old behavior, LineWriter
// would then try to buffer B and C, but because its capacity is 5,
// it will only be able to buffer part of B. Because it's not possible
// for it to buffer any complete lines, it should buffer as much of B as
// possible
assert_eq!(writer.write(content).unwrap(), 10);
assert_eq!(writer.get_ref().buffer, *b"AAAAA");
writer.flush().unwrap();
assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB");
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum RecordedEvent {
Write(String),
Flush,
}
#[derive(Debug, Clone, Default)]
struct WriteRecorder {
pub events: Vec<RecordedEvent>,
}
impl Write for WriteRecorder {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
use crate::str::from_utf8;
self.events.push(RecordedEvent::Write(from_utf8(buf).unwrap().to_string()));
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.events.push(RecordedEvent::Flush);
Ok(())
}
}
/// Test that a normal, formatted writeln only results in a single write
/// call to the underlying writer. A naive implementation of
/// LineWriter::write_all results in two writes: one of the buffered data,
/// and another of the final substring in the formatted set
#[test]
fn single_formatted_write() {
let writer = WriteRecorder::default();
let mut writer = LineWriter::new(writer);
// Under a naive implementation of LineWriter, this will result in two
// writes: "hello, world" and "!\n", because write() has to flush the
// buffer before attempting to write the last "!\n". write_all shouldn't
// have this limitation.
writeln!(&mut writer, "{}, {}!", "hello", "world").unwrap();
assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]);
}
}

View file

@ -0,0 +1,916 @@
use crate::io::prelude::*;
use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom};
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::thread;
/// A dummy reader intended at testing short-reads propagation.
pub struct ShortReader {
lengths: Vec<usize>,
}
// FIXME: rustfmt and tidy disagree about the correct formatting of this
// function. This leads to issues for users with editors configured to
// rustfmt-on-save.
impl Read for ShortReader {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) }
}
}
#[test]
fn test_buffered_reader() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, inner);
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 3);
assert_eq!(buf, [5, 6, 7]);
assert_eq!(reader.buffer(), []);
let mut buf = [0, 0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 2);
assert_eq!(buf, [0, 1]);
assert_eq!(reader.buffer(), []);
let mut buf = [0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 1);
assert_eq!(buf, [2]);
assert_eq!(reader.buffer(), [3]);
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 1);
assert_eq!(buf, [3, 0, 0]);
assert_eq!(reader.buffer(), []);
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 1);
assert_eq!(buf, [4, 0, 0]);
assert_eq!(reader.buffer(), []);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_buffered_reader_seek() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3));
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3));
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4));
assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..]));
reader.consume(1);
assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3));
}
#[test]
fn test_buffered_reader_seek_relative() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
assert!(reader.seek_relative(3).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert!(reader.seek_relative(0).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert!(reader.seek_relative(1).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[1][..]));
assert!(reader.seek_relative(-1).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert!(reader.seek_relative(2).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..]));
}
#[test]
fn test_buffered_reader_invalidated_after_read() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner));
assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..]));
reader.consume(3);
let mut buffer = [0, 0, 0, 0, 0];
assert_eq!(reader.read(&mut buffer).ok(), Some(5));
assert_eq!(buffer, [0, 1, 2, 3, 4]);
assert!(reader.seek_relative(-2).is_ok());
let mut buffer = [0, 0];
assert_eq!(reader.read(&mut buffer).ok(), Some(2));
assert_eq!(buffer, [3, 4]);
}
#[test]
fn test_buffered_reader_invalidated_after_seek() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner));
assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..]));
reader.consume(3);
assert!(reader.seek(SeekFrom::Current(5)).is_ok());
assert!(reader.seek_relative(-2).is_ok());
let mut buffer = [0, 0];
assert_eq!(reader.read(&mut buffer).ok(), Some(2));
assert_eq!(buffer, [3, 4]);
}
#[test]
fn test_buffered_reader_seek_underflow() {
// gimmick reader that yields its position modulo 256 for each byte
struct PositionReader {
pos: u64,
}
impl Read for PositionReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let len = buf.len();
for x in buf {
*x = self.pos as u8;
self.pos = self.pos.wrapping_add(1);
}
Ok(len)
}
}
impl Seek for PositionReader {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
match pos {
SeekFrom::Start(n) => {
self.pos = n;
}
SeekFrom::Current(n) => {
self.pos = self.pos.wrapping_add(n as u64);
}
SeekFrom::End(n) => {
self.pos = u64::MAX.wrapping_add(n as u64);
}
}
Ok(self.pos)
}
}
let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 });
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..]));
assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::MAX - 5));
assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
// the following seek will require two underlying seeks
let expected = 9223372036854775802;
assert_eq!(reader.seek(SeekFrom::Current(i64::MIN)).ok(), Some(expected));
assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
// seeking to 0 should empty the buffer.
assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected));
assert_eq!(reader.get_ref().pos, expected);
}
#[test]
fn test_buffered_reader_seek_underflow_discard_buffer_between_seeks() {
// gimmick reader that returns Err after first seek
struct ErrAfterFirstSeekReader {
first_seek: bool,
}
impl Read for ErrAfterFirstSeekReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
for x in &mut *buf {
*x = 0;
}
Ok(buf.len())
}
}
impl Seek for ErrAfterFirstSeekReader {
fn seek(&mut self, _: SeekFrom) -> io::Result<u64> {
if self.first_seek {
self.first_seek = false;
Ok(0)
} else {
Err(io::Error::new(io::ErrorKind::Other, "oh no!"))
}
}
}
let mut reader = BufReader::with_capacity(5, ErrAfterFirstSeekReader { first_seek: true });
assert_eq!(reader.fill_buf().ok(), Some(&[0, 0, 0, 0, 0][..]));
// The following seek will require two underlying seeks. The first will
// succeed but the second will fail. This should still invalidate the
// buffer.
assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err());
assert_eq!(reader.buffer().len(), 0);
}
#[test]
fn test_buffered_writer() {
let inner = Vec::new();
let mut writer = BufWriter::with_capacity(2, inner);
writer.write(&[0, 1]).unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[2]).unwrap();
assert_eq!(writer.buffer(), [2]);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[3]).unwrap();
assert_eq!(writer.buffer(), [2, 3]);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.flush().unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
writer.write(&[4]).unwrap();
writer.write(&[5]).unwrap();
assert_eq!(writer.buffer(), [4, 5]);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
writer.write(&[6]).unwrap();
assert_eq!(writer.buffer(), [6]);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]);
writer.write(&[7, 8]).unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]);
writer.write(&[9, 10, 11]).unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
writer.flush().unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
}
#[test]
fn test_buffered_writer_inner_flushes() {
let mut w = BufWriter::with_capacity(3, Vec::new());
w.write(&[0, 1]).unwrap();
assert_eq!(*w.get_ref(), []);
let w = w.into_inner().unwrap();
assert_eq!(w, [0, 1]);
}
#[test]
fn test_buffered_writer_seek() {
let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new()));
w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap();
w.write_all(&[6, 7]).unwrap();
assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8));
assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]);
assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2));
w.write_all(&[8, 9]).unwrap();
assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]);
}
#[test]
fn test_read_until() {
let inner: &[u8] = &[0, 1, 2, 1, 0];
let mut reader = BufReader::with_capacity(2, inner);
let mut v = Vec::new();
reader.read_until(0, &mut v).unwrap();
assert_eq!(v, [0]);
v.truncate(0);
reader.read_until(2, &mut v).unwrap();
assert_eq!(v, [1, 2]);
v.truncate(0);
reader.read_until(1, &mut v).unwrap();
assert_eq!(v, [1]);
v.truncate(0);
reader.read_until(8, &mut v).unwrap();
assert_eq!(v, [0]);
v.truncate(0);
reader.read_until(9, &mut v).unwrap();
assert_eq!(v, []);
}
#[test]
fn test_line_buffer() {
let mut writer = LineWriter::new(Vec::new());
writer.write(&[0]).unwrap();
assert_eq!(*writer.get_ref(), []);
writer.write(&[1]).unwrap();
assert_eq!(*writer.get_ref(), []);
writer.flush().unwrap();
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']);
writer.flush().unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]);
writer.write(&[3, b'\n']).unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']);
}
#[test]
fn test_read_line() {
let in_buf: &[u8] = b"a\nb\nc";
let mut reader = BufReader::with_capacity(2, in_buf);
let mut s = String::new();
reader.read_line(&mut s).unwrap();
assert_eq!(s, "a\n");
s.truncate(0);
reader.read_line(&mut s).unwrap();
assert_eq!(s, "b\n");
s.truncate(0);
reader.read_line(&mut s).unwrap();
assert_eq!(s, "c");
s.truncate(0);
reader.read_line(&mut s).unwrap();
assert_eq!(s, "");
}
#[test]
fn test_lines() {
let in_buf: &[u8] = b"a\nb\nc";
let reader = BufReader::with_capacity(2, in_buf);
let mut it = reader.lines();
assert_eq!(it.next().unwrap().unwrap(), "a".to_string());
assert_eq!(it.next().unwrap().unwrap(), "b".to_string());
assert_eq!(it.next().unwrap().unwrap(), "c".to_string());
assert!(it.next().is_none());
}
#[test]
fn test_short_reads() {
let inner = ShortReader { lengths: vec![0, 1, 2, 0, 1, 0] };
let mut reader = BufReader::new(inner);
let mut buf = [0, 0];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.read(&mut buf).unwrap(), 2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
#[should_panic]
fn dont_panic_in_drop_on_panicked_flush() {
struct FailFlushWriter;
impl Write for FailFlushWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Err(io::Error::last_os_error())
}
}
let writer = FailFlushWriter;
let _writer = BufWriter::new(writer);
// If writer panics *again* due to the flush error then the process will
// abort.
panic!();
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn panic_in_write_doesnt_flush_in_drop() {
static WRITES: AtomicUsize = AtomicUsize::new(0);
struct PanicWriter;
impl Write for PanicWriter {
fn write(&mut self, _: &[u8]) -> io::Result<usize> {
WRITES.fetch_add(1, Ordering::SeqCst);
panic!();
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
thread::spawn(|| {
let mut writer = BufWriter::new(PanicWriter);
let _ = writer.write(b"hello world");
let _ = writer.flush();
})
.join()
.unwrap_err();
assert_eq!(WRITES.load(Ordering::SeqCst), 1);
}
#[bench]
fn bench_buffered_reader(b: &mut test::Bencher) {
b.iter(|| BufReader::new(io::empty()));
}
#[bench]
fn bench_buffered_writer(b: &mut test::Bencher) {
b.iter(|| BufWriter::new(io::sink()));
}
/// A simple `Write` target, designed to be wrapped by `LineWriter` /
/// `BufWriter` / etc, that can have its `write` & `flush` behavior
/// configured
#[derive(Default, Clone)]
struct ProgrammableSink {
// Writes append to this slice
pub buffer: Vec<u8>,
// Flush sets this flag
pub flushed: bool,
// If true, writes will always be an error
pub always_write_error: bool,
// If true, flushes will always be an error
pub always_flush_error: bool,
// If set, only up to this number of bytes will be written in a single
// call to `write`
pub accept_prefix: Option<usize>,
// If set, counts down with each write, and writes return an error
// when it hits 0
pub max_writes: Option<usize>,
// If set, attempting to write when max_writes == Some(0) will be an
// error; otherwise, it will return Ok(0).
pub error_after_max_writes: bool,
}
impl Write for ProgrammableSink {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
if self.always_write_error {
return Err(io::Error::new(io::ErrorKind::Other, "test - always_write_error"));
}
match self.max_writes {
Some(0) if self.error_after_max_writes => {
return Err(io::Error::new(io::ErrorKind::Other, "test - max_writes"));
}
Some(0) => return Ok(0),
Some(ref mut count) => *count -= 1,
None => {}
}
let len = match self.accept_prefix {
None => data.len(),
Some(prefix) => data.len().min(prefix),
};
let data = &data[..len];
self.buffer.extend_from_slice(data);
Ok(len)
}
fn flush(&mut self) -> io::Result<()> {
if self.always_flush_error {
Err(io::Error::new(io::ErrorKind::Other, "test - always_flush_error"))
} else {
self.flushed = true;
Ok(())
}
}
}
/// Previously the `LineWriter` could successfully write some bytes but
/// then fail to report that it has done so. Additionally, an erroneous
/// flush after a successful write was permanently ignored.
///
/// Test that a line writer correctly reports the number of written bytes,
/// and that it attempts to flush buffered lines from previous writes
/// before processing new data
///
/// Regression test for #37807
#[test]
fn erroneous_flush_retried() {
let writer = ProgrammableSink {
// Only write up to 4 bytes at a time
accept_prefix: Some(4),
// Accept the first two writes, then error the others
max_writes: Some(2),
error_after_max_writes: true,
..Default::default()
};
// This should write the first 4 bytes. The rest will be buffered, out
// to the last newline.
let mut writer = LineWriter::new(writer);
assert_eq!(writer.write(b"a\nb\nc\nd\ne").unwrap(), 8);
// This write should attempt to flush "c\nd\n", then buffer "e". No
// errors should happen here because no further writes should be
// attempted against `writer`.
assert_eq!(writer.write(b"e").unwrap(), 1);
assert_eq!(&writer.get_ref().buffer, b"a\nb\nc\nd\n");
}
#[test]
fn line_vectored() {
let mut a = LineWriter::new(Vec::new());
assert_eq!(
a.write_vectored(&[
IoSlice::new(&[]),
IoSlice::new(b"\n"),
IoSlice::new(&[]),
IoSlice::new(b"a"),
])
.unwrap(),
2,
);
assert_eq!(a.get_ref(), b"\n");
assert_eq!(
a.write_vectored(&[
IoSlice::new(&[]),
IoSlice::new(b"b"),
IoSlice::new(&[]),
IoSlice::new(b"a"),
IoSlice::new(&[]),
IoSlice::new(b"c"),
])
.unwrap(),
3,
);
assert_eq!(a.get_ref(), b"\n");
a.flush().unwrap();
assert_eq!(a.get_ref(), b"\nabac");
assert_eq!(a.write_vectored(&[]).unwrap(), 0);
assert_eq!(
a.write_vectored(&[
IoSlice::new(&[]),
IoSlice::new(&[]),
IoSlice::new(&[]),
IoSlice::new(&[]),
])
.unwrap(),
0,
);
assert_eq!(a.write_vectored(&[IoSlice::new(b"a\nb"),]).unwrap(), 3);
assert_eq!(a.get_ref(), b"\nabaca\nb");
}
#[test]
fn line_vectored_partial_and_errors() {
use crate::collections::VecDeque;
enum Call {
Write { inputs: Vec<&'static [u8]>, output: io::Result<usize> },
Flush { output: io::Result<()> },
}
#[derive(Default)]
struct Writer {
calls: VecDeque<Call>,
}
impl Write for Writer {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.write_vectored(&[IoSlice::new(buf)])
}
fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> io::Result<usize> {
match self.calls.pop_front().expect("unexpected call to write") {
Call::Write { inputs, output } => {
assert_eq!(inputs, buf.iter().map(|b| &**b).collect::<Vec<_>>());
output
}
Call::Flush { .. } => panic!("unexpected call to write; expected a flush"),
}
}
fn is_write_vectored(&self) -> bool {
true
}
fn flush(&mut self) -> io::Result<()> {
match self.calls.pop_front().expect("Unexpected call to flush") {
Call::Flush { output } => output,
Call::Write { .. } => panic!("unexpected call to flush; expected a write"),
}
}
}
impl Drop for Writer {
fn drop(&mut self) {
if !thread::panicking() {
assert_eq!(self.calls.len(), 0);
}
}
}
// partial writes keep going
let mut a = LineWriter::new(Writer::default());
a.write_vectored(&[IoSlice::new(&[]), IoSlice::new(b"abc")]).unwrap();
a.get_mut().calls.push_back(Call::Write { inputs: vec![b"abc"], output: Ok(1) });
a.get_mut().calls.push_back(Call::Write { inputs: vec![b"bc"], output: Ok(2) });
a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\n"], output: Ok(2) });
a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\n")]).unwrap();
a.get_mut().calls.push_back(Call::Flush { output: Ok(()) });
a.flush().unwrap();
// erroneous writes stop and don't write more
a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\na"], output: Err(err()) });
a.get_mut().calls.push_back(Call::Flush { output: Ok(()) });
assert!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).is_err());
a.flush().unwrap();
fn err() -> io::Error {
io::Error::new(io::ErrorKind::Other, "x")
}
}
/// Test that, in cases where vectored writing is not enabled, the
/// LineWriter uses the normal `write` call, which more-correctly handles
/// partial lines
#[test]
fn line_vectored_ignored() {
let writer = ProgrammableSink::default();
let mut writer = LineWriter::new(writer);
let content = [
IoSlice::new(&[]),
IoSlice::new(b"Line 1\nLine"),
IoSlice::new(b" 2\nLine 3\nL"),
IoSlice::new(&[]),
IoSlice::new(&[]),
IoSlice::new(b"ine 4"),
IoSlice::new(b"\nLine 5\n"),
];
let count = writer.write_vectored(&content).unwrap();
assert_eq!(count, 11);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
let count = writer.write_vectored(&content[2..]).unwrap();
assert_eq!(count, 11);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
let count = writer.write_vectored(&content[5..]).unwrap();
assert_eq!(count, 5);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
let count = writer.write_vectored(&content[6..]).unwrap();
assert_eq!(count, 8);
assert_eq!(
writer.get_ref().buffer.as_slice(),
b"Line 1\nLine 2\nLine 3\nLine 4\nLine 5\n".as_ref()
);
}
/// Test that, given this input:
///
/// Line 1\n
/// Line 2\n
/// Line 3\n
/// Line 4
///
/// And given a result that only writes to midway through Line 2
///
/// That only up to the end of Line 3 is buffered
///
/// This behavior is desirable because it prevents flushing partial lines
#[test]
fn partial_write_buffers_line() {
let writer = ProgrammableSink { accept_prefix: Some(13), ..Default::default() };
let mut writer = LineWriter::new(writer);
assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3\nLine4").unwrap(), 21);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2");
assert_eq!(writer.write(b"Line 4").unwrap(), 6);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
}
/// Test that, given this input:
///
/// Line 1\n
/// Line 2\n
/// Line 3
///
/// And given that the full write of lines 1 and 2 was successful
/// That data up to Line 3 is buffered
#[test]
fn partial_line_buffered_after_line_write() {
let writer = ProgrammableSink::default();
let mut writer = LineWriter::new(writer);
assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3").unwrap(), 20);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\n");
assert!(writer.flush().is_ok());
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3");
}
/// Test that, given a partial line that exceeds the length of
/// LineBuffer's buffer (that is, without a trailing newline), that that
/// line is written to the inner writer
#[test]
fn long_line_flushed() {
let writer = ProgrammableSink::default();
let mut writer = LineWriter::with_capacity(5, writer);
assert_eq!(writer.write(b"0123456789").unwrap(), 10);
assert_eq!(&writer.get_ref().buffer, b"0123456789");
}
/// Test that, given a very long partial line *after* successfully
/// flushing a complete line, that that line is buffered unconditionally,
/// and no additional writes take place. This assures the property that
/// `write` should make at-most-one attempt to write new data.
#[test]
fn line_long_tail_not_flushed() {
let writer = ProgrammableSink::default();
let mut writer = LineWriter::with_capacity(5, writer);
// Assert that Line 1\n is flushed, and 01234 is buffered
assert_eq!(writer.write(b"Line 1\n0123456789").unwrap(), 12);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
// Because the buffer is full, this subsequent write will flush it
assert_eq!(writer.write(b"5").unwrap(), 1);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n01234");
}
/// Test that, if an attempt to pre-flush buffered data returns Ok(0),
/// this is propagated as an error.
#[test]
fn line_buffer_write0_error() {
let writer = ProgrammableSink {
// Accept one write, then return Ok(0) on subsequent ones
max_writes: Some(1),
..Default::default()
};
let mut writer = LineWriter::new(writer);
// This should write "Line 1\n" and buffer "Partial"
assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
// This will attempt to flush "partial", which will return Ok(0), which
// needs to be an error, because we've already informed the client
// that we accepted the write.
let err = writer.write(b" Line End\n").unwrap_err();
assert_eq!(err.kind(), ErrorKind::WriteZero);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
}
/// Test that, if a write returns Ok(0) after a successful pre-flush, this
/// is propagated as Ok(0)
#[test]
fn line_buffer_write0_normal() {
let writer = ProgrammableSink {
// Accept two writes, then return Ok(0) on subsequent ones
max_writes: Some(2),
..Default::default()
};
let mut writer = LineWriter::new(writer);
// This should write "Line 1\n" and buffer "Partial"
assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
// This will flush partial, which will succeed, but then return Ok(0)
// when flushing " Line End\n"
assert_eq!(writer.write(b" Line End\n").unwrap(), 0);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nPartial");
}
/// LineWriter has a custom `write_all`; make sure it works correctly
#[test]
fn line_write_all() {
let writer = ProgrammableSink {
// Only write 5 bytes at a time
accept_prefix: Some(5),
..Default::default()
};
let mut writer = LineWriter::new(writer);
writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial").unwrap();
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\nLine 4\n");
writer.write_all(b" Line 5\n").unwrap();
assert_eq!(
writer.get_ref().buffer.as_slice(),
b"Line 1\nLine 2\nLine 3\nLine 4\nPartial Line 5\n".as_ref(),
);
}
#[test]
fn line_write_all_error() {
let writer = ProgrammableSink {
// Only accept up to 3 writes of up to 5 bytes each
accept_prefix: Some(5),
max_writes: Some(3),
..Default::default()
};
let mut writer = LineWriter::new(writer);
let res = writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial");
assert!(res.is_err());
// An error from write_all leaves everything in an indeterminate state,
// so there's nothing else to test here
}
/// Under certain circumstances, the old implementation of LineWriter
/// would try to buffer "to the last newline" but be forced to buffer
/// less than that, leading to inappropriate partial line writes.
/// Regression test for that issue.
#[test]
fn partial_multiline_buffering() {
let writer = ProgrammableSink {
// Write only up to 5 bytes at a time
accept_prefix: Some(5),
..Default::default()
};
let mut writer = LineWriter::with_capacity(10, writer);
let content = b"AAAAABBBBB\nCCCCDDDDDD\nEEE";
// When content is written, LineWriter will try to write blocks A, B,
// C, and D. Only block A will succeed. Under the old behavior, LineWriter
// would then try to buffer B, C and D, but because its capacity is 10,
// it will only be able to buffer B and C. We don't want to buffer
// partial lines concurrent with whole lines, so the correct behavior
// is to buffer only block B (out to the newline)
assert_eq!(writer.write(content).unwrap(), 11);
assert_eq!(writer.get_ref().buffer, *b"AAAAA");
writer.flush().unwrap();
assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB\n");
}
/// Same as test_partial_multiline_buffering, but in the event NO full lines
/// fit in the buffer, just buffer as much as possible
#[test]
fn partial_multiline_buffering_without_full_line() {
let writer = ProgrammableSink {
// Write only up to 5 bytes at a time
accept_prefix: Some(5),
..Default::default()
};
let mut writer = LineWriter::with_capacity(5, writer);
let content = b"AAAAABBBBBBBBBB\nCCCCC\nDDDDD";
// When content is written, LineWriter will try to write blocks A, B,
// and C. Only block A will succeed. Under the old behavior, LineWriter
// would then try to buffer B and C, but because its capacity is 5,
// it will only be able to buffer part of B. Because it's not possible
// for it to buffer any complete lines, it should buffer as much of B as
// possible
assert_eq!(writer.write(content).unwrap(), 10);
assert_eq!(writer.get_ref().buffer, *b"AAAAA");
writer.flush().unwrap();
assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB");
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum RecordedEvent {
Write(String),
Flush,
}
#[derive(Debug, Clone, Default)]
struct WriteRecorder {
pub events: Vec<RecordedEvent>,
}
impl Write for WriteRecorder {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
use crate::str::from_utf8;
self.events.push(RecordedEvent::Write(from_utf8(buf).unwrap().to_string()));
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.events.push(RecordedEvent::Flush);
Ok(())
}
}
/// Test that a normal, formatted writeln only results in a single write
/// call to the underlying writer. A naive implementation of
/// LineWriter::write_all results in two writes: one of the buffered data,
/// and another of the final substring in the formatted set
#[test]
fn single_formatted_write() {
let writer = WriteRecorder::default();
let mut writer = LineWriter::new(writer);
// Under a naive implementation of LineWriter, this will result in two
// writes: "hello, world" and "!\n", because write() has to flush the
// buffer before attempting to write the last "!\n". write_all shouldn't
// have this limitation.
writeln!(&mut writer, "{}, {}!", "hello", "world").unwrap();
assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]);
}

View file

@ -1,3 +1,6 @@
#[cfg(test)]
mod tests;
use crate::io::prelude::*;
use crate::cmp;
@ -447,531 +450,3 @@ impl Write for Cursor<Box<[u8]>> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::io::prelude::*;
use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom};
#[test]
fn test_vec_writer() {
let mut writer = Vec::new();
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
.unwrap(),
3
);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(writer, b);
}
#[test]
fn test_mem_writer() {
let mut writer = Cursor::new(Vec::new());
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
.unwrap(),
3
);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn test_mem_mut_writer() {
let mut vec = Vec::new();
let mut writer = Cursor::new(&mut vec);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
.unwrap(),
3
);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn test_box_slice_writer() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
assert_eq!(writer.write(&[10]).unwrap(), 0);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(&**writer.get_ref(), b);
}
#[test]
fn test_box_slice_writer_vectored() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
assert_eq!(writer.position(), 0);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7]),])
.unwrap(),
7,
);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(&**writer.get_ref(), b);
}
#[test]
fn test_buf_writer() {
let mut buf = [0 as u8; 9];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
assert_eq!(writer.write(&[10]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_vectored() {
let mut buf = [0 as u8; 9];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],)
.unwrap(),
7,
);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_seek() {
let mut buf = [0 as u8; 8];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[1]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2);
assert_eq!(writer.position(), 2);
assert_eq!(writer.write(&[2]).unwrap(), 1);
assert_eq!(writer.position(), 3);
assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[3]).unwrap(), 1);
assert_eq!(writer.position(), 2);
assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
assert_eq!(writer.position(), 7);
assert_eq!(writer.write(&[4]).unwrap(), 1);
assert_eq!(writer.position(), 8);
}
let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_error() {
let mut buf = [0 as u8; 2];
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[0, 0]).unwrap(), 1);
assert_eq!(writer.write(&[0, 0]).unwrap(), 0);
}
#[test]
fn test_mem_reader() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_mem_reader_vectored() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
let mut buf = [];
assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),])
.unwrap(),
1,
);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf1 = [0; 4];
let mut buf2 = [0; 4];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2),])
.unwrap(),
7,
);
let b1: &[_] = &[1, 2, 3, 4];
let b2: &[_] = &[5, 6, 7];
assert_eq!(buf1, b1);
assert_eq!(&buf2[..3], b2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_boxed_slice_reader() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_boxed_slice_reader_vectored() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
let mut buf = [];
assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),])
.unwrap(),
1,
);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf1 = [0; 4];
let mut buf2 = [0; 4];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)
.unwrap(),
7,
);
let b1: &[_] = &[1, 2, 3, 4];
let b2: &[_] = &[5, 6, 7];
assert_eq!(buf1, b1);
assert_eq!(&buf2[..3], b2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn read_to_end() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
let mut v = Vec::new();
reader.read_to_end(&mut v).unwrap();
assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]);
}
#[test]
fn test_slice_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let reader = &mut &in_buf[..];
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.len(), 7);
let b: &[_] = &[0];
assert_eq!(&buf[..], b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.len(), 3);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(&buf[..], b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_slice_reader_vectored() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let reader = &mut &in_buf[..];
let mut buf = [];
assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
let mut buf = [0];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),])
.unwrap(),
1,
);
assert_eq!(reader.len(), 7);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf1 = [0; 4];
let mut buf2 = [0; 4];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)
.unwrap(),
7,
);
let b1: &[_] = &[1, 2, 3, 4];
let b2: &[_] = &[5, 6, 7];
assert_eq!(buf1, b1);
assert_eq!(&buf2[..3], b2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_read_exact() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let reader = &mut &in_buf[..];
let mut buf = [];
assert!(reader.read_exact(&mut buf).is_ok());
let mut buf = [8];
assert!(reader.read_exact(&mut buf).is_ok());
assert_eq!(buf[0], 0);
assert_eq!(reader.len(), 7);
let mut buf = [0, 0, 0, 0, 0, 0, 0];
assert!(reader.read_exact(&mut buf).is_ok());
assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]);
assert_eq!(reader.len(), 0);
let mut buf = [0];
assert!(reader.read_exact(&mut buf).is_err());
}
#[test]
fn test_buf_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let mut reader = Cursor::new(&in_buf[..]);
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn seek_past_end() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.read(&mut [0]).unwrap(), 0);
let mut r = Cursor::new(vec![10]);
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.read(&mut [0]).unwrap(), 0);
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.write(&[3]).unwrap(), 0);
let mut r = Cursor::new(vec![10].into_boxed_slice());
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.write(&[3]).unwrap(), 0);
}
#[test]
fn seek_past_i64() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
let mut r = Cursor::new(vec![10]);
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
let mut r = Cursor::new(vec![10].into_boxed_slice());
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
}
#[test]
fn seek_before_0() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut r = Cursor::new(vec![10]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut r = Cursor::new(vec![10].into_boxed_slice());
assert!(r.seek(SeekFrom::End(-2)).is_err());
}
#[test]
fn test_seekable_mem_writer() {
let mut writer = Cursor::new(Vec::<u8>::new());
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[3, 4]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3);
assert_eq!(writer.write(&[0, 1]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
assert_eq!(writer.write(&[1, 2]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10);
assert_eq!(writer.write(&[1]).unwrap(), 1);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn vec_seek_past_end() {
let mut r = Cursor::new(Vec::new());
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.write(&[3]).unwrap(), 1);
}
#[test]
fn vec_seek_before_0() {
let mut r = Cursor::new(Vec::new());
assert!(r.seek(SeekFrom::End(-2)).is_err());
}
#[test]
#[cfg(target_pointer_width = "32")]
fn vec_seek_and_write_past_usize_max() {
let mut c = Cursor::new(Vec::new());
c.set_position(usize::MAX as u64 + 1);
assert!(c.write_all(&[1, 2, 3]).is_err());
}
#[test]
fn test_partial_eq() {
assert_eq!(Cursor::new(Vec::<u8>::new()), Cursor::new(Vec::<u8>::new()));
}
#[test]
fn test_eq() {
struct AssertEq<T: Eq>(pub T);
let _: AssertEq<Cursor<Vec<u8>>> = AssertEq(Cursor::new(Vec::new()));
}
}

View file

@ -0,0 +1,516 @@
use crate::io::prelude::*;
use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom};
#[test]
fn test_vec_writer() {
let mut writer = Vec::new();
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
.unwrap(),
3
);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(writer, b);
}
#[test]
fn test_mem_writer() {
let mut writer = Cursor::new(Vec::new());
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
.unwrap(),
3
);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn test_mem_mut_writer() {
let mut vec = Vec::new();
let mut writer = Cursor::new(&mut vec);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
.unwrap(),
3
);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn test_box_slice_writer() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
assert_eq!(writer.write(&[10]).unwrap(), 0);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(&**writer.get_ref(), b);
}
#[test]
fn test_box_slice_writer_vectored() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
assert_eq!(writer.position(), 0);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(
writer.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7]),]).unwrap(),
7,
);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(&**writer.get_ref(), b);
}
#[test]
fn test_buf_writer() {
let mut buf = [0 as u8; 9];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
assert_eq!(writer.write(&[10]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_vectored() {
let mut buf = [0 as u8; 9];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],)
.unwrap(),
7,
);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_seek() {
let mut buf = [0 as u8; 8];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[1]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2);
assert_eq!(writer.position(), 2);
assert_eq!(writer.write(&[2]).unwrap(), 1);
assert_eq!(writer.position(), 3);
assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[3]).unwrap(), 1);
assert_eq!(writer.position(), 2);
assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
assert_eq!(writer.position(), 7);
assert_eq!(writer.write(&[4]).unwrap(), 1);
assert_eq!(writer.position(), 8);
}
let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_error() {
let mut buf = [0 as u8; 2];
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[0, 0]).unwrap(), 1);
assert_eq!(writer.write(&[0, 0]).unwrap(), 0);
}
#[test]
fn test_mem_reader() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_mem_reader_vectored() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
let mut buf = [];
assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(
reader.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(),
1,
);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf1 = [0; 4];
let mut buf2 = [0; 4];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2),])
.unwrap(),
7,
);
let b1: &[_] = &[1, 2, 3, 4];
let b2: &[_] = &[5, 6, 7];
assert_eq!(buf1, b1);
assert_eq!(&buf2[..3], b2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_boxed_slice_reader() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_boxed_slice_reader_vectored() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
let mut buf = [];
assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(
reader.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(),
1,
);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf1 = [0; 4];
let mut buf2 = [0; 4];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)
.unwrap(),
7,
);
let b1: &[_] = &[1, 2, 3, 4];
let b2: &[_] = &[5, 6, 7];
assert_eq!(buf1, b1);
assert_eq!(&buf2[..3], b2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn read_to_end() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
let mut v = Vec::new();
reader.read_to_end(&mut v).unwrap();
assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]);
}
#[test]
fn test_slice_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let reader = &mut &in_buf[..];
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.len(), 7);
let b: &[_] = &[0];
assert_eq!(&buf[..], b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.len(), 3);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(&buf[..], b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_slice_reader_vectored() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let reader = &mut &in_buf[..];
let mut buf = [];
assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
let mut buf = [0];
assert_eq!(
reader.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(),
1,
);
assert_eq!(reader.len(), 7);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf1 = [0; 4];
let mut buf2 = [0; 4];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)
.unwrap(),
7,
);
let b1: &[_] = &[1, 2, 3, 4];
let b2: &[_] = &[5, 6, 7];
assert_eq!(buf1, b1);
assert_eq!(&buf2[..3], b2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_read_exact() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let reader = &mut &in_buf[..];
let mut buf = [];
assert!(reader.read_exact(&mut buf).is_ok());
let mut buf = [8];
assert!(reader.read_exact(&mut buf).is_ok());
assert_eq!(buf[0], 0);
assert_eq!(reader.len(), 7);
let mut buf = [0, 0, 0, 0, 0, 0, 0];
assert!(reader.read_exact(&mut buf).is_ok());
assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]);
assert_eq!(reader.len(), 0);
let mut buf = [0];
assert!(reader.read_exact(&mut buf).is_err());
}
#[test]
fn test_buf_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let mut reader = Cursor::new(&in_buf[..]);
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn seek_past_end() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.read(&mut [0]).unwrap(), 0);
let mut r = Cursor::new(vec![10]);
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.read(&mut [0]).unwrap(), 0);
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.write(&[3]).unwrap(), 0);
let mut r = Cursor::new(vec![10].into_boxed_slice());
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.write(&[3]).unwrap(), 0);
}
#[test]
fn seek_past_i64() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
let mut r = Cursor::new(vec![10]);
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
let mut r = Cursor::new(vec![10].into_boxed_slice());
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
}
#[test]
fn seek_before_0() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut r = Cursor::new(vec![10]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut r = Cursor::new(vec![10].into_boxed_slice());
assert!(r.seek(SeekFrom::End(-2)).is_err());
}
#[test]
fn test_seekable_mem_writer() {
let mut writer = Cursor::new(Vec::<u8>::new());
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[3, 4]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3);
assert_eq!(writer.write(&[0, 1]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
assert_eq!(writer.write(&[1, 2]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10);
assert_eq!(writer.write(&[1]).unwrap(), 1);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn vec_seek_past_end() {
let mut r = Cursor::new(Vec::new());
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.write(&[3]).unwrap(), 1);
}
#[test]
fn vec_seek_before_0() {
let mut r = Cursor::new(Vec::new());
assert!(r.seek(SeekFrom::End(-2)).is_err());
}
#[test]
#[cfg(target_pointer_width = "32")]
fn vec_seek_and_write_past_usize_max() {
let mut c = Cursor::new(Vec::new());
c.set_position(usize::MAX as u64 + 1);
assert!(c.write_all(&[1, 2, 3]).is_err());
}
#[test]
fn test_partial_eq() {
assert_eq!(Cursor::new(Vec::<u8>::new()), Cursor::new(Vec::<u8>::new()));
}
#[test]
fn test_eq() {
struct AssertEq<T: Eq>(pub T);
let _: AssertEq<Cursor<Vec<u8>>> = AssertEq(Cursor::new(Vec::new()));
}

View file

@ -1,3 +1,6 @@
#[cfg(test)]
mod tests;
use crate::convert::From;
use crate::error;
use crate::fmt;
@ -574,60 +577,3 @@ fn _assert_error_is_sync_send() {
fn _is_sync_send<T: Sync + Send>() {}
_is_sync_send::<Error>();
}
#[cfg(test)]
mod test {
use super::{Custom, Error, ErrorKind, Repr};
use crate::error;
use crate::fmt;
use crate::sys::decode_error_kind;
use crate::sys::os::error_string;
#[test]
fn test_debug_error() {
let code = 6;
let msg = error_string(code);
let kind = decode_error_kind(code);
let err = Error {
repr: Repr::Custom(box Custom {
kind: ErrorKind::InvalidInput,
error: box Error { repr: super::Repr::Os(code) },
}),
};
let expected = format!(
"Custom {{ \
kind: InvalidInput, \
error: Os {{ \
code: {:?}, \
kind: {:?}, \
message: {:?} \
}} \
}}",
code, kind, msg
);
assert_eq!(format!("{:?}", err), expected);
}
#[test]
fn test_downcasting() {
#[derive(Debug)]
struct TestError;
impl fmt::Display for TestError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("asdf")
}
}
impl error::Error for TestError {}
// we have to call all of these UFCS style right now since method
// resolution won't implicitly drop the Send+Sync bounds
let mut err = Error::new(ErrorKind::Other, TestError);
assert!(err.get_ref().unwrap().is::<TestError>());
assert_eq!("asdf", err.get_ref().unwrap().to_string());
assert!(err.get_mut().unwrap().is::<TestError>());
let extracted = err.into_inner().unwrap();
extracted.downcast::<TestError>().unwrap();
}
}

View file

@ -0,0 +1,53 @@
use super::{Custom, Error, ErrorKind, Repr};
use crate::error;
use crate::fmt;
use crate::sys::decode_error_kind;
use crate::sys::os::error_string;
#[test]
fn test_debug_error() {
let code = 6;
let msg = error_string(code);
let kind = decode_error_kind(code);
let err = Error {
repr: Repr::Custom(box Custom {
kind: ErrorKind::InvalidInput,
error: box Error { repr: super::Repr::Os(code) },
}),
};
let expected = format!(
"Custom {{ \
kind: InvalidInput, \
error: Os {{ \
code: {:?}, \
kind: {:?}, \
message: {:?} \
}} \
}}",
code, kind, msg
);
assert_eq!(format!("{:?}", err), expected);
}
#[test]
fn test_downcasting() {
#[derive(Debug)]
struct TestError;
impl fmt::Display for TestError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("asdf")
}
}
impl error::Error for TestError {}
// we have to call all of these UFCS style right now since method
// resolution won't implicitly drop the Send+Sync bounds
let mut err = Error::new(ErrorKind::Other, TestError);
assert!(err.get_ref().unwrap().is::<TestError>());
assert_eq!("asdf", err.get_ref().unwrap().to_string());
assert!(err.get_mut().unwrap().is::<TestError>());
let extracted = err.into_inner().unwrap();
extracted.downcast::<TestError>().unwrap();
}

View file

@ -1,3 +1,6 @@
#[cfg(test)]
mod tests;
use crate::cmp;
use crate::fmt;
use crate::io::{
@ -397,64 +400,3 @@ impl Write for Vec<u8> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::io::prelude::*;
#[bench]
fn bench_read_slice(b: &mut test::Bencher) {
let buf = [5; 1024];
let mut dst = [0; 128];
b.iter(|| {
let mut rd = &buf[..];
for _ in 0..8 {
let _ = rd.read(&mut dst);
test::black_box(&dst);
}
})
}
#[bench]
fn bench_write_slice(b: &mut test::Bencher) {
let mut buf = [0; 1024];
let src = [5; 128];
b.iter(|| {
let mut wr = &mut buf[..];
for _ in 0..8 {
let _ = wr.write_all(&src);
test::black_box(&wr);
}
})
}
#[bench]
fn bench_read_vec(b: &mut test::Bencher) {
let buf = vec![5; 1024];
let mut dst = [0; 128];
b.iter(|| {
let mut rd = &buf[..];
for _ in 0..8 {
let _ = rd.read(&mut dst);
test::black_box(&dst);
}
})
}
#[bench]
fn bench_write_vec(b: &mut test::Bencher) {
let mut buf = Vec::with_capacity(1024);
let src = [5; 128];
b.iter(|| {
let mut wr = &mut buf[..];
for _ in 0..8 {
let _ = wr.write_all(&src);
test::black_box(&wr);
}
})
}
}

View file

@ -0,0 +1,57 @@
use crate::io::prelude::*;
#[bench]
fn bench_read_slice(b: &mut test::Bencher) {
let buf = [5; 1024];
let mut dst = [0; 128];
b.iter(|| {
let mut rd = &buf[..];
for _ in 0..8 {
let _ = rd.read(&mut dst);
test::black_box(&dst);
}
})
}
#[bench]
fn bench_write_slice(b: &mut test::Bencher) {
let mut buf = [0; 1024];
let src = [5; 128];
b.iter(|| {
let mut wr = &mut buf[..];
for _ in 0..8 {
let _ = wr.write_all(&src);
test::black_box(&wr);
}
})
}
#[bench]
fn bench_read_vec(b: &mut test::Bencher) {
let buf = vec![5; 1024];
let mut dst = [0; 128];
b.iter(|| {
let mut rd = &buf[..];
for _ in 0..8 {
let _ = rd.read(&mut dst);
test::black_box(&dst);
}
})
}
#[bench]
fn bench_write_vec(b: &mut test::Bencher) {
let mut buf = Vec::with_capacity(1024);
let src = [5; 128];
b.iter(|| {
let mut wr = &mut buf[..];
for _ in 0..8 {
let _ = wr.write_all(&src);
test::black_box(&wr);
}
})
}

View file

@ -249,6 +249,9 @@
#![stable(feature = "rust1", since = "1.0.0")]
#[cfg(test)]
mod tests;
use crate::cmp;
use crate::fmt;
use crate::memchr;
@ -2481,501 +2484,3 @@ impl<B: BufRead> Iterator for Lines<B> {
}
}
}
#[cfg(test)]
mod tests {
use super::{repeat, Cursor, SeekFrom};
use crate::cmp::{self, min};
use crate::io::prelude::*;
use crate::io::{self, IoSlice, IoSliceMut};
use crate::ops::Deref;
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn read_until() {
let mut buf = Cursor::new(&b"12"[..]);
let mut v = Vec::new();
assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2);
assert_eq!(v, b"12");
let mut buf = Cursor::new(&b"1233"[..]);
let mut v = Vec::new();
assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3);
assert_eq!(v, b"123");
v.truncate(0);
assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1);
assert_eq!(v, b"3");
v.truncate(0);
assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0);
assert_eq!(v, []);
}
#[test]
fn split() {
let buf = Cursor::new(&b"12"[..]);
let mut s = buf.split(b'3');
assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
assert!(s.next().is_none());
let buf = Cursor::new(&b"1233"[..]);
let mut s = buf.split(b'3');
assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
assert_eq!(s.next().unwrap().unwrap(), vec![]);
assert!(s.next().is_none());
}
#[test]
fn read_line() {
let mut buf = Cursor::new(&b"12"[..]);
let mut v = String::new();
assert_eq!(buf.read_line(&mut v).unwrap(), 2);
assert_eq!(v, "12");
let mut buf = Cursor::new(&b"12\n\n"[..]);
let mut v = String::new();
assert_eq!(buf.read_line(&mut v).unwrap(), 3);
assert_eq!(v, "12\n");
v.truncate(0);
assert_eq!(buf.read_line(&mut v).unwrap(), 1);
assert_eq!(v, "\n");
v.truncate(0);
assert_eq!(buf.read_line(&mut v).unwrap(), 0);
assert_eq!(v, "");
}
#[test]
fn lines() {
let buf = Cursor::new(&b"12\r"[..]);
let mut s = buf.lines();
assert_eq!(s.next().unwrap().unwrap(), "12\r".to_string());
assert!(s.next().is_none());
let buf = Cursor::new(&b"12\r\n\n"[..]);
let mut s = buf.lines();
assert_eq!(s.next().unwrap().unwrap(), "12".to_string());
assert_eq!(s.next().unwrap().unwrap(), "".to_string());
assert!(s.next().is_none());
}
#[test]
fn read_to_end() {
let mut c = Cursor::new(&b""[..]);
let mut v = Vec::new();
assert_eq!(c.read_to_end(&mut v).unwrap(), 0);
assert_eq!(v, []);
let mut c = Cursor::new(&b"1"[..]);
let mut v = Vec::new();
assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
assert_eq!(v, b"1");
let cap = 1024 * 1024;
let data = (0..cap).map(|i| (i / 3) as u8).collect::<Vec<_>>();
let mut v = Vec::new();
let (a, b) = data.split_at(data.len() / 2);
assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len());
assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len());
assert_eq!(v, data);
}
#[test]
fn read_to_string() {
let mut c = Cursor::new(&b""[..]);
let mut v = String::new();
assert_eq!(c.read_to_string(&mut v).unwrap(), 0);
assert_eq!(v, "");
let mut c = Cursor::new(&b"1"[..]);
let mut v = String::new();
assert_eq!(c.read_to_string(&mut v).unwrap(), 1);
assert_eq!(v, "1");
let mut c = Cursor::new(&b"\xff"[..]);
let mut v = String::new();
assert!(c.read_to_string(&mut v).is_err());
}
#[test]
fn read_exact() {
let mut buf = [0; 4];
let mut c = Cursor::new(&b""[..]);
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..]));
c.read_exact(&mut buf).unwrap();
assert_eq!(&buf, b"1234");
c.read_exact(&mut buf).unwrap();
assert_eq!(&buf, b"5678");
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
}
#[test]
fn read_exact_slice() {
let mut buf = [0; 4];
let mut c = &b""[..];
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
let mut c = &b"123"[..];
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
// make sure the optimized (early returning) method is being used
assert_eq!(&buf, &[0; 4]);
let mut c = &b"1234"[..];
c.read_exact(&mut buf).unwrap();
assert_eq!(&buf, b"1234");
let mut c = &b"56789"[..];
c.read_exact(&mut buf).unwrap();
assert_eq!(&buf, b"5678");
assert_eq!(c, b"9");
}
#[test]
fn take_eof() {
struct R;
impl Read for R {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
Err(io::Error::new(io::ErrorKind::Other, ""))
}
}
impl BufRead for R {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
Err(io::Error::new(io::ErrorKind::Other, ""))
}
fn consume(&mut self, _amt: usize) {}
}
let mut buf = [0; 1];
assert_eq!(0, R.take(0).read(&mut buf).unwrap());
assert_eq!(b"", R.take(0).fill_buf().unwrap());
}
fn cmp_bufread<Br1: BufRead, Br2: BufRead>(mut br1: Br1, mut br2: Br2, exp: &[u8]) {
let mut cat = Vec::new();
loop {
let consume = {
let buf1 = br1.fill_buf().unwrap();
let buf2 = br2.fill_buf().unwrap();
let minlen = if buf1.len() < buf2.len() { buf1.len() } else { buf2.len() };
assert_eq!(buf1[..minlen], buf2[..minlen]);
cat.extend_from_slice(&buf1[..minlen]);
minlen
};
if consume == 0 {
break;
}
br1.consume(consume);
br2.consume(consume);
}
assert_eq!(br1.fill_buf().unwrap().len(), 0);
assert_eq!(br2.fill_buf().unwrap().len(), 0);
assert_eq!(&cat[..], &exp[..])
}
#[test]
fn chain_bufread() {
let testdata = b"ABCDEFGHIJKL";
let chain1 =
(&testdata[..3]).chain(&testdata[3..6]).chain(&testdata[6..9]).chain(&testdata[9..]);
let chain2 = (&testdata[..4]).chain(&testdata[4..8]).chain(&testdata[8..]);
cmp_bufread(chain1, chain2, &testdata[..]);
}
#[test]
fn chain_zero_length_read_is_not_eof() {
let a = b"A";
let b = b"B";
let mut s = String::new();
let mut chain = (&a[..]).chain(&b[..]);
chain.read(&mut []).unwrap();
chain.read_to_string(&mut s).unwrap();
assert_eq!("AB", s);
}
#[bench]
#[cfg_attr(target_os = "emscripten", ignore)]
fn bench_read_to_end(b: &mut test::Bencher) {
b.iter(|| {
let mut lr = repeat(1).take(10000000);
let mut vec = Vec::with_capacity(1024);
super::read_to_end(&mut lr, &mut vec)
});
}
#[test]
fn seek_len() -> io::Result<()> {
let mut c = Cursor::new(vec![0; 15]);
assert_eq!(c.stream_len()?, 15);
c.seek(SeekFrom::End(0))?;
let old_pos = c.stream_position()?;
assert_eq!(c.stream_len()?, 15);
assert_eq!(c.stream_position()?, old_pos);
c.seek(SeekFrom::Start(7))?;
c.seek(SeekFrom::Current(2))?;
let old_pos = c.stream_position()?;
assert_eq!(c.stream_len()?, 15);
assert_eq!(c.stream_position()?, old_pos);
Ok(())
}
#[test]
fn seek_position() -> io::Result<()> {
// All `asserts` are duplicated here to make sure the method does not
// change anything about the seek state.
let mut c = Cursor::new(vec![0; 15]);
assert_eq!(c.stream_position()?, 0);
assert_eq!(c.stream_position()?, 0);
c.seek(SeekFrom::End(0))?;
assert_eq!(c.stream_position()?, 15);
assert_eq!(c.stream_position()?, 15);
c.seek(SeekFrom::Start(7))?;
c.seek(SeekFrom::Current(2))?;
assert_eq!(c.stream_position()?, 9);
assert_eq!(c.stream_position()?, 9);
c.seek(SeekFrom::End(-3))?;
c.seek(SeekFrom::Current(1))?;
c.seek(SeekFrom::Current(-5))?;
assert_eq!(c.stream_position()?, 8);
assert_eq!(c.stream_position()?, 8);
Ok(())
}
// A simple example reader which uses the default implementation of
// read_to_end.
struct ExampleSliceReader<'a> {
slice: &'a [u8],
}
impl<'a> Read for ExampleSliceReader<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let len = cmp::min(self.slice.len(), buf.len());
buf[..len].copy_from_slice(&self.slice[..len]);
self.slice = &self.slice[len..];
Ok(len)
}
}
#[test]
fn test_read_to_end_capacity() -> io::Result<()> {
let input = &b"foo"[..];
// read_to_end() generally needs to over-allocate, both for efficiency
// and so that it can distinguish EOF. Assert that this is the case
// with this simple ExampleSliceReader struct, which uses the default
// implementation of read_to_end. Even though vec1 is allocated with
// exactly enough capacity for the read, read_to_end will allocate more
// space here.
let mut vec1 = Vec::with_capacity(input.len());
ExampleSliceReader { slice: input }.read_to_end(&mut vec1)?;
assert_eq!(vec1.len(), input.len());
assert!(vec1.capacity() > input.len(), "allocated more");
// However, std::io::Take includes an implementation of read_to_end
// that will not allocate when the limit has already been reached. In
// this case, vec2 never grows.
let mut vec2 = Vec::with_capacity(input.len());
ExampleSliceReader { slice: input }.take(input.len() as u64).read_to_end(&mut vec2)?;
assert_eq!(vec2.len(), input.len());
assert_eq!(vec2.capacity(), input.len(), "did not allocate more");
Ok(())
}
#[test]
fn io_slice_mut_advance() {
let mut buf1 = [1; 8];
let mut buf2 = [2; 16];
let mut buf3 = [3; 8];
let mut bufs = &mut [
IoSliceMut::new(&mut buf1),
IoSliceMut::new(&mut buf2),
IoSliceMut::new(&mut buf3),
][..];
// Only in a single buffer..
bufs = IoSliceMut::advance(bufs, 1);
assert_eq!(bufs[0].deref(), [1; 7].as_ref());
assert_eq!(bufs[1].deref(), [2; 16].as_ref());
assert_eq!(bufs[2].deref(), [3; 8].as_ref());
// Removing a buffer, leaving others as is.
bufs = IoSliceMut::advance(bufs, 7);
assert_eq!(bufs[0].deref(), [2; 16].as_ref());
assert_eq!(bufs[1].deref(), [3; 8].as_ref());
// Removing a buffer and removing from the next buffer.
bufs = IoSliceMut::advance(bufs, 18);
assert_eq!(bufs[0].deref(), [3; 6].as_ref());
}
#[test]
fn io_slice_mut_advance_empty_slice() {
let empty_bufs = &mut [][..];
// Shouldn't panic.
IoSliceMut::advance(empty_bufs, 1);
}
#[test]
fn io_slice_mut_advance_beyond_total_length() {
let mut buf1 = [1; 8];
let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..];
// Going beyond the total length should be ok.
bufs = IoSliceMut::advance(bufs, 9);
assert!(bufs.is_empty());
}
#[test]
fn io_slice_advance() {
let buf1 = [1; 8];
let buf2 = [2; 16];
let buf3 = [3; 8];
let mut bufs = &mut [IoSlice::new(&buf1), IoSlice::new(&buf2), IoSlice::new(&buf3)][..];
// Only in a single buffer..
bufs = IoSlice::advance(bufs, 1);
assert_eq!(bufs[0].deref(), [1; 7].as_ref());
assert_eq!(bufs[1].deref(), [2; 16].as_ref());
assert_eq!(bufs[2].deref(), [3; 8].as_ref());
// Removing a buffer, leaving others as is.
bufs = IoSlice::advance(bufs, 7);
assert_eq!(bufs[0].deref(), [2; 16].as_ref());
assert_eq!(bufs[1].deref(), [3; 8].as_ref());
// Removing a buffer and removing from the next buffer.
bufs = IoSlice::advance(bufs, 18);
assert_eq!(bufs[0].deref(), [3; 6].as_ref());
}
#[test]
fn io_slice_advance_empty_slice() {
let empty_bufs = &mut [][..];
// Shouldn't panic.
IoSlice::advance(empty_bufs, 1);
}
#[test]
fn io_slice_advance_beyond_total_length() {
let buf1 = [1; 8];
let mut bufs = &mut [IoSlice::new(&buf1)][..];
// Going beyond the total length should be ok.
bufs = IoSlice::advance(bufs, 9);
assert!(bufs.is_empty());
}
/// Create a new writer that reads from at most `n_bufs` and reads
/// `per_call` bytes (in total) per call to write.
fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter {
TestWriter { n_bufs, per_call, written: Vec::new() }
}
struct TestWriter {
n_bufs: usize,
per_call: usize,
written: Vec<u8>,
}
impl Write for TestWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.write_vectored(&[IoSlice::new(buf)])
}
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let mut left = self.per_call;
let mut written = 0;
for buf in bufs.iter().take(self.n_bufs) {
let n = min(left, buf.len());
self.written.extend_from_slice(&buf[0..n]);
left -= n;
written += n;
}
Ok(written)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[test]
fn test_writer_read_from_one_buf() {
let mut writer = test_writer(1, 2);
assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
// Read at most 2 bytes.
assert_eq!(writer.write(&[1, 1, 1]).unwrap(), 2);
let bufs = &[IoSlice::new(&[2, 2, 2])];
assert_eq!(writer.write_vectored(bufs).unwrap(), 2);
// Only read from first buf.
let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4, 4])];
assert_eq!(writer.write_vectored(bufs).unwrap(), 1);
assert_eq!(writer.written, &[1, 1, 2, 2, 3]);
}
#[test]
fn test_writer_read_from_multiple_bufs() {
let mut writer = test_writer(3, 3);
// Read at most 3 bytes from two buffers.
let bufs = &[IoSlice::new(&[1]), IoSlice::new(&[2, 2, 2])];
assert_eq!(writer.write_vectored(bufs).unwrap(), 3);
// Read at most 3 bytes from three buffers.
let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4]), IoSlice::new(&[5, 5])];
assert_eq!(writer.write_vectored(bufs).unwrap(), 3);
assert_eq!(writer.written, &[1, 2, 2, 3, 4, 5]);
}
#[test]
fn test_write_all_vectored() {
#[rustfmt::skip] // Becomes unreadable otherwise.
let tests: Vec<(_, &'static [u8])> = vec![
(vec![], &[]),
(vec![IoSlice::new(&[]), IoSlice::new(&[])], &[]),
(vec![IoSlice::new(&[1])], &[1]),
(vec![IoSlice::new(&[1, 2])], &[1, 2]),
(vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]),
(vec![IoSlice::new(&[1, 2, 3, 4])], &[1, 2, 3, 4]),
(vec![IoSlice::new(&[1, 2, 3, 4, 5])], &[1, 2, 3, 4, 5]),
(vec![IoSlice::new(&[1]), IoSlice::new(&[2])], &[1, 2]),
(vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2])], &[1, 2, 2]),
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2])], &[1, 1, 2, 2]),
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]),
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]),
(vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 1, 2, 2, 2]),
(vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 2, 2, 2, 2]),
(vec![IoSlice::new(&[1, 1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 1, 2, 2, 2, 2]),
(vec![IoSlice::new(&[1]), IoSlice::new(&[2]), IoSlice::new(&[3])], &[1, 2, 3]),
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3])], &[1, 1, 2, 2, 3, 3]),
(vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 2, 2, 3, 3, 3]),
(vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 1, 1, 2, 2, 2, 3, 3, 3]),
];
let writer_configs = &[(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)];
for (n_bufs, per_call) in writer_configs.iter().copied() {
for (mut input, wanted) in tests.clone().into_iter() {
let mut writer = test_writer(n_bufs, per_call);
assert!(writer.write_all_vectored(&mut *input).is_ok());
assert_eq!(&*writer.written, &*wanted);
}
}
}
}

View file

@ -1,5 +1,8 @@
#![cfg_attr(test, allow(unused))]
#[cfg(test)]
mod tests;
use crate::io::prelude::*;
use crate::cell::RefCell;
@ -920,54 +923,3 @@ pub fn _eprint(args: fmt::Arguments<'_>) {
#[cfg(test)]
pub use realstd::io::{_eprint, _print};
#[cfg(test)]
mod tests {
use super::*;
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::thread;
#[test]
fn stdout_unwind_safe() {
assert_unwind_safe::<Stdout>();
}
#[test]
fn stdoutlock_unwind_safe() {
assert_unwind_safe::<StdoutLock<'_>>();
assert_unwind_safe::<StdoutLock<'static>>();
}
#[test]
fn stderr_unwind_safe() {
assert_unwind_safe::<Stderr>();
}
#[test]
fn stderrlock_unwind_safe() {
assert_unwind_safe::<StderrLock<'_>>();
assert_unwind_safe::<StderrLock<'static>>();
}
fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn panic_doesnt_poison() {
thread::spawn(|| {
let _a = stdin();
let _a = _a.lock();
let _a = stdout();
let _a = _a.lock();
let _a = stderr();
let _a = _a.lock();
panic!();
})
.join()
.unwrap_err();
let _a = stdin();
let _a = _a.lock();
let _a = stdout();
let _a = _a.lock();
let _a = stderr();
let _a = _a.lock();
}
}

View file

@ -0,0 +1,47 @@
use super::*;
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::thread;
#[test]
fn stdout_unwind_safe() {
assert_unwind_safe::<Stdout>();
}
#[test]
fn stdoutlock_unwind_safe() {
assert_unwind_safe::<StdoutLock<'_>>();
assert_unwind_safe::<StdoutLock<'static>>();
}
#[test]
fn stderr_unwind_safe() {
assert_unwind_safe::<Stderr>();
}
#[test]
fn stderrlock_unwind_safe() {
assert_unwind_safe::<StderrLock<'_>>();
assert_unwind_safe::<StderrLock<'static>>();
}
fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn panic_doesnt_poison() {
thread::spawn(|| {
let _a = stdin();
let _a = _a.lock();
let _a = stdout();
let _a = _a.lock();
let _a = stderr();
let _a = _a.lock();
panic!();
})
.join()
.unwrap_err();
let _a = stdin();
let _a = _a.lock();
let _a = stdout();
let _a = _a.lock();
let _a = stderr();
let _a = _a.lock();
}

494
library/std/src/io/tests.rs Normal file
View file

@ -0,0 +1,494 @@
use super::{repeat, Cursor, SeekFrom};
use crate::cmp::{self, min};
use crate::io::prelude::*;
use crate::io::{self, IoSlice, IoSliceMut};
use crate::ops::Deref;
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn read_until() {
let mut buf = Cursor::new(&b"12"[..]);
let mut v = Vec::new();
assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2);
assert_eq!(v, b"12");
let mut buf = Cursor::new(&b"1233"[..]);
let mut v = Vec::new();
assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3);
assert_eq!(v, b"123");
v.truncate(0);
assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1);
assert_eq!(v, b"3");
v.truncate(0);
assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0);
assert_eq!(v, []);
}
#[test]
fn split() {
let buf = Cursor::new(&b"12"[..]);
let mut s = buf.split(b'3');
assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
assert!(s.next().is_none());
let buf = Cursor::new(&b"1233"[..]);
let mut s = buf.split(b'3');
assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
assert_eq!(s.next().unwrap().unwrap(), vec![]);
assert!(s.next().is_none());
}
#[test]
fn read_line() {
let mut buf = Cursor::new(&b"12"[..]);
let mut v = String::new();
assert_eq!(buf.read_line(&mut v).unwrap(), 2);
assert_eq!(v, "12");
let mut buf = Cursor::new(&b"12\n\n"[..]);
let mut v = String::new();
assert_eq!(buf.read_line(&mut v).unwrap(), 3);
assert_eq!(v, "12\n");
v.truncate(0);
assert_eq!(buf.read_line(&mut v).unwrap(), 1);
assert_eq!(v, "\n");
v.truncate(0);
assert_eq!(buf.read_line(&mut v).unwrap(), 0);
assert_eq!(v, "");
}
#[test]
fn lines() {
let buf = Cursor::new(&b"12\r"[..]);
let mut s = buf.lines();
assert_eq!(s.next().unwrap().unwrap(), "12\r".to_string());
assert!(s.next().is_none());
let buf = Cursor::new(&b"12\r\n\n"[..]);
let mut s = buf.lines();
assert_eq!(s.next().unwrap().unwrap(), "12".to_string());
assert_eq!(s.next().unwrap().unwrap(), "".to_string());
assert!(s.next().is_none());
}
#[test]
fn read_to_end() {
let mut c = Cursor::new(&b""[..]);
let mut v = Vec::new();
assert_eq!(c.read_to_end(&mut v).unwrap(), 0);
assert_eq!(v, []);
let mut c = Cursor::new(&b"1"[..]);
let mut v = Vec::new();
assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
assert_eq!(v, b"1");
let cap = 1024 * 1024;
let data = (0..cap).map(|i| (i / 3) as u8).collect::<Vec<_>>();
let mut v = Vec::new();
let (a, b) = data.split_at(data.len() / 2);
assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len());
assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len());
assert_eq!(v, data);
}
#[test]
fn read_to_string() {
let mut c = Cursor::new(&b""[..]);
let mut v = String::new();
assert_eq!(c.read_to_string(&mut v).unwrap(), 0);
assert_eq!(v, "");
let mut c = Cursor::new(&b"1"[..]);
let mut v = String::new();
assert_eq!(c.read_to_string(&mut v).unwrap(), 1);
assert_eq!(v, "1");
let mut c = Cursor::new(&b"\xff"[..]);
let mut v = String::new();
assert!(c.read_to_string(&mut v).is_err());
}
#[test]
fn read_exact() {
let mut buf = [0; 4];
let mut c = Cursor::new(&b""[..]);
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..]));
c.read_exact(&mut buf).unwrap();
assert_eq!(&buf, b"1234");
c.read_exact(&mut buf).unwrap();
assert_eq!(&buf, b"5678");
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
}
#[test]
fn read_exact_slice() {
let mut buf = [0; 4];
let mut c = &b""[..];
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
let mut c = &b"123"[..];
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
// make sure the optimized (early returning) method is being used
assert_eq!(&buf, &[0; 4]);
let mut c = &b"1234"[..];
c.read_exact(&mut buf).unwrap();
assert_eq!(&buf, b"1234");
let mut c = &b"56789"[..];
c.read_exact(&mut buf).unwrap();
assert_eq!(&buf, b"5678");
assert_eq!(c, b"9");
}
#[test]
fn take_eof() {
struct R;
impl Read for R {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
Err(io::Error::new(io::ErrorKind::Other, ""))
}
}
impl BufRead for R {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
Err(io::Error::new(io::ErrorKind::Other, ""))
}
fn consume(&mut self, _amt: usize) {}
}
let mut buf = [0; 1];
assert_eq!(0, R.take(0).read(&mut buf).unwrap());
assert_eq!(b"", R.take(0).fill_buf().unwrap());
}
fn cmp_bufread<Br1: BufRead, Br2: BufRead>(mut br1: Br1, mut br2: Br2, exp: &[u8]) {
let mut cat = Vec::new();
loop {
let consume = {
let buf1 = br1.fill_buf().unwrap();
let buf2 = br2.fill_buf().unwrap();
let minlen = if buf1.len() < buf2.len() { buf1.len() } else { buf2.len() };
assert_eq!(buf1[..minlen], buf2[..minlen]);
cat.extend_from_slice(&buf1[..minlen]);
minlen
};
if consume == 0 {
break;
}
br1.consume(consume);
br2.consume(consume);
}
assert_eq!(br1.fill_buf().unwrap().len(), 0);
assert_eq!(br2.fill_buf().unwrap().len(), 0);
assert_eq!(&cat[..], &exp[..])
}
#[test]
fn chain_bufread() {
let testdata = b"ABCDEFGHIJKL";
let chain1 =
(&testdata[..3]).chain(&testdata[3..6]).chain(&testdata[6..9]).chain(&testdata[9..]);
let chain2 = (&testdata[..4]).chain(&testdata[4..8]).chain(&testdata[8..]);
cmp_bufread(chain1, chain2, &testdata[..]);
}
#[test]
fn chain_zero_length_read_is_not_eof() {
let a = b"A";
let b = b"B";
let mut s = String::new();
let mut chain = (&a[..]).chain(&b[..]);
chain.read(&mut []).unwrap();
chain.read_to_string(&mut s).unwrap();
assert_eq!("AB", s);
}
#[bench]
#[cfg_attr(target_os = "emscripten", ignore)]
fn bench_read_to_end(b: &mut test::Bencher) {
b.iter(|| {
let mut lr = repeat(1).take(10000000);
let mut vec = Vec::with_capacity(1024);
super::read_to_end(&mut lr, &mut vec)
});
}
#[test]
fn seek_len() -> io::Result<()> {
let mut c = Cursor::new(vec![0; 15]);
assert_eq!(c.stream_len()?, 15);
c.seek(SeekFrom::End(0))?;
let old_pos = c.stream_position()?;
assert_eq!(c.stream_len()?, 15);
assert_eq!(c.stream_position()?, old_pos);
c.seek(SeekFrom::Start(7))?;
c.seek(SeekFrom::Current(2))?;
let old_pos = c.stream_position()?;
assert_eq!(c.stream_len()?, 15);
assert_eq!(c.stream_position()?, old_pos);
Ok(())
}
#[test]
fn seek_position() -> io::Result<()> {
// All `asserts` are duplicated here to make sure the method does not
// change anything about the seek state.
let mut c = Cursor::new(vec![0; 15]);
assert_eq!(c.stream_position()?, 0);
assert_eq!(c.stream_position()?, 0);
c.seek(SeekFrom::End(0))?;
assert_eq!(c.stream_position()?, 15);
assert_eq!(c.stream_position()?, 15);
c.seek(SeekFrom::Start(7))?;
c.seek(SeekFrom::Current(2))?;
assert_eq!(c.stream_position()?, 9);
assert_eq!(c.stream_position()?, 9);
c.seek(SeekFrom::End(-3))?;
c.seek(SeekFrom::Current(1))?;
c.seek(SeekFrom::Current(-5))?;
assert_eq!(c.stream_position()?, 8);
assert_eq!(c.stream_position()?, 8);
Ok(())
}
// A simple example reader which uses the default implementation of
// read_to_end.
struct ExampleSliceReader<'a> {
slice: &'a [u8],
}
impl<'a> Read for ExampleSliceReader<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let len = cmp::min(self.slice.len(), buf.len());
buf[..len].copy_from_slice(&self.slice[..len]);
self.slice = &self.slice[len..];
Ok(len)
}
}
#[test]
fn test_read_to_end_capacity() -> io::Result<()> {
let input = &b"foo"[..];
// read_to_end() generally needs to over-allocate, both for efficiency
// and so that it can distinguish EOF. Assert that this is the case
// with this simple ExampleSliceReader struct, which uses the default
// implementation of read_to_end. Even though vec1 is allocated with
// exactly enough capacity for the read, read_to_end will allocate more
// space here.
let mut vec1 = Vec::with_capacity(input.len());
ExampleSliceReader { slice: input }.read_to_end(&mut vec1)?;
assert_eq!(vec1.len(), input.len());
assert!(vec1.capacity() > input.len(), "allocated more");
// However, std::io::Take includes an implementation of read_to_end
// that will not allocate when the limit has already been reached. In
// this case, vec2 never grows.
let mut vec2 = Vec::with_capacity(input.len());
ExampleSliceReader { slice: input }.take(input.len() as u64).read_to_end(&mut vec2)?;
assert_eq!(vec2.len(), input.len());
assert_eq!(vec2.capacity(), input.len(), "did not allocate more");
Ok(())
}
#[test]
fn io_slice_mut_advance() {
let mut buf1 = [1; 8];
let mut buf2 = [2; 16];
let mut buf3 = [3; 8];
let mut bufs = &mut [
IoSliceMut::new(&mut buf1),
IoSliceMut::new(&mut buf2),
IoSliceMut::new(&mut buf3),
][..];
// Only in a single buffer..
bufs = IoSliceMut::advance(bufs, 1);
assert_eq!(bufs[0].deref(), [1; 7].as_ref());
assert_eq!(bufs[1].deref(), [2; 16].as_ref());
assert_eq!(bufs[2].deref(), [3; 8].as_ref());
// Removing a buffer, leaving others as is.
bufs = IoSliceMut::advance(bufs, 7);
assert_eq!(bufs[0].deref(), [2; 16].as_ref());
assert_eq!(bufs[1].deref(), [3; 8].as_ref());
// Removing a buffer and removing from the next buffer.
bufs = IoSliceMut::advance(bufs, 18);
assert_eq!(bufs[0].deref(), [3; 6].as_ref());
}
#[test]
fn io_slice_mut_advance_empty_slice() {
let empty_bufs = &mut [][..];
// Shouldn't panic.
IoSliceMut::advance(empty_bufs, 1);
}
#[test]
fn io_slice_mut_advance_beyond_total_length() {
let mut buf1 = [1; 8];
let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..];
// Going beyond the total length should be ok.
bufs = IoSliceMut::advance(bufs, 9);
assert!(bufs.is_empty());
}
#[test]
fn io_slice_advance() {
let buf1 = [1; 8];
let buf2 = [2; 16];
let buf3 = [3; 8];
let mut bufs = &mut [IoSlice::new(&buf1), IoSlice::new(&buf2), IoSlice::new(&buf3)][..];
// Only in a single buffer..
bufs = IoSlice::advance(bufs, 1);
assert_eq!(bufs[0].deref(), [1; 7].as_ref());
assert_eq!(bufs[1].deref(), [2; 16].as_ref());
assert_eq!(bufs[2].deref(), [3; 8].as_ref());
// Removing a buffer, leaving others as is.
bufs = IoSlice::advance(bufs, 7);
assert_eq!(bufs[0].deref(), [2; 16].as_ref());
assert_eq!(bufs[1].deref(), [3; 8].as_ref());
// Removing a buffer and removing from the next buffer.
bufs = IoSlice::advance(bufs, 18);
assert_eq!(bufs[0].deref(), [3; 6].as_ref());
}
#[test]
fn io_slice_advance_empty_slice() {
let empty_bufs = &mut [][..];
// Shouldn't panic.
IoSlice::advance(empty_bufs, 1);
}
#[test]
fn io_slice_advance_beyond_total_length() {
let buf1 = [1; 8];
let mut bufs = &mut [IoSlice::new(&buf1)][..];
// Going beyond the total length should be ok.
bufs = IoSlice::advance(bufs, 9);
assert!(bufs.is_empty());
}
/// Create a new writer that reads from at most `n_bufs` and reads
/// `per_call` bytes (in total) per call to write.
fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter {
TestWriter { n_bufs, per_call, written: Vec::new() }
}
struct TestWriter {
n_bufs: usize,
per_call: usize,
written: Vec<u8>,
}
impl Write for TestWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.write_vectored(&[IoSlice::new(buf)])
}
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let mut left = self.per_call;
let mut written = 0;
for buf in bufs.iter().take(self.n_bufs) {
let n = min(left, buf.len());
self.written.extend_from_slice(&buf[0..n]);
left -= n;
written += n;
}
Ok(written)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[test]
fn test_writer_read_from_one_buf() {
let mut writer = test_writer(1, 2);
assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
// Read at most 2 bytes.
assert_eq!(writer.write(&[1, 1, 1]).unwrap(), 2);
let bufs = &[IoSlice::new(&[2, 2, 2])];
assert_eq!(writer.write_vectored(bufs).unwrap(), 2);
// Only read from first buf.
let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4, 4])];
assert_eq!(writer.write_vectored(bufs).unwrap(), 1);
assert_eq!(writer.written, &[1, 1, 2, 2, 3]);
}
#[test]
fn test_writer_read_from_multiple_bufs() {
let mut writer = test_writer(3, 3);
// Read at most 3 bytes from two buffers.
let bufs = &[IoSlice::new(&[1]), IoSlice::new(&[2, 2, 2])];
assert_eq!(writer.write_vectored(bufs).unwrap(), 3);
// Read at most 3 bytes from three buffers.
let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4]), IoSlice::new(&[5, 5])];
assert_eq!(writer.write_vectored(bufs).unwrap(), 3);
assert_eq!(writer.written, &[1, 2, 2, 3, 4, 5]);
}
#[test]
fn test_write_all_vectored() {
#[rustfmt::skip] // Becomes unreadable otherwise.
let tests: Vec<(_, &'static [u8])> = vec![
(vec![], &[]),
(vec![IoSlice::new(&[]), IoSlice::new(&[])], &[]),
(vec![IoSlice::new(&[1])], &[1]),
(vec![IoSlice::new(&[1, 2])], &[1, 2]),
(vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]),
(vec![IoSlice::new(&[1, 2, 3, 4])], &[1, 2, 3, 4]),
(vec![IoSlice::new(&[1, 2, 3, 4, 5])], &[1, 2, 3, 4, 5]),
(vec![IoSlice::new(&[1]), IoSlice::new(&[2])], &[1, 2]),
(vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2])], &[1, 2, 2]),
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2])], &[1, 1, 2, 2]),
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]),
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]),
(vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 1, 2, 2, 2]),
(vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 2, 2, 2, 2]),
(vec![IoSlice::new(&[1, 1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 1, 2, 2, 2, 2]),
(vec![IoSlice::new(&[1]), IoSlice::new(&[2]), IoSlice::new(&[3])], &[1, 2, 3]),
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3])], &[1, 1, 2, 2, 3, 3]),
(vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 2, 2, 3, 3, 3]),
(vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 1, 1, 2, 2, 2, 3, 3, 3]),
];
let writer_configs = &[(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)];
for (n_bufs, per_call) in writer_configs.iter().copied() {
for (mut input, wanted) in tests.clone().into_iter() {
let mut writer = test_writer(n_bufs, per_call);
assert!(writer.write_all_vectored(&mut *input).is_ok());
assert_eq!(&*writer.written, &*wanted);
}
}
}

View file

@ -1,5 +1,8 @@
#![allow(missing_copy_implementations)]
#[cfg(test)]
mod tests;
use crate::fmt;
use crate::io::{self, BufRead, ErrorKind, Initializer, IoSlice, IoSliceMut, Read, Write};
use crate::mem::MaybeUninit;
@ -254,52 +257,3 @@ impl fmt::Debug for Sink {
f.pad("Sink { .. }")
}
}
#[cfg(test)]
mod tests {
use crate::io::prelude::*;
use crate::io::{copy, empty, repeat, sink};
#[test]
fn copy_copies() {
let mut r = repeat(0).take(4);
let mut w = sink();
assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
let mut r = repeat(0).take(1 << 17);
assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
}
#[test]
fn sink_sinks() {
let mut s = sink();
assert_eq!(s.write(&[]).unwrap(), 0);
assert_eq!(s.write(&[0]).unwrap(), 1);
assert_eq!(s.write(&[0; 1024]).unwrap(), 1024);
assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024);
}
#[test]
fn empty_reads() {
let mut e = empty();
assert_eq!(e.read(&mut []).unwrap(), 0);
assert_eq!(e.read(&mut [0]).unwrap(), 0);
assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
}
#[test]
fn repeat_repeats() {
let mut r = repeat(4);
let mut b = [0; 1024];
assert_eq!(r.read(&mut b).unwrap(), 1024);
assert!(b.iter().all(|b| *b == 4));
}
#[test]
fn take_some_bytes() {
assert_eq!(repeat(4).take(100).bytes().count(), 100);
assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
}
}

View file

@ -0,0 +1,45 @@
use crate::io::prelude::*;
use crate::io::{copy, empty, repeat, sink};
#[test]
fn copy_copies() {
let mut r = repeat(0).take(4);
let mut w = sink();
assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
let mut r = repeat(0).take(1 << 17);
assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
}
#[test]
fn sink_sinks() {
let mut s = sink();
assert_eq!(s.write(&[]).unwrap(), 0);
assert_eq!(s.write(&[0]).unwrap(), 1);
assert_eq!(s.write(&[0; 1024]).unwrap(), 1024);
assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024);
}
#[test]
fn empty_reads() {
let mut e = empty();
assert_eq!(e.read(&mut []).unwrap(), 0);
assert_eq!(e.read(&mut [0]).unwrap(), 0);
assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
}
#[test]
fn repeat_repeats() {
let mut r = repeat(4);
let mut b = [0; 1024];
assert_eq!(r.read(&mut b).unwrap(), 1024);
assert!(b.iter().all(|b| *b == 4));
}
#[test]
fn take_some_bytes() {
assert_eq!(repeat(4).take(100).bytes().count(), 100);
assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
}

View file

@ -1,5 +1,8 @@
//! Lazy values and one-time initialization of static data.
#[cfg(test)]
mod tests;
use crate::{
cell::{Cell, UnsafeCell},
fmt,
@ -506,333 +509,3 @@ impl<T: Default> Default for SyncLazy<T> {
SyncLazy::new(T::default)
}
}
#[cfg(test)]
mod tests {
use crate::{
lazy::{Lazy, SyncLazy, SyncOnceCell},
panic,
sync::{
atomic::{AtomicUsize, Ordering::SeqCst},
mpsc::channel,
Mutex,
},
thread,
};
#[test]
fn lazy_default() {
static CALLED: AtomicUsize = AtomicUsize::new(0);
struct Foo(u8);
impl Default for Foo {
fn default() -> Self {
CALLED.fetch_add(1, SeqCst);
Foo(42)
}
}
let lazy: Lazy<Mutex<Foo>> = <_>::default();
assert_eq!(CALLED.load(SeqCst), 0);
assert_eq!(lazy.lock().unwrap().0, 42);
assert_eq!(CALLED.load(SeqCst), 1);
lazy.lock().unwrap().0 = 21;
assert_eq!(lazy.lock().unwrap().0, 21);
assert_eq!(CALLED.load(SeqCst), 1);
}
#[test]
fn lazy_poisoning() {
let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
for _ in 0..2 {
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len()));
assert!(res.is_err());
}
}
fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
thread::spawn(f).join().unwrap()
}
#[test]
fn sync_once_cell() {
static ONCE_CELL: SyncOnceCell<i32> = SyncOnceCell::new();
assert!(ONCE_CELL.get().is_none());
spawn_and_wait(|| {
ONCE_CELL.get_or_init(|| 92);
assert_eq!(ONCE_CELL.get(), Some(&92));
});
ONCE_CELL.get_or_init(|| panic!("Kabom!"));
assert_eq!(ONCE_CELL.get(), Some(&92));
}
#[test]
fn sync_once_cell_get_mut() {
let mut c = SyncOnceCell::new();
assert!(c.get_mut().is_none());
c.set(90).unwrap();
*c.get_mut().unwrap() += 2;
assert_eq!(c.get_mut(), Some(&mut 92));
}
#[test]
fn sync_once_cell_get_unchecked() {
let c = SyncOnceCell::new();
c.set(92).unwrap();
unsafe {
assert_eq!(c.get_unchecked(), &92);
}
}
#[test]
fn sync_once_cell_drop() {
static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
struct Dropper;
impl Drop for Dropper {
fn drop(&mut self) {
DROP_CNT.fetch_add(1, SeqCst);
}
}
let x = SyncOnceCell::new();
spawn_and_wait(move || {
x.get_or_init(|| Dropper);
assert_eq!(DROP_CNT.load(SeqCst), 0);
drop(x);
});
assert_eq!(DROP_CNT.load(SeqCst), 1);
}
#[test]
fn sync_once_cell_drop_empty() {
let x = SyncOnceCell::<String>::new();
drop(x);
}
#[test]
fn clone() {
let s = SyncOnceCell::new();
let c = s.clone();
assert!(c.get().is_none());
s.set("hello".to_string()).unwrap();
let c = s.clone();
assert_eq!(c.get().map(String::as_str), Some("hello"));
}
#[test]
fn get_or_try_init() {
let cell: SyncOnceCell<String> = SyncOnceCell::new();
assert!(cell.get().is_none());
let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() }));
assert!(res.is_err());
assert!(!cell.is_initialized());
assert!(cell.get().is_none());
assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
assert_eq!(
cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())),
Ok(&"hello".to_string())
);
assert_eq!(cell.get(), Some(&"hello".to_string()));
}
#[test]
fn from_impl() {
assert_eq!(SyncOnceCell::from("value").get(), Some(&"value"));
assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar"));
}
#[test]
fn partialeq_impl() {
assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value"));
assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar"));
assert!(SyncOnceCell::<String>::new() == SyncOnceCell::new());
assert!(SyncOnceCell::<String>::new() != SyncOnceCell::from("value".to_owned()));
}
#[test]
fn into_inner() {
let cell: SyncOnceCell<String> = SyncOnceCell::new();
assert_eq!(cell.into_inner(), None);
let cell = SyncOnceCell::new();
cell.set("hello".to_string()).unwrap();
assert_eq!(cell.into_inner(), Some("hello".to_string()));
}
#[test]
fn sync_lazy_new() {
static CALLED: AtomicUsize = AtomicUsize::new(0);
static SYNC_LAZY: SyncLazy<i32> = SyncLazy::new(|| {
CALLED.fetch_add(1, SeqCst);
92
});
assert_eq!(CALLED.load(SeqCst), 0);
spawn_and_wait(|| {
let y = *SYNC_LAZY - 30;
assert_eq!(y, 62);
assert_eq!(CALLED.load(SeqCst), 1);
});
let y = *SYNC_LAZY - 30;
assert_eq!(y, 62);
assert_eq!(CALLED.load(SeqCst), 1);
}
#[test]
fn sync_lazy_default() {
static CALLED: AtomicUsize = AtomicUsize::new(0);
struct Foo(u8);
impl Default for Foo {
fn default() -> Self {
CALLED.fetch_add(1, SeqCst);
Foo(42)
}
}
let lazy: SyncLazy<Mutex<Foo>> = <_>::default();
assert_eq!(CALLED.load(SeqCst), 0);
assert_eq!(lazy.lock().unwrap().0, 42);
assert_eq!(CALLED.load(SeqCst), 1);
lazy.lock().unwrap().0 = 21;
assert_eq!(lazy.lock().unwrap().0, 21);
assert_eq!(CALLED.load(SeqCst), 1);
}
#[test]
fn static_sync_lazy() {
static XS: SyncLazy<Vec<i32>> = SyncLazy::new(|| {
let mut xs = Vec::new();
xs.push(1);
xs.push(2);
xs.push(3);
xs
});
spawn_and_wait(|| {
assert_eq!(&*XS, &vec![1, 2, 3]);
});
assert_eq!(&*XS, &vec![1, 2, 3]);
}
#[test]
fn static_sync_lazy_via_fn() {
fn xs() -> &'static Vec<i32> {
static XS: SyncOnceCell<Vec<i32>> = SyncOnceCell::new();
XS.get_or_init(|| {
let mut xs = Vec::new();
xs.push(1);
xs.push(2);
xs.push(3);
xs
})
}
assert_eq!(xs(), &vec![1, 2, 3]);
}
#[test]
fn sync_lazy_poisoning() {
let x: SyncLazy<String> = SyncLazy::new(|| panic!("kaboom"));
for _ in 0..2 {
let res = panic::catch_unwind(|| x.len());
assert!(res.is_err());
}
}
#[test]
fn is_sync_send() {
fn assert_traits<T: Send + Sync>() {}
assert_traits::<SyncOnceCell<String>>();
assert_traits::<SyncLazy<String>>();
}
#[test]
fn eval_once_macro() {
macro_rules! eval_once {
(|| -> $ty:ty {
$($body:tt)*
}) => {{
static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new();
fn init() -> $ty {
$($body)*
}
ONCE_CELL.get_or_init(init)
}};
}
let fib: &'static Vec<i32> = eval_once! {
|| -> Vec<i32> {
let mut res = vec![1, 1];
for i in 0..10 {
let next = res[i] + res[i + 1];
res.push(next);
}
res
}
};
assert_eq!(fib[5], 8)
}
#[test]
fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
static ONCE_CELL: SyncOnceCell<String> = SyncOnceCell::new();
let n_readers = 10;
let n_writers = 3;
const MSG: &str = "Hello, World";
let (tx, rx) = channel();
for _ in 0..n_readers {
let tx = tx.clone();
thread::spawn(move || {
loop {
if let Some(msg) = ONCE_CELL.get() {
tx.send(msg).unwrap();
break;
}
#[cfg(target_env = "sgx")]
crate::thread::yield_now();
}
});
}
for _ in 0..n_writers {
thread::spawn(move || {
let _ = ONCE_CELL.set(MSG.to_owned());
});
}
for _ in 0..n_readers {
let msg = rx.recv().unwrap();
assert_eq!(msg, MSG);
}
}
#[test]
fn dropck() {
let cell = SyncOnceCell::new();
{
let s = String::new();
cell.set(&s).unwrap();
}
}
}

View file

@ -0,0 +1,323 @@
use crate::{
lazy::{Lazy, SyncLazy, SyncOnceCell},
panic,
sync::{
atomic::{AtomicUsize, Ordering::SeqCst},
mpsc::channel,
Mutex,
},
thread,
};
#[test]
fn lazy_default() {
static CALLED: AtomicUsize = AtomicUsize::new(0);
struct Foo(u8);
impl Default for Foo {
fn default() -> Self {
CALLED.fetch_add(1, SeqCst);
Foo(42)
}
}
let lazy: Lazy<Mutex<Foo>> = <_>::default();
assert_eq!(CALLED.load(SeqCst), 0);
assert_eq!(lazy.lock().unwrap().0, 42);
assert_eq!(CALLED.load(SeqCst), 1);
lazy.lock().unwrap().0 = 21;
assert_eq!(lazy.lock().unwrap().0, 21);
assert_eq!(CALLED.load(SeqCst), 1);
}
#[test]
fn lazy_poisoning() {
let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
for _ in 0..2 {
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len()));
assert!(res.is_err());
}
}
fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
thread::spawn(f).join().unwrap()
}
#[test]
fn sync_once_cell() {
static ONCE_CELL: SyncOnceCell<i32> = SyncOnceCell::new();
assert!(ONCE_CELL.get().is_none());
spawn_and_wait(|| {
ONCE_CELL.get_or_init(|| 92);
assert_eq!(ONCE_CELL.get(), Some(&92));
});
ONCE_CELL.get_or_init(|| panic!("Kabom!"));
assert_eq!(ONCE_CELL.get(), Some(&92));
}
#[test]
fn sync_once_cell_get_mut() {
let mut c = SyncOnceCell::new();
assert!(c.get_mut().is_none());
c.set(90).unwrap();
*c.get_mut().unwrap() += 2;
assert_eq!(c.get_mut(), Some(&mut 92));
}
#[test]
fn sync_once_cell_get_unchecked() {
let c = SyncOnceCell::new();
c.set(92).unwrap();
unsafe {
assert_eq!(c.get_unchecked(), &92);
}
}
#[test]
fn sync_once_cell_drop() {
static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
struct Dropper;
impl Drop for Dropper {
fn drop(&mut self) {
DROP_CNT.fetch_add(1, SeqCst);
}
}
let x = SyncOnceCell::new();
spawn_and_wait(move || {
x.get_or_init(|| Dropper);
assert_eq!(DROP_CNT.load(SeqCst), 0);
drop(x);
});
assert_eq!(DROP_CNT.load(SeqCst), 1);
}
#[test]
fn sync_once_cell_drop_empty() {
let x = SyncOnceCell::<String>::new();
drop(x);
}
#[test]
fn clone() {
let s = SyncOnceCell::new();
let c = s.clone();
assert!(c.get().is_none());
s.set("hello".to_string()).unwrap();
let c = s.clone();
assert_eq!(c.get().map(String::as_str), Some("hello"));
}
#[test]
fn get_or_try_init() {
let cell: SyncOnceCell<String> = SyncOnceCell::new();
assert!(cell.get().is_none());
let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() }));
assert!(res.is_err());
assert!(!cell.is_initialized());
assert!(cell.get().is_none());
assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
assert_eq!(cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), Ok(&"hello".to_string()));
assert_eq!(cell.get(), Some(&"hello".to_string()));
}
#[test]
fn from_impl() {
assert_eq!(SyncOnceCell::from("value").get(), Some(&"value"));
assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar"));
}
#[test]
fn partialeq_impl() {
assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value"));
assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar"));
assert!(SyncOnceCell::<String>::new() == SyncOnceCell::new());
assert!(SyncOnceCell::<String>::new() != SyncOnceCell::from("value".to_owned()));
}
#[test]
fn into_inner() {
let cell: SyncOnceCell<String> = SyncOnceCell::new();
assert_eq!(cell.into_inner(), None);
let cell = SyncOnceCell::new();
cell.set("hello".to_string()).unwrap();
assert_eq!(cell.into_inner(), Some("hello".to_string()));
}
#[test]
fn sync_lazy_new() {
static CALLED: AtomicUsize = AtomicUsize::new(0);
static SYNC_LAZY: SyncLazy<i32> = SyncLazy::new(|| {
CALLED.fetch_add(1, SeqCst);
92
});
assert_eq!(CALLED.load(SeqCst), 0);
spawn_and_wait(|| {
let y = *SYNC_LAZY - 30;
assert_eq!(y, 62);
assert_eq!(CALLED.load(SeqCst), 1);
});
let y = *SYNC_LAZY - 30;
assert_eq!(y, 62);
assert_eq!(CALLED.load(SeqCst), 1);
}
#[test]
fn sync_lazy_default() {
static CALLED: AtomicUsize = AtomicUsize::new(0);
struct Foo(u8);
impl Default for Foo {
fn default() -> Self {
CALLED.fetch_add(1, SeqCst);
Foo(42)
}
}
let lazy: SyncLazy<Mutex<Foo>> = <_>::default();
assert_eq!(CALLED.load(SeqCst), 0);
assert_eq!(lazy.lock().unwrap().0, 42);
assert_eq!(CALLED.load(SeqCst), 1);
lazy.lock().unwrap().0 = 21;
assert_eq!(lazy.lock().unwrap().0, 21);
assert_eq!(CALLED.load(SeqCst), 1);
}
#[test]
fn static_sync_lazy() {
static XS: SyncLazy<Vec<i32>> = SyncLazy::new(|| {
let mut xs = Vec::new();
xs.push(1);
xs.push(2);
xs.push(3);
xs
});
spawn_and_wait(|| {
assert_eq!(&*XS, &vec![1, 2, 3]);
});
assert_eq!(&*XS, &vec![1, 2, 3]);
}
#[test]
fn static_sync_lazy_via_fn() {
fn xs() -> &'static Vec<i32> {
static XS: SyncOnceCell<Vec<i32>> = SyncOnceCell::new();
XS.get_or_init(|| {
let mut xs = Vec::new();
xs.push(1);
xs.push(2);
xs.push(3);
xs
})
}
assert_eq!(xs(), &vec![1, 2, 3]);
}
#[test]
fn sync_lazy_poisoning() {
let x: SyncLazy<String> = SyncLazy::new(|| panic!("kaboom"));
for _ in 0..2 {
let res = panic::catch_unwind(|| x.len());
assert!(res.is_err());
}
}
#[test]
fn is_sync_send() {
fn assert_traits<T: Send + Sync>() {}
assert_traits::<SyncOnceCell<String>>();
assert_traits::<SyncLazy<String>>();
}
#[test]
fn eval_once_macro() {
macro_rules! eval_once {
(|| -> $ty:ty {
$($body:tt)*
}) => {{
static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new();
fn init() -> $ty {
$($body)*
}
ONCE_CELL.get_or_init(init)
}};
}
let fib: &'static Vec<i32> = eval_once! {
|| -> Vec<i32> {
let mut res = vec![1, 1];
for i in 0..10 {
let next = res[i] + res[i + 1];
res.push(next);
}
res
}
};
assert_eq!(fib[5], 8)
}
#[test]
fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
static ONCE_CELL: SyncOnceCell<String> = SyncOnceCell::new();
let n_readers = 10;
let n_writers = 3;
const MSG: &str = "Hello, World";
let (tx, rx) = channel();
for _ in 0..n_readers {
let tx = tx.clone();
thread::spawn(move || {
loop {
if let Some(msg) = ONCE_CELL.get() {
tx.send(msg).unwrap();
break;
}
#[cfg(target_env = "sgx")]
crate::thread::yield_now();
}
});
}
for _ in 0..n_writers {
thread::spawn(move || {
let _ = ONCE_CELL.set(MSG.to_owned());
});
}
for _ in 0..n_readers {
let msg = rx.recv().unwrap();
assert_eq!(msg, MSG);
}
}
#[test]
fn dropck() {
let cell = SyncOnceCell::new();
{
let s = String::new();
cell.set(&s).unwrap();
}
}

View file

@ -1,6 +1,9 @@
// Original implementation taken from rust-memchr.
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
#[cfg(test)]
mod tests;
/// A safe interface to `memchr`.
///
/// Returns the index corresponding to the first occurrence of `needle` in
@ -44,90 +47,3 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
crate::sys::memchr::memrchr(needle, haystack)
}
#[cfg(test)]
mod tests {
// test the implementations for the current platform
use super::{memchr, memrchr};
#[test]
fn matches_one() {
assert_eq!(Some(0), memchr(b'a', b"a"));
}
#[test]
fn matches_begin() {
assert_eq!(Some(0), memchr(b'a', b"aaaa"));
}
#[test]
fn matches_end() {
assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
}
#[test]
fn matches_nul() {
assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
}
#[test]
fn matches_past_nul() {
assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
}
#[test]
fn no_match_empty() {
assert_eq!(None, memchr(b'a', b""));
}
#[test]
fn no_match() {
assert_eq!(None, memchr(b'a', b"xyz"));
}
#[test]
fn matches_one_reversed() {
assert_eq!(Some(0), memrchr(b'a', b"a"));
}
#[test]
fn matches_begin_reversed() {
assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
}
#[test]
fn matches_end_reversed() {
assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
}
#[test]
fn matches_nul_reversed() {
assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
}
#[test]
fn matches_past_nul_reversed() {
assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
}
#[test]
fn no_match_empty_reversed() {
assert_eq!(None, memrchr(b'a', b""));
}
#[test]
fn no_match_reversed() {
assert_eq!(None, memrchr(b'a', b"xyz"));
}
#[test]
fn each_alignment() {
let mut data = [1u8; 64];
let needle = 2;
let pos = 40;
data[pos] = needle;
for start in 0..16 {
assert_eq!(Some(pos - start), memchr(needle, &data[start..]));
}
}
}

View file

@ -0,0 +1,86 @@
// Original implementation taken from rust-memchr.
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
// test the implementations for the current platform
use super::{memchr, memrchr};
#[test]
fn matches_one() {
assert_eq!(Some(0), memchr(b'a', b"a"));
}
#[test]
fn matches_begin() {
assert_eq!(Some(0), memchr(b'a', b"aaaa"));
}
#[test]
fn matches_end() {
assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
}
#[test]
fn matches_nul() {
assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
}
#[test]
fn matches_past_nul() {
assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
}
#[test]
fn no_match_empty() {
assert_eq!(None, memchr(b'a', b""));
}
#[test]
fn no_match() {
assert_eq!(None, memchr(b'a', b"xyz"));
}
#[test]
fn matches_one_reversed() {
assert_eq!(Some(0), memrchr(b'a', b"a"));
}
#[test]
fn matches_begin_reversed() {
assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
}
#[test]
fn matches_end_reversed() {
assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
}
#[test]
fn matches_nul_reversed() {
assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
}
#[test]
fn matches_past_nul_reversed() {
assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
}
#[test]
fn no_match_empty_reversed() {
assert_eq!(None, memrchr(b'a', b""));
}
#[test]
fn no_match_reversed() {
assert_eq!(None, memrchr(b'a', b"xyz"));
}
#[test]
fn each_alignment() {
let mut data = [1u8; 64];
let needle = 2;
let pos = 40;
data[pos] = needle;
for start in 0..16 {
assert_eq!(Some(pos - start), memchr(needle, &data[start..]));
}
}

View file

@ -1,3 +1,6 @@
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
use crate::cmp::Ordering;
use crate::convert::TryInto;
use crate::fmt;
@ -991,236 +994,3 @@ impl ToSocketAddrs for String {
(&**self).to_socket_addrs()
}
}
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use crate::net::test::{sa4, sa6, tsa};
use crate::net::*;
#[test]
fn to_socket_addr_ipaddr_u16() {
let a = Ipv4Addr::new(77, 88, 21, 11);
let p = 12345;
let e = SocketAddr::V4(SocketAddrV4::new(a, p));
assert_eq!(Ok(vec![e]), tsa((a, p)));
}
#[test]
fn to_socket_addr_str_u16() {
let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352)));
let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53)));
let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924);
#[cfg(not(target_env = "sgx"))]
assert!(tsa(("localhost", 23924)).unwrap().contains(&a));
#[cfg(target_env = "sgx")]
let _ = a;
}
#[test]
fn to_socket_addr_str() {
let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352"));
let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53"));
let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924);
#[cfg(not(target_env = "sgx"))]
assert!(tsa("localhost:23924").unwrap().contains(&a));
#[cfg(target_env = "sgx")]
let _ = a;
}
#[test]
fn to_socket_addr_string() {
let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
assert_eq!(Ok(vec![a]), tsa(&*format!("{}:{}", "77.88.21.11", "24352")));
assert_eq!(Ok(vec![a]), tsa(&format!("{}:{}", "77.88.21.11", "24352")));
assert_eq!(Ok(vec![a]), tsa(format!("{}:{}", "77.88.21.11", "24352")));
let s = format!("{}:{}", "77.88.21.11", "24352");
assert_eq!(Ok(vec![a]), tsa(s));
// s has been moved into the tsa call
}
#[test]
fn bind_udp_socket_bad() {
// rust-lang/rust#53957: This is a regression test for a parsing problem
// discovered as part of issue rust-lang/rust#23076, where we were
// incorrectly parsing invalid input and then that would result in a
// successful `UdpSocket` binding when we would expect failure.
//
// At one time, this test was written as a call to `tsa` with
// INPUT_23076. However, that structure yields an unreliable test,
// because it ends up passing junk input to the DNS server, and some DNS
// servers will respond with `Ok` to such input, with the ip address of
// the DNS server itself.
//
// This form of the test is more robust: even when the DNS server
// returns its own address, it is still an error to bind a UDP socket to
// a non-local address, and so we still get an error here in that case.
const INPUT_23076: &'static str = "1200::AB00:1234::2552:7777:1313:34300";
assert!(crate::net::UdpSocket::bind(INPUT_23076).is_err())
}
#[test]
fn set_ip() {
fn ip4(low: u8) -> Ipv4Addr {
Ipv4Addr::new(77, 88, 21, low)
}
fn ip6(low: u16) -> Ipv6Addr {
Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low)
}
let mut v4 = SocketAddrV4::new(ip4(11), 80);
assert_eq!(v4.ip(), &ip4(11));
v4.set_ip(ip4(12));
assert_eq!(v4.ip(), &ip4(12));
let mut addr = SocketAddr::V4(v4);
assert_eq!(addr.ip(), IpAddr::V4(ip4(12)));
addr.set_ip(IpAddr::V4(ip4(13)));
assert_eq!(addr.ip(), IpAddr::V4(ip4(13)));
addr.set_ip(IpAddr::V6(ip6(14)));
assert_eq!(addr.ip(), IpAddr::V6(ip6(14)));
let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0);
assert_eq!(v6.ip(), &ip6(1));
v6.set_ip(ip6(2));
assert_eq!(v6.ip(), &ip6(2));
let mut addr = SocketAddr::V6(v6);
assert_eq!(addr.ip(), IpAddr::V6(ip6(2)));
addr.set_ip(IpAddr::V6(ip6(3)));
assert_eq!(addr.ip(), IpAddr::V6(ip6(3)));
addr.set_ip(IpAddr::V4(ip4(4)));
assert_eq!(addr.ip(), IpAddr::V4(ip4(4)));
}
#[test]
fn set_port() {
let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80);
assert_eq!(v4.port(), 80);
v4.set_port(443);
assert_eq!(v4.port(), 443);
let mut addr = SocketAddr::V4(v4);
assert_eq!(addr.port(), 443);
addr.set_port(8080);
assert_eq!(addr.port(), 8080);
let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0);
assert_eq!(v6.port(), 80);
v6.set_port(443);
assert_eq!(v6.port(), 443);
let mut addr = SocketAddr::V6(v6);
assert_eq!(addr.port(), 443);
addr.set_port(8080);
assert_eq!(addr.port(), 8080);
}
#[test]
fn set_flowinfo() {
let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0);
assert_eq!(v6.flowinfo(), 10);
v6.set_flowinfo(20);
assert_eq!(v6.flowinfo(), 20);
}
#[test]
fn set_scope_id() {
let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10);
assert_eq!(v6.scope_id(), 10);
v6.set_scope_id(20);
assert_eq!(v6.scope_id(), 20);
}
#[test]
fn is_v4() {
let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80));
assert!(v4.is_ipv4());
assert!(!v4.is_ipv6());
}
#[test]
fn is_v6() {
let v6 = SocketAddr::V6(SocketAddrV6::new(
Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1),
80,
10,
0,
));
assert!(!v6.is_ipv4());
assert!(v6.is_ipv6());
}
#[test]
fn socket_v4_to_str() {
let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080);
assert_eq!(format!("{}", socket), "192.168.0.1:8080");
assert_eq!(format!("{:<20}", socket), "192.168.0.1:8080 ");
assert_eq!(format!("{:>20}", socket), " 192.168.0.1:8080");
assert_eq!(format!("{:^20}", socket), " 192.168.0.1:8080 ");
assert_eq!(format!("{:.10}", socket), "192.168.0.");
}
#[test]
fn socket_v6_to_str() {
let socket: SocketAddrV6 = "[2a02:6b8:0:1::1]:53".parse().unwrap();
assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53");
assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53 ");
assert_eq!(format!("{:>24}", socket), " [2a02:6b8:0:1::1]:53");
assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1]:53 ");
assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::");
}
#[test]
fn compare() {
let v4_1 = "224.120.45.1:23456".parse::<SocketAddrV4>().unwrap();
let v4_2 = "224.210.103.5:12345".parse::<SocketAddrV4>().unwrap();
let v4_3 = "224.210.103.5:23456".parse::<SocketAddrV4>().unwrap();
let v6_1 = "[2001:db8:f00::1002]:23456".parse::<SocketAddrV6>().unwrap();
let v6_2 = "[2001:db8:f00::2001]:12345".parse::<SocketAddrV6>().unwrap();
let v6_3 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap();
// equality
assert_eq!(v4_1, v4_1);
assert_eq!(v6_1, v6_1);
assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1));
assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1));
assert!(v4_1 != v4_2);
assert!(v6_1 != v6_2);
// compare different addresses
assert!(v4_1 < v4_2);
assert!(v6_1 < v6_2);
assert!(v4_2 > v4_1);
assert!(v6_2 > v6_1);
// compare the same address with different ports
assert!(v4_2 < v4_3);
assert!(v6_2 < v6_3);
assert!(v4_3 > v4_2);
assert!(v6_3 > v6_2);
// compare different addresses with the same port
assert!(v4_1 < v4_3);
assert!(v6_1 < v6_3);
assert!(v4_3 > v4_1);
assert!(v6_3 > v6_1);
// compare with an inferred right-hand side
assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap());
assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap());
assert_eq!(SocketAddr::V4(v4_1), "224.120.45.1:23456".parse().unwrap());
}
}

View file

@ -0,0 +1,229 @@
use crate::net::test::{sa4, sa6, tsa};
use crate::net::*;
#[test]
fn to_socket_addr_ipaddr_u16() {
let a = Ipv4Addr::new(77, 88, 21, 11);
let p = 12345;
let e = SocketAddr::V4(SocketAddrV4::new(a, p));
assert_eq!(Ok(vec![e]), tsa((a, p)));
}
#[test]
fn to_socket_addr_str_u16() {
let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352)));
let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53)));
let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924);
#[cfg(not(target_env = "sgx"))]
assert!(tsa(("localhost", 23924)).unwrap().contains(&a));
#[cfg(target_env = "sgx")]
let _ = a;
}
#[test]
fn to_socket_addr_str() {
let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352"));
let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53"));
let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924);
#[cfg(not(target_env = "sgx"))]
assert!(tsa("localhost:23924").unwrap().contains(&a));
#[cfg(target_env = "sgx")]
let _ = a;
}
#[test]
fn to_socket_addr_string() {
let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
assert_eq!(Ok(vec![a]), tsa(&*format!("{}:{}", "77.88.21.11", "24352")));
assert_eq!(Ok(vec![a]), tsa(&format!("{}:{}", "77.88.21.11", "24352")));
assert_eq!(Ok(vec![a]), tsa(format!("{}:{}", "77.88.21.11", "24352")));
let s = format!("{}:{}", "77.88.21.11", "24352");
assert_eq!(Ok(vec![a]), tsa(s));
// s has been moved into the tsa call
}
#[test]
fn bind_udp_socket_bad() {
// rust-lang/rust#53957: This is a regression test for a parsing problem
// discovered as part of issue rust-lang/rust#23076, where we were
// incorrectly parsing invalid input and then that would result in a
// successful `UdpSocket` binding when we would expect failure.
//
// At one time, this test was written as a call to `tsa` with
// INPUT_23076. However, that structure yields an unreliable test,
// because it ends up passing junk input to the DNS server, and some DNS
// servers will respond with `Ok` to such input, with the ip address of
// the DNS server itself.
//
// This form of the test is more robust: even when the DNS server
// returns its own address, it is still an error to bind a UDP socket to
// a non-local address, and so we still get an error here in that case.
const INPUT_23076: &'static str = "1200::AB00:1234::2552:7777:1313:34300";
assert!(crate::net::UdpSocket::bind(INPUT_23076).is_err())
}
#[test]
fn set_ip() {
fn ip4(low: u8) -> Ipv4Addr {
Ipv4Addr::new(77, 88, 21, low)
}
fn ip6(low: u16) -> Ipv6Addr {
Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low)
}
let mut v4 = SocketAddrV4::new(ip4(11), 80);
assert_eq!(v4.ip(), &ip4(11));
v4.set_ip(ip4(12));
assert_eq!(v4.ip(), &ip4(12));
let mut addr = SocketAddr::V4(v4);
assert_eq!(addr.ip(), IpAddr::V4(ip4(12)));
addr.set_ip(IpAddr::V4(ip4(13)));
assert_eq!(addr.ip(), IpAddr::V4(ip4(13)));
addr.set_ip(IpAddr::V6(ip6(14)));
assert_eq!(addr.ip(), IpAddr::V6(ip6(14)));
let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0);
assert_eq!(v6.ip(), &ip6(1));
v6.set_ip(ip6(2));
assert_eq!(v6.ip(), &ip6(2));
let mut addr = SocketAddr::V6(v6);
assert_eq!(addr.ip(), IpAddr::V6(ip6(2)));
addr.set_ip(IpAddr::V6(ip6(3)));
assert_eq!(addr.ip(), IpAddr::V6(ip6(3)));
addr.set_ip(IpAddr::V4(ip4(4)));
assert_eq!(addr.ip(), IpAddr::V4(ip4(4)));
}
#[test]
fn set_port() {
let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80);
assert_eq!(v4.port(), 80);
v4.set_port(443);
assert_eq!(v4.port(), 443);
let mut addr = SocketAddr::V4(v4);
assert_eq!(addr.port(), 443);
addr.set_port(8080);
assert_eq!(addr.port(), 8080);
let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0);
assert_eq!(v6.port(), 80);
v6.set_port(443);
assert_eq!(v6.port(), 443);
let mut addr = SocketAddr::V6(v6);
assert_eq!(addr.port(), 443);
addr.set_port(8080);
assert_eq!(addr.port(), 8080);
}
#[test]
fn set_flowinfo() {
let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0);
assert_eq!(v6.flowinfo(), 10);
v6.set_flowinfo(20);
assert_eq!(v6.flowinfo(), 20);
}
#[test]
fn set_scope_id() {
let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10);
assert_eq!(v6.scope_id(), 10);
v6.set_scope_id(20);
assert_eq!(v6.scope_id(), 20);
}
#[test]
fn is_v4() {
let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80));
assert!(v4.is_ipv4());
assert!(!v4.is_ipv6());
}
#[test]
fn is_v6() {
let v6 = SocketAddr::V6(SocketAddrV6::new(
Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1),
80,
10,
0,
));
assert!(!v6.is_ipv4());
assert!(v6.is_ipv6());
}
#[test]
fn socket_v4_to_str() {
let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080);
assert_eq!(format!("{}", socket), "192.168.0.1:8080");
assert_eq!(format!("{:<20}", socket), "192.168.0.1:8080 ");
assert_eq!(format!("{:>20}", socket), " 192.168.0.1:8080");
assert_eq!(format!("{:^20}", socket), " 192.168.0.1:8080 ");
assert_eq!(format!("{:.10}", socket), "192.168.0.");
}
#[test]
fn socket_v6_to_str() {
let socket: SocketAddrV6 = "[2a02:6b8:0:1::1]:53".parse().unwrap();
assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53");
assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53 ");
assert_eq!(format!("{:>24}", socket), " [2a02:6b8:0:1::1]:53");
assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1]:53 ");
assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::");
}
#[test]
fn compare() {
let v4_1 = "224.120.45.1:23456".parse::<SocketAddrV4>().unwrap();
let v4_2 = "224.210.103.5:12345".parse::<SocketAddrV4>().unwrap();
let v4_3 = "224.210.103.5:23456".parse::<SocketAddrV4>().unwrap();
let v6_1 = "[2001:db8:f00::1002]:23456".parse::<SocketAddrV6>().unwrap();
let v6_2 = "[2001:db8:f00::2001]:12345".parse::<SocketAddrV6>().unwrap();
let v6_3 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap();
// equality
assert_eq!(v4_1, v4_1);
assert_eq!(v6_1, v6_1);
assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1));
assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1));
assert!(v4_1 != v4_2);
assert!(v6_1 != v6_2);
// compare different addresses
assert!(v4_1 < v4_2);
assert!(v6_1 < v6_2);
assert!(v4_2 > v4_1);
assert!(v6_2 > v6_1);
// compare the same address with different ports
assert!(v4_2 < v4_3);
assert!(v6_2 < v6_3);
assert!(v4_3 > v4_2);
assert!(v6_3 > v6_2);
// compare different addresses with the same port
assert!(v4_1 < v4_3);
assert!(v6_1 < v6_3);
assert!(v4_3 > v4_1);
assert!(v6_3 > v6_1);
// compare with an inferred right-hand side
assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap());
assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap());
assert_eq!(SocketAddr::V4(v4_1), "224.120.45.1:23456".parse().unwrap());
}

View file

@ -6,6 +6,10 @@
issue = "27709"
)]
// Tests for this module
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
use crate::cmp::Ordering;
use crate::fmt::{self, Write as FmtWrite};
use crate::hash;
@ -1895,862 +1899,3 @@ impl From<[u16; 8]> for IpAddr {
IpAddr::V6(Ipv6Addr::from(segments))
}
}
// Tests for this module
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use crate::net::test::{sa4, sa6, tsa};
use crate::net::*;
use crate::str::FromStr;
#[test]
fn test_from_str_ipv4() {
assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse());
assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse());
assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse());
// out of range
let none: Option<Ipv4Addr> = "256.0.0.1".parse().ok();
assert_eq!(None, none);
// too short
let none: Option<Ipv4Addr> = "255.0.0".parse().ok();
assert_eq!(None, none);
// too long
let none: Option<Ipv4Addr> = "255.0.0.1.2".parse().ok();
assert_eq!(None, none);
// no number between dots
let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
assert_eq!(None, none);
}
#[test]
fn test_from_str_ipv6() {
assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse());
assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse());
assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse());
assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse());
assert_eq!(
Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)),
"2a02:6b8::11:11".parse()
);
// too long group
let none: Option<Ipv6Addr> = "::00000".parse().ok();
assert_eq!(None, none);
// too short
let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7".parse().ok();
assert_eq!(None, none);
// too long
let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:8:9".parse().ok();
assert_eq!(None, none);
// triple colon
let none: Option<Ipv6Addr> = "1:2:::6:7:8".parse().ok();
assert_eq!(None, none);
// two double colons
let none: Option<Ipv6Addr> = "1:2::6::8".parse().ok();
assert_eq!(None, none);
// `::` indicating zero groups of zeros
let none: Option<Ipv6Addr> = "1:2:3:4::5:6:7:8".parse().ok();
assert_eq!(None, none);
}
#[test]
fn test_from_str_ipv4_in_ipv6() {
assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse());
assert_eq!(
Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)),
"::FFFF:192.0.2.33".parse()
);
assert_eq!(
Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
"64:ff9b::192.0.2.33".parse()
);
assert_eq!(
Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
"2001:db8:122:c000:2:2100:192.0.2.33".parse()
);
// colon after v4
let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
assert_eq!(None, none);
// not enough groups
let none: Option<Ipv6Addr> = "1.2.3.4.5:127.0.0.1".parse().ok();
assert_eq!(None, none);
// too many groups
let none: Option<Ipv6Addr> = "1.2.3.4.5:6:7:127.0.0.1".parse().ok();
assert_eq!(None, none);
}
#[test]
fn test_from_str_socket_addr() {
assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
assert_eq!(
Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)),
"77.88.21.11:80".parse()
);
assert_eq!(
Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)),
"[2a02:6b8:0:1::1]:53".parse()
);
assert_eq!(
Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)),
"[2a02:6b8:0:1::1]:53".parse()
);
assert_eq!(
Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)),
"[::127.0.0.1]:22".parse()
);
assert_eq!(
Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)),
"[::127.0.0.1]:22".parse()
);
// without port
let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
assert_eq!(None, none);
// without port
let none: Option<SocketAddr> = "127.0.0.1:".parse().ok();
assert_eq!(None, none);
// wrong brackets around v4
let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok();
assert_eq!(None, none);
// port out of range
let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok();
assert_eq!(None, none);
}
#[test]
fn ipv4_addr_to_string() {
assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1");
// Short address
assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1");
// Long address
assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127");
// Test padding
assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 ");
assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1");
}
#[test]
fn ipv6_addr_to_string() {
// ipv4-mapped address
let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280);
assert_eq!(a1.to_string(), "::ffff:192.0.2.128");
// ipv4-compatible address
let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280);
assert_eq!(a1.to_string(), "::192.0.2.128");
// v6 address with no zero segments
assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f");
// longest possible IPv6 length
assert_eq!(
Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888)
.to_string(),
"1111:2222:3333:4444:5555:6666:7777:8888"
);
// padding
assert_eq!(
&format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)),
"1:2:3:4:5:6:7:8 "
);
assert_eq!(
&format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)),
" 1:2:3:4:5:6:7:8"
);
// reduce a single run of zeros
assert_eq!(
"ae::ffff:102:304",
Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string()
);
// don't reduce just a single zero segment
assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string());
// 'any' address
assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string());
// loopback address
assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string());
// ends in zeros
assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string());
// two runs of zeros, second one is longer
assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string());
// two runs of zeros, equal length
assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string());
}
#[test]
fn ipv4_to_ipv6() {
assert_eq!(
Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678),
Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped()
);
assert_eq!(
Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678),
Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible()
);
}
#[test]
fn ipv6_to_ipv4_mapped() {
assert_eq!(
Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(),
Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
);
assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None);
}
#[test]
fn ipv6_to_ipv4() {
assert_eq!(
Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(),
Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
);
assert_eq!(
Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
);
assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None);
}
#[test]
fn ip_properties() {
macro_rules! ip {
($s:expr) => {
IpAddr::from_str($s).unwrap()
};
}
macro_rules! check {
($s:expr) => {
check!($s, 0);
};
($s:expr, $mask:expr) => {{
let unspec: u8 = 1 << 0;
let loopback: u8 = 1 << 1;
let global: u8 = 1 << 2;
let multicast: u8 = 1 << 3;
let doc: u8 = 1 << 4;
if ($mask & unspec) == unspec {
assert!(ip!($s).is_unspecified());
} else {
assert!(!ip!($s).is_unspecified());
}
if ($mask & loopback) == loopback {
assert!(ip!($s).is_loopback());
} else {
assert!(!ip!($s).is_loopback());
}
if ($mask & global) == global {
assert!(ip!($s).is_global());
} else {
assert!(!ip!($s).is_global());
}
if ($mask & multicast) == multicast {
assert!(ip!($s).is_multicast());
} else {
assert!(!ip!($s).is_multicast());
}
if ($mask & doc) == doc {
assert!(ip!($s).is_documentation());
} else {
assert!(!ip!($s).is_documentation());
}
}};
}
let unspec: u8 = 1 << 0;
let loopback: u8 = 1 << 1;
let global: u8 = 1 << 2;
let multicast: u8 = 1 << 3;
let doc: u8 = 1 << 4;
check!("0.0.0.0", unspec);
check!("0.0.0.1");
check!("0.1.0.0");
check!("10.9.8.7");
check!("127.1.2.3", loopback);
check!("172.31.254.253");
check!("169.254.253.242");
check!("192.0.2.183", doc);
check!("192.1.2.183", global);
check!("192.168.254.253");
check!("198.51.100.0", doc);
check!("203.0.113.0", doc);
check!("203.2.113.0", global);
check!("224.0.0.0", global | multicast);
check!("239.255.255.255", global | multicast);
check!("255.255.255.255");
// make sure benchmarking addresses are not global
check!("198.18.0.0");
check!("198.18.54.2");
check!("198.19.255.255");
// make sure addresses reserved for protocol assignment are not global
check!("192.0.0.0");
check!("192.0.0.255");
check!("192.0.0.100");
// make sure reserved addresses are not global
check!("240.0.0.0");
check!("251.54.1.76");
check!("254.255.255.255");
// make sure shared addresses are not global
check!("100.64.0.0");
check!("100.127.255.255");
check!("100.100.100.0");
check!("::", unspec);
check!("::1", loopback);
check!("::0.0.0.2", global);
check!("1::", global);
check!("fc00::");
check!("fdff:ffff::");
check!("fe80:ffff::");
check!("febf:ffff::");
check!("fec0::", global);
check!("ff01::", multicast);
check!("ff02::", multicast);
check!("ff03::", multicast);
check!("ff04::", multicast);
check!("ff05::", multicast);
check!("ff08::", multicast);
check!("ff0e::", global | multicast);
check!("2001:db8:85a3::8a2e:370:7334", doc);
check!("102:304:506:708:90a:b0c:d0e:f10", global);
}
#[test]
fn ipv4_properties() {
macro_rules! ip {
($s:expr) => {
Ipv4Addr::from_str($s).unwrap()
};
}
macro_rules! check {
($s:expr) => {
check!($s, 0);
};
($s:expr, $mask:expr) => {{
let unspec: u16 = 1 << 0;
let loopback: u16 = 1 << 1;
let private: u16 = 1 << 2;
let link_local: u16 = 1 << 3;
let global: u16 = 1 << 4;
let multicast: u16 = 1 << 5;
let broadcast: u16 = 1 << 6;
let documentation: u16 = 1 << 7;
let benchmarking: u16 = 1 << 8;
let ietf_protocol_assignment: u16 = 1 << 9;
let reserved: u16 = 1 << 10;
let shared: u16 = 1 << 11;
if ($mask & unspec) == unspec {
assert!(ip!($s).is_unspecified());
} else {
assert!(!ip!($s).is_unspecified());
}
if ($mask & loopback) == loopback {
assert!(ip!($s).is_loopback());
} else {
assert!(!ip!($s).is_loopback());
}
if ($mask & private) == private {
assert!(ip!($s).is_private());
} else {
assert!(!ip!($s).is_private());
}
if ($mask & link_local) == link_local {
assert!(ip!($s).is_link_local());
} else {
assert!(!ip!($s).is_link_local());
}
if ($mask & global) == global {
assert!(ip!($s).is_global());
} else {
assert!(!ip!($s).is_global());
}
if ($mask & multicast) == multicast {
assert!(ip!($s).is_multicast());
} else {
assert!(!ip!($s).is_multicast());
}
if ($mask & broadcast) == broadcast {
assert!(ip!($s).is_broadcast());
} else {
assert!(!ip!($s).is_broadcast());
}
if ($mask & documentation) == documentation {
assert!(ip!($s).is_documentation());
} else {
assert!(!ip!($s).is_documentation());
}
if ($mask & benchmarking) == benchmarking {
assert!(ip!($s).is_benchmarking());
} else {
assert!(!ip!($s).is_benchmarking());
}
if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment {
assert!(ip!($s).is_ietf_protocol_assignment());
} else {
assert!(!ip!($s).is_ietf_protocol_assignment());
}
if ($mask & reserved) == reserved {
assert!(ip!($s).is_reserved());
} else {
assert!(!ip!($s).is_reserved());
}
if ($mask & shared) == shared {
assert!(ip!($s).is_shared());
} else {
assert!(!ip!($s).is_shared());
}
}};
}
let unspec: u16 = 1 << 0;
let loopback: u16 = 1 << 1;
let private: u16 = 1 << 2;
let link_local: u16 = 1 << 3;
let global: u16 = 1 << 4;
let multicast: u16 = 1 << 5;
let broadcast: u16 = 1 << 6;
let documentation: u16 = 1 << 7;
let benchmarking: u16 = 1 << 8;
let ietf_protocol_assignment: u16 = 1 << 9;
let reserved: u16 = 1 << 10;
let shared: u16 = 1 << 11;
check!("0.0.0.0", unspec);
check!("0.0.0.1");
check!("0.1.0.0");
check!("10.9.8.7", private);
check!("127.1.2.3", loopback);
check!("172.31.254.253", private);
check!("169.254.253.242", link_local);
check!("192.0.2.183", documentation);
check!("192.1.2.183", global);
check!("192.168.254.253", private);
check!("198.51.100.0", documentation);
check!("203.0.113.0", documentation);
check!("203.2.113.0", global);
check!("224.0.0.0", global | multicast);
check!("239.255.255.255", global | multicast);
check!("255.255.255.255", broadcast);
check!("198.18.0.0", benchmarking);
check!("198.18.54.2", benchmarking);
check!("198.19.255.255", benchmarking);
check!("192.0.0.0", ietf_protocol_assignment);
check!("192.0.0.255", ietf_protocol_assignment);
check!("192.0.0.100", ietf_protocol_assignment);
check!("240.0.0.0", reserved);
check!("251.54.1.76", reserved);
check!("254.255.255.255", reserved);
check!("100.64.0.0", shared);
check!("100.127.255.255", shared);
check!("100.100.100.0", shared);
}
#[test]
fn ipv6_properties() {
macro_rules! ip {
($s:expr) => {
Ipv6Addr::from_str($s).unwrap()
};
}
macro_rules! check {
($s:expr, &[$($octet:expr),*], $mask:expr) => {
assert_eq!($s, ip!($s).to_string());
let octets = &[$($octet),*];
assert_eq!(&ip!($s).octets(), octets);
assert_eq!(Ipv6Addr::from(*octets), ip!($s));
let unspecified: u16 = 1 << 0;
let loopback: u16 = 1 << 1;
let unique_local: u16 = 1 << 2;
let global: u16 = 1 << 3;
let unicast_link_local: u16 = 1 << 4;
let unicast_link_local_strict: u16 = 1 << 5;
let unicast_site_local: u16 = 1 << 6;
let unicast_global: u16 = 1 << 7;
let documentation: u16 = 1 << 8;
let multicast_interface_local: u16 = 1 << 9;
let multicast_link_local: u16 = 1 << 10;
let multicast_realm_local: u16 = 1 << 11;
let multicast_admin_local: u16 = 1 << 12;
let multicast_site_local: u16 = 1 << 13;
let multicast_organization_local: u16 = 1 << 14;
let multicast_global: u16 = 1 << 15;
let multicast: u16 = multicast_interface_local
| multicast_admin_local
| multicast_global
| multicast_link_local
| multicast_realm_local
| multicast_site_local
| multicast_organization_local;
if ($mask & unspecified) == unspecified {
assert!(ip!($s).is_unspecified());
} else {
assert!(!ip!($s).is_unspecified());
}
if ($mask & loopback) == loopback {
assert!(ip!($s).is_loopback());
} else {
assert!(!ip!($s).is_loopback());
}
if ($mask & unique_local) == unique_local {
assert!(ip!($s).is_unique_local());
} else {
assert!(!ip!($s).is_unique_local());
}
if ($mask & global) == global {
assert!(ip!($s).is_global());
} else {
assert!(!ip!($s).is_global());
}
if ($mask & unicast_link_local) == unicast_link_local {
assert!(ip!($s).is_unicast_link_local());
} else {
assert!(!ip!($s).is_unicast_link_local());
}
if ($mask & unicast_link_local_strict) == unicast_link_local_strict {
assert!(ip!($s).is_unicast_link_local_strict());
} else {
assert!(!ip!($s).is_unicast_link_local_strict());
}
if ($mask & unicast_site_local) == unicast_site_local {
assert!(ip!($s).is_unicast_site_local());
} else {
assert!(!ip!($s).is_unicast_site_local());
}
if ($mask & unicast_global) == unicast_global {
assert!(ip!($s).is_unicast_global());
} else {
assert!(!ip!($s).is_unicast_global());
}
if ($mask & documentation) == documentation {
assert!(ip!($s).is_documentation());
} else {
assert!(!ip!($s).is_documentation());
}
if ($mask & multicast) != 0 {
assert!(ip!($s).multicast_scope().is_some());
assert!(ip!($s).is_multicast());
} else {
assert!(ip!($s).multicast_scope().is_none());
assert!(!ip!($s).is_multicast());
}
if ($mask & multicast_interface_local) == multicast_interface_local {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::InterfaceLocal);
}
if ($mask & multicast_link_local) == multicast_link_local {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::LinkLocal);
}
if ($mask & multicast_realm_local) == multicast_realm_local {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::RealmLocal);
}
if ($mask & multicast_admin_local) == multicast_admin_local {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::AdminLocal);
}
if ($mask & multicast_site_local) == multicast_site_local {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::SiteLocal);
}
if ($mask & multicast_organization_local) == multicast_organization_local {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::OrganizationLocal);
}
if ($mask & multicast_global) == multicast_global {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::Global);
}
}
}
let unspecified: u16 = 1 << 0;
let loopback: u16 = 1 << 1;
let unique_local: u16 = 1 << 2;
let global: u16 = 1 << 3;
let unicast_link_local: u16 = 1 << 4;
let unicast_link_local_strict: u16 = 1 << 5;
let unicast_site_local: u16 = 1 << 6;
let unicast_global: u16 = 1 << 7;
let documentation: u16 = 1 << 8;
let multicast_interface_local: u16 = 1 << 9;
let multicast_link_local: u16 = 1 << 10;
let multicast_realm_local: u16 = 1 << 11;
let multicast_admin_local: u16 = 1 << 12;
let multicast_site_local: u16 = 1 << 13;
let multicast_organization_local: u16 = 1 << 14;
let multicast_global: u16 = 1 << 15;
check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified);
check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback);
check!(
"::0.0.0.2",
&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
global | unicast_global
);
check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
check!(
"fdff:ffff::",
&[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unique_local
);
check!(
"fe80:ffff::",
&[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unicast_link_local
);
check!(
"fe80::",
&[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unicast_link_local | unicast_link_local_strict
);
check!(
"febf:ffff::",
&[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unicast_link_local
);
check!(
"febf::",
&[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unicast_link_local
);
check!(
"febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
&[
0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff
],
unicast_link_local
);
check!(
"fe80::ffff:ffff:ffff:ffff",
&[
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff
],
unicast_link_local | unicast_link_local_strict
);
check!(
"fe80:0:0:1::",
&[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
unicast_link_local
);
check!(
"fec0::",
&[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unicast_site_local | unicast_global | global
);
check!(
"ff01::",
&[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
multicast_interface_local
);
check!(
"ff02::",
&[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
multicast_link_local
);
check!(
"ff03::",
&[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
multicast_realm_local
);
check!(
"ff04::",
&[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
multicast_admin_local
);
check!(
"ff05::",
&[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
multicast_site_local
);
check!(
"ff08::",
&[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
multicast_organization_local
);
check!(
"ff0e::",
&[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
multicast_global | global
);
check!(
"2001:db8:85a3::8a2e:370:7334",
&[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],
documentation
);
check!(
"102:304:506:708:90a:b0c:d0e:f10",
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
global | unicast_global
);
}
#[test]
fn to_socket_addr_socketaddr() {
let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345);
assert_eq!(Ok(vec![a]), tsa(a));
}
#[test]
fn test_ipv4_to_int() {
let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
assert_eq!(u32::from(a), 0x11223344);
}
#[test]
fn test_int_to_ipv4() {
let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
assert_eq!(Ipv4Addr::from(0x11223344), a);
}
#[test]
fn test_ipv6_to_int() {
let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128);
}
#[test]
fn test_int_to_ipv6() {
let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a);
}
#[test]
fn ipv4_from_constructors() {
assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1));
assert!(Ipv4Addr::LOCALHOST.is_loopback());
assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0));
assert!(Ipv4Addr::UNSPECIFIED.is_unspecified());
assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255));
assert!(Ipv4Addr::BROADCAST.is_broadcast());
}
#[test]
fn ipv6_from_contructors() {
assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
assert!(Ipv6Addr::LOCALHOST.is_loopback());
assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
assert!(Ipv6Addr::UNSPECIFIED.is_unspecified());
}
#[test]
fn ipv4_from_octets() {
assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1))
}
#[test]
fn ipv6_from_segments() {
let from_u16s =
Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff);
assert_eq!(new, from_u16s);
}
#[test]
fn ipv6_from_octets() {
let from_u16s =
Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
let from_u8s = Ipv6Addr::from([
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
0xee, 0xff,
]);
assert_eq!(from_u16s, from_u8s);
}
#[test]
fn cmp() {
let v41 = Ipv4Addr::new(100, 64, 3, 3);
let v42 = Ipv4Addr::new(192, 0, 2, 2);
let v61 = "2001:db8:f00::1002".parse::<Ipv6Addr>().unwrap();
let v62 = "2001:db8:f00::2001".parse::<Ipv6Addr>().unwrap();
assert!(v41 < v42);
assert!(v61 < v62);
assert_eq!(v41, IpAddr::V4(v41));
assert_eq!(v61, IpAddr::V6(v61));
assert!(v41 != IpAddr::V4(v42));
assert!(v61 != IpAddr::V6(v62));
assert!(v41 < IpAddr::V4(v42));
assert!(v61 < IpAddr::V6(v62));
assert!(IpAddr::V4(v41) < v42);
assert!(IpAddr::V6(v61) < v62);
assert!(v41 < IpAddr::V6(v61));
assert!(IpAddr::V4(v41) < v61);
}
#[test]
fn is_v4() {
let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3));
assert!(ip.is_ipv4());
assert!(!ip.is_ipv6());
}
#[test]
fn is_v6() {
let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678));
assert!(!ip.is_ipv4());
assert!(ip.is_ipv6());
}
}

View file

@ -0,0 +1,811 @@
use crate::net::test::{sa4, sa6, tsa};
use crate::net::*;
use crate::str::FromStr;
#[test]
fn test_from_str_ipv4() {
assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse());
assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse());
assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse());
// out of range
let none: Option<Ipv4Addr> = "256.0.0.1".parse().ok();
assert_eq!(None, none);
// too short
let none: Option<Ipv4Addr> = "255.0.0".parse().ok();
assert_eq!(None, none);
// too long
let none: Option<Ipv4Addr> = "255.0.0.1.2".parse().ok();
assert_eq!(None, none);
// no number between dots
let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
assert_eq!(None, none);
}
#[test]
fn test_from_str_ipv6() {
assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse());
assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse());
assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse());
assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse());
assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse());
// too long group
let none: Option<Ipv6Addr> = "::00000".parse().ok();
assert_eq!(None, none);
// too short
let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7".parse().ok();
assert_eq!(None, none);
// too long
let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:8:9".parse().ok();
assert_eq!(None, none);
// triple colon
let none: Option<Ipv6Addr> = "1:2:::6:7:8".parse().ok();
assert_eq!(None, none);
// two double colons
let none: Option<Ipv6Addr> = "1:2::6::8".parse().ok();
assert_eq!(None, none);
// `::` indicating zero groups of zeros
let none: Option<Ipv6Addr> = "1:2:3:4::5:6:7:8".parse().ok();
assert_eq!(None, none);
}
#[test]
fn test_from_str_ipv4_in_ipv6() {
assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse());
assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse());
assert_eq!(
Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
"64:ff9b::192.0.2.33".parse()
);
assert_eq!(
Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
"2001:db8:122:c000:2:2100:192.0.2.33".parse()
);
// colon after v4
let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
assert_eq!(None, none);
// not enough groups
let none: Option<Ipv6Addr> = "1.2.3.4.5:127.0.0.1".parse().ok();
assert_eq!(None, none);
// too many groups
let none: Option<Ipv6Addr> = "1.2.3.4.5:6:7:127.0.0.1".parse().ok();
assert_eq!(None, none);
}
#[test]
fn test_from_str_socket_addr() {
assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
assert_eq!(
Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)),
"[2a02:6b8:0:1::1]:53".parse()
);
assert_eq!(
Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)),
"[2a02:6b8:0:1::1]:53".parse()
);
assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse());
assert_eq!(
Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)),
"[::127.0.0.1]:22".parse()
);
// without port
let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
assert_eq!(None, none);
// without port
let none: Option<SocketAddr> = "127.0.0.1:".parse().ok();
assert_eq!(None, none);
// wrong brackets around v4
let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok();
assert_eq!(None, none);
// port out of range
let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok();
assert_eq!(None, none);
}
#[test]
fn ipv4_addr_to_string() {
assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1");
// Short address
assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1");
// Long address
assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127");
// Test padding
assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 ");
assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1");
}
#[test]
fn ipv6_addr_to_string() {
// ipv4-mapped address
let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280);
assert_eq!(a1.to_string(), "::ffff:192.0.2.128");
// ipv4-compatible address
let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280);
assert_eq!(a1.to_string(), "::192.0.2.128");
// v6 address with no zero segments
assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f");
// longest possible IPv6 length
assert_eq!(
Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(),
"1111:2222:3333:4444:5555:6666:7777:8888"
);
// padding
assert_eq!(&format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8 ");
assert_eq!(&format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), " 1:2:3:4:5:6:7:8");
// reduce a single run of zeros
assert_eq!(
"ae::ffff:102:304",
Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string()
);
// don't reduce just a single zero segment
assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string());
// 'any' address
assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string());
// loopback address
assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string());
// ends in zeros
assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string());
// two runs of zeros, second one is longer
assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string());
// two runs of zeros, equal length
assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string());
}
#[test]
fn ipv4_to_ipv6() {
assert_eq!(
Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678),
Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped()
);
assert_eq!(
Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678),
Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible()
);
}
#[test]
fn ipv6_to_ipv4_mapped() {
assert_eq!(
Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(),
Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
);
assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None);
}
#[test]
fn ipv6_to_ipv4() {
assert_eq!(
Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(),
Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
);
assert_eq!(
Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
);
assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None);
}
#[test]
fn ip_properties() {
macro_rules! ip {
($s:expr) => {
IpAddr::from_str($s).unwrap()
};
}
macro_rules! check {
($s:expr) => {
check!($s, 0);
};
($s:expr, $mask:expr) => {{
let unspec: u8 = 1 << 0;
let loopback: u8 = 1 << 1;
let global: u8 = 1 << 2;
let multicast: u8 = 1 << 3;
let doc: u8 = 1 << 4;
if ($mask & unspec) == unspec {
assert!(ip!($s).is_unspecified());
} else {
assert!(!ip!($s).is_unspecified());
}
if ($mask & loopback) == loopback {
assert!(ip!($s).is_loopback());
} else {
assert!(!ip!($s).is_loopback());
}
if ($mask & global) == global {
assert!(ip!($s).is_global());
} else {
assert!(!ip!($s).is_global());
}
if ($mask & multicast) == multicast {
assert!(ip!($s).is_multicast());
} else {
assert!(!ip!($s).is_multicast());
}
if ($mask & doc) == doc {
assert!(ip!($s).is_documentation());
} else {
assert!(!ip!($s).is_documentation());
}
}};
}
let unspec: u8 = 1 << 0;
let loopback: u8 = 1 << 1;
let global: u8 = 1 << 2;
let multicast: u8 = 1 << 3;
let doc: u8 = 1 << 4;
check!("0.0.0.0", unspec);
check!("0.0.0.1");
check!("0.1.0.0");
check!("10.9.8.7");
check!("127.1.2.3", loopback);
check!("172.31.254.253");
check!("169.254.253.242");
check!("192.0.2.183", doc);
check!("192.1.2.183", global);
check!("192.168.254.253");
check!("198.51.100.0", doc);
check!("203.0.113.0", doc);
check!("203.2.113.0", global);
check!("224.0.0.0", global | multicast);
check!("239.255.255.255", global | multicast);
check!("255.255.255.255");
// make sure benchmarking addresses are not global
check!("198.18.0.0");
check!("198.18.54.2");
check!("198.19.255.255");
// make sure addresses reserved for protocol assignment are not global
check!("192.0.0.0");
check!("192.0.0.255");
check!("192.0.0.100");
// make sure reserved addresses are not global
check!("240.0.0.0");
check!("251.54.1.76");
check!("254.255.255.255");
// make sure shared addresses are not global
check!("100.64.0.0");
check!("100.127.255.255");
check!("100.100.100.0");
check!("::", unspec);
check!("::1", loopback);
check!("::0.0.0.2", global);
check!("1::", global);
check!("fc00::");
check!("fdff:ffff::");
check!("fe80:ffff::");
check!("febf:ffff::");
check!("fec0::", global);
check!("ff01::", multicast);
check!("ff02::", multicast);
check!("ff03::", multicast);
check!("ff04::", multicast);
check!("ff05::", multicast);
check!("ff08::", multicast);
check!("ff0e::", global | multicast);
check!("2001:db8:85a3::8a2e:370:7334", doc);
check!("102:304:506:708:90a:b0c:d0e:f10", global);
}
#[test]
fn ipv4_properties() {
macro_rules! ip {
($s:expr) => {
Ipv4Addr::from_str($s).unwrap()
};
}
macro_rules! check {
($s:expr) => {
check!($s, 0);
};
($s:expr, $mask:expr) => {{
let unspec: u16 = 1 << 0;
let loopback: u16 = 1 << 1;
let private: u16 = 1 << 2;
let link_local: u16 = 1 << 3;
let global: u16 = 1 << 4;
let multicast: u16 = 1 << 5;
let broadcast: u16 = 1 << 6;
let documentation: u16 = 1 << 7;
let benchmarking: u16 = 1 << 8;
let ietf_protocol_assignment: u16 = 1 << 9;
let reserved: u16 = 1 << 10;
let shared: u16 = 1 << 11;
if ($mask & unspec) == unspec {
assert!(ip!($s).is_unspecified());
} else {
assert!(!ip!($s).is_unspecified());
}
if ($mask & loopback) == loopback {
assert!(ip!($s).is_loopback());
} else {
assert!(!ip!($s).is_loopback());
}
if ($mask & private) == private {
assert!(ip!($s).is_private());
} else {
assert!(!ip!($s).is_private());
}
if ($mask & link_local) == link_local {
assert!(ip!($s).is_link_local());
} else {
assert!(!ip!($s).is_link_local());
}
if ($mask & global) == global {
assert!(ip!($s).is_global());
} else {
assert!(!ip!($s).is_global());
}
if ($mask & multicast) == multicast {
assert!(ip!($s).is_multicast());
} else {
assert!(!ip!($s).is_multicast());
}
if ($mask & broadcast) == broadcast {
assert!(ip!($s).is_broadcast());
} else {
assert!(!ip!($s).is_broadcast());
}
if ($mask & documentation) == documentation {
assert!(ip!($s).is_documentation());
} else {
assert!(!ip!($s).is_documentation());
}
if ($mask & benchmarking) == benchmarking {
assert!(ip!($s).is_benchmarking());
} else {
assert!(!ip!($s).is_benchmarking());
}
if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment {
assert!(ip!($s).is_ietf_protocol_assignment());
} else {
assert!(!ip!($s).is_ietf_protocol_assignment());
}
if ($mask & reserved) == reserved {
assert!(ip!($s).is_reserved());
} else {
assert!(!ip!($s).is_reserved());
}
if ($mask & shared) == shared {
assert!(ip!($s).is_shared());
} else {
assert!(!ip!($s).is_shared());
}
}};
}
let unspec: u16 = 1 << 0;
let loopback: u16 = 1 << 1;
let private: u16 = 1 << 2;
let link_local: u16 = 1 << 3;
let global: u16 = 1 << 4;
let multicast: u16 = 1 << 5;
let broadcast: u16 = 1 << 6;
let documentation: u16 = 1 << 7;
let benchmarking: u16 = 1 << 8;
let ietf_protocol_assignment: u16 = 1 << 9;
let reserved: u16 = 1 << 10;
let shared: u16 = 1 << 11;
check!("0.0.0.0", unspec);
check!("0.0.0.1");
check!("0.1.0.0");
check!("10.9.8.7", private);
check!("127.1.2.3", loopback);
check!("172.31.254.253", private);
check!("169.254.253.242", link_local);
check!("192.0.2.183", documentation);
check!("192.1.2.183", global);
check!("192.168.254.253", private);
check!("198.51.100.0", documentation);
check!("203.0.113.0", documentation);
check!("203.2.113.0", global);
check!("224.0.0.0", global | multicast);
check!("239.255.255.255", global | multicast);
check!("255.255.255.255", broadcast);
check!("198.18.0.0", benchmarking);
check!("198.18.54.2", benchmarking);
check!("198.19.255.255", benchmarking);
check!("192.0.0.0", ietf_protocol_assignment);
check!("192.0.0.255", ietf_protocol_assignment);
check!("192.0.0.100", ietf_protocol_assignment);
check!("240.0.0.0", reserved);
check!("251.54.1.76", reserved);
check!("254.255.255.255", reserved);
check!("100.64.0.0", shared);
check!("100.127.255.255", shared);
check!("100.100.100.0", shared);
}
#[test]
fn ipv6_properties() {
macro_rules! ip {
($s:expr) => {
Ipv6Addr::from_str($s).unwrap()
};
}
macro_rules! check {
($s:expr, &[$($octet:expr),*], $mask:expr) => {
assert_eq!($s, ip!($s).to_string());
let octets = &[$($octet),*];
assert_eq!(&ip!($s).octets(), octets);
assert_eq!(Ipv6Addr::from(*octets), ip!($s));
let unspecified: u16 = 1 << 0;
let loopback: u16 = 1 << 1;
let unique_local: u16 = 1 << 2;
let global: u16 = 1 << 3;
let unicast_link_local: u16 = 1 << 4;
let unicast_link_local_strict: u16 = 1 << 5;
let unicast_site_local: u16 = 1 << 6;
let unicast_global: u16 = 1 << 7;
let documentation: u16 = 1 << 8;
let multicast_interface_local: u16 = 1 << 9;
let multicast_link_local: u16 = 1 << 10;
let multicast_realm_local: u16 = 1 << 11;
let multicast_admin_local: u16 = 1 << 12;
let multicast_site_local: u16 = 1 << 13;
let multicast_organization_local: u16 = 1 << 14;
let multicast_global: u16 = 1 << 15;
let multicast: u16 = multicast_interface_local
| multicast_admin_local
| multicast_global
| multicast_link_local
| multicast_realm_local
| multicast_site_local
| multicast_organization_local;
if ($mask & unspecified) == unspecified {
assert!(ip!($s).is_unspecified());
} else {
assert!(!ip!($s).is_unspecified());
}
if ($mask & loopback) == loopback {
assert!(ip!($s).is_loopback());
} else {
assert!(!ip!($s).is_loopback());
}
if ($mask & unique_local) == unique_local {
assert!(ip!($s).is_unique_local());
} else {
assert!(!ip!($s).is_unique_local());
}
if ($mask & global) == global {
assert!(ip!($s).is_global());
} else {
assert!(!ip!($s).is_global());
}
if ($mask & unicast_link_local) == unicast_link_local {
assert!(ip!($s).is_unicast_link_local());
} else {
assert!(!ip!($s).is_unicast_link_local());
}
if ($mask & unicast_link_local_strict) == unicast_link_local_strict {
assert!(ip!($s).is_unicast_link_local_strict());
} else {
assert!(!ip!($s).is_unicast_link_local_strict());
}
if ($mask & unicast_site_local) == unicast_site_local {
assert!(ip!($s).is_unicast_site_local());
} else {
assert!(!ip!($s).is_unicast_site_local());
}
if ($mask & unicast_global) == unicast_global {
assert!(ip!($s).is_unicast_global());
} else {
assert!(!ip!($s).is_unicast_global());
}
if ($mask & documentation) == documentation {
assert!(ip!($s).is_documentation());
} else {
assert!(!ip!($s).is_documentation());
}
if ($mask & multicast) != 0 {
assert!(ip!($s).multicast_scope().is_some());
assert!(ip!($s).is_multicast());
} else {
assert!(ip!($s).multicast_scope().is_none());
assert!(!ip!($s).is_multicast());
}
if ($mask & multicast_interface_local) == multicast_interface_local {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::InterfaceLocal);
}
if ($mask & multicast_link_local) == multicast_link_local {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::LinkLocal);
}
if ($mask & multicast_realm_local) == multicast_realm_local {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::RealmLocal);
}
if ($mask & multicast_admin_local) == multicast_admin_local {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::AdminLocal);
}
if ($mask & multicast_site_local) == multicast_site_local {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::SiteLocal);
}
if ($mask & multicast_organization_local) == multicast_organization_local {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::OrganizationLocal);
}
if ($mask & multicast_global) == multicast_global {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::Global);
}
}
}
let unspecified: u16 = 1 << 0;
let loopback: u16 = 1 << 1;
let unique_local: u16 = 1 << 2;
let global: u16 = 1 << 3;
let unicast_link_local: u16 = 1 << 4;
let unicast_link_local_strict: u16 = 1 << 5;
let unicast_site_local: u16 = 1 << 6;
let unicast_global: u16 = 1 << 7;
let documentation: u16 = 1 << 8;
let multicast_interface_local: u16 = 1 << 9;
let multicast_link_local: u16 = 1 << 10;
let multicast_realm_local: u16 = 1 << 11;
let multicast_admin_local: u16 = 1 << 12;
let multicast_site_local: u16 = 1 << 13;
let multicast_organization_local: u16 = 1 << 14;
let multicast_global: u16 = 1 << 15;
check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified);
check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback);
check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global);
check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
check!(
"fdff:ffff::",
&[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unique_local
);
check!(
"fe80:ffff::",
&[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unicast_link_local
);
check!(
"fe80::",
&[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unicast_link_local | unicast_link_local_strict
);
check!(
"febf:ffff::",
&[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unicast_link_local
);
check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
check!(
"febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
&[
0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff
],
unicast_link_local
);
check!(
"fe80::ffff:ffff:ffff:ffff",
&[
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff
],
unicast_link_local | unicast_link_local_strict
);
check!(
"fe80:0:0:1::",
&[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
unicast_link_local
);
check!(
"fec0::",
&[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unicast_site_local | unicast_global | global
);
check!(
"ff01::",
&[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
multicast_interface_local
);
check!("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_link_local);
check!("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_realm_local);
check!("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_admin_local);
check!("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_site_local);
check!(
"ff08::",
&[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
multicast_organization_local
);
check!(
"ff0e::",
&[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
multicast_global | global
);
check!(
"2001:db8:85a3::8a2e:370:7334",
&[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],
documentation
);
check!(
"102:304:506:708:90a:b0c:d0e:f10",
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
global | unicast_global
);
}
#[test]
fn to_socket_addr_socketaddr() {
let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345);
assert_eq!(Ok(vec![a]), tsa(a));
}
#[test]
fn test_ipv4_to_int() {
let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
assert_eq!(u32::from(a), 0x11223344);
}
#[test]
fn test_int_to_ipv4() {
let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
assert_eq!(Ipv4Addr::from(0x11223344), a);
}
#[test]
fn test_ipv6_to_int() {
let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128);
}
#[test]
fn test_int_to_ipv6() {
let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a);
}
#[test]
fn ipv4_from_constructors() {
assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1));
assert!(Ipv4Addr::LOCALHOST.is_loopback());
assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0));
assert!(Ipv4Addr::UNSPECIFIED.is_unspecified());
assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255));
assert!(Ipv4Addr::BROADCAST.is_broadcast());
}
#[test]
fn ipv6_from_contructors() {
assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
assert!(Ipv6Addr::LOCALHOST.is_loopback());
assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
assert!(Ipv6Addr::UNSPECIFIED.is_unspecified());
}
#[test]
fn ipv4_from_octets() {
assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1))
}
#[test]
fn ipv6_from_segments() {
let from_u16s =
Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff);
assert_eq!(new, from_u16s);
}
#[test]
fn ipv6_from_octets() {
let from_u16s =
Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
let from_u8s = Ipv6Addr::from([
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
0xff,
]);
assert_eq!(from_u16s, from_u8s);
}
#[test]
fn cmp() {
let v41 = Ipv4Addr::new(100, 64, 3, 3);
let v42 = Ipv4Addr::new(192, 0, 2, 2);
let v61 = "2001:db8:f00::1002".parse::<Ipv6Addr>().unwrap();
let v62 = "2001:db8:f00::2001".parse::<Ipv6Addr>().unwrap();
assert!(v41 < v42);
assert!(v61 < v62);
assert_eq!(v41, IpAddr::V4(v41));
assert_eq!(v61, IpAddr::V6(v61));
assert!(v41 != IpAddr::V4(v42));
assert!(v61 != IpAddr::V6(v62));
assert!(v41 < IpAddr::V4(v42));
assert!(v61 < IpAddr::V6(v62));
assert!(IpAddr::V4(v41) < v42);
assert!(IpAddr::V6(v61) < v62);
assert!(v41 < IpAddr::V6(v61));
assert!(IpAddr::V4(v41) < v61);
}
#[test]
fn is_v4() {
let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3));
assert!(ip.is_ipv4());
assert!(!ip.is_ipv6());
}
#[test]
fn is_v6() {
let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678));
assert!(!ip.is_ipv4());
assert!(ip.is_ipv6());
}

View file

@ -3,6 +3,9 @@
//! This module is "publicly exported" through the `FromStr` implementations
//! below.
#[cfg(test)]
mod tests;
use crate::error::Error;
use crate::fmt;
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
@ -321,146 +324,3 @@ impl Error for AddrParseError {
"invalid IP address syntax"
}
}
#[cfg(test)]
mod tests {
// FIXME: These tests are all excellent candidates for AFL fuzz testing
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use crate::str::FromStr;
const PORT: u16 = 8080;
const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1);
const IPV4_STR: &str = "192.168.0.1";
const IPV4_STR_PORT: &str = "192.168.0.1:8080";
const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1);
const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1";
const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1";
const IPV6_STR_V4: &str = "2001:db8::192.168.0.1";
const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080";
#[test]
fn parse_ipv4() {
let result: Ipv4Addr = IPV4_STR.parse().unwrap();
assert_eq!(result, IPV4);
assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err());
assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err());
assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err());
assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err());
assert!(Ipv4Addr::from_str(IPV6_STR_PORT).is_err());
}
#[test]
fn parse_ipv6() {
let result: Ipv6Addr = IPV6_STR_FULL.parse().unwrap();
assert_eq!(result, IPV6);
let result: Ipv6Addr = IPV6_STR_COMPRESS.parse().unwrap();
assert_eq!(result, IPV6);
let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap();
assert_eq!(result, IPV6);
assert!(Ipv6Addr::from_str(IPV4_STR).is_err());
assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err());
assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err());
}
#[test]
fn parse_ip() {
let result: IpAddr = IPV4_STR.parse().unwrap();
assert_eq!(result, IpAddr::from(IPV4));
let result: IpAddr = IPV6_STR_FULL.parse().unwrap();
assert_eq!(result, IpAddr::from(IPV6));
let result: IpAddr = IPV6_STR_COMPRESS.parse().unwrap();
assert_eq!(result, IpAddr::from(IPV6));
let result: IpAddr = IPV6_STR_V4.parse().unwrap();
assert_eq!(result, IpAddr::from(IPV6));
assert!(IpAddr::from_str(IPV4_STR_PORT).is_err());
assert!(IpAddr::from_str(IPV6_STR_PORT).is_err());
}
#[test]
fn parse_socket_v4() {
let result: SocketAddrV4 = IPV4_STR_PORT.parse().unwrap();
assert_eq!(result, SocketAddrV4::new(IPV4, PORT));
assert!(SocketAddrV4::from_str(IPV4_STR).is_err());
assert!(SocketAddrV4::from_str(IPV6_STR_FULL).is_err());
assert!(SocketAddrV4::from_str(IPV6_STR_COMPRESS).is_err());
assert!(SocketAddrV4::from_str(IPV6_STR_V4).is_err());
assert!(SocketAddrV4::from_str(IPV6_STR_PORT).is_err());
}
#[test]
fn parse_socket_v6() {
let result: SocketAddrV6 = IPV6_STR_PORT.parse().unwrap();
assert_eq!(result, SocketAddrV6::new(IPV6, PORT, 0, 0));
assert!(SocketAddrV6::from_str(IPV4_STR).is_err());
assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err());
assert!(SocketAddrV6::from_str(IPV6_STR_FULL).is_err());
assert!(SocketAddrV6::from_str(IPV6_STR_COMPRESS).is_err());
assert!(SocketAddrV6::from_str(IPV6_STR_V4).is_err());
}
#[test]
fn parse_socket() {
let result: SocketAddr = IPV4_STR_PORT.parse().unwrap();
assert_eq!(result, SocketAddr::from((IPV4, PORT)));
let result: SocketAddr = IPV6_STR_PORT.parse().unwrap();
assert_eq!(result, SocketAddr::from((IPV6, PORT)));
assert!(SocketAddr::from_str(IPV4_STR).is_err());
assert!(SocketAddr::from_str(IPV6_STR_FULL).is_err());
assert!(SocketAddr::from_str(IPV6_STR_COMPRESS).is_err());
assert!(SocketAddr::from_str(IPV6_STR_V4).is_err());
}
#[test]
fn ipv6_corner_cases() {
let result: Ipv6Addr = "1::".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0));
let result: Ipv6Addr = "1:1::".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(1, 1, 0, 0, 0, 0, 0, 0));
let result: Ipv6Addr = "::1".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
let result: Ipv6Addr = "::1:1".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 1, 1));
let result: Ipv6Addr = "::".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
let result: Ipv6Addr = "::192.168.0.1".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc0a8, 0x1));
let result: Ipv6Addr = "::1:192.168.0.1".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 1, 0xc0a8, 0x1));
let result: Ipv6Addr = "1:1:1:1:1:1:192.168.0.1".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(1, 1, 1, 1, 1, 1, 0xc0a8, 0x1));
}
// Things that might not seem like failures but are
#[test]
fn ipv6_corner_failures() {
// No IP address before the ::
assert!(Ipv6Addr::from_str("1:192.168.0.1::").is_err());
// :: must have at least 1 set of zeroes
assert!(Ipv6Addr::from_str("1:1:1:1::1:1:1:1").is_err());
// Need brackets for a port
assert!(SocketAddrV6::from_str("1:1:1:1:1:1:1:1:8080").is_err());
}
}

View file

@ -0,0 +1,139 @@
// FIXME: These tests are all excellent candidates for AFL fuzz testing
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use crate::str::FromStr;
const PORT: u16 = 8080;
const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1);
const IPV4_STR: &str = "192.168.0.1";
const IPV4_STR_PORT: &str = "192.168.0.1:8080";
const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1);
const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1";
const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1";
const IPV6_STR_V4: &str = "2001:db8::192.168.0.1";
const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080";
#[test]
fn parse_ipv4() {
let result: Ipv4Addr = IPV4_STR.parse().unwrap();
assert_eq!(result, IPV4);
assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err());
assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err());
assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err());
assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err());
assert!(Ipv4Addr::from_str(IPV6_STR_PORT).is_err());
}
#[test]
fn parse_ipv6() {
let result: Ipv6Addr = IPV6_STR_FULL.parse().unwrap();
assert_eq!(result, IPV6);
let result: Ipv6Addr = IPV6_STR_COMPRESS.parse().unwrap();
assert_eq!(result, IPV6);
let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap();
assert_eq!(result, IPV6);
assert!(Ipv6Addr::from_str(IPV4_STR).is_err());
assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err());
assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err());
}
#[test]
fn parse_ip() {
let result: IpAddr = IPV4_STR.parse().unwrap();
assert_eq!(result, IpAddr::from(IPV4));
let result: IpAddr = IPV6_STR_FULL.parse().unwrap();
assert_eq!(result, IpAddr::from(IPV6));
let result: IpAddr = IPV6_STR_COMPRESS.parse().unwrap();
assert_eq!(result, IpAddr::from(IPV6));
let result: IpAddr = IPV6_STR_V4.parse().unwrap();
assert_eq!(result, IpAddr::from(IPV6));
assert!(IpAddr::from_str(IPV4_STR_PORT).is_err());
assert!(IpAddr::from_str(IPV6_STR_PORT).is_err());
}
#[test]
fn parse_socket_v4() {
let result: SocketAddrV4 = IPV4_STR_PORT.parse().unwrap();
assert_eq!(result, SocketAddrV4::new(IPV4, PORT));
assert!(SocketAddrV4::from_str(IPV4_STR).is_err());
assert!(SocketAddrV4::from_str(IPV6_STR_FULL).is_err());
assert!(SocketAddrV4::from_str(IPV6_STR_COMPRESS).is_err());
assert!(SocketAddrV4::from_str(IPV6_STR_V4).is_err());
assert!(SocketAddrV4::from_str(IPV6_STR_PORT).is_err());
}
#[test]
fn parse_socket_v6() {
let result: SocketAddrV6 = IPV6_STR_PORT.parse().unwrap();
assert_eq!(result, SocketAddrV6::new(IPV6, PORT, 0, 0));
assert!(SocketAddrV6::from_str(IPV4_STR).is_err());
assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err());
assert!(SocketAddrV6::from_str(IPV6_STR_FULL).is_err());
assert!(SocketAddrV6::from_str(IPV6_STR_COMPRESS).is_err());
assert!(SocketAddrV6::from_str(IPV6_STR_V4).is_err());
}
#[test]
fn parse_socket() {
let result: SocketAddr = IPV4_STR_PORT.parse().unwrap();
assert_eq!(result, SocketAddr::from((IPV4, PORT)));
let result: SocketAddr = IPV6_STR_PORT.parse().unwrap();
assert_eq!(result, SocketAddr::from((IPV6, PORT)));
assert!(SocketAddr::from_str(IPV4_STR).is_err());
assert!(SocketAddr::from_str(IPV6_STR_FULL).is_err());
assert!(SocketAddr::from_str(IPV6_STR_COMPRESS).is_err());
assert!(SocketAddr::from_str(IPV6_STR_V4).is_err());
}
#[test]
fn ipv6_corner_cases() {
let result: Ipv6Addr = "1::".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0));
let result: Ipv6Addr = "1:1::".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(1, 1, 0, 0, 0, 0, 0, 0));
let result: Ipv6Addr = "::1".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
let result: Ipv6Addr = "::1:1".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 1, 1));
let result: Ipv6Addr = "::".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
let result: Ipv6Addr = "::192.168.0.1".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc0a8, 0x1));
let result: Ipv6Addr = "::1:192.168.0.1".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 1, 0xc0a8, 0x1));
let result: Ipv6Addr = "1:1:1:1:1:1:192.168.0.1".parse().unwrap();
assert_eq!(result, Ipv6Addr::new(1, 1, 1, 1, 1, 1, 0xc0a8, 0x1));
}
// Things that might not seem like failures but are
#[test]
fn ipv6_corner_failures() {
// No IP address before the ::
assert!(Ipv6Addr::from_str("1:192.168.0.1::").is_err());
// :: must have at least 1 set of zeroes
assert!(Ipv6Addr::from_str("1:1:1:1::1:1:1:1").is_err());
// Need brackets for a port
assert!(SocketAddrV6::from_str("1:1:1:1:1:1:1:1:8080").is_err());
}

View file

@ -1,4 +1,8 @@
#![deny(unsafe_op_in_unsafe_fn)]
#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
mod tests;
use crate::io::prelude::*;
use crate::fmt;
@ -936,869 +940,3 @@ impl fmt::Debug for TcpListener {
self.0.fmt(f)
}
}
#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
mod tests {
use crate::fmt;
use crate::io::prelude::*;
use crate::io::{ErrorKind, IoSlice, IoSliceMut};
use crate::net::test::{next_test_ip4, next_test_ip6};
use crate::net::*;
use crate::sync::mpsc::channel;
use crate::thread;
use crate::time::{Duration, Instant};
fn each_ip(f: &mut dyn FnMut(SocketAddr)) {
f(next_test_ip4());
f(next_test_ip6());
}
macro_rules! t {
($e:expr) => {
match $e {
Ok(t) => t,
Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
}
};
}
#[test]
fn bind_error() {
match TcpListener::bind("1.1.1.1:9999") {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable),
}
}
#[test]
fn connect_error() {
match TcpStream::connect("0.0.0.0:1") {
Ok(..) => panic!(),
Err(e) => assert!(
e.kind() == ErrorKind::ConnectionRefused
|| e.kind() == ErrorKind::InvalidInput
|| e.kind() == ErrorKind::AddrInUse
|| e.kind() == ErrorKind::AddrNotAvailable,
"bad error: {} {:?}",
e,
e.kind()
),
}
}
#[test]
fn listen_localhost() {
let socket_addr = next_test_ip4();
let listener = t!(TcpListener::bind(&socket_addr));
let _t = thread::spawn(move || {
let mut stream = t!(TcpStream::connect(&("localhost", socket_addr.port())));
t!(stream.write(&[144]));
});
let mut stream = t!(listener.accept()).0;
let mut buf = [0];
t!(stream.read(&mut buf));
assert!(buf[0] == 144);
}
#[test]
fn connect_loopback() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let host = match addr {
SocketAddr::V4(..) => "127.0.0.1",
SocketAddr::V6(..) => "::1",
};
let mut stream = t!(TcpStream::connect(&(host, addr.port())));
t!(stream.write(&[66]));
});
let mut stream = t!(acceptor.accept()).0;
let mut buf = [0];
t!(stream.read(&mut buf));
assert!(buf[0] == 66);
})
}
#[test]
fn smoke_test() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let (tx, rx) = channel();
let _t = thread::spawn(move || {
let mut stream = t!(TcpStream::connect(&addr));
t!(stream.write(&[99]));
tx.send(t!(stream.local_addr())).unwrap();
});
let (mut stream, addr) = t!(acceptor.accept());
let mut buf = [0];
t!(stream.read(&mut buf));
assert!(buf[0] == 99);
assert_eq!(addr, t!(rx.recv()));
})
}
#[test]
fn read_eof() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let _stream = t!(TcpStream::connect(&addr));
// Close
});
let mut stream = t!(acceptor.accept()).0;
let mut buf = [0];
let nread = t!(stream.read(&mut buf));
assert_eq!(nread, 0);
let nread = t!(stream.read(&mut buf));
assert_eq!(nread, 0);
})
}
#[test]
fn write_close() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let (tx, rx) = channel();
let _t = thread::spawn(move || {
drop(t!(TcpStream::connect(&addr)));
tx.send(()).unwrap();
});
let mut stream = t!(acceptor.accept()).0;
rx.recv().unwrap();
let buf = [0];
match stream.write(&buf) {
Ok(..) => {}
Err(e) => {
assert!(
e.kind() == ErrorKind::ConnectionReset
|| e.kind() == ErrorKind::BrokenPipe
|| e.kind() == ErrorKind::ConnectionAborted,
"unknown error: {}",
e
);
}
}
})
}
#[test]
fn multiple_connect_serial() {
each_ip(&mut |addr| {
let max = 10;
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
for _ in 0..max {
let mut stream = t!(TcpStream::connect(&addr));
t!(stream.write(&[99]));
}
});
for stream in acceptor.incoming().take(max) {
let mut stream = t!(stream);
let mut buf = [0];
t!(stream.read(&mut buf));
assert_eq!(buf[0], 99);
}
})
}
#[test]
fn multiple_connect_interleaved_greedy_schedule() {
const MAX: usize = 10;
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let acceptor = acceptor;
for (i, stream) in acceptor.incoming().enumerate().take(MAX) {
// Start another thread to handle the connection
let _t = thread::spawn(move || {
let mut stream = t!(stream);
let mut buf = [0];
t!(stream.read(&mut buf));
assert!(buf[0] == i as u8);
});
}
});
connect(0, addr);
});
fn connect(i: usize, addr: SocketAddr) {
if i == MAX {
return;
}
let t = thread::spawn(move || {
let mut stream = t!(TcpStream::connect(&addr));
// Connect again before writing
connect(i + 1, addr);
t!(stream.write(&[i as u8]));
});
t.join().ok().expect("thread panicked");
}
}
#[test]
fn multiple_connect_interleaved_lazy_schedule() {
const MAX: usize = 10;
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
for stream in acceptor.incoming().take(MAX) {
// Start another thread to handle the connection
let _t = thread::spawn(move || {
let mut stream = t!(stream);
let mut buf = [0];
t!(stream.read(&mut buf));
assert!(buf[0] == 99);
});
}
});
connect(0, addr);
});
fn connect(i: usize, addr: SocketAddr) {
if i == MAX {
return;
}
let t = thread::spawn(move || {
let mut stream = t!(TcpStream::connect(&addr));
connect(i + 1, addr);
t!(stream.write(&[99]));
});
t.join().ok().expect("thread panicked");
}
}
#[test]
fn socket_and_peer_name() {
each_ip(&mut |addr| {
let listener = t!(TcpListener::bind(&addr));
let so_name = t!(listener.local_addr());
assert_eq!(addr, so_name);
let _t = thread::spawn(move || {
t!(listener.accept());
});
let stream = t!(TcpStream::connect(&addr));
assert_eq!(addr, t!(stream.peer_addr()));
})
}
#[test]
fn partial_read() {
each_ip(&mut |addr| {
let (tx, rx) = channel();
let srv = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let mut cl = t!(srv.accept()).0;
cl.write(&[10]).unwrap();
let mut b = [0];
t!(cl.read(&mut b));
tx.send(()).unwrap();
});
let mut c = t!(TcpStream::connect(&addr));
let mut b = [0; 10];
assert_eq!(c.read(&mut b).unwrap(), 1);
t!(c.write(&[1]));
rx.recv().unwrap();
})
}
#[test]
fn read_vectored() {
each_ip(&mut |addr| {
let srv = t!(TcpListener::bind(&addr));
let mut s1 = t!(TcpStream::connect(&addr));
let mut s2 = t!(srv.accept()).0;
let len = s1.write(&[10, 11, 12]).unwrap();
assert_eq!(len, 3);
let mut a = [];
let mut b = [0];
let mut c = [0; 3];
let len = t!(s2.read_vectored(&mut [
IoSliceMut::new(&mut a),
IoSliceMut::new(&mut b),
IoSliceMut::new(&mut c)
],));
assert!(len > 0);
assert_eq!(b, [10]);
// some implementations don't support readv, so we may only fill the first buffer
assert!(len == 1 || c == [11, 12, 0]);
})
}
#[test]
fn write_vectored() {
each_ip(&mut |addr| {
let srv = t!(TcpListener::bind(&addr));
let mut s1 = t!(TcpStream::connect(&addr));
let mut s2 = t!(srv.accept()).0;
let a = [];
let b = [10];
let c = [11, 12];
t!(s1.write_vectored(&[IoSlice::new(&a), IoSlice::new(&b), IoSlice::new(&c)]));
let mut buf = [0; 4];
let len = t!(s2.read(&mut buf));
// some implementations don't support writev, so we may only write the first buffer
if len == 1 {
assert_eq!(buf, [10, 0, 0, 0]);
} else {
assert_eq!(len, 3);
assert_eq!(buf, [10, 11, 12, 0]);
}
})
}
#[test]
fn double_bind() {
each_ip(&mut |addr| {
let listener1 = t!(TcpListener::bind(&addr));
match TcpListener::bind(&addr) {
Ok(listener2) => panic!(
"This system (perhaps due to options set by TcpListener::bind) \
permits double binding: {:?} and {:?}",
listener1, listener2
),
Err(e) => {
assert!(
e.kind() == ErrorKind::ConnectionRefused
|| e.kind() == ErrorKind::Other
|| e.kind() == ErrorKind::AddrInUse,
"unknown error: {} {:?}",
e,
e.kind()
);
}
}
})
}
#[test]
fn tcp_clone_smoke() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let mut s = t!(TcpStream::connect(&addr));
let mut buf = [0, 0];
assert_eq!(s.read(&mut buf).unwrap(), 1);
assert_eq!(buf[0], 1);
t!(s.write(&[2]));
});
let mut s1 = t!(acceptor.accept()).0;
let s2 = t!(s1.try_clone());
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let _t = thread::spawn(move || {
let mut s2 = s2;
rx1.recv().unwrap();
t!(s2.write(&[1]));
tx2.send(()).unwrap();
});
tx1.send(()).unwrap();
let mut buf = [0, 0];
assert_eq!(s1.read(&mut buf).unwrap(), 1);
rx2.recv().unwrap();
})
}
#[test]
fn tcp_clone_two_read() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let (tx1, rx) = channel();
let tx2 = tx1.clone();
let _t = thread::spawn(move || {
let mut s = t!(TcpStream::connect(&addr));
t!(s.write(&[1]));
rx.recv().unwrap();
t!(s.write(&[2]));
rx.recv().unwrap();
});
let mut s1 = t!(acceptor.accept()).0;
let s2 = t!(s1.try_clone());
let (done, rx) = channel();
let _t = thread::spawn(move || {
let mut s2 = s2;
let mut buf = [0, 0];
t!(s2.read(&mut buf));
tx2.send(()).unwrap();
done.send(()).unwrap();
});
let mut buf = [0, 0];
t!(s1.read(&mut buf));
tx1.send(()).unwrap();
rx.recv().unwrap();
})
}
#[test]
fn tcp_clone_two_write() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let mut s = t!(TcpStream::connect(&addr));
let mut buf = [0, 1];
t!(s.read(&mut buf));
t!(s.read(&mut buf));
});
let mut s1 = t!(acceptor.accept()).0;
let s2 = t!(s1.try_clone());
let (done, rx) = channel();
let _t = thread::spawn(move || {
let mut s2 = s2;
t!(s2.write(&[1]));
done.send(()).unwrap();
});
t!(s1.write(&[2]));
rx.recv().unwrap();
})
}
#[test]
// FIXME: https://github.com/fortanix/rust-sgx/issues/110
#[cfg_attr(target_env = "sgx", ignore)]
fn shutdown_smoke() {
each_ip(&mut |addr| {
let a = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let mut c = t!(a.accept()).0;
let mut b = [0];
assert_eq!(c.read(&mut b).unwrap(), 0);
t!(c.write(&[1]));
});
let mut s = t!(TcpStream::connect(&addr));
t!(s.shutdown(Shutdown::Write));
assert!(s.write(&[1]).is_err());
let mut b = [0, 0];
assert_eq!(t!(s.read(&mut b)), 1);
assert_eq!(b[0], 1);
})
}
#[test]
// FIXME: https://github.com/fortanix/rust-sgx/issues/110
#[cfg_attr(target_env = "sgx", ignore)]
fn close_readwrite_smoke() {
each_ip(&mut |addr| {
let a = t!(TcpListener::bind(&addr));
let (tx, rx) = channel::<()>();
let _t = thread::spawn(move || {
let _s = t!(a.accept());
let _ = rx.recv();
});
let mut b = [0];
let mut s = t!(TcpStream::connect(&addr));
let mut s2 = t!(s.try_clone());
// closing should prevent reads/writes
t!(s.shutdown(Shutdown::Write));
assert!(s.write(&[0]).is_err());
t!(s.shutdown(Shutdown::Read));
assert_eq!(s.read(&mut b).unwrap(), 0);
// closing should affect previous handles
assert!(s2.write(&[0]).is_err());
assert_eq!(s2.read(&mut b).unwrap(), 0);
// closing should affect new handles
let mut s3 = t!(s.try_clone());
assert!(s3.write(&[0]).is_err());
assert_eq!(s3.read(&mut b).unwrap(), 0);
// make sure these don't die
let _ = s2.shutdown(Shutdown::Read);
let _ = s2.shutdown(Shutdown::Write);
let _ = s3.shutdown(Shutdown::Read);
let _ = s3.shutdown(Shutdown::Write);
drop(tx);
})
}
#[test]
#[cfg(unix)] // test doesn't work on Windows, see #31657
fn close_read_wakes_up() {
each_ip(&mut |addr| {
let a = t!(TcpListener::bind(&addr));
let (tx1, rx) = channel::<()>();
let _t = thread::spawn(move || {
let _s = t!(a.accept());
let _ = rx.recv();
});
let s = t!(TcpStream::connect(&addr));
let s2 = t!(s.try_clone());
let (tx, rx) = channel();
let _t = thread::spawn(move || {
let mut s2 = s2;
assert_eq!(t!(s2.read(&mut [0])), 0);
tx.send(()).unwrap();
});
// this should wake up the child thread
t!(s.shutdown(Shutdown::Read));
// this test will never finish if the child doesn't wake up
rx.recv().unwrap();
drop(tx1);
})
}
#[test]
fn clone_while_reading() {
each_ip(&mut |addr| {
let accept = t!(TcpListener::bind(&addr));
// Enqueue a thread to write to a socket
let (tx, rx) = channel();
let (txdone, rxdone) = channel();
let txdone2 = txdone.clone();
let _t = thread::spawn(move || {
let mut tcp = t!(TcpStream::connect(&addr));
rx.recv().unwrap();
t!(tcp.write(&[0]));
txdone2.send(()).unwrap();
});
// Spawn off a reading clone
let tcp = t!(accept.accept()).0;
let tcp2 = t!(tcp.try_clone());
let txdone3 = txdone.clone();
let _t = thread::spawn(move || {
let mut tcp2 = tcp2;
t!(tcp2.read(&mut [0]));
txdone3.send(()).unwrap();
});
// Try to ensure that the reading clone is indeed reading
for _ in 0..50 {
thread::yield_now();
}
// clone the handle again while it's reading, then let it finish the
// read.
let _ = t!(tcp.try_clone());
tx.send(()).unwrap();
rxdone.recv().unwrap();
rxdone.recv().unwrap();
})
}
#[test]
fn clone_accept_smoke() {
each_ip(&mut |addr| {
let a = t!(TcpListener::bind(&addr));
let a2 = t!(a.try_clone());
let _t = thread::spawn(move || {
let _ = TcpStream::connect(&addr);
});
let _t = thread::spawn(move || {
let _ = TcpStream::connect(&addr);
});
t!(a.accept());
t!(a2.accept());
})
}
#[test]
fn clone_accept_concurrent() {
each_ip(&mut |addr| {
let a = t!(TcpListener::bind(&addr));
let a2 = t!(a.try_clone());
let (tx, rx) = channel();
let tx2 = tx.clone();
let _t = thread::spawn(move || {
tx.send(t!(a.accept())).unwrap();
});
let _t = thread::spawn(move || {
tx2.send(t!(a2.accept())).unwrap();
});
let _t = thread::spawn(move || {
let _ = TcpStream::connect(&addr);
});
let _t = thread::spawn(move || {
let _ = TcpStream::connect(&addr);
});
rx.recv().unwrap();
rx.recv().unwrap();
})
}
#[test]
fn debug() {
#[cfg(not(target_env = "sgx"))]
fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a {
addr
}
#[cfg(target_env = "sgx")]
fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a {
addr.to_string()
}
#[cfg(target_env = "sgx")]
use crate::os::fortanix_sgx::io::AsRawFd;
#[cfg(unix)]
use crate::os::unix::io::AsRawFd;
#[cfg(not(windows))]
fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug {
addr.as_raw_fd()
}
#[cfg(windows)]
fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Debug {
addr.as_raw_socket()
}
let inner_name = if cfg!(windows) { "socket" } else { "fd" };
let socket_addr = next_test_ip4();
let listener = t!(TcpListener::bind(&socket_addr));
let compare = format!(
"TcpListener {{ addr: {:?}, {}: {:?} }}",
render_socket_addr(&socket_addr),
inner_name,
render_inner(&listener)
);
assert_eq!(format!("{:?}", listener), compare);
let stream = t!(TcpStream::connect(&("localhost", socket_addr.port())));
let compare = format!(
"TcpStream {{ addr: {:?}, peer: {:?}, {}: {:?} }}",
render_socket_addr(&stream.local_addr().unwrap()),
render_socket_addr(&stream.peer_addr().unwrap()),
inner_name,
render_inner(&stream)
);
assert_eq!(format!("{:?}", stream), compare);
}
// FIXME: re-enabled openbsd tests once their socket timeout code
// no longer has rounding errors.
// VxWorks ignores SO_SNDTIMEO.
#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)]
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
#[test]
fn timeouts() {
let addr = next_test_ip4();
let listener = t!(TcpListener::bind(&addr));
let stream = t!(TcpStream::connect(&("localhost", addr.port())));
let dur = Duration::new(15410, 0);
assert_eq!(None, t!(stream.read_timeout()));
t!(stream.set_read_timeout(Some(dur)));
assert_eq!(Some(dur), t!(stream.read_timeout()));
assert_eq!(None, t!(stream.write_timeout()));
t!(stream.set_write_timeout(Some(dur)));
assert_eq!(Some(dur), t!(stream.write_timeout()));
t!(stream.set_read_timeout(None));
assert_eq!(None, t!(stream.read_timeout()));
t!(stream.set_write_timeout(None));
assert_eq!(None, t!(stream.write_timeout()));
drop(listener);
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
fn test_read_timeout() {
let addr = next_test_ip4();
let listener = t!(TcpListener::bind(&addr));
let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
let mut buf = [0; 10];
let start = Instant::now();
let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
assert!(
kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
"unexpected_error: {:?}",
kind
);
assert!(start.elapsed() > Duration::from_millis(400));
drop(listener);
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
fn test_read_with_timeout() {
let addr = next_test_ip4();
let listener = t!(TcpListener::bind(&addr));
let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
let mut other_end = t!(listener.accept()).0;
t!(other_end.write_all(b"hello world"));
let mut buf = [0; 11];
t!(stream.read(&mut buf));
assert_eq!(b"hello world", &buf[..]);
let start = Instant::now();
let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
assert!(
kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
"unexpected_error: {:?}",
kind
);
assert!(start.elapsed() > Duration::from_millis(400));
drop(listener);
}
// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
// when passed zero Durations
#[test]
fn test_timeout_zero_duration() {
let addr = next_test_ip4();
let listener = t!(TcpListener::bind(&addr));
let stream = t!(TcpStream::connect(&addr));
let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
drop(listener);
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)]
fn nodelay() {
let addr = next_test_ip4();
let _listener = t!(TcpListener::bind(&addr));
let stream = t!(TcpStream::connect(&("localhost", addr.port())));
assert_eq!(false, t!(stream.nodelay()));
t!(stream.set_nodelay(true));
assert_eq!(true, t!(stream.nodelay()));
t!(stream.set_nodelay(false));
assert_eq!(false, t!(stream.nodelay()));
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)]
fn ttl() {
let ttl = 100;
let addr = next_test_ip4();
let listener = t!(TcpListener::bind(&addr));
t!(listener.set_ttl(ttl));
assert_eq!(ttl, t!(listener.ttl()));
let stream = t!(TcpStream::connect(&("localhost", addr.port())));
t!(stream.set_ttl(ttl));
assert_eq!(ttl, t!(stream.ttl()));
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)]
fn set_nonblocking() {
let addr = next_test_ip4();
let listener = t!(TcpListener::bind(&addr));
t!(listener.set_nonblocking(true));
t!(listener.set_nonblocking(false));
let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
t!(stream.set_nonblocking(false));
t!(stream.set_nonblocking(true));
let mut buf = [0];
match stream.read(&mut buf) {
Ok(_) => panic!("expected error"),
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
Err(e) => panic!("unexpected error {}", e),
}
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
fn peek() {
each_ip(&mut |addr| {
let (txdone, rxdone) = channel();
let srv = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let mut cl = t!(srv.accept()).0;
cl.write(&[1, 3, 3, 7]).unwrap();
t!(rxdone.recv());
});
let mut c = t!(TcpStream::connect(&addr));
let mut b = [0; 10];
for _ in 1..3 {
let len = c.peek(&mut b).unwrap();
assert_eq!(len, 4);
}
let len = c.read(&mut b).unwrap();
assert_eq!(len, 4);
t!(c.set_nonblocking(true));
match c.peek(&mut b) {
Ok(_) => panic!("expected error"),
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
Err(e) => panic!("unexpected error {}", e),
}
t!(txdone.send(()));
})
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
fn connect_timeout_valid() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();
TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap();
}
}

View file

@ -0,0 +1,862 @@
use crate::fmt;
use crate::io::prelude::*;
use crate::io::{ErrorKind, IoSlice, IoSliceMut};
use crate::net::test::{next_test_ip4, next_test_ip6};
use crate::net::*;
use crate::sync::mpsc::channel;
use crate::thread;
use crate::time::{Duration, Instant};
fn each_ip(f: &mut dyn FnMut(SocketAddr)) {
f(next_test_ip4());
f(next_test_ip6());
}
macro_rules! t {
($e:expr) => {
match $e {
Ok(t) => t,
Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
}
};
}
#[test]
fn bind_error() {
match TcpListener::bind("1.1.1.1:9999") {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable),
}
}
#[test]
fn connect_error() {
match TcpStream::connect("0.0.0.0:1") {
Ok(..) => panic!(),
Err(e) => assert!(
e.kind() == ErrorKind::ConnectionRefused
|| e.kind() == ErrorKind::InvalidInput
|| e.kind() == ErrorKind::AddrInUse
|| e.kind() == ErrorKind::AddrNotAvailable,
"bad error: {} {:?}",
e,
e.kind()
),
}
}
#[test]
fn listen_localhost() {
let socket_addr = next_test_ip4();
let listener = t!(TcpListener::bind(&socket_addr));
let _t = thread::spawn(move || {
let mut stream = t!(TcpStream::connect(&("localhost", socket_addr.port())));
t!(stream.write(&[144]));
});
let mut stream = t!(listener.accept()).0;
let mut buf = [0];
t!(stream.read(&mut buf));
assert!(buf[0] == 144);
}
#[test]
fn connect_loopback() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let host = match addr {
SocketAddr::V4(..) => "127.0.0.1",
SocketAddr::V6(..) => "::1",
};
let mut stream = t!(TcpStream::connect(&(host, addr.port())));
t!(stream.write(&[66]));
});
let mut stream = t!(acceptor.accept()).0;
let mut buf = [0];
t!(stream.read(&mut buf));
assert!(buf[0] == 66);
})
}
#[test]
fn smoke_test() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let (tx, rx) = channel();
let _t = thread::spawn(move || {
let mut stream = t!(TcpStream::connect(&addr));
t!(stream.write(&[99]));
tx.send(t!(stream.local_addr())).unwrap();
});
let (mut stream, addr) = t!(acceptor.accept());
let mut buf = [0];
t!(stream.read(&mut buf));
assert!(buf[0] == 99);
assert_eq!(addr, t!(rx.recv()));
})
}
#[test]
fn read_eof() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let _stream = t!(TcpStream::connect(&addr));
// Close
});
let mut stream = t!(acceptor.accept()).0;
let mut buf = [0];
let nread = t!(stream.read(&mut buf));
assert_eq!(nread, 0);
let nread = t!(stream.read(&mut buf));
assert_eq!(nread, 0);
})
}
#[test]
fn write_close() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let (tx, rx) = channel();
let _t = thread::spawn(move || {
drop(t!(TcpStream::connect(&addr)));
tx.send(()).unwrap();
});
let mut stream = t!(acceptor.accept()).0;
rx.recv().unwrap();
let buf = [0];
match stream.write(&buf) {
Ok(..) => {}
Err(e) => {
assert!(
e.kind() == ErrorKind::ConnectionReset
|| e.kind() == ErrorKind::BrokenPipe
|| e.kind() == ErrorKind::ConnectionAborted,
"unknown error: {}",
e
);
}
}
})
}
#[test]
fn multiple_connect_serial() {
each_ip(&mut |addr| {
let max = 10;
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
for _ in 0..max {
let mut stream = t!(TcpStream::connect(&addr));
t!(stream.write(&[99]));
}
});
for stream in acceptor.incoming().take(max) {
let mut stream = t!(stream);
let mut buf = [0];
t!(stream.read(&mut buf));
assert_eq!(buf[0], 99);
}
})
}
#[test]
fn multiple_connect_interleaved_greedy_schedule() {
const MAX: usize = 10;
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let acceptor = acceptor;
for (i, stream) in acceptor.incoming().enumerate().take(MAX) {
// Start another thread to handle the connection
let _t = thread::spawn(move || {
let mut stream = t!(stream);
let mut buf = [0];
t!(stream.read(&mut buf));
assert!(buf[0] == i as u8);
});
}
});
connect(0, addr);
});
fn connect(i: usize, addr: SocketAddr) {
if i == MAX {
return;
}
let t = thread::spawn(move || {
let mut stream = t!(TcpStream::connect(&addr));
// Connect again before writing
connect(i + 1, addr);
t!(stream.write(&[i as u8]));
});
t.join().ok().expect("thread panicked");
}
}
#[test]
fn multiple_connect_interleaved_lazy_schedule() {
const MAX: usize = 10;
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
for stream in acceptor.incoming().take(MAX) {
// Start another thread to handle the connection
let _t = thread::spawn(move || {
let mut stream = t!(stream);
let mut buf = [0];
t!(stream.read(&mut buf));
assert!(buf[0] == 99);
});
}
});
connect(0, addr);
});
fn connect(i: usize, addr: SocketAddr) {
if i == MAX {
return;
}
let t = thread::spawn(move || {
let mut stream = t!(TcpStream::connect(&addr));
connect(i + 1, addr);
t!(stream.write(&[99]));
});
t.join().ok().expect("thread panicked");
}
}
#[test]
fn socket_and_peer_name() {
each_ip(&mut |addr| {
let listener = t!(TcpListener::bind(&addr));
let so_name = t!(listener.local_addr());
assert_eq!(addr, so_name);
let _t = thread::spawn(move || {
t!(listener.accept());
});
let stream = t!(TcpStream::connect(&addr));
assert_eq!(addr, t!(stream.peer_addr()));
})
}
#[test]
fn partial_read() {
each_ip(&mut |addr| {
let (tx, rx) = channel();
let srv = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let mut cl = t!(srv.accept()).0;
cl.write(&[10]).unwrap();
let mut b = [0];
t!(cl.read(&mut b));
tx.send(()).unwrap();
});
let mut c = t!(TcpStream::connect(&addr));
let mut b = [0; 10];
assert_eq!(c.read(&mut b).unwrap(), 1);
t!(c.write(&[1]));
rx.recv().unwrap();
})
}
#[test]
fn read_vectored() {
each_ip(&mut |addr| {
let srv = t!(TcpListener::bind(&addr));
let mut s1 = t!(TcpStream::connect(&addr));
let mut s2 = t!(srv.accept()).0;
let len = s1.write(&[10, 11, 12]).unwrap();
assert_eq!(len, 3);
let mut a = [];
let mut b = [0];
let mut c = [0; 3];
let len = t!(s2.read_vectored(&mut [
IoSliceMut::new(&mut a),
IoSliceMut::new(&mut b),
IoSliceMut::new(&mut c)
],));
assert!(len > 0);
assert_eq!(b, [10]);
// some implementations don't support readv, so we may only fill the first buffer
assert!(len == 1 || c == [11, 12, 0]);
})
}
#[test]
fn write_vectored() {
each_ip(&mut |addr| {
let srv = t!(TcpListener::bind(&addr));
let mut s1 = t!(TcpStream::connect(&addr));
let mut s2 = t!(srv.accept()).0;
let a = [];
let b = [10];
let c = [11, 12];
t!(s1.write_vectored(&[IoSlice::new(&a), IoSlice::new(&b), IoSlice::new(&c)]));
let mut buf = [0; 4];
let len = t!(s2.read(&mut buf));
// some implementations don't support writev, so we may only write the first buffer
if len == 1 {
assert_eq!(buf, [10, 0, 0, 0]);
} else {
assert_eq!(len, 3);
assert_eq!(buf, [10, 11, 12, 0]);
}
})
}
#[test]
fn double_bind() {
each_ip(&mut |addr| {
let listener1 = t!(TcpListener::bind(&addr));
match TcpListener::bind(&addr) {
Ok(listener2) => panic!(
"This system (perhaps due to options set by TcpListener::bind) \
permits double binding: {:?} and {:?}",
listener1, listener2
),
Err(e) => {
assert!(
e.kind() == ErrorKind::ConnectionRefused
|| e.kind() == ErrorKind::Other
|| e.kind() == ErrorKind::AddrInUse,
"unknown error: {} {:?}",
e,
e.kind()
);
}
}
})
}
#[test]
fn tcp_clone_smoke() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let mut s = t!(TcpStream::connect(&addr));
let mut buf = [0, 0];
assert_eq!(s.read(&mut buf).unwrap(), 1);
assert_eq!(buf[0], 1);
t!(s.write(&[2]));
});
let mut s1 = t!(acceptor.accept()).0;
let s2 = t!(s1.try_clone());
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let _t = thread::spawn(move || {
let mut s2 = s2;
rx1.recv().unwrap();
t!(s2.write(&[1]));
tx2.send(()).unwrap();
});
tx1.send(()).unwrap();
let mut buf = [0, 0];
assert_eq!(s1.read(&mut buf).unwrap(), 1);
rx2.recv().unwrap();
})
}
#[test]
fn tcp_clone_two_read() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let (tx1, rx) = channel();
let tx2 = tx1.clone();
let _t = thread::spawn(move || {
let mut s = t!(TcpStream::connect(&addr));
t!(s.write(&[1]));
rx.recv().unwrap();
t!(s.write(&[2]));
rx.recv().unwrap();
});
let mut s1 = t!(acceptor.accept()).0;
let s2 = t!(s1.try_clone());
let (done, rx) = channel();
let _t = thread::spawn(move || {
let mut s2 = s2;
let mut buf = [0, 0];
t!(s2.read(&mut buf));
tx2.send(()).unwrap();
done.send(()).unwrap();
});
let mut buf = [0, 0];
t!(s1.read(&mut buf));
tx1.send(()).unwrap();
rx.recv().unwrap();
})
}
#[test]
fn tcp_clone_two_write() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let mut s = t!(TcpStream::connect(&addr));
let mut buf = [0, 1];
t!(s.read(&mut buf));
t!(s.read(&mut buf));
});
let mut s1 = t!(acceptor.accept()).0;
let s2 = t!(s1.try_clone());
let (done, rx) = channel();
let _t = thread::spawn(move || {
let mut s2 = s2;
t!(s2.write(&[1]));
done.send(()).unwrap();
});
t!(s1.write(&[2]));
rx.recv().unwrap();
})
}
#[test]
// FIXME: https://github.com/fortanix/rust-sgx/issues/110
#[cfg_attr(target_env = "sgx", ignore)]
fn shutdown_smoke() {
each_ip(&mut |addr| {
let a = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let mut c = t!(a.accept()).0;
let mut b = [0];
assert_eq!(c.read(&mut b).unwrap(), 0);
t!(c.write(&[1]));
});
let mut s = t!(TcpStream::connect(&addr));
t!(s.shutdown(Shutdown::Write));
assert!(s.write(&[1]).is_err());
let mut b = [0, 0];
assert_eq!(t!(s.read(&mut b)), 1);
assert_eq!(b[0], 1);
})
}
#[test]
// FIXME: https://github.com/fortanix/rust-sgx/issues/110
#[cfg_attr(target_env = "sgx", ignore)]
fn close_readwrite_smoke() {
each_ip(&mut |addr| {
let a = t!(TcpListener::bind(&addr));
let (tx, rx) = channel::<()>();
let _t = thread::spawn(move || {
let _s = t!(a.accept());
let _ = rx.recv();
});
let mut b = [0];
let mut s = t!(TcpStream::connect(&addr));
let mut s2 = t!(s.try_clone());
// closing should prevent reads/writes
t!(s.shutdown(Shutdown::Write));
assert!(s.write(&[0]).is_err());
t!(s.shutdown(Shutdown::Read));
assert_eq!(s.read(&mut b).unwrap(), 0);
// closing should affect previous handles
assert!(s2.write(&[0]).is_err());
assert_eq!(s2.read(&mut b).unwrap(), 0);
// closing should affect new handles
let mut s3 = t!(s.try_clone());
assert!(s3.write(&[0]).is_err());
assert_eq!(s3.read(&mut b).unwrap(), 0);
// make sure these don't die
let _ = s2.shutdown(Shutdown::Read);
let _ = s2.shutdown(Shutdown::Write);
let _ = s3.shutdown(Shutdown::Read);
let _ = s3.shutdown(Shutdown::Write);
drop(tx);
})
}
#[test]
#[cfg(unix)] // test doesn't work on Windows, see #31657
fn close_read_wakes_up() {
each_ip(&mut |addr| {
let a = t!(TcpListener::bind(&addr));
let (tx1, rx) = channel::<()>();
let _t = thread::spawn(move || {
let _s = t!(a.accept());
let _ = rx.recv();
});
let s = t!(TcpStream::connect(&addr));
let s2 = t!(s.try_clone());
let (tx, rx) = channel();
let _t = thread::spawn(move || {
let mut s2 = s2;
assert_eq!(t!(s2.read(&mut [0])), 0);
tx.send(()).unwrap();
});
// this should wake up the child thread
t!(s.shutdown(Shutdown::Read));
// this test will never finish if the child doesn't wake up
rx.recv().unwrap();
drop(tx1);
})
}
#[test]
fn clone_while_reading() {
each_ip(&mut |addr| {
let accept = t!(TcpListener::bind(&addr));
// Enqueue a thread to write to a socket
let (tx, rx) = channel();
let (txdone, rxdone) = channel();
let txdone2 = txdone.clone();
let _t = thread::spawn(move || {
let mut tcp = t!(TcpStream::connect(&addr));
rx.recv().unwrap();
t!(tcp.write(&[0]));
txdone2.send(()).unwrap();
});
// Spawn off a reading clone
let tcp = t!(accept.accept()).0;
let tcp2 = t!(tcp.try_clone());
let txdone3 = txdone.clone();
let _t = thread::spawn(move || {
let mut tcp2 = tcp2;
t!(tcp2.read(&mut [0]));
txdone3.send(()).unwrap();
});
// Try to ensure that the reading clone is indeed reading
for _ in 0..50 {
thread::yield_now();
}
// clone the handle again while it's reading, then let it finish the
// read.
let _ = t!(tcp.try_clone());
tx.send(()).unwrap();
rxdone.recv().unwrap();
rxdone.recv().unwrap();
})
}
#[test]
fn clone_accept_smoke() {
each_ip(&mut |addr| {
let a = t!(TcpListener::bind(&addr));
let a2 = t!(a.try_clone());
let _t = thread::spawn(move || {
let _ = TcpStream::connect(&addr);
});
let _t = thread::spawn(move || {
let _ = TcpStream::connect(&addr);
});
t!(a.accept());
t!(a2.accept());
})
}
#[test]
fn clone_accept_concurrent() {
each_ip(&mut |addr| {
let a = t!(TcpListener::bind(&addr));
let a2 = t!(a.try_clone());
let (tx, rx) = channel();
let tx2 = tx.clone();
let _t = thread::spawn(move || {
tx.send(t!(a.accept())).unwrap();
});
let _t = thread::spawn(move || {
tx2.send(t!(a2.accept())).unwrap();
});
let _t = thread::spawn(move || {
let _ = TcpStream::connect(&addr);
});
let _t = thread::spawn(move || {
let _ = TcpStream::connect(&addr);
});
rx.recv().unwrap();
rx.recv().unwrap();
})
}
#[test]
fn debug() {
#[cfg(not(target_env = "sgx"))]
fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a {
addr
}
#[cfg(target_env = "sgx")]
fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a {
addr.to_string()
}
#[cfg(target_env = "sgx")]
use crate::os::fortanix_sgx::io::AsRawFd;
#[cfg(unix)]
use crate::os::unix::io::AsRawFd;
#[cfg(not(windows))]
fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug {
addr.as_raw_fd()
}
#[cfg(windows)]
fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Debug {
addr.as_raw_socket()
}
let inner_name = if cfg!(windows) { "socket" } else { "fd" };
let socket_addr = next_test_ip4();
let listener = t!(TcpListener::bind(&socket_addr));
let compare = format!(
"TcpListener {{ addr: {:?}, {}: {:?} }}",
render_socket_addr(&socket_addr),
inner_name,
render_inner(&listener)
);
assert_eq!(format!("{:?}", listener), compare);
let stream = t!(TcpStream::connect(&("localhost", socket_addr.port())));
let compare = format!(
"TcpStream {{ addr: {:?}, peer: {:?}, {}: {:?} }}",
render_socket_addr(&stream.local_addr().unwrap()),
render_socket_addr(&stream.peer_addr().unwrap()),
inner_name,
render_inner(&stream)
);
assert_eq!(format!("{:?}", stream), compare);
}
// FIXME: re-enabled openbsd tests once their socket timeout code
// no longer has rounding errors.
// VxWorks ignores SO_SNDTIMEO.
#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)]
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
#[test]
fn timeouts() {
let addr = next_test_ip4();
let listener = t!(TcpListener::bind(&addr));
let stream = t!(TcpStream::connect(&("localhost", addr.port())));
let dur = Duration::new(15410, 0);
assert_eq!(None, t!(stream.read_timeout()));
t!(stream.set_read_timeout(Some(dur)));
assert_eq!(Some(dur), t!(stream.read_timeout()));
assert_eq!(None, t!(stream.write_timeout()));
t!(stream.set_write_timeout(Some(dur)));
assert_eq!(Some(dur), t!(stream.write_timeout()));
t!(stream.set_read_timeout(None));
assert_eq!(None, t!(stream.read_timeout()));
t!(stream.set_write_timeout(None));
assert_eq!(None, t!(stream.write_timeout()));
drop(listener);
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
fn test_read_timeout() {
let addr = next_test_ip4();
let listener = t!(TcpListener::bind(&addr));
let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
let mut buf = [0; 10];
let start = Instant::now();
let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
assert!(
kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
"unexpected_error: {:?}",
kind
);
assert!(start.elapsed() > Duration::from_millis(400));
drop(listener);
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
fn test_read_with_timeout() {
let addr = next_test_ip4();
let listener = t!(TcpListener::bind(&addr));
let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
let mut other_end = t!(listener.accept()).0;
t!(other_end.write_all(b"hello world"));
let mut buf = [0; 11];
t!(stream.read(&mut buf));
assert_eq!(b"hello world", &buf[..]);
let start = Instant::now();
let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
assert!(
kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
"unexpected_error: {:?}",
kind
);
assert!(start.elapsed() > Duration::from_millis(400));
drop(listener);
}
// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
// when passed zero Durations
#[test]
fn test_timeout_zero_duration() {
let addr = next_test_ip4();
let listener = t!(TcpListener::bind(&addr));
let stream = t!(TcpStream::connect(&addr));
let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
drop(listener);
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)]
fn nodelay() {
let addr = next_test_ip4();
let _listener = t!(TcpListener::bind(&addr));
let stream = t!(TcpStream::connect(&("localhost", addr.port())));
assert_eq!(false, t!(stream.nodelay()));
t!(stream.set_nodelay(true));
assert_eq!(true, t!(stream.nodelay()));
t!(stream.set_nodelay(false));
assert_eq!(false, t!(stream.nodelay()));
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)]
fn ttl() {
let ttl = 100;
let addr = next_test_ip4();
let listener = t!(TcpListener::bind(&addr));
t!(listener.set_ttl(ttl));
assert_eq!(ttl, t!(listener.ttl()));
let stream = t!(TcpStream::connect(&("localhost", addr.port())));
t!(stream.set_ttl(ttl));
assert_eq!(ttl, t!(stream.ttl()));
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)]
fn set_nonblocking() {
let addr = next_test_ip4();
let listener = t!(TcpListener::bind(&addr));
t!(listener.set_nonblocking(true));
t!(listener.set_nonblocking(false));
let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
t!(stream.set_nonblocking(false));
t!(stream.set_nonblocking(true));
let mut buf = [0];
match stream.read(&mut buf) {
Ok(_) => panic!("expected error"),
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
Err(e) => panic!("unexpected error {}", e),
}
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
fn peek() {
each_ip(&mut |addr| {
let (txdone, rxdone) = channel();
let srv = t!(TcpListener::bind(&addr));
let _t = thread::spawn(move || {
let mut cl = t!(srv.accept()).0;
cl.write(&[1, 3, 3, 7]).unwrap();
t!(rxdone.recv());
});
let mut c = t!(TcpStream::connect(&addr));
let mut b = [0; 10];
for _ in 1..3 {
let len = c.peek(&mut b).unwrap();
assert_eq!(len, 4);
}
let len = c.read(&mut b).unwrap();
assert_eq!(len, 4);
t!(c.set_nonblocking(true));
match c.peek(&mut b) {
Ok(_) => panic!("expected error"),
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
Err(e) => panic!("unexpected error {}", e),
}
t!(txdone.send(()));
})
}
#[test]
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
fn connect_timeout_valid() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();
TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap();
}

View file

@ -1,3 +1,6 @@
#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
mod tests;
use crate::fmt;
use crate::io::{self, Error, ErrorKind};
use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
@ -798,380 +801,3 @@ impl fmt::Debug for UdpSocket {
self.0.fmt(f)
}
}
#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
mod tests {
use crate::io::ErrorKind;
use crate::net::test::{next_test_ip4, next_test_ip6};
use crate::net::*;
use crate::sync::mpsc::channel;
use crate::sys_common::AsInner;
use crate::thread;
use crate::time::{Duration, Instant};
fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) {
f(next_test_ip4(), next_test_ip4());
f(next_test_ip6(), next_test_ip6());
}
macro_rules! t {
($e:expr) => {
match $e {
Ok(t) => t,
Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
}
};
}
#[test]
fn bind_error() {
match UdpSocket::bind("1.1.1.1:9999") {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable),
}
}
#[test]
fn socket_smoke_test_ip4() {
each_ip(&mut |server_ip, client_ip| {
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let _t = thread::spawn(move || {
let client = t!(UdpSocket::bind(&client_ip));
rx1.recv().unwrap();
t!(client.send_to(&[99], &server_ip));
tx2.send(()).unwrap();
});
let server = t!(UdpSocket::bind(&server_ip));
tx1.send(()).unwrap();
let mut buf = [0];
let (nread, src) = t!(server.recv_from(&mut buf));
assert_eq!(nread, 1);
assert_eq!(buf[0], 99);
assert_eq!(src, client_ip);
rx2.recv().unwrap();
})
}
#[test]
fn socket_name() {
each_ip(&mut |addr, _| {
let server = t!(UdpSocket::bind(&addr));
assert_eq!(addr, t!(server.local_addr()));
})
}
#[test]
fn socket_peer() {
each_ip(&mut |addr1, addr2| {
let server = t!(UdpSocket::bind(&addr1));
assert_eq!(server.peer_addr().unwrap_err().kind(), ErrorKind::NotConnected);
t!(server.connect(&addr2));
assert_eq!(addr2, t!(server.peer_addr()));
})
}
#[test]
fn udp_clone_smoke() {
each_ip(&mut |addr1, addr2| {
let sock1 = t!(UdpSocket::bind(&addr1));
let sock2 = t!(UdpSocket::bind(&addr2));
let _t = thread::spawn(move || {
let mut buf = [0, 0];
assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1));
assert_eq!(buf[0], 1);
t!(sock2.send_to(&[2], &addr1));
});
let sock3 = t!(sock1.try_clone());
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let _t = thread::spawn(move || {
rx1.recv().unwrap();
t!(sock3.send_to(&[1], &addr2));
tx2.send(()).unwrap();
});
tx1.send(()).unwrap();
let mut buf = [0, 0];
assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2));
rx2.recv().unwrap();
})
}
#[test]
fn udp_clone_two_read() {
each_ip(&mut |addr1, addr2| {
let sock1 = t!(UdpSocket::bind(&addr1));
let sock2 = t!(UdpSocket::bind(&addr2));
let (tx1, rx) = channel();
let tx2 = tx1.clone();
let _t = thread::spawn(move || {
t!(sock2.send_to(&[1], &addr1));
rx.recv().unwrap();
t!(sock2.send_to(&[2], &addr1));
rx.recv().unwrap();
});
let sock3 = t!(sock1.try_clone());
let (done, rx) = channel();
let _t = thread::spawn(move || {
let mut buf = [0, 0];
t!(sock3.recv_from(&mut buf));
tx2.send(()).unwrap();
done.send(()).unwrap();
});
let mut buf = [0, 0];
t!(sock1.recv_from(&mut buf));
tx1.send(()).unwrap();
rx.recv().unwrap();
})
}
#[test]
fn udp_clone_two_write() {
each_ip(&mut |addr1, addr2| {
let sock1 = t!(UdpSocket::bind(&addr1));
let sock2 = t!(UdpSocket::bind(&addr2));
let (tx, rx) = channel();
let (serv_tx, serv_rx) = channel();
let _t = thread::spawn(move || {
let mut buf = [0, 1];
rx.recv().unwrap();
t!(sock2.recv_from(&mut buf));
serv_tx.send(()).unwrap();
});
let sock3 = t!(sock1.try_clone());
let (done, rx) = channel();
let tx2 = tx.clone();
let _t = thread::spawn(move || {
match sock3.send_to(&[1], &addr2) {
Ok(..) => {
let _ = tx2.send(());
}
Err(..) => {}
}
done.send(()).unwrap();
});
match sock1.send_to(&[2], &addr2) {
Ok(..) => {
let _ = tx.send(());
}
Err(..) => {}
}
drop(tx);
rx.recv().unwrap();
serv_rx.recv().unwrap();
})
}
#[test]
fn debug() {
let name = if cfg!(windows) { "socket" } else { "fd" };
let socket_addr = next_test_ip4();
let udpsock = t!(UdpSocket::bind(&socket_addr));
let udpsock_inner = udpsock.0.socket().as_inner();
let compare =
format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner);
assert_eq!(format!("{:?}", udpsock), compare);
}
// FIXME: re-enabled openbsd/netbsd tests once their socket timeout code
// no longer has rounding errors.
// VxWorks ignores SO_SNDTIMEO.
#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)]
#[test]
fn timeouts() {
let addr = next_test_ip4();
let stream = t!(UdpSocket::bind(&addr));
let dur = Duration::new(15410, 0);
assert_eq!(None, t!(stream.read_timeout()));
t!(stream.set_read_timeout(Some(dur)));
assert_eq!(Some(dur), t!(stream.read_timeout()));
assert_eq!(None, t!(stream.write_timeout()));
t!(stream.set_write_timeout(Some(dur)));
assert_eq!(Some(dur), t!(stream.write_timeout()));
t!(stream.set_read_timeout(None));
assert_eq!(None, t!(stream.read_timeout()));
t!(stream.set_write_timeout(None));
assert_eq!(None, t!(stream.write_timeout()));
}
#[test]
fn test_read_timeout() {
let addr = next_test_ip4();
let stream = t!(UdpSocket::bind(&addr));
t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
let mut buf = [0; 10];
let start = Instant::now();
loop {
let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
if kind != ErrorKind::Interrupted {
assert!(
kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
"unexpected_error: {:?}",
kind
);
break;
}
}
assert!(start.elapsed() > Duration::from_millis(400));
}
#[test]
fn test_read_with_timeout() {
let addr = next_test_ip4();
let stream = t!(UdpSocket::bind(&addr));
t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
t!(stream.send_to(b"hello world", &addr));
let mut buf = [0; 11];
t!(stream.recv_from(&mut buf));
assert_eq!(b"hello world", &buf[..]);
let start = Instant::now();
loop {
let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
if kind != ErrorKind::Interrupted {
assert!(
kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
"unexpected_error: {:?}",
kind
);
break;
}
}
assert!(start.elapsed() > Duration::from_millis(400));
}
// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
// when passed zero Durations
#[test]
fn test_timeout_zero_duration() {
let addr = next_test_ip4();
let socket = t!(UdpSocket::bind(&addr));
let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
}
#[test]
fn connect_send_recv() {
let addr = next_test_ip4();
let socket = t!(UdpSocket::bind(&addr));
t!(socket.connect(addr));
t!(socket.send(b"hello world"));
let mut buf = [0; 11];
t!(socket.recv(&mut buf));
assert_eq!(b"hello world", &buf[..]);
}
#[test]
fn connect_send_peek_recv() {
each_ip(&mut |addr, _| {
let socket = t!(UdpSocket::bind(&addr));
t!(socket.connect(addr));
t!(socket.send(b"hello world"));
for _ in 1..3 {
let mut buf = [0; 11];
let size = t!(socket.peek(&mut buf));
assert_eq!(b"hello world", &buf[..]);
assert_eq!(size, 11);
}
let mut buf = [0; 11];
let size = t!(socket.recv(&mut buf));
assert_eq!(b"hello world", &buf[..]);
assert_eq!(size, 11);
})
}
#[test]
fn peek_from() {
each_ip(&mut |addr, _| {
let socket = t!(UdpSocket::bind(&addr));
t!(socket.send_to(b"hello world", &addr));
for _ in 1..3 {
let mut buf = [0; 11];
let (size, _) = t!(socket.peek_from(&mut buf));
assert_eq!(b"hello world", &buf[..]);
assert_eq!(size, 11);
}
let mut buf = [0; 11];
let (size, _) = t!(socket.recv_from(&mut buf));
assert_eq!(b"hello world", &buf[..]);
assert_eq!(size, 11);
})
}
#[test]
fn ttl() {
let ttl = 100;
let addr = next_test_ip4();
let stream = t!(UdpSocket::bind(&addr));
t!(stream.set_ttl(ttl));
assert_eq!(ttl, t!(stream.ttl()));
}
#[test]
fn set_nonblocking() {
each_ip(&mut |addr, _| {
let socket = t!(UdpSocket::bind(&addr));
t!(socket.set_nonblocking(true));
t!(socket.set_nonblocking(false));
t!(socket.connect(addr));
t!(socket.set_nonblocking(false));
t!(socket.set_nonblocking(true));
let mut buf = [0];
match socket.recv(&mut buf) {
Ok(_) => panic!("expected error"),
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
Err(e) => panic!("unexpected error {}", e),
}
})
}
}

View file

@ -0,0 +1,372 @@
use crate::io::ErrorKind;
use crate::net::test::{next_test_ip4, next_test_ip6};
use crate::net::*;
use crate::sync::mpsc::channel;
use crate::sys_common::AsInner;
use crate::thread;
use crate::time::{Duration, Instant};
fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) {
f(next_test_ip4(), next_test_ip4());
f(next_test_ip6(), next_test_ip6());
}
macro_rules! t {
($e:expr) => {
match $e {
Ok(t) => t,
Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
}
};
}
#[test]
fn bind_error() {
match UdpSocket::bind("1.1.1.1:9999") {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable),
}
}
#[test]
fn socket_smoke_test_ip4() {
each_ip(&mut |server_ip, client_ip| {
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let _t = thread::spawn(move || {
let client = t!(UdpSocket::bind(&client_ip));
rx1.recv().unwrap();
t!(client.send_to(&[99], &server_ip));
tx2.send(()).unwrap();
});
let server = t!(UdpSocket::bind(&server_ip));
tx1.send(()).unwrap();
let mut buf = [0];
let (nread, src) = t!(server.recv_from(&mut buf));
assert_eq!(nread, 1);
assert_eq!(buf[0], 99);
assert_eq!(src, client_ip);
rx2.recv().unwrap();
})
}
#[test]
fn socket_name() {
each_ip(&mut |addr, _| {
let server = t!(UdpSocket::bind(&addr));
assert_eq!(addr, t!(server.local_addr()));
})
}
#[test]
fn socket_peer() {
each_ip(&mut |addr1, addr2| {
let server = t!(UdpSocket::bind(&addr1));
assert_eq!(server.peer_addr().unwrap_err().kind(), ErrorKind::NotConnected);
t!(server.connect(&addr2));
assert_eq!(addr2, t!(server.peer_addr()));
})
}
#[test]
fn udp_clone_smoke() {
each_ip(&mut |addr1, addr2| {
let sock1 = t!(UdpSocket::bind(&addr1));
let sock2 = t!(UdpSocket::bind(&addr2));
let _t = thread::spawn(move || {
let mut buf = [0, 0];
assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1));
assert_eq!(buf[0], 1);
t!(sock2.send_to(&[2], &addr1));
});
let sock3 = t!(sock1.try_clone());
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let _t = thread::spawn(move || {
rx1.recv().unwrap();
t!(sock3.send_to(&[1], &addr2));
tx2.send(()).unwrap();
});
tx1.send(()).unwrap();
let mut buf = [0, 0];
assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2));
rx2.recv().unwrap();
})
}
#[test]
fn udp_clone_two_read() {
each_ip(&mut |addr1, addr2| {
let sock1 = t!(UdpSocket::bind(&addr1));
let sock2 = t!(UdpSocket::bind(&addr2));
let (tx1, rx) = channel();
let tx2 = tx1.clone();
let _t = thread::spawn(move || {
t!(sock2.send_to(&[1], &addr1));
rx.recv().unwrap();
t!(sock2.send_to(&[2], &addr1));
rx.recv().unwrap();
});
let sock3 = t!(sock1.try_clone());
let (done, rx) = channel();
let _t = thread::spawn(move || {
let mut buf = [0, 0];
t!(sock3.recv_from(&mut buf));
tx2.send(()).unwrap();
done.send(()).unwrap();
});
let mut buf = [0, 0];
t!(sock1.recv_from(&mut buf));
tx1.send(()).unwrap();
rx.recv().unwrap();
})
}
#[test]
fn udp_clone_two_write() {
each_ip(&mut |addr1, addr2| {
let sock1 = t!(UdpSocket::bind(&addr1));
let sock2 = t!(UdpSocket::bind(&addr2));
let (tx, rx) = channel();
let (serv_tx, serv_rx) = channel();
let _t = thread::spawn(move || {
let mut buf = [0, 1];
rx.recv().unwrap();
t!(sock2.recv_from(&mut buf));
serv_tx.send(()).unwrap();
});
let sock3 = t!(sock1.try_clone());
let (done, rx) = channel();
let tx2 = tx.clone();
let _t = thread::spawn(move || {
match sock3.send_to(&[1], &addr2) {
Ok(..) => {
let _ = tx2.send(());
}
Err(..) => {}
}
done.send(()).unwrap();
});
match sock1.send_to(&[2], &addr2) {
Ok(..) => {
let _ = tx.send(());
}
Err(..) => {}
}
drop(tx);
rx.recv().unwrap();
serv_rx.recv().unwrap();
})
}
#[test]
fn debug() {
let name = if cfg!(windows) { "socket" } else { "fd" };
let socket_addr = next_test_ip4();
let udpsock = t!(UdpSocket::bind(&socket_addr));
let udpsock_inner = udpsock.0.socket().as_inner();
let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner);
assert_eq!(format!("{:?}", udpsock), compare);
}
// FIXME: re-enabled openbsd/netbsd tests once their socket timeout code
// no longer has rounding errors.
// VxWorks ignores SO_SNDTIMEO.
#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)]
#[test]
fn timeouts() {
let addr = next_test_ip4();
let stream = t!(UdpSocket::bind(&addr));
let dur = Duration::new(15410, 0);
assert_eq!(None, t!(stream.read_timeout()));
t!(stream.set_read_timeout(Some(dur)));
assert_eq!(Some(dur), t!(stream.read_timeout()));
assert_eq!(None, t!(stream.write_timeout()));
t!(stream.set_write_timeout(Some(dur)));
assert_eq!(Some(dur), t!(stream.write_timeout()));
t!(stream.set_read_timeout(None));
assert_eq!(None, t!(stream.read_timeout()));
t!(stream.set_write_timeout(None));
assert_eq!(None, t!(stream.write_timeout()));
}
#[test]
fn test_read_timeout() {
let addr = next_test_ip4();
let stream = t!(UdpSocket::bind(&addr));
t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
let mut buf = [0; 10];
let start = Instant::now();
loop {
let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
if kind != ErrorKind::Interrupted {
assert!(
kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
"unexpected_error: {:?}",
kind
);
break;
}
}
assert!(start.elapsed() > Duration::from_millis(400));
}
#[test]
fn test_read_with_timeout() {
let addr = next_test_ip4();
let stream = t!(UdpSocket::bind(&addr));
t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
t!(stream.send_to(b"hello world", &addr));
let mut buf = [0; 11];
t!(stream.recv_from(&mut buf));
assert_eq!(b"hello world", &buf[..]);
let start = Instant::now();
loop {
let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
if kind != ErrorKind::Interrupted {
assert!(
kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
"unexpected_error: {:?}",
kind
);
break;
}
}
assert!(start.elapsed() > Duration::from_millis(400));
}
// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
// when passed zero Durations
#[test]
fn test_timeout_zero_duration() {
let addr = next_test_ip4();
let socket = t!(UdpSocket::bind(&addr));
let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
}
#[test]
fn connect_send_recv() {
let addr = next_test_ip4();
let socket = t!(UdpSocket::bind(&addr));
t!(socket.connect(addr));
t!(socket.send(b"hello world"));
let mut buf = [0; 11];
t!(socket.recv(&mut buf));
assert_eq!(b"hello world", &buf[..]);
}
#[test]
fn connect_send_peek_recv() {
each_ip(&mut |addr, _| {
let socket = t!(UdpSocket::bind(&addr));
t!(socket.connect(addr));
t!(socket.send(b"hello world"));
for _ in 1..3 {
let mut buf = [0; 11];
let size = t!(socket.peek(&mut buf));
assert_eq!(b"hello world", &buf[..]);
assert_eq!(size, 11);
}
let mut buf = [0; 11];
let size = t!(socket.recv(&mut buf));
assert_eq!(b"hello world", &buf[..]);
assert_eq!(size, 11);
})
}
#[test]
fn peek_from() {
each_ip(&mut |addr, _| {
let socket = t!(UdpSocket::bind(&addr));
t!(socket.send_to(b"hello world", &addr));
for _ in 1..3 {
let mut buf = [0; 11];
let (size, _) = t!(socket.peek_from(&mut buf));
assert_eq!(b"hello world", &buf[..]);
assert_eq!(size, 11);
}
let mut buf = [0; 11];
let (size, _) = t!(socket.recv_from(&mut buf));
assert_eq!(b"hello world", &buf[..]);
assert_eq!(size, 11);
})
}
#[test]
fn ttl() {
let ttl = 100;
let addr = next_test_ip4();
let stream = t!(UdpSocket::bind(&addr));
t!(stream.set_ttl(ttl));
assert_eq!(ttl, t!(stream.ttl()));
}
#[test]
fn set_nonblocking() {
each_ip(&mut |addr, _| {
let socket = t!(UdpSocket::bind(&addr));
t!(socket.set_nonblocking(true));
t!(socket.set_nonblocking(false));
t!(socket.connect(addr));
t!(socket.set_nonblocking(false));
t!(socket.set_nonblocking(true));
let mut buf = [0];
match socket.recv(&mut buf) {
Ok(_) => panic!("expected error"),
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
Err(e) => panic!("unexpected error {}", e),
}
})
}

View file

@ -6,6 +6,12 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
#[cfg(test)]
mod tests;
#[cfg(test)]
mod benches;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::num::Wrapping;
#[stable(feature = "rust1", since = "1.0.0")]
@ -48,250 +54,3 @@ where
assert_eq!(ten.div(two), ten / two);
assert_eq!(ten.rem(two), ten % two);
}
#[cfg(test)]
mod tests {
use crate::ops::Mul;
#[test]
fn test_saturating_add_uint() {
assert_eq!(3_usize.saturating_add(5_usize), 8_usize);
assert_eq!(3_usize.saturating_add(usize::MAX - 1), usize::MAX);
assert_eq!(usize::MAX.saturating_add(usize::MAX), usize::MAX);
assert_eq!((usize::MAX - 2).saturating_add(1), usize::MAX - 1);
}
#[test]
fn test_saturating_sub_uint() {
assert_eq!(5_usize.saturating_sub(3_usize), 2_usize);
assert_eq!(3_usize.saturating_sub(5_usize), 0_usize);
assert_eq!(0_usize.saturating_sub(1_usize), 0_usize);
assert_eq!((usize::MAX - 1).saturating_sub(usize::MAX), 0);
}
#[test]
fn test_saturating_add_int() {
assert_eq!(3i32.saturating_add(5), 8);
assert_eq!(3isize.saturating_add(isize::MAX - 1), isize::MAX);
assert_eq!(isize::MAX.saturating_add(isize::MAX), isize::MAX);
assert_eq!((isize::MAX - 2).saturating_add(1), isize::MAX - 1);
assert_eq!(3i32.saturating_add(-5), -2);
assert_eq!(isize::MIN.saturating_add(-1), isize::MIN);
assert_eq!((-2isize).saturating_add(-isize::MAX), isize::MIN);
}
#[test]
fn test_saturating_sub_int() {
assert_eq!(3i32.saturating_sub(5), -2);
assert_eq!(isize::MIN.saturating_sub(1), isize::MIN);
assert_eq!((-2isize).saturating_sub(isize::MAX), isize::MIN);
assert_eq!(3i32.saturating_sub(-5), 8);
assert_eq!(3isize.saturating_sub(-(isize::MAX - 1)), isize::MAX);
assert_eq!(isize::MAX.saturating_sub(-isize::MAX), isize::MAX);
assert_eq!((isize::MAX - 2).saturating_sub(-1), isize::MAX - 1);
}
#[test]
fn test_checked_add() {
let five_less = usize::MAX - 5;
assert_eq!(five_less.checked_add(0), Some(usize::MAX - 5));
assert_eq!(five_less.checked_add(1), Some(usize::MAX - 4));
assert_eq!(five_less.checked_add(2), Some(usize::MAX - 3));
assert_eq!(five_less.checked_add(3), Some(usize::MAX - 2));
assert_eq!(five_less.checked_add(4), Some(usize::MAX - 1));
assert_eq!(five_less.checked_add(5), Some(usize::MAX));
assert_eq!(five_less.checked_add(6), None);
assert_eq!(five_less.checked_add(7), None);
}
#[test]
fn test_checked_sub() {
assert_eq!(5_usize.checked_sub(0), Some(5));
assert_eq!(5_usize.checked_sub(1), Some(4));
assert_eq!(5_usize.checked_sub(2), Some(3));
assert_eq!(5_usize.checked_sub(3), Some(2));
assert_eq!(5_usize.checked_sub(4), Some(1));
assert_eq!(5_usize.checked_sub(5), Some(0));
assert_eq!(5_usize.checked_sub(6), None);
assert_eq!(5_usize.checked_sub(7), None);
}
#[test]
fn test_checked_mul() {
let third = usize::MAX / 3;
assert_eq!(third.checked_mul(0), Some(0));
assert_eq!(third.checked_mul(1), Some(third));
assert_eq!(third.checked_mul(2), Some(third * 2));
assert_eq!(third.checked_mul(3), Some(third * 3));
assert_eq!(third.checked_mul(4), None);
}
macro_rules! test_is_power_of_two {
($test_name:ident, $T:ident) => {
fn $test_name() {
#![test]
assert_eq!((0 as $T).is_power_of_two(), false);
assert_eq!((1 as $T).is_power_of_two(), true);
assert_eq!((2 as $T).is_power_of_two(), true);
assert_eq!((3 as $T).is_power_of_two(), false);
assert_eq!((4 as $T).is_power_of_two(), true);
assert_eq!((5 as $T).is_power_of_two(), false);
assert_eq!(($T::MAX / 2 + 1).is_power_of_two(), true);
}
};
}
test_is_power_of_two! { test_is_power_of_two_u8, u8 }
test_is_power_of_two! { test_is_power_of_two_u16, u16 }
test_is_power_of_two! { test_is_power_of_two_u32, u32 }
test_is_power_of_two! { test_is_power_of_two_u64, u64 }
test_is_power_of_two! { test_is_power_of_two_uint, usize }
macro_rules! test_next_power_of_two {
($test_name:ident, $T:ident) => {
fn $test_name() {
#![test]
assert_eq!((0 as $T).next_power_of_two(), 1);
let mut next_power = 1;
for i in 1 as $T..40 {
assert_eq!(i.next_power_of_two(), next_power);
if i == next_power {
next_power *= 2
}
}
}
};
}
test_next_power_of_two! { test_next_power_of_two_u8, u8 }
test_next_power_of_two! { test_next_power_of_two_u16, u16 }
test_next_power_of_two! { test_next_power_of_two_u32, u32 }
test_next_power_of_two! { test_next_power_of_two_u64, u64 }
test_next_power_of_two! { test_next_power_of_two_uint, usize }
macro_rules! test_checked_next_power_of_two {
($test_name:ident, $T:ident) => {
fn $test_name() {
#![test]
assert_eq!((0 as $T).checked_next_power_of_two(), Some(1));
let smax = $T::MAX >> 1;
assert_eq!(smax.checked_next_power_of_two(), Some(smax + 1));
assert_eq!((smax + 1).checked_next_power_of_two(), Some(smax + 1));
assert_eq!((smax + 2).checked_next_power_of_two(), None);
assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None);
assert_eq!($T::MAX.checked_next_power_of_two(), None);
let mut next_power = 1;
for i in 1 as $T..40 {
assert_eq!(i.checked_next_power_of_two(), Some(next_power));
if i == next_power {
next_power *= 2
}
}
}
};
}
test_checked_next_power_of_two! { test_checked_next_power_of_two_u8, u8 }
test_checked_next_power_of_two! { test_checked_next_power_of_two_u16, u16 }
test_checked_next_power_of_two! { test_checked_next_power_of_two_u32, u32 }
test_checked_next_power_of_two! { test_checked_next_power_of_two_u64, u64 }
test_checked_next_power_of_two! { test_checked_next_power_of_two_uint, usize }
#[test]
fn test_pow() {
fn naive_pow<T: Mul<Output = T> + Copy>(one: T, base: T, exp: usize) -> T {
(0..exp).fold(one, |acc, _| acc * base)
}
macro_rules! assert_pow {
(($num:expr, $exp:expr) => $expected:expr) => {{
let result = $num.pow($exp);
assert_eq!(result, $expected);
assert_eq!(result, naive_pow(1, $num, $exp));
}};
}
assert_pow!((3u32, 0 ) => 1);
assert_pow!((5u32, 1 ) => 5);
assert_pow!((-4i32, 2 ) => 16);
assert_pow!((8u32, 3 ) => 512);
assert_pow!((2u64, 50) => 1125899906842624);
}
#[test]
fn test_uint_to_str_overflow() {
let mut u8_val: u8 = 255;
assert_eq!(u8_val.to_string(), "255");
u8_val = u8_val.wrapping_add(1);
assert_eq!(u8_val.to_string(), "0");
let mut u16_val: u16 = 65_535;
assert_eq!(u16_val.to_string(), "65535");
u16_val = u16_val.wrapping_add(1);
assert_eq!(u16_val.to_string(), "0");
let mut u32_val: u32 = 4_294_967_295;
assert_eq!(u32_val.to_string(), "4294967295");
u32_val = u32_val.wrapping_add(1);
assert_eq!(u32_val.to_string(), "0");
let mut u64_val: u64 = 18_446_744_073_709_551_615;
assert_eq!(u64_val.to_string(), "18446744073709551615");
u64_val = u64_val.wrapping_add(1);
assert_eq!(u64_val.to_string(), "0");
}
fn from_str<T: crate::str::FromStr>(t: &str) -> Option<T> {
crate::str::FromStr::from_str(t).ok()
}
#[test]
fn test_uint_from_str_overflow() {
let mut u8_val: u8 = 255;
assert_eq!(from_str::<u8>("255"), Some(u8_val));
assert_eq!(from_str::<u8>("256"), None);
u8_val = u8_val.wrapping_add(1);
assert_eq!(from_str::<u8>("0"), Some(u8_val));
assert_eq!(from_str::<u8>("-1"), None);
let mut u16_val: u16 = 65_535;
assert_eq!(from_str::<u16>("65535"), Some(u16_val));
assert_eq!(from_str::<u16>("65536"), None);
u16_val = u16_val.wrapping_add(1);
assert_eq!(from_str::<u16>("0"), Some(u16_val));
assert_eq!(from_str::<u16>("-1"), None);
let mut u32_val: u32 = 4_294_967_295;
assert_eq!(from_str::<u32>("4294967295"), Some(u32_val));
assert_eq!(from_str::<u32>("4294967296"), None);
u32_val = u32_val.wrapping_add(1);
assert_eq!(from_str::<u32>("0"), Some(u32_val));
assert_eq!(from_str::<u32>("-1"), None);
let mut u64_val: u64 = 18_446_744_073_709_551_615;
assert_eq!(from_str::<u64>("18446744073709551615"), Some(u64_val));
assert_eq!(from_str::<u64>("18446744073709551616"), None);
u64_val = u64_val.wrapping_add(1);
assert_eq!(from_str::<u64>("0"), Some(u64_val));
assert_eq!(from_str::<u64>("-1"), None);
}
}
#[cfg(test)]
mod bench {
use test::Bencher;
#[bench]
fn bench_pow_function(b: &mut Bencher) {
let v = (0..1024).collect::<Vec<u32>>();
b.iter(|| {
v.iter().fold(0u32, |old, new| old.pow(*new as u32));
});
}
}

View file

@ -0,0 +1,9 @@
use test::Bencher;
#[bench]
fn bench_pow_function(b: &mut Bencher) {
let v = (0..1024).collect::<Vec<u32>>();
b.iter(|| {
v.iter().fold(0u32, |old, new| old.pow(*new as u32));
});
}

View file

@ -0,0 +1,230 @@
use crate::ops::Mul;
#[test]
fn test_saturating_add_uint() {
assert_eq!(3_usize.saturating_add(5_usize), 8_usize);
assert_eq!(3_usize.saturating_add(usize::MAX - 1), usize::MAX);
assert_eq!(usize::MAX.saturating_add(usize::MAX), usize::MAX);
assert_eq!((usize::MAX - 2).saturating_add(1), usize::MAX - 1);
}
#[test]
fn test_saturating_sub_uint() {
assert_eq!(5_usize.saturating_sub(3_usize), 2_usize);
assert_eq!(3_usize.saturating_sub(5_usize), 0_usize);
assert_eq!(0_usize.saturating_sub(1_usize), 0_usize);
assert_eq!((usize::MAX - 1).saturating_sub(usize::MAX), 0);
}
#[test]
fn test_saturating_add_int() {
assert_eq!(3i32.saturating_add(5), 8);
assert_eq!(3isize.saturating_add(isize::MAX - 1), isize::MAX);
assert_eq!(isize::MAX.saturating_add(isize::MAX), isize::MAX);
assert_eq!((isize::MAX - 2).saturating_add(1), isize::MAX - 1);
assert_eq!(3i32.saturating_add(-5), -2);
assert_eq!(isize::MIN.saturating_add(-1), isize::MIN);
assert_eq!((-2isize).saturating_add(-isize::MAX), isize::MIN);
}
#[test]
fn test_saturating_sub_int() {
assert_eq!(3i32.saturating_sub(5), -2);
assert_eq!(isize::MIN.saturating_sub(1), isize::MIN);
assert_eq!((-2isize).saturating_sub(isize::MAX), isize::MIN);
assert_eq!(3i32.saturating_sub(-5), 8);
assert_eq!(3isize.saturating_sub(-(isize::MAX - 1)), isize::MAX);
assert_eq!(isize::MAX.saturating_sub(-isize::MAX), isize::MAX);
assert_eq!((isize::MAX - 2).saturating_sub(-1), isize::MAX - 1);
}
#[test]
fn test_checked_add() {
let five_less = usize::MAX - 5;
assert_eq!(five_less.checked_add(0), Some(usize::MAX - 5));
assert_eq!(five_less.checked_add(1), Some(usize::MAX - 4));
assert_eq!(five_less.checked_add(2), Some(usize::MAX - 3));
assert_eq!(five_less.checked_add(3), Some(usize::MAX - 2));
assert_eq!(five_less.checked_add(4), Some(usize::MAX - 1));
assert_eq!(five_less.checked_add(5), Some(usize::MAX));
assert_eq!(five_less.checked_add(6), None);
assert_eq!(five_less.checked_add(7), None);
}
#[test]
fn test_checked_sub() {
assert_eq!(5_usize.checked_sub(0), Some(5));
assert_eq!(5_usize.checked_sub(1), Some(4));
assert_eq!(5_usize.checked_sub(2), Some(3));
assert_eq!(5_usize.checked_sub(3), Some(2));
assert_eq!(5_usize.checked_sub(4), Some(1));
assert_eq!(5_usize.checked_sub(5), Some(0));
assert_eq!(5_usize.checked_sub(6), None);
assert_eq!(5_usize.checked_sub(7), None);
}
#[test]
fn test_checked_mul() {
let third = usize::MAX / 3;
assert_eq!(third.checked_mul(0), Some(0));
assert_eq!(third.checked_mul(1), Some(third));
assert_eq!(third.checked_mul(2), Some(third * 2));
assert_eq!(third.checked_mul(3), Some(third * 3));
assert_eq!(third.checked_mul(4), None);
}
macro_rules! test_is_power_of_two {
($test_name:ident, $T:ident) => {
fn $test_name() {
#![test]
assert_eq!((0 as $T).is_power_of_two(), false);
assert_eq!((1 as $T).is_power_of_two(), true);
assert_eq!((2 as $T).is_power_of_two(), true);
assert_eq!((3 as $T).is_power_of_two(), false);
assert_eq!((4 as $T).is_power_of_two(), true);
assert_eq!((5 as $T).is_power_of_two(), false);
assert_eq!(($T::MAX / 2 + 1).is_power_of_two(), true);
}
};
}
test_is_power_of_two! { test_is_power_of_two_u8, u8 }
test_is_power_of_two! { test_is_power_of_two_u16, u16 }
test_is_power_of_two! { test_is_power_of_two_u32, u32 }
test_is_power_of_two! { test_is_power_of_two_u64, u64 }
test_is_power_of_two! { test_is_power_of_two_uint, usize }
macro_rules! test_next_power_of_two {
($test_name:ident, $T:ident) => {
fn $test_name() {
#![test]
assert_eq!((0 as $T).next_power_of_two(), 1);
let mut next_power = 1;
for i in 1 as $T..40 {
assert_eq!(i.next_power_of_two(), next_power);
if i == next_power {
next_power *= 2
}
}
}
};
}
test_next_power_of_two! { test_next_power_of_two_u8, u8 }
test_next_power_of_two! { test_next_power_of_two_u16, u16 }
test_next_power_of_two! { test_next_power_of_two_u32, u32 }
test_next_power_of_two! { test_next_power_of_two_u64, u64 }
test_next_power_of_two! { test_next_power_of_two_uint, usize }
macro_rules! test_checked_next_power_of_two {
($test_name:ident, $T:ident) => {
fn $test_name() {
#![test]
assert_eq!((0 as $T).checked_next_power_of_two(), Some(1));
let smax = $T::MAX >> 1;
assert_eq!(smax.checked_next_power_of_two(), Some(smax + 1));
assert_eq!((smax + 1).checked_next_power_of_two(), Some(smax + 1));
assert_eq!((smax + 2).checked_next_power_of_two(), None);
assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None);
assert_eq!($T::MAX.checked_next_power_of_two(), None);
let mut next_power = 1;
for i in 1 as $T..40 {
assert_eq!(i.checked_next_power_of_two(), Some(next_power));
if i == next_power {
next_power *= 2
}
}
}
};
}
test_checked_next_power_of_two! { test_checked_next_power_of_two_u8, u8 }
test_checked_next_power_of_two! { test_checked_next_power_of_two_u16, u16 }
test_checked_next_power_of_two! { test_checked_next_power_of_two_u32, u32 }
test_checked_next_power_of_two! { test_checked_next_power_of_two_u64, u64 }
test_checked_next_power_of_two! { test_checked_next_power_of_two_uint, usize }
#[test]
fn test_pow() {
fn naive_pow<T: Mul<Output = T> + Copy>(one: T, base: T, exp: usize) -> T {
(0..exp).fold(one, |acc, _| acc * base)
}
macro_rules! assert_pow {
(($num:expr, $exp:expr) => $expected:expr) => {{
let result = $num.pow($exp);
assert_eq!(result, $expected);
assert_eq!(result, naive_pow(1, $num, $exp));
}};
}
assert_pow!((3u32, 0 ) => 1);
assert_pow!((5u32, 1 ) => 5);
assert_pow!((-4i32, 2 ) => 16);
assert_pow!((8u32, 3 ) => 512);
assert_pow!((2u64, 50) => 1125899906842624);
}
#[test]
fn test_uint_to_str_overflow() {
let mut u8_val: u8 = 255;
assert_eq!(u8_val.to_string(), "255");
u8_val = u8_val.wrapping_add(1);
assert_eq!(u8_val.to_string(), "0");
let mut u16_val: u16 = 65_535;
assert_eq!(u16_val.to_string(), "65535");
u16_val = u16_val.wrapping_add(1);
assert_eq!(u16_val.to_string(), "0");
let mut u32_val: u32 = 4_294_967_295;
assert_eq!(u32_val.to_string(), "4294967295");
u32_val = u32_val.wrapping_add(1);
assert_eq!(u32_val.to_string(), "0");
let mut u64_val: u64 = 18_446_744_073_709_551_615;
assert_eq!(u64_val.to_string(), "18446744073709551615");
u64_val = u64_val.wrapping_add(1);
assert_eq!(u64_val.to_string(), "0");
}
fn from_str<T: crate::str::FromStr>(t: &str) -> Option<T> {
crate::str::FromStr::from_str(t).ok()
}
#[test]
fn test_uint_from_str_overflow() {
let mut u8_val: u8 = 255;
assert_eq!(from_str::<u8>("255"), Some(u8_val));
assert_eq!(from_str::<u8>("256"), None);
u8_val = u8_val.wrapping_add(1);
assert_eq!(from_str::<u8>("0"), Some(u8_val));
assert_eq!(from_str::<u8>("-1"), None);
let mut u16_val: u16 = 65_535;
assert_eq!(from_str::<u16>("65535"), Some(u16_val));
assert_eq!(from_str::<u16>("65536"), None);
u16_val = u16_val.wrapping_add(1);
assert_eq!(from_str::<u16>("0"), Some(u16_val));
assert_eq!(from_str::<u16>("-1"), None);
let mut u32_val: u32 = 4_294_967_295;
assert_eq!(from_str::<u32>("4294967295"), Some(u32_val));
assert_eq!(from_str::<u32>("4294967296"), None);
u32_val = u32_val.wrapping_add(1);
assert_eq!(from_str::<u32>("0"), Some(u32_val));
assert_eq!(from_str::<u32>("-1"), None);
let mut u64_val: u64 = 18_446_744_073_709_551_615;
assert_eq!(from_str::<u64>("18446744073709551615"), Some(u64_val));
assert_eq!(from_str::<u64>("18446744073709551616"), None);
u64_val = u64_val.wrapping_add(1);
assert_eq!(from_str::<u64>("0"), Some(u64_val));
assert_eq!(from_str::<u64>("-1"), None);
}

View file

@ -8,6 +8,10 @@
#![stable(feature = "raw_os", since = "1.1.0")]
#[cfg(test)]
#[allow(unused_imports)]
mod tests;
#[doc(include = "char.md")]
#[cfg(any(
all(
@ -144,24 +148,3 @@ pub type c_double = f64;
#[stable(feature = "raw_os", since = "1.1.0")]
#[doc(no_inline)]
pub use core::ffi::c_void;
#[cfg(test)]
#[allow(unused_imports)]
mod tests {
use crate::any::TypeId;
use crate::mem;
macro_rules! ok {
($($t:ident)*) => {$(
assert!(TypeId::of::<libc::$t>() == TypeId::of::<raw::$t>(),
"{} is wrong", stringify!($t));
)*}
}
#[test]
fn same() {
use crate::os::raw;
ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong
c_longlong c_ulonglong c_float c_double);
}
}

View file

@ -0,0 +1,16 @@
use crate::any::TypeId;
use crate::mem;
macro_rules! ok {
($($t:ident)*) => {$(
assert!(TypeId::of::<libc::$t>() == TypeId::of::<raw::$t>(),
"{} is wrong", stringify!($t));
)*}
}
#[test]
fn same() {
use crate::os::raw;
ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong
c_longlong c_ulonglong c_float c_double);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -96,6 +96,9 @@
#![stable(feature = "process", since = "1.0.0")]
#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
mod tests;
use crate::io::prelude::*;
use crate::ffi::OsStr;
@ -1702,411 +1705,3 @@ impl Termination for ExitCode {
self.0.as_i32()
}
}
#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
mod tests {
use crate::io::prelude::*;
use super::{Command, Output, Stdio};
use crate::io::ErrorKind;
use crate::str;
// FIXME(#10380) these tests should not all be ignored on android.
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn smoke() {
let p = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 0"]).spawn()
} else {
Command::new("true").spawn()
};
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.wait().unwrap().success());
}
#[test]
#[cfg_attr(target_os = "android", ignore)]
fn smoke_failure() {
match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
Ok(..) => panic!(),
Err(..) => {}
}
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn exit_reported_right() {
let p = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 1"]).spawn()
} else {
Command::new("false").spawn()
};
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.wait().unwrap().code() == Some(1));
drop(p.wait());
}
#[test]
#[cfg(unix)]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn signal_reported_right() {
use crate::os::unix::process::ExitStatusExt;
let mut p =
Command::new("/bin/sh").arg("-c").arg("read a").stdin(Stdio::piped()).spawn().unwrap();
p.kill().unwrap();
match p.wait().unwrap().signal() {
Some(9) => {}
result => panic!("not terminated by signal 9 (instead, {:?})", result),
}
}
pub fn run_output(mut cmd: Command) -> String {
let p = cmd.spawn();
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.stdout.is_some());
let mut ret = String::new();
p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap();
assert!(p.wait().unwrap().success());
return ret;
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn stdout_works() {
if cfg!(target_os = "windows") {
let mut cmd = Command::new("cmd");
cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped());
assert_eq!(run_output(cmd), "foobar\r\n");
} else {
let mut cmd = Command::new("echo");
cmd.arg("foobar").stdout(Stdio::piped());
assert_eq!(run_output(cmd), "foobar\n");
}
}
#[test]
#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)]
fn set_current_dir_works() {
let mut cmd = Command::new("/bin/sh");
cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped());
assert_eq!(run_output(cmd), "/\n");
}
#[test]
#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)]
fn stdin_works() {
let mut p = Command::new("/bin/sh")
.arg("-c")
.arg("read line; echo $line")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap();
p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap();
drop(p.stdin.take());
let mut out = String::new();
p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap();
assert!(p.wait().unwrap().success());
assert_eq!(out, "foobar\n");
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn test_process_status() {
let mut status = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap()
} else {
Command::new("false").status().unwrap()
};
assert!(status.code() == Some(1));
status = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap()
} else {
Command::new("true").status().unwrap()
};
assert!(status.success());
}
#[test]
fn test_process_output_fail_to_start() {
match Command::new("/no-binary-by-this-name-should-exist").output() {
Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound),
Ok(..) => panic!(),
}
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn test_process_output_output() {
let Output { status, stdout, stderr } = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap()
} else {
Command::new("echo").arg("hello").output().unwrap()
};
let output_str = str::from_utf8(&stdout).unwrap();
assert!(status.success());
assert_eq!(output_str.trim().to_string(), "hello");
assert_eq!(stderr, Vec::new());
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn test_process_output_error() {
let Output { status, stdout, stderr } = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap()
} else {
Command::new("mkdir").arg("./").output().unwrap()
};
assert!(status.code() == Some(1));
assert_eq!(stdout, Vec::new());
assert!(!stderr.is_empty());
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn test_finish_once() {
let mut prog = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
} else {
Command::new("false").spawn().unwrap()
};
assert!(prog.wait().unwrap().code() == Some(1));
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn test_finish_twice() {
let mut prog = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
} else {
Command::new("false").spawn().unwrap()
};
assert!(prog.wait().unwrap().code() == Some(1));
assert!(prog.wait().unwrap().code() == Some(1));
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn test_wait_with_output_once() {
let prog = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap()
} else {
Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap()
};
let Output { status, stdout, stderr } = prog.wait_with_output().unwrap();
let output_str = str::from_utf8(&stdout).unwrap();
assert!(status.success());
assert_eq!(output_str.trim().to_string(), "hello");
assert_eq!(stderr, Vec::new());
}
#[cfg(all(unix, not(target_os = "android")))]
pub fn env_cmd() -> Command {
Command::new("env")
}
#[cfg(target_os = "android")]
pub fn env_cmd() -> Command {
let mut cmd = Command::new("/system/bin/sh");
cmd.arg("-c").arg("set");
cmd
}
#[cfg(windows)]
pub fn env_cmd() -> Command {
let mut cmd = Command::new("cmd");
cmd.arg("/c").arg("set");
cmd
}
#[test]
#[cfg_attr(target_os = "vxworks", ignore)]
fn test_override_env() {
use crate::env;
// In some build environments (such as chrooted Nix builds), `env` can
// only be found in the explicitly-provided PATH env variable, not in
// default places such as /bin or /usr/bin. So we need to pass through
// PATH to our sub-process.
let mut cmd = env_cmd();
cmd.env_clear().env("RUN_TEST_NEW_ENV", "123");
if let Some(p) = env::var_os("PATH") {
cmd.env("PATH", &p);
}
let result = cmd.output().unwrap();
let output = String::from_utf8_lossy(&result.stdout).to_string();
assert!(
output.contains("RUN_TEST_NEW_ENV=123"),
"didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
output
);
}
#[test]
#[cfg_attr(target_os = "vxworks", ignore)]
fn test_add_to_env() {
let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap();
let output = String::from_utf8_lossy(&result.stdout).to_string();
assert!(
output.contains("RUN_TEST_NEW_ENV=123"),
"didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
output
);
}
#[test]
#[cfg_attr(target_os = "vxworks", ignore)]
fn test_capture_env_at_spawn() {
use crate::env;
let mut cmd = env_cmd();
cmd.env("RUN_TEST_NEW_ENV1", "123");
// This variable will not be present if the environment has already
// been captured above.
env::set_var("RUN_TEST_NEW_ENV2", "456");
let result = cmd.output().unwrap();
env::remove_var("RUN_TEST_NEW_ENV2");
let output = String::from_utf8_lossy(&result.stdout).to_string();
assert!(
output.contains("RUN_TEST_NEW_ENV1=123"),
"didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}",
output
);
assert!(
output.contains("RUN_TEST_NEW_ENV2=456"),
"didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}",
output
);
}
// Regression tests for #30858.
#[test]
fn test_interior_nul_in_progname_is_error() {
match Command::new("has-some-\0\0s-inside").spawn() {
Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
Ok(_) => panic!(),
}
}
#[test]
fn test_interior_nul_in_arg_is_error() {
match Command::new("echo").arg("has-some-\0\0s-inside").spawn() {
Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
Ok(_) => panic!(),
}
}
#[test]
fn test_interior_nul_in_args_is_error() {
match Command::new("echo").args(&["has-some-\0\0s-inside"]).spawn() {
Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
Ok(_) => panic!(),
}
}
#[test]
fn test_interior_nul_in_current_dir_is_error() {
match Command::new("echo").current_dir("has-some-\0\0s-inside").spawn() {
Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
Ok(_) => panic!(),
}
}
// Regression tests for #30862.
#[test]
#[cfg_attr(target_os = "vxworks", ignore)]
fn test_interior_nul_in_env_key_is_error() {
match env_cmd().env("has-some-\0\0s-inside", "value").spawn() {
Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
Ok(_) => panic!(),
}
}
#[test]
#[cfg_attr(target_os = "vxworks", ignore)]
fn test_interior_nul_in_env_value_is_error() {
match env_cmd().env("key", "has-some-\0\0s-inside").spawn() {
Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
Ok(_) => panic!(),
}
}
/// Tests that process creation flags work by debugging a process.
/// Other creation flags make it hard or impossible to detect
/// behavioral changes in the process.
#[test]
#[cfg(windows)]
fn test_creation_flags() {
use crate::os::windows::process::CommandExt;
use crate::sys::c::{BOOL, DWORD, INFINITE};
#[repr(C, packed)]
struct DEBUG_EVENT {
pub event_code: DWORD,
pub process_id: DWORD,
pub thread_id: DWORD,
// This is a union in the real struct, but we don't
// need this data for the purposes of this test.
pub _junk: [u8; 164],
}
extern "system" {
fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL;
fn ContinueDebugEvent(
dwProcessId: DWORD,
dwThreadId: DWORD,
dwContinueStatus: DWORD,
) -> BOOL;
}
const DEBUG_PROCESS: DWORD = 1;
const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5;
const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001;
let mut child = Command::new("cmd")
.creation_flags(DEBUG_PROCESS)
.stdin(Stdio::piped())
.spawn()
.unwrap();
child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap();
let mut events = 0;
let mut event = DEBUG_EVENT { event_code: 0, process_id: 0, thread_id: 0, _junk: [0; 164] };
loop {
if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 {
panic!("WaitForDebugEvent failed!");
}
events += 1;
if event.event_code == EXIT_PROCESS_DEBUG_EVENT {
break;
}
if unsafe {
ContinueDebugEvent(event.process_id, event.thread_id, DBG_EXCEPTION_NOT_HANDLED)
} == 0
{
panic!("ContinueDebugEvent failed!");
}
}
assert!(events > 0);
}
#[test]
fn test_command_implements_send_sync() {
fn take_send_sync_type<T: Send + Sync>(_: T) {}
take_send_sync_type(Command::new(""))
}
}

View file

@ -0,0 +1,401 @@
use crate::io::prelude::*;
use super::{Command, Output, Stdio};
use crate::io::ErrorKind;
use crate::str;
// FIXME(#10380) these tests should not all be ignored on android.
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn smoke() {
let p = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 0"]).spawn()
} else {
Command::new("true").spawn()
};
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.wait().unwrap().success());
}
#[test]
#[cfg_attr(target_os = "android", ignore)]
fn smoke_failure() {
match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
Ok(..) => panic!(),
Err(..) => {}
}
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn exit_reported_right() {
let p = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 1"]).spawn()
} else {
Command::new("false").spawn()
};
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.wait().unwrap().code() == Some(1));
drop(p.wait());
}
#[test]
#[cfg(unix)]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn signal_reported_right() {
use crate::os::unix::process::ExitStatusExt;
let mut p =
Command::new("/bin/sh").arg("-c").arg("read a").stdin(Stdio::piped()).spawn().unwrap();
p.kill().unwrap();
match p.wait().unwrap().signal() {
Some(9) => {}
result => panic!("not terminated by signal 9 (instead, {:?})", result),
}
}
pub fn run_output(mut cmd: Command) -> String {
let p = cmd.spawn();
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.stdout.is_some());
let mut ret = String::new();
p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap();
assert!(p.wait().unwrap().success());
return ret;
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn stdout_works() {
if cfg!(target_os = "windows") {
let mut cmd = Command::new("cmd");
cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped());
assert_eq!(run_output(cmd), "foobar\r\n");
} else {
let mut cmd = Command::new("echo");
cmd.arg("foobar").stdout(Stdio::piped());
assert_eq!(run_output(cmd), "foobar\n");
}
}
#[test]
#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)]
fn set_current_dir_works() {
let mut cmd = Command::new("/bin/sh");
cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped());
assert_eq!(run_output(cmd), "/\n");
}
#[test]
#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)]
fn stdin_works() {
let mut p = Command::new("/bin/sh")
.arg("-c")
.arg("read line; echo $line")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap();
p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap();
drop(p.stdin.take());
let mut out = String::new();
p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap();
assert!(p.wait().unwrap().success());
assert_eq!(out, "foobar\n");
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn test_process_status() {
let mut status = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap()
} else {
Command::new("false").status().unwrap()
};
assert!(status.code() == Some(1));
status = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap()
} else {
Command::new("true").status().unwrap()
};
assert!(status.success());
}
#[test]
fn test_process_output_fail_to_start() {
match Command::new("/no-binary-by-this-name-should-exist").output() {
Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound),
Ok(..) => panic!(),
}
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn test_process_output_output() {
let Output { status, stdout, stderr } = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap()
} else {
Command::new("echo").arg("hello").output().unwrap()
};
let output_str = str::from_utf8(&stdout).unwrap();
assert!(status.success());
assert_eq!(output_str.trim().to_string(), "hello");
assert_eq!(stderr, Vec::new());
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn test_process_output_error() {
let Output { status, stdout, stderr } = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap()
} else {
Command::new("mkdir").arg("./").output().unwrap()
};
assert!(status.code() == Some(1));
assert_eq!(stdout, Vec::new());
assert!(!stderr.is_empty());
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn test_finish_once() {
let mut prog = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
} else {
Command::new("false").spawn().unwrap()
};
assert!(prog.wait().unwrap().code() == Some(1));
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn test_finish_twice() {
let mut prog = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
} else {
Command::new("false").spawn().unwrap()
};
assert!(prog.wait().unwrap().code() == Some(1));
assert!(prog.wait().unwrap().code() == Some(1));
}
#[test]
#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
fn test_wait_with_output_once() {
let prog = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap()
} else {
Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap()
};
let Output { status, stdout, stderr } = prog.wait_with_output().unwrap();
let output_str = str::from_utf8(&stdout).unwrap();
assert!(status.success());
assert_eq!(output_str.trim().to_string(), "hello");
assert_eq!(stderr, Vec::new());
}
#[cfg(all(unix, not(target_os = "android")))]
pub fn env_cmd() -> Command {
Command::new("env")
}
#[cfg(target_os = "android")]
pub fn env_cmd() -> Command {
let mut cmd = Command::new("/system/bin/sh");
cmd.arg("-c").arg("set");
cmd
}
#[cfg(windows)]
pub fn env_cmd() -> Command {
let mut cmd = Command::new("cmd");
cmd.arg("/c").arg("set");
cmd
}
#[test]
#[cfg_attr(target_os = "vxworks", ignore)]
fn test_override_env() {
use crate::env;
// In some build environments (such as chrooted Nix builds), `env` can
// only be found in the explicitly-provided PATH env variable, not in
// default places such as /bin or /usr/bin. So we need to pass through
// PATH to our sub-process.
let mut cmd = env_cmd();
cmd.env_clear().env("RUN_TEST_NEW_ENV", "123");
if let Some(p) = env::var_os("PATH") {
cmd.env("PATH", &p);
}
let result = cmd.output().unwrap();
let output = String::from_utf8_lossy(&result.stdout).to_string();
assert!(
output.contains("RUN_TEST_NEW_ENV=123"),
"didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
output
);
}
#[test]
#[cfg_attr(target_os = "vxworks", ignore)]
fn test_add_to_env() {
let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap();
let output = String::from_utf8_lossy(&result.stdout).to_string();
assert!(
output.contains("RUN_TEST_NEW_ENV=123"),
"didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
output
);
}
#[test]
#[cfg_attr(target_os = "vxworks", ignore)]
fn test_capture_env_at_spawn() {
use crate::env;
let mut cmd = env_cmd();
cmd.env("RUN_TEST_NEW_ENV1", "123");
// This variable will not be present if the environment has already
// been captured above.
env::set_var("RUN_TEST_NEW_ENV2", "456");
let result = cmd.output().unwrap();
env::remove_var("RUN_TEST_NEW_ENV2");
let output = String::from_utf8_lossy(&result.stdout).to_string();
assert!(
output.contains("RUN_TEST_NEW_ENV1=123"),
"didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}",
output
);
assert!(
output.contains("RUN_TEST_NEW_ENV2=456"),
"didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}",
output
);
}
// Regression tests for #30858.
#[test]
fn test_interior_nul_in_progname_is_error() {
match Command::new("has-some-\0\0s-inside").spawn() {
Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
Ok(_) => panic!(),
}
}
#[test]
fn test_interior_nul_in_arg_is_error() {
match Command::new("echo").arg("has-some-\0\0s-inside").spawn() {
Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
Ok(_) => panic!(),
}
}
#[test]
fn test_interior_nul_in_args_is_error() {
match Command::new("echo").args(&["has-some-\0\0s-inside"]).spawn() {
Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
Ok(_) => panic!(),
}
}
#[test]
fn test_interior_nul_in_current_dir_is_error() {
match Command::new("echo").current_dir("has-some-\0\0s-inside").spawn() {
Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
Ok(_) => panic!(),
}
}
// Regression tests for #30862.
#[test]
#[cfg_attr(target_os = "vxworks", ignore)]
fn test_interior_nul_in_env_key_is_error() {
match env_cmd().env("has-some-\0\0s-inside", "value").spawn() {
Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
Ok(_) => panic!(),
}
}
#[test]
#[cfg_attr(target_os = "vxworks", ignore)]
fn test_interior_nul_in_env_value_is_error() {
match env_cmd().env("key", "has-some-\0\0s-inside").spawn() {
Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
Ok(_) => panic!(),
}
}
/// Tests that process creation flags work by debugging a process.
/// Other creation flags make it hard or impossible to detect
/// behavioral changes in the process.
#[test]
#[cfg(windows)]
fn test_creation_flags() {
use crate::os::windows::process::CommandExt;
use crate::sys::c::{BOOL, DWORD, INFINITE};
#[repr(C, packed)]
struct DEBUG_EVENT {
pub event_code: DWORD,
pub process_id: DWORD,
pub thread_id: DWORD,
// This is a union in the real struct, but we don't
// need this data for the purposes of this test.
pub _junk: [u8; 164],
}
extern "system" {
fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL;
fn ContinueDebugEvent(
dwProcessId: DWORD,
dwThreadId: DWORD,
dwContinueStatus: DWORD,
) -> BOOL;
}
const DEBUG_PROCESS: DWORD = 1;
const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5;
const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001;
let mut child =
Command::new("cmd").creation_flags(DEBUG_PROCESS).stdin(Stdio::piped()).spawn().unwrap();
child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap();
let mut events = 0;
let mut event = DEBUG_EVENT { event_code: 0, process_id: 0, thread_id: 0, _junk: [0; 164] };
loop {
if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 {
panic!("WaitForDebugEvent failed!");
}
events += 1;
if event.event_code == EXIT_PROCESS_DEBUG_EVENT {
break;
}
if unsafe {
ContinueDebugEvent(event.process_id, event.thread_id, DBG_EXCEPTION_NOT_HANDLED)
} == 0
{
panic!("ContinueDebugEvent failed!");
}
}
assert!(events > 0);
}
#[test]
fn test_command_implements_send_sync() {
fn take_send_sync_type<T: Send + Sync>(_: T) {}
take_send_sync_type(Command::new(""))
}

View file

@ -1,3 +1,6 @@
#[cfg(test)]
mod tests;
use crate::fmt;
use crate::sync::{Condvar, Mutex};
@ -174,42 +177,3 @@ impl BarrierWaitResult {
self.0
}
}
#[cfg(test)]
mod tests {
use crate::sync::mpsc::{channel, TryRecvError};
use crate::sync::{Arc, Barrier};
use crate::thread;
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_barrier() {
const N: usize = 10;
let barrier = Arc::new(Barrier::new(N));
let (tx, rx) = channel();
for _ in 0..N - 1 {
let c = barrier.clone();
let tx = tx.clone();
thread::spawn(move || {
tx.send(c.wait().is_leader()).unwrap();
});
}
// At this point, all spawned threads should be blocked,
// so we shouldn't get anything from the port
assert!(matches!(rx.try_recv(), Err(TryRecvError::Empty)));
let mut leader_found = barrier.wait().is_leader();
// Now, the barrier is cleared and we should get data.
for _ in 0..N - 1 {
if rx.recv().unwrap() {
assert!(!leader_found);
leader_found = true;
}
}
assert!(leader_found);
}
}

View file

@ -0,0 +1,35 @@
use crate::sync::mpsc::{channel, TryRecvError};
use crate::sync::{Arc, Barrier};
use crate::thread;
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_barrier() {
const N: usize = 10;
let barrier = Arc::new(Barrier::new(N));
let (tx, rx) = channel();
for _ in 0..N - 1 {
let c = barrier.clone();
let tx = tx.clone();
thread::spawn(move || {
tx.send(c.wait().is_leader()).unwrap();
});
}
// At this point, all spawned threads should be blocked,
// so we shouldn't get anything from the port
assert!(matches!(rx.try_recv(), Err(TryRecvError::Empty)));
let mut leader_found = barrier.wait().is_leader();
// Now, the barrier is cleared and we should get data.
for _ in 0..N - 1 {
if rx.recv().unwrap() {
assert!(!leader_found);
leader_found = true;
}
}
assert!(leader_found);
}

View file

@ -1,3 +1,6 @@
#[cfg(test)]
mod tests;
use crate::fmt;
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::{mutex, MutexGuard, PoisonError};
@ -598,218 +601,3 @@ impl Drop for Condvar {
unsafe { self.inner.destroy() }
}
}
#[cfg(test)]
mod tests {
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sync::mpsc::channel;
use crate::sync::{Arc, Condvar, Mutex};
use crate::thread;
use crate::time::Duration;
#[test]
fn smoke() {
let c = Condvar::new();
c.notify_one();
c.notify_all();
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn notify_one() {
let m = Arc::new(Mutex::new(()));
let m2 = m.clone();
let c = Arc::new(Condvar::new());
let c2 = c.clone();
let g = m.lock().unwrap();
let _t = thread::spawn(move || {
let _g = m2.lock().unwrap();
c2.notify_one();
});
let g = c.wait(g).unwrap();
drop(g);
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn notify_all() {
const N: usize = 10;
let data = Arc::new((Mutex::new(0), Condvar::new()));
let (tx, rx) = channel();
for _ in 0..N {
let data = data.clone();
let tx = tx.clone();
thread::spawn(move || {
let &(ref lock, ref cond) = &*data;
let mut cnt = lock.lock().unwrap();
*cnt += 1;
if *cnt == N {
tx.send(()).unwrap();
}
while *cnt != 0 {
cnt = cond.wait(cnt).unwrap();
}
tx.send(()).unwrap();
});
}
drop(tx);
let &(ref lock, ref cond) = &*data;
rx.recv().unwrap();
let mut cnt = lock.lock().unwrap();
*cnt = 0;
cond.notify_all();
drop(cnt);
for _ in 0..N {
rx.recv().unwrap();
}
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_while() {
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair2 = pair.clone();
// Inside of our lock, spawn a new thread, and then wait for it to start.
thread::spawn(move || {
let &(ref lock, ref cvar) = &*pair2;
let mut started = lock.lock().unwrap();
*started = true;
// We notify the condvar that the value has changed.
cvar.notify_one();
});
// Wait for the thread to start up.
let &(ref lock, ref cvar) = &*pair;
let guard = cvar.wait_while(lock.lock().unwrap(), |started| !*started);
assert!(*guard.unwrap());
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_wait() {
let m = Arc::new(Mutex::new(()));
let c = Arc::new(Condvar::new());
loop {
let g = m.lock().unwrap();
let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap();
// spurious wakeups mean this isn't necessarily true
// so execute test again, if not timeout
if !no_timeout.timed_out() {
continue;
}
break;
}
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_while_wait() {
let m = Arc::new(Mutex::new(()));
let c = Arc::new(Condvar::new());
let g = m.lock().unwrap();
let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(1), |_| true).unwrap();
// no spurious wakeups. ensure it timed-out
assert!(wait.timed_out());
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_while_instant_satisfy() {
let m = Arc::new(Mutex::new(()));
let c = Arc::new(Condvar::new());
let g = m.lock().unwrap();
let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(0), |_| false).unwrap();
// ensure it didn't time-out even if we were not given any time.
assert!(!wait.timed_out());
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_while_wake() {
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair_copy = pair.clone();
let &(ref m, ref c) = &*pair;
let g = m.lock().unwrap();
let _t = thread::spawn(move || {
let &(ref lock, ref cvar) = &*pair_copy;
let mut started = lock.lock().unwrap();
thread::sleep(Duration::from_millis(1));
*started = true;
cvar.notify_one();
});
let (g2, wait) = c
.wait_timeout_while(g, Duration::from_millis(u64::MAX), |&mut notified| !notified)
.unwrap();
// ensure it didn't time-out even if we were not given any time.
assert!(!wait.timed_out());
assert!(*g2);
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_wake() {
let m = Arc::new(Mutex::new(()));
let c = Arc::new(Condvar::new());
loop {
let g = m.lock().unwrap();
let c2 = c.clone();
let m2 = m.clone();
let notified = Arc::new(AtomicBool::new(false));
let notified_copy = notified.clone();
let t = thread::spawn(move || {
let _g = m2.lock().unwrap();
thread::sleep(Duration::from_millis(1));
notified_copy.store(true, Ordering::SeqCst);
c2.notify_one();
});
let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap();
assert!(!timeout_res.timed_out());
// spurious wakeups mean this isn't necessarily true
// so execute test again, if not notified
if !notified.load(Ordering::SeqCst) {
t.join().unwrap();
continue;
}
drop(g);
t.join().unwrap();
break;
}
}
#[test]
#[should_panic]
#[cfg_attr(target_os = "emscripten", ignore)]
fn two_mutexes() {
let m = Arc::new(Mutex::new(()));
let m2 = m.clone();
let c = Arc::new(Condvar::new());
let c2 = c.clone();
let mut g = m.lock().unwrap();
let _t = thread::spawn(move || {
let _g = m2.lock().unwrap();
c2.notify_one();
});
g = c.wait(g).unwrap();
drop(g);
let m = Mutex::new(());
let _ = c.wait(m.lock().unwrap()).unwrap();
}
}

View file

@ -0,0 +1,211 @@
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sync::mpsc::channel;
use crate::sync::{Arc, Condvar, Mutex};
use crate::thread;
use crate::time::Duration;
#[test]
fn smoke() {
let c = Condvar::new();
c.notify_one();
c.notify_all();
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn notify_one() {
let m = Arc::new(Mutex::new(()));
let m2 = m.clone();
let c = Arc::new(Condvar::new());
let c2 = c.clone();
let g = m.lock().unwrap();
let _t = thread::spawn(move || {
let _g = m2.lock().unwrap();
c2.notify_one();
});
let g = c.wait(g).unwrap();
drop(g);
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn notify_all() {
const N: usize = 10;
let data = Arc::new((Mutex::new(0), Condvar::new()));
let (tx, rx) = channel();
for _ in 0..N {
let data = data.clone();
let tx = tx.clone();
thread::spawn(move || {
let &(ref lock, ref cond) = &*data;
let mut cnt = lock.lock().unwrap();
*cnt += 1;
if *cnt == N {
tx.send(()).unwrap();
}
while *cnt != 0 {
cnt = cond.wait(cnt).unwrap();
}
tx.send(()).unwrap();
});
}
drop(tx);
let &(ref lock, ref cond) = &*data;
rx.recv().unwrap();
let mut cnt = lock.lock().unwrap();
*cnt = 0;
cond.notify_all();
drop(cnt);
for _ in 0..N {
rx.recv().unwrap();
}
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_while() {
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair2 = pair.clone();
// Inside of our lock, spawn a new thread, and then wait for it to start.
thread::spawn(move || {
let &(ref lock, ref cvar) = &*pair2;
let mut started = lock.lock().unwrap();
*started = true;
// We notify the condvar that the value has changed.
cvar.notify_one();
});
// Wait for the thread to start up.
let &(ref lock, ref cvar) = &*pair;
let guard = cvar.wait_while(lock.lock().unwrap(), |started| !*started);
assert!(*guard.unwrap());
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_wait() {
let m = Arc::new(Mutex::new(()));
let c = Arc::new(Condvar::new());
loop {
let g = m.lock().unwrap();
let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap();
// spurious wakeups mean this isn't necessarily true
// so execute test again, if not timeout
if !no_timeout.timed_out() {
continue;
}
break;
}
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_while_wait() {
let m = Arc::new(Mutex::new(()));
let c = Arc::new(Condvar::new());
let g = m.lock().unwrap();
let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(1), |_| true).unwrap();
// no spurious wakeups. ensure it timed-out
assert!(wait.timed_out());
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_while_instant_satisfy() {
let m = Arc::new(Mutex::new(()));
let c = Arc::new(Condvar::new());
let g = m.lock().unwrap();
let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(0), |_| false).unwrap();
// ensure it didn't time-out even if we were not given any time.
assert!(!wait.timed_out());
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_while_wake() {
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair_copy = pair.clone();
let &(ref m, ref c) = &*pair;
let g = m.lock().unwrap();
let _t = thread::spawn(move || {
let &(ref lock, ref cvar) = &*pair_copy;
let mut started = lock.lock().unwrap();
thread::sleep(Duration::from_millis(1));
*started = true;
cvar.notify_one();
});
let (g2, wait) = c
.wait_timeout_while(g, Duration::from_millis(u64::MAX), |&mut notified| !notified)
.unwrap();
// ensure it didn't time-out even if we were not given any time.
assert!(!wait.timed_out());
assert!(*g2);
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_wake() {
let m = Arc::new(Mutex::new(()));
let c = Arc::new(Condvar::new());
loop {
let g = m.lock().unwrap();
let c2 = c.clone();
let m2 = m.clone();
let notified = Arc::new(AtomicBool::new(false));
let notified_copy = notified.clone();
let t = thread::spawn(move || {
let _g = m2.lock().unwrap();
thread::sleep(Duration::from_millis(1));
notified_copy.store(true, Ordering::SeqCst);
c2.notify_one();
});
let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap();
assert!(!timeout_res.timed_out());
// spurious wakeups mean this isn't necessarily true
// so execute test again, if not notified
if !notified.load(Ordering::SeqCst) {
t.join().unwrap();
continue;
}
drop(g);
t.join().unwrap();
break;
}
}
#[test]
#[should_panic]
#[cfg_attr(target_os = "emscripten", ignore)]
fn two_mutexes() {
let m = Arc::new(Mutex::new(()));
let m2 = m.clone();
let c = Arc::new(Condvar::new());
let c2 = c.clone();
let mut g = m.lock().unwrap();
let _t = thread::spawn(move || {
let _g = m2.lock().unwrap();
c2.notify_one();
});
g = c.wait(g).unwrap();
drop(g);
let m = Mutex::new(());
let _ = c.wait(m.lock().unwrap()).unwrap();
}

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,9 @@
// http://www.1024cores.net/home/lock-free-algorithms
// /queues/non-intrusive-mpsc-node-based-queue
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
pub use self::PopResult::*;
use core::cell::UnsafeCell;
@ -112,54 +115,3 @@ impl<T> Drop for Queue<T> {
}
}
}
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use super::{Data, Empty, Inconsistent, Queue};
use crate::sync::mpsc::channel;
use crate::sync::Arc;
use crate::thread;
#[test]
fn test_full() {
let q: Queue<Box<_>> = Queue::new();
q.push(box 1);
q.push(box 2);
}
#[test]
fn test() {
let nthreads = 8;
let nmsgs = 1000;
let q = Queue::new();
match q.pop() {
Empty => {}
Inconsistent | Data(..) => panic!(),
}
let (tx, rx) = channel();
let q = Arc::new(q);
for _ in 0..nthreads {
let tx = tx.clone();
let q = q.clone();
thread::spawn(move || {
for i in 0..nmsgs {
q.push(i);
}
tx.send(()).unwrap();
});
}
let mut i = 0;
while i < nthreads * nmsgs {
match q.pop() {
Empty | Inconsistent => {}
Data(_) => i += 1,
}
}
drop(tx);
for _ in 0..nthreads {
rx.recv().unwrap();
}
}
}

View file

@ -0,0 +1,47 @@
use super::{Data, Empty, Inconsistent, Queue};
use crate::sync::mpsc::channel;
use crate::sync::Arc;
use crate::thread;
#[test]
fn test_full() {
let q: Queue<Box<_>> = Queue::new();
q.push(box 1);
q.push(box 2);
}
#[test]
fn test() {
let nthreads = 8;
let nmsgs = 1000;
let q = Queue::new();
match q.pop() {
Empty => {}
Inconsistent | Data(..) => panic!(),
}
let (tx, rx) = channel();
let q = Arc::new(q);
for _ in 0..nthreads {
let tx = tx.clone();
let q = q.clone();
thread::spawn(move || {
for i in 0..nmsgs {
q.push(i);
}
tx.send(()).unwrap();
});
}
let mut i = 0;
while i < nthreads * nmsgs {
match q.pop() {
Empty | Inconsistent => {}
Data(_) => i += 1,
}
}
drop(tx);
for _ in 0..nthreads {
rx.recv().unwrap();
}
}

View file

@ -6,6 +6,9 @@
// http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
use core::cell::UnsafeCell;
use core::ptr;
@ -231,108 +234,3 @@ impl<T, ProducerAddition, ConsumerAddition> Drop for Queue<T, ProducerAddition,
}
}
}
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use super::Queue;
use crate::sync::mpsc::channel;
use crate::sync::Arc;
use crate::thread;
#[test]
fn smoke() {
unsafe {
let queue = Queue::with_additions(0, (), ());
queue.push(1);
queue.push(2);
assert_eq!(queue.pop(), Some(1));
assert_eq!(queue.pop(), Some(2));
assert_eq!(queue.pop(), None);
queue.push(3);
queue.push(4);
assert_eq!(queue.pop(), Some(3));
assert_eq!(queue.pop(), Some(4));
assert_eq!(queue.pop(), None);
}
}
#[test]
fn peek() {
unsafe {
let queue = Queue::with_additions(0, (), ());
queue.push(vec![1]);
// Ensure the borrowchecker works
match queue.peek() {
Some(vec) => {
assert_eq!(&*vec, &[1]);
}
None => unreachable!(),
}
match queue.pop() {
Some(vec) => {
assert_eq!(&*vec, &[1]);
}
None => unreachable!(),
}
}
}
#[test]
fn drop_full() {
unsafe {
let q: Queue<Box<_>> = Queue::with_additions(0, (), ());
q.push(box 1);
q.push(box 2);
}
}
#[test]
fn smoke_bound() {
unsafe {
let q = Queue::with_additions(0, (), ());
q.push(1);
q.push(2);
assert_eq!(q.pop(), Some(1));
assert_eq!(q.pop(), Some(2));
assert_eq!(q.pop(), None);
q.push(3);
q.push(4);
assert_eq!(q.pop(), Some(3));
assert_eq!(q.pop(), Some(4));
assert_eq!(q.pop(), None);
}
}
#[test]
fn stress() {
unsafe {
stress_bound(0);
stress_bound(1);
}
unsafe fn stress_bound(bound: usize) {
let q = Arc::new(Queue::with_additions(bound, (), ()));
let (tx, rx) = channel();
let q2 = q.clone();
let _t = thread::spawn(move || {
for _ in 0..100000 {
loop {
match q2.pop() {
Some(1) => break,
Some(_) => panic!(),
None => {}
}
}
}
tx.send(()).unwrap();
});
for _ in 0..100000 {
q.push(1);
}
rx.recv().unwrap();
}
}
}

View file

@ -0,0 +1,101 @@
use super::Queue;
use crate::sync::mpsc::channel;
use crate::sync::Arc;
use crate::thread;
#[test]
fn smoke() {
unsafe {
let queue = Queue::with_additions(0, (), ());
queue.push(1);
queue.push(2);
assert_eq!(queue.pop(), Some(1));
assert_eq!(queue.pop(), Some(2));
assert_eq!(queue.pop(), None);
queue.push(3);
queue.push(4);
assert_eq!(queue.pop(), Some(3));
assert_eq!(queue.pop(), Some(4));
assert_eq!(queue.pop(), None);
}
}
#[test]
fn peek() {
unsafe {
let queue = Queue::with_additions(0, (), ());
queue.push(vec![1]);
// Ensure the borrowchecker works
match queue.peek() {
Some(vec) => {
assert_eq!(&*vec, &[1]);
}
None => unreachable!(),
}
match queue.pop() {
Some(vec) => {
assert_eq!(&*vec, &[1]);
}
None => unreachable!(),
}
}
}
#[test]
fn drop_full() {
unsafe {
let q: Queue<Box<_>> = Queue::with_additions(0, (), ());
q.push(box 1);
q.push(box 2);
}
}
#[test]
fn smoke_bound() {
unsafe {
let q = Queue::with_additions(0, (), ());
q.push(1);
q.push(2);
assert_eq!(q.pop(), Some(1));
assert_eq!(q.pop(), Some(2));
assert_eq!(q.pop(), None);
q.push(3);
q.push(4);
assert_eq!(q.pop(), Some(3));
assert_eq!(q.pop(), Some(4));
assert_eq!(q.pop(), None);
}
}
#[test]
fn stress() {
unsafe {
stress_bound(0);
stress_bound(1);
}
unsafe fn stress_bound(bound: usize) {
let q = Arc::new(Queue::with_additions(bound, (), ()));
let (tx, rx) = channel();
let q2 = q.clone();
let _t = thread::spawn(move || {
for _ in 0..100000 {
loop {
match q2.pop() {
Some(1) => break,
Some(_) => panic!(),
None => {}
}
}
}
tx.send(()).unwrap();
});
for _ in 0..100000 {
q.push(1);
}
rx.recv().unwrap();
}
}

View file

@ -0,0 +1,647 @@
use super::*;
use crate::env;
use crate::thread;
use crate::time::Duration;
pub fn stress_factor() -> usize {
match env::var("RUST_TEST_STRESS") {
Ok(val) => val.parse().unwrap(),
Err(..) => 1,
}
}
#[test]
fn smoke() {
let (tx, rx) = sync_channel::<i32>(1);
tx.send(1).unwrap();
assert_eq!(rx.recv().unwrap(), 1);
}
#[test]
fn drop_full() {
let (tx, _rx) = sync_channel::<Box<isize>>(1);
tx.send(box 1).unwrap();
}
#[test]
fn smoke_shared() {
let (tx, rx) = sync_channel::<i32>(1);
tx.send(1).unwrap();
assert_eq!(rx.recv().unwrap(), 1);
let tx = tx.clone();
tx.send(1).unwrap();
assert_eq!(rx.recv().unwrap(), 1);
}
#[test]
fn recv_timeout() {
let (tx, rx) = sync_channel::<i32>(1);
assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
tx.send(1).unwrap();
assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1));
}
#[test]
fn smoke_threads() {
let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move || {
tx.send(1).unwrap();
});
assert_eq!(rx.recv().unwrap(), 1);
}
#[test]
fn smoke_port_gone() {
let (tx, rx) = sync_channel::<i32>(0);
drop(rx);
assert!(tx.send(1).is_err());
}
#[test]
fn smoke_shared_port_gone2() {
let (tx, rx) = sync_channel::<i32>(0);
drop(rx);
let tx2 = tx.clone();
drop(tx);
assert!(tx2.send(1).is_err());
}
#[test]
fn port_gone_concurrent() {
let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move || {
rx.recv().unwrap();
});
while tx.send(1).is_ok() {}
}
#[test]
fn port_gone_concurrent_shared() {
let (tx, rx) = sync_channel::<i32>(0);
let tx2 = tx.clone();
let _t = thread::spawn(move || {
rx.recv().unwrap();
});
while tx.send(1).is_ok() && tx2.send(1).is_ok() {}
}
#[test]
fn smoke_chan_gone() {
let (tx, rx) = sync_channel::<i32>(0);
drop(tx);
assert!(rx.recv().is_err());
}
#[test]
fn smoke_chan_gone_shared() {
let (tx, rx) = sync_channel::<()>(0);
let tx2 = tx.clone();
drop(tx);
drop(tx2);
assert!(rx.recv().is_err());
}
#[test]
fn chan_gone_concurrent() {
let (tx, rx) = sync_channel::<i32>(0);
thread::spawn(move || {
tx.send(1).unwrap();
tx.send(1).unwrap();
});
while rx.recv().is_ok() {}
}
#[test]
fn stress() {
let (tx, rx) = sync_channel::<i32>(0);
thread::spawn(move || {
for _ in 0..10000 {
tx.send(1).unwrap();
}
});
for _ in 0..10000 {
assert_eq!(rx.recv().unwrap(), 1);
}
}
#[test]
fn stress_recv_timeout_two_threads() {
let (tx, rx) = sync_channel::<i32>(0);
thread::spawn(move || {
for _ in 0..10000 {
tx.send(1).unwrap();
}
});
let mut recv_count = 0;
loop {
match rx.recv_timeout(Duration::from_millis(1)) {
Ok(v) => {
assert_eq!(v, 1);
recv_count += 1;
}
Err(RecvTimeoutError::Timeout) => continue,
Err(RecvTimeoutError::Disconnected) => break,
}
}
assert_eq!(recv_count, 10000);
}
#[test]
fn stress_recv_timeout_shared() {
const AMT: u32 = 1000;
const NTHREADS: u32 = 8;
let (tx, rx) = sync_channel::<i32>(0);
let (dtx, drx) = sync_channel::<()>(0);
thread::spawn(move || {
let mut recv_count = 0;
loop {
match rx.recv_timeout(Duration::from_millis(10)) {
Ok(v) => {
assert_eq!(v, 1);
recv_count += 1;
}
Err(RecvTimeoutError::Timeout) => continue,
Err(RecvTimeoutError::Disconnected) => break,
}
}
assert_eq!(recv_count, AMT * NTHREADS);
assert!(rx.try_recv().is_err());
dtx.send(()).unwrap();
});
for _ in 0..NTHREADS {
let tx = tx.clone();
thread::spawn(move || {
for _ in 0..AMT {
tx.send(1).unwrap();
}
});
}
drop(tx);
drx.recv().unwrap();
}
#[test]
fn stress_shared() {
const AMT: u32 = 1000;
const NTHREADS: u32 = 8;
let (tx, rx) = sync_channel::<i32>(0);
let (dtx, drx) = sync_channel::<()>(0);
thread::spawn(move || {
for _ in 0..AMT * NTHREADS {
assert_eq!(rx.recv().unwrap(), 1);
}
match rx.try_recv() {
Ok(..) => panic!(),
_ => {}
}
dtx.send(()).unwrap();
});
for _ in 0..NTHREADS {
let tx = tx.clone();
thread::spawn(move || {
for _ in 0..AMT {
tx.send(1).unwrap();
}
});
}
drop(tx);
drx.recv().unwrap();
}
#[test]
fn oneshot_single_thread_close_port_first() {
// Simple test of closing without sending
let (_tx, rx) = sync_channel::<i32>(0);
drop(rx);
}
#[test]
fn oneshot_single_thread_close_chan_first() {
// Simple test of closing without sending
let (tx, _rx) = sync_channel::<i32>(0);
drop(tx);
}
#[test]
fn oneshot_single_thread_send_port_close() {
// Testing that the sender cleans up the payload if receiver is closed
let (tx, rx) = sync_channel::<Box<i32>>(0);
drop(rx);
assert!(tx.send(box 0).is_err());
}
#[test]
fn oneshot_single_thread_recv_chan_close() {
// Receiving on a closed chan will panic
let res = thread::spawn(move || {
let (tx, rx) = sync_channel::<i32>(0);
drop(tx);
rx.recv().unwrap();
})
.join();
// What is our res?
assert!(res.is_err());
}
#[test]
fn oneshot_single_thread_send_then_recv() {
let (tx, rx) = sync_channel::<Box<i32>>(1);
tx.send(box 10).unwrap();
assert!(*rx.recv().unwrap() == 10);
}
#[test]
fn oneshot_single_thread_try_send_open() {
let (tx, rx) = sync_channel::<i32>(1);
assert_eq!(tx.try_send(10), Ok(()));
assert!(rx.recv().unwrap() == 10);
}
#[test]
fn oneshot_single_thread_try_send_closed() {
let (tx, rx) = sync_channel::<i32>(0);
drop(rx);
assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10)));
}
#[test]
fn oneshot_single_thread_try_send_closed2() {
let (tx, _rx) = sync_channel::<i32>(0);
assert_eq!(tx.try_send(10), Err(TrySendError::Full(10)));
}
#[test]
fn oneshot_single_thread_try_recv_open() {
let (tx, rx) = sync_channel::<i32>(1);
tx.send(10).unwrap();
assert!(rx.recv() == Ok(10));
}
#[test]
fn oneshot_single_thread_try_recv_closed() {
let (tx, rx) = sync_channel::<i32>(0);
drop(tx);
assert!(rx.recv().is_err());
}
#[test]
fn oneshot_single_thread_try_recv_closed_with_data() {
let (tx, rx) = sync_channel::<i32>(1);
tx.send(10).unwrap();
drop(tx);
assert_eq!(rx.try_recv(), Ok(10));
assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
}
#[test]
fn oneshot_single_thread_peek_data() {
let (tx, rx) = sync_channel::<i32>(1);
assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
tx.send(10).unwrap();
assert_eq!(rx.try_recv(), Ok(10));
}
#[test]
fn oneshot_single_thread_peek_close() {
let (tx, rx) = sync_channel::<i32>(0);
drop(tx);
assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
}
#[test]
fn oneshot_single_thread_peek_open() {
let (_tx, rx) = sync_channel::<i32>(0);
assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
}
#[test]
fn oneshot_multi_task_recv_then_send() {
let (tx, rx) = sync_channel::<Box<i32>>(0);
let _t = thread::spawn(move || {
assert!(*rx.recv().unwrap() == 10);
});
tx.send(box 10).unwrap();
}
#[test]
fn oneshot_multi_task_recv_then_close() {
let (tx, rx) = sync_channel::<Box<i32>>(0);
let _t = thread::spawn(move || {
drop(tx);
});
let res = thread::spawn(move || {
assert!(*rx.recv().unwrap() == 10);
})
.join();
assert!(res.is_err());
}
#[test]
fn oneshot_multi_thread_close_stress() {
for _ in 0..stress_factor() {
let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move || {
drop(rx);
});
drop(tx);
}
}
#[test]
fn oneshot_multi_thread_send_close_stress() {
for _ in 0..stress_factor() {
let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move || {
drop(rx);
});
let _ = thread::spawn(move || {
tx.send(1).unwrap();
})
.join();
}
}
#[test]
fn oneshot_multi_thread_recv_close_stress() {
for _ in 0..stress_factor() {
let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move || {
let res = thread::spawn(move || {
rx.recv().unwrap();
})
.join();
assert!(res.is_err());
});
let _t = thread::spawn(move || {
thread::spawn(move || {
drop(tx);
});
});
}
}
#[test]
fn oneshot_multi_thread_send_recv_stress() {
for _ in 0..stress_factor() {
let (tx, rx) = sync_channel::<Box<i32>>(0);
let _t = thread::spawn(move || {
tx.send(box 10).unwrap();
});
assert!(*rx.recv().unwrap() == 10);
}
}
#[test]
fn stream_send_recv_stress() {
for _ in 0..stress_factor() {
let (tx, rx) = sync_channel::<Box<i32>>(0);
send(tx, 0);
recv(rx, 0);
fn send(tx: SyncSender<Box<i32>>, i: i32) {
if i == 10 {
return;
}
thread::spawn(move || {
tx.send(box i).unwrap();
send(tx, i + 1);
});
}
fn recv(rx: Receiver<Box<i32>>, i: i32) {
if i == 10 {
return;
}
thread::spawn(move || {
assert!(*rx.recv().unwrap() == i);
recv(rx, i + 1);
});
}
}
}
#[test]
fn recv_a_lot() {
// Regression test that we don't run out of stack in scheduler context
let (tx, rx) = sync_channel(10000);
for _ in 0..10000 {
tx.send(()).unwrap();
}
for _ in 0..10000 {
rx.recv().unwrap();
}
}
#[test]
fn shared_chan_stress() {
let (tx, rx) = sync_channel(0);
let total = stress_factor() + 100;
for _ in 0..total {
let tx = tx.clone();
thread::spawn(move || {
tx.send(()).unwrap();
});
}
for _ in 0..total {
rx.recv().unwrap();
}
}
#[test]
fn test_nested_recv_iter() {
let (tx, rx) = sync_channel::<i32>(0);
let (total_tx, total_rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move || {
let mut acc = 0;
for x in rx.iter() {
acc += x;
}
total_tx.send(acc).unwrap();
});
tx.send(3).unwrap();
tx.send(1).unwrap();
tx.send(2).unwrap();
drop(tx);
assert_eq!(total_rx.recv().unwrap(), 6);
}
#[test]
fn test_recv_iter_break() {
let (tx, rx) = sync_channel::<i32>(0);
let (count_tx, count_rx) = sync_channel(0);
let _t = thread::spawn(move || {
let mut count = 0;
for x in rx.iter() {
if count >= 3 {
break;
} else {
count += x;
}
}
count_tx.send(count).unwrap();
});
tx.send(2).unwrap();
tx.send(2).unwrap();
tx.send(2).unwrap();
let _ = tx.try_send(2);
drop(tx);
assert_eq!(count_rx.recv().unwrap(), 4);
}
#[test]
fn try_recv_states() {
let (tx1, rx1) = sync_channel::<i32>(1);
let (tx2, rx2) = sync_channel::<()>(1);
let (tx3, rx3) = sync_channel::<()>(1);
let _t = thread::spawn(move || {
rx2.recv().unwrap();
tx1.send(1).unwrap();
tx3.send(()).unwrap();
rx2.recv().unwrap();
drop(tx1);
tx3.send(()).unwrap();
});
assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
tx2.send(()).unwrap();
rx3.recv().unwrap();
assert_eq!(rx1.try_recv(), Ok(1));
assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
tx2.send(()).unwrap();
rx3.recv().unwrap();
assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected));
}
// This bug used to end up in a livelock inside of the Receiver destructor
// because the internal state of the Shared packet was corrupted
#[test]
fn destroy_upgraded_shared_port_when_sender_still_active() {
let (tx, rx) = sync_channel::<()>(0);
let (tx2, rx2) = sync_channel::<()>(0);
let _t = thread::spawn(move || {
rx.recv().unwrap(); // wait on a oneshot
drop(rx); // destroy a shared
tx2.send(()).unwrap();
});
// make sure the other thread has gone to sleep
for _ in 0..5000 {
thread::yield_now();
}
// upgrade to a shared chan and send a message
let t = tx.clone();
drop(tx);
t.send(()).unwrap();
// wait for the child thread to exit before we exit
rx2.recv().unwrap();
}
#[test]
fn send1() {
let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move || {
rx.recv().unwrap();
});
assert_eq!(tx.send(1), Ok(()));
}
#[test]
fn send2() {
let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move || {
drop(rx);
});
assert!(tx.send(1).is_err());
}
#[test]
fn send3() {
let (tx, rx) = sync_channel::<i32>(1);
assert_eq!(tx.send(1), Ok(()));
let _t = thread::spawn(move || {
drop(rx);
});
assert!(tx.send(1).is_err());
}
#[test]
fn send4() {
let (tx, rx) = sync_channel::<i32>(0);
let tx2 = tx.clone();
let (done, donerx) = channel();
let done2 = done.clone();
let _t = thread::spawn(move || {
assert!(tx.send(1).is_err());
done.send(()).unwrap();
});
let _t = thread::spawn(move || {
assert!(tx2.send(2).is_err());
done2.send(()).unwrap();
});
drop(rx);
donerx.recv().unwrap();
donerx.recv().unwrap();
}
#[test]
fn try_send1() {
let (tx, _rx) = sync_channel::<i32>(0);
assert_eq!(tx.try_send(1), Err(TrySendError::Full(1)));
}
#[test]
fn try_send2() {
let (tx, _rx) = sync_channel::<i32>(1);
assert_eq!(tx.try_send(1), Ok(()));
assert_eq!(tx.try_send(1), Err(TrySendError::Full(1)));
}
#[test]
fn try_send3() {
let (tx, rx) = sync_channel::<i32>(1);
assert_eq!(tx.try_send(1), Ok(()));
drop(rx);
assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1)));
}
#[test]
fn issue_15761() {
fn repro() {
let (tx1, rx1) = sync_channel::<()>(3);
let (tx2, rx2) = sync_channel::<()>(3);
let _t = thread::spawn(move || {
rx1.recv().unwrap();
tx2.try_send(()).unwrap();
});
tx1.try_send(()).unwrap();
rx2.recv().unwrap();
}
for _ in 0..100 {
repro()
}
}

View file

@ -0,0 +1,706 @@
use super::*;
use crate::env;
use crate::thread;
use crate::time::{Duration, Instant};
pub fn stress_factor() -> usize {
match env::var("RUST_TEST_STRESS") {
Ok(val) => val.parse().unwrap(),
Err(..) => 1,
}
}
#[test]
fn smoke() {
let (tx, rx) = channel::<i32>();
tx.send(1).unwrap();
assert_eq!(rx.recv().unwrap(), 1);
}
#[test]
fn drop_full() {
let (tx, _rx) = channel::<Box<isize>>();
tx.send(box 1).unwrap();
}
#[test]
fn drop_full_shared() {
let (tx, _rx) = channel::<Box<isize>>();
drop(tx.clone());
drop(tx.clone());
tx.send(box 1).unwrap();
}
#[test]
fn smoke_shared() {
let (tx, rx) = channel::<i32>();
tx.send(1).unwrap();
assert_eq!(rx.recv().unwrap(), 1);
let tx = tx.clone();
tx.send(1).unwrap();
assert_eq!(rx.recv().unwrap(), 1);
}
#[test]
fn smoke_threads() {
let (tx, rx) = channel::<i32>();
let _t = thread::spawn(move || {
tx.send(1).unwrap();
});
assert_eq!(rx.recv().unwrap(), 1);
}
#[test]
fn smoke_port_gone() {
let (tx, rx) = channel::<i32>();
drop(rx);
assert!(tx.send(1).is_err());
}
#[test]
fn smoke_shared_port_gone() {
let (tx, rx) = channel::<i32>();
drop(rx);
assert!(tx.send(1).is_err())
}
#[test]
fn smoke_shared_port_gone2() {
let (tx, rx) = channel::<i32>();
drop(rx);
let tx2 = tx.clone();
drop(tx);
assert!(tx2.send(1).is_err());
}
#[test]
fn port_gone_concurrent() {
let (tx, rx) = channel::<i32>();
let _t = thread::spawn(move || {
rx.recv().unwrap();
});
while tx.send(1).is_ok() {}
}
#[test]
fn port_gone_concurrent_shared() {
let (tx, rx) = channel::<i32>();
let tx2 = tx.clone();
let _t = thread::spawn(move || {
rx.recv().unwrap();
});
while tx.send(1).is_ok() && tx2.send(1).is_ok() {}
}
#[test]
fn smoke_chan_gone() {
let (tx, rx) = channel::<i32>();
drop(tx);
assert!(rx.recv().is_err());
}
#[test]
fn smoke_chan_gone_shared() {
let (tx, rx) = channel::<()>();
let tx2 = tx.clone();
drop(tx);
drop(tx2);
assert!(rx.recv().is_err());
}
#[test]
fn chan_gone_concurrent() {
let (tx, rx) = channel::<i32>();
let _t = thread::spawn(move || {
tx.send(1).unwrap();
tx.send(1).unwrap();
});
while rx.recv().is_ok() {}
}
#[test]
fn stress() {
let (tx, rx) = channel::<i32>();
let t = thread::spawn(move || {
for _ in 0..10000 {
tx.send(1).unwrap();
}
});
for _ in 0..10000 {
assert_eq!(rx.recv().unwrap(), 1);
}
t.join().ok().expect("thread panicked");
}
#[test]
fn stress_shared() {
const AMT: u32 = 10000;
const NTHREADS: u32 = 8;
let (tx, rx) = channel::<i32>();
let t = thread::spawn(move || {
for _ in 0..AMT * NTHREADS {
assert_eq!(rx.recv().unwrap(), 1);
}
match rx.try_recv() {
Ok(..) => panic!(),
_ => {}
}
});
for _ in 0..NTHREADS {
let tx = tx.clone();
thread::spawn(move || {
for _ in 0..AMT {
tx.send(1).unwrap();
}
});
}
drop(tx);
t.join().ok().expect("thread panicked");
}
#[test]
fn send_from_outside_runtime() {
let (tx1, rx1) = channel::<()>();
let (tx2, rx2) = channel::<i32>();
let t1 = thread::spawn(move || {
tx1.send(()).unwrap();
for _ in 0..40 {
assert_eq!(rx2.recv().unwrap(), 1);
}
});
rx1.recv().unwrap();
let t2 = thread::spawn(move || {
for _ in 0..40 {
tx2.send(1).unwrap();
}
});
t1.join().ok().expect("thread panicked");
t2.join().ok().expect("thread panicked");
}
#[test]
fn recv_from_outside_runtime() {
let (tx, rx) = channel::<i32>();
let t = thread::spawn(move || {
for _ in 0..40 {
assert_eq!(rx.recv().unwrap(), 1);
}
});
for _ in 0..40 {
tx.send(1).unwrap();
}
t.join().ok().expect("thread panicked");
}
#[test]
fn no_runtime() {
let (tx1, rx1) = channel::<i32>();
let (tx2, rx2) = channel::<i32>();
let t1 = thread::spawn(move || {
assert_eq!(rx1.recv().unwrap(), 1);
tx2.send(2).unwrap();
});
let t2 = thread::spawn(move || {
tx1.send(1).unwrap();
assert_eq!(rx2.recv().unwrap(), 2);
});
t1.join().ok().expect("thread panicked");
t2.join().ok().expect("thread panicked");
}
#[test]
fn oneshot_single_thread_close_port_first() {
// Simple test of closing without sending
let (_tx, rx) = channel::<i32>();
drop(rx);
}
#[test]
fn oneshot_single_thread_close_chan_first() {
// Simple test of closing without sending
let (tx, _rx) = channel::<i32>();
drop(tx);
}
#[test]
fn oneshot_single_thread_send_port_close() {
// Testing that the sender cleans up the payload if receiver is closed
let (tx, rx) = channel::<Box<i32>>();
drop(rx);
assert!(tx.send(box 0).is_err());
}
#[test]
fn oneshot_single_thread_recv_chan_close() {
// Receiving on a closed chan will panic
let res = thread::spawn(move || {
let (tx, rx) = channel::<i32>();
drop(tx);
rx.recv().unwrap();
})
.join();
// What is our res?
assert!(res.is_err());
}
#[test]
fn oneshot_single_thread_send_then_recv() {
let (tx, rx) = channel::<Box<i32>>();
tx.send(box 10).unwrap();
assert!(*rx.recv().unwrap() == 10);
}
#[test]
fn oneshot_single_thread_try_send_open() {
let (tx, rx) = channel::<i32>();
assert!(tx.send(10).is_ok());
assert!(rx.recv().unwrap() == 10);
}
#[test]
fn oneshot_single_thread_try_send_closed() {
let (tx, rx) = channel::<i32>();
drop(rx);
assert!(tx.send(10).is_err());
}
#[test]
fn oneshot_single_thread_try_recv_open() {
let (tx, rx) = channel::<i32>();
tx.send(10).unwrap();
assert!(rx.recv() == Ok(10));
}
#[test]
fn oneshot_single_thread_try_recv_closed() {
let (tx, rx) = channel::<i32>();
drop(tx);
assert!(rx.recv().is_err());
}
#[test]
fn oneshot_single_thread_peek_data() {
let (tx, rx) = channel::<i32>();
assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
tx.send(10).unwrap();
assert_eq!(rx.try_recv(), Ok(10));
}
#[test]
fn oneshot_single_thread_peek_close() {
let (tx, rx) = channel::<i32>();
drop(tx);
assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
}
#[test]
fn oneshot_single_thread_peek_open() {
let (_tx, rx) = channel::<i32>();
assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
}
#[test]
fn oneshot_multi_task_recv_then_send() {
let (tx, rx) = channel::<Box<i32>>();
let _t = thread::spawn(move || {
assert!(*rx.recv().unwrap() == 10);
});
tx.send(box 10).unwrap();
}
#[test]
fn oneshot_multi_task_recv_then_close() {
let (tx, rx) = channel::<Box<i32>>();
let _t = thread::spawn(move || {
drop(tx);
});
let res = thread::spawn(move || {
assert!(*rx.recv().unwrap() == 10);
})
.join();
assert!(res.is_err());
}
#[test]
fn oneshot_multi_thread_close_stress() {
for _ in 0..stress_factor() {
let (tx, rx) = channel::<i32>();
let _t = thread::spawn(move || {
drop(rx);
});
drop(tx);
}
}
#[test]
fn oneshot_multi_thread_send_close_stress() {
for _ in 0..stress_factor() {
let (tx, rx) = channel::<i32>();
let _t = thread::spawn(move || {
drop(rx);
});
let _ = thread::spawn(move || {
tx.send(1).unwrap();
})
.join();
}
}
#[test]
fn oneshot_multi_thread_recv_close_stress() {
for _ in 0..stress_factor() {
let (tx, rx) = channel::<i32>();
thread::spawn(move || {
let res = thread::spawn(move || {
rx.recv().unwrap();
})
.join();
assert!(res.is_err());
});
let _t = thread::spawn(move || {
thread::spawn(move || {
drop(tx);
});
});
}
}
#[test]
fn oneshot_multi_thread_send_recv_stress() {
for _ in 0..stress_factor() {
let (tx, rx) = channel::<Box<isize>>();
let _t = thread::spawn(move || {
tx.send(box 10).unwrap();
});
assert!(*rx.recv().unwrap() == 10);
}
}
#[test]
fn stream_send_recv_stress() {
for _ in 0..stress_factor() {
let (tx, rx) = channel();
send(tx, 0);
recv(rx, 0);
fn send(tx: Sender<Box<i32>>, i: i32) {
if i == 10 {
return;
}
thread::spawn(move || {
tx.send(box i).unwrap();
send(tx, i + 1);
});
}
fn recv(rx: Receiver<Box<i32>>, i: i32) {
if i == 10 {
return;
}
thread::spawn(move || {
assert!(*rx.recv().unwrap() == i);
recv(rx, i + 1);
});
}
}
}
#[test]
fn oneshot_single_thread_recv_timeout() {
let (tx, rx) = channel();
tx.send(()).unwrap();
assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
tx.send(()).unwrap();
assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
}
#[test]
fn stress_recv_timeout_two_threads() {
let (tx, rx) = channel();
let stress = stress_factor() + 100;
let timeout = Duration::from_millis(100);
thread::spawn(move || {
for i in 0..stress {
if i % 2 == 0 {
thread::sleep(timeout * 2);
}
tx.send(1usize).unwrap();
}
});
let mut recv_count = 0;
loop {
match rx.recv_timeout(timeout) {
Ok(n) => {
assert_eq!(n, 1usize);
recv_count += 1;
}
Err(RecvTimeoutError::Timeout) => continue,
Err(RecvTimeoutError::Disconnected) => break,
}
}
assert_eq!(recv_count, stress);
}
#[test]
fn recv_timeout_upgrade() {
let (tx, rx) = channel::<()>();
let timeout = Duration::from_millis(1);
let _tx_clone = tx.clone();
let start = Instant::now();
assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout));
assert!(Instant::now() >= start + timeout);
}
#[test]
fn stress_recv_timeout_shared() {
let (tx, rx) = channel();
let stress = stress_factor() + 100;
for i in 0..stress {
let tx = tx.clone();
thread::spawn(move || {
thread::sleep(Duration::from_millis(i as u64 * 10));
tx.send(1usize).unwrap();
});
}
drop(tx);
let mut recv_count = 0;
loop {
match rx.recv_timeout(Duration::from_millis(10)) {
Ok(n) => {
assert_eq!(n, 1usize);
recv_count += 1;
}
Err(RecvTimeoutError::Timeout) => continue,
Err(RecvTimeoutError::Disconnected) => break,
}
}
assert_eq!(recv_count, stress);
}
#[test]
fn very_long_recv_timeout_wont_panic() {
let (tx, rx) = channel::<()>();
let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX)));
thread::sleep(Duration::from_secs(1));
assert!(tx.send(()).is_ok());
assert_eq!(join_handle.join().unwrap(), Ok(()));
}
#[test]
fn recv_a_lot() {
// Regression test that we don't run out of stack in scheduler context
let (tx, rx) = channel();
for _ in 0..10000 {
tx.send(()).unwrap();
}
for _ in 0..10000 {
rx.recv().unwrap();
}
}
#[test]
fn shared_recv_timeout() {
let (tx, rx) = channel();
let total = 5;
for _ in 0..total {
let tx = tx.clone();
thread::spawn(move || {
tx.send(()).unwrap();
});
}
for _ in 0..total {
rx.recv().unwrap();
}
assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
tx.send(()).unwrap();
assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
}
#[test]
fn shared_chan_stress() {
let (tx, rx) = channel();
let total = stress_factor() + 100;
for _ in 0..total {
let tx = tx.clone();
thread::spawn(move || {
tx.send(()).unwrap();
});
}
for _ in 0..total {
rx.recv().unwrap();
}
}
#[test]
fn test_nested_recv_iter() {
let (tx, rx) = channel::<i32>();
let (total_tx, total_rx) = channel::<i32>();
let _t = thread::spawn(move || {
let mut acc = 0;
for x in rx.iter() {
acc += x;
}
total_tx.send(acc).unwrap();
});
tx.send(3).unwrap();
tx.send(1).unwrap();
tx.send(2).unwrap();
drop(tx);
assert_eq!(total_rx.recv().unwrap(), 6);
}
#[test]
fn test_recv_iter_break() {
let (tx, rx) = channel::<i32>();
let (count_tx, count_rx) = channel();
let _t = thread::spawn(move || {
let mut count = 0;
for x in rx.iter() {
if count >= 3 {
break;
} else {
count += x;
}
}
count_tx.send(count).unwrap();
});
tx.send(2).unwrap();
tx.send(2).unwrap();
tx.send(2).unwrap();
let _ = tx.send(2);
drop(tx);
assert_eq!(count_rx.recv().unwrap(), 4);
}
#[test]
fn test_recv_try_iter() {
let (request_tx, request_rx) = channel();
let (response_tx, response_rx) = channel();
// Request `x`s until we have `6`.
let t = thread::spawn(move || {
let mut count = 0;
loop {
for x in response_rx.try_iter() {
count += x;
if count == 6 {
return count;
}
}
request_tx.send(()).unwrap();
}
});
for _ in request_rx.iter() {
if response_tx.send(2).is_err() {
break;
}
}
assert_eq!(t.join().unwrap(), 6);
}
#[test]
fn test_recv_into_iter_owned() {
let mut iter = {
let (tx, rx) = channel::<i32>();
tx.send(1).unwrap();
tx.send(2).unwrap();
rx.into_iter()
};
assert_eq!(iter.next().unwrap(), 1);
assert_eq!(iter.next().unwrap(), 2);
assert_eq!(iter.next().is_none(), true);
}
#[test]
fn test_recv_into_iter_borrowed() {
let (tx, rx) = channel::<i32>();
tx.send(1).unwrap();
tx.send(2).unwrap();
drop(tx);
let mut iter = (&rx).into_iter();
assert_eq!(iter.next().unwrap(), 1);
assert_eq!(iter.next().unwrap(), 2);
assert_eq!(iter.next().is_none(), true);
}
#[test]
fn try_recv_states() {
let (tx1, rx1) = channel::<i32>();
let (tx2, rx2) = channel::<()>();
let (tx3, rx3) = channel::<()>();
let _t = thread::spawn(move || {
rx2.recv().unwrap();
tx1.send(1).unwrap();
tx3.send(()).unwrap();
rx2.recv().unwrap();
drop(tx1);
tx3.send(()).unwrap();
});
assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
tx2.send(()).unwrap();
rx3.recv().unwrap();
assert_eq!(rx1.try_recv(), Ok(1));
assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
tx2.send(()).unwrap();
rx3.recv().unwrap();
assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected));
}
// This bug used to end up in a livelock inside of the Receiver destructor
// because the internal state of the Shared packet was corrupted
#[test]
fn destroy_upgraded_shared_port_when_sender_still_active() {
let (tx, rx) = channel();
let (tx2, rx2) = channel();
let _t = thread::spawn(move || {
rx.recv().unwrap(); // wait on a oneshot
drop(rx); // destroy a shared
tx2.send(()).unwrap();
});
// make sure the other thread has gone to sleep
for _ in 0..5000 {
thread::yield_now();
}
// upgrade to a shared chan and send a message
let t = tx.clone();
drop(tx);
t.send(()).unwrap();
// wait for the child thread to exit before we exit
rx2.recv().unwrap();
}
#[test]
fn issue_32114() {
let (tx, _) = channel();
let _ = tx.send(123);
assert_eq!(tx.send(123), Err(SendError(123)));
}

View file

@ -1,3 +1,6 @@
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::mem;
@ -515,245 +518,3 @@ pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
&guard.lock.poison
}
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::mpsc::channel;
use crate::sync::{Arc, Condvar, Mutex};
use crate::thread;
struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
#[derive(Eq, PartialEq, Debug)]
struct NonCopy(i32);
#[test]
fn smoke() {
let m = Mutex::new(());
drop(m.lock().unwrap());
drop(m.lock().unwrap());
}
#[test]
fn lots_and_lots() {
const J: u32 = 1000;
const K: u32 = 3;
let m = Arc::new(Mutex::new(0));
fn inc(m: &Mutex<u32>) {
for _ in 0..J {
*m.lock().unwrap() += 1;
}
}
let (tx, rx) = channel();
for _ in 0..K {
let tx2 = tx.clone();
let m2 = m.clone();
thread::spawn(move || {
inc(&m2);
tx2.send(()).unwrap();
});
let tx2 = tx.clone();
let m2 = m.clone();
thread::spawn(move || {
inc(&m2);
tx2.send(()).unwrap();
});
}
drop(tx);
for _ in 0..2 * K {
rx.recv().unwrap();
}
assert_eq!(*m.lock().unwrap(), J * K * 2);
}
#[test]
fn try_lock() {
let m = Mutex::new(());
*m.try_lock().unwrap() = ();
}
#[test]
fn test_into_inner() {
let m = Mutex::new(NonCopy(10));
assert_eq!(m.into_inner().unwrap(), NonCopy(10));
}
#[test]
fn test_into_inner_drop() {
struct Foo(Arc<AtomicUsize>);
impl Drop for Foo {
fn drop(&mut self) {
self.0.fetch_add(1, Ordering::SeqCst);
}
}
let num_drops = Arc::new(AtomicUsize::new(0));
let m = Mutex::new(Foo(num_drops.clone()));
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
{
let _inner = m.into_inner().unwrap();
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
}
assert_eq!(num_drops.load(Ordering::SeqCst), 1);
}
#[test]
fn test_into_inner_poison() {
let m = Arc::new(Mutex::new(NonCopy(10)));
let m2 = m.clone();
let _ = thread::spawn(move || {
let _lock = m2.lock().unwrap();
panic!("test panic in inner thread to poison mutex");
})
.join();
assert!(m.is_poisoned());
match Arc::try_unwrap(m).unwrap().into_inner() {
Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x),
}
}
#[test]
fn test_get_mut() {
let mut m = Mutex::new(NonCopy(10));
*m.get_mut().unwrap() = NonCopy(20);
assert_eq!(m.into_inner().unwrap(), NonCopy(20));
}
#[test]
fn test_get_mut_poison() {
let m = Arc::new(Mutex::new(NonCopy(10)));
let m2 = m.clone();
let _ = thread::spawn(move || {
let _lock = m2.lock().unwrap();
panic!("test panic in inner thread to poison mutex");
})
.join();
assert!(m.is_poisoned());
match Arc::try_unwrap(m).unwrap().get_mut() {
Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x),
}
}
#[test]
fn test_mutex_arc_condvar() {
let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
let packet2 = Packet(packet.0.clone());
let (tx, rx) = channel();
let _t = thread::spawn(move || {
// wait until parent gets in
rx.recv().unwrap();
let &(ref lock, ref cvar) = &*packet2.0;
let mut lock = lock.lock().unwrap();
*lock = true;
cvar.notify_one();
});
let &(ref lock, ref cvar) = &*packet.0;
let mut lock = lock.lock().unwrap();
tx.send(()).unwrap();
assert!(!*lock);
while !*lock {
lock = cvar.wait(lock).unwrap();
}
}
#[test]
fn test_arc_condvar_poison() {
let packet = Packet(Arc::new((Mutex::new(1), Condvar::new())));
let packet2 = Packet(packet.0.clone());
let (tx, rx) = channel();
let _t = thread::spawn(move || -> () {
rx.recv().unwrap();
let &(ref lock, ref cvar) = &*packet2.0;
let _g = lock.lock().unwrap();
cvar.notify_one();
// Parent should fail when it wakes up.
panic!();
});
let &(ref lock, ref cvar) = &*packet.0;
let mut lock = lock.lock().unwrap();
tx.send(()).unwrap();
while *lock == 1 {
match cvar.wait(lock) {
Ok(l) => {
lock = l;
assert_eq!(*lock, 1);
}
Err(..) => break,
}
}
}
#[test]
fn test_mutex_arc_poison() {
let arc = Arc::new(Mutex::new(1));
assert!(!arc.is_poisoned());
let arc2 = arc.clone();
let _ = thread::spawn(move || {
let lock = arc2.lock().unwrap();
assert_eq!(*lock, 2);
})
.join();
assert!(arc.lock().is_err());
assert!(arc.is_poisoned());
}
#[test]
fn test_mutex_arc_nested() {
// Tests nested mutexes and access
// to underlying data.
let arc = Arc::new(Mutex::new(1));
let arc2 = Arc::new(Mutex::new(arc));
let (tx, rx) = channel();
let _t = thread::spawn(move || {
let lock = arc2.lock().unwrap();
let lock2 = lock.lock().unwrap();
assert_eq!(*lock2, 1);
tx.send(()).unwrap();
});
rx.recv().unwrap();
}
#[test]
fn test_mutex_arc_access_in_unwind() {
let arc = Arc::new(Mutex::new(1));
let arc2 = arc.clone();
let _ = thread::spawn(move || -> () {
struct Unwinder {
i: Arc<Mutex<i32>>,
}
impl Drop for Unwinder {
fn drop(&mut self) {
*self.i.lock().unwrap() += 1;
}
}
let _u = Unwinder { i: arc2 };
panic!();
})
.join();
let lock = arc.lock().unwrap();
assert_eq!(*lock, 2);
}
#[test]
fn test_mutex_unsized() {
let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
{
let b = &mut *mutex.lock().unwrap();
b[0] = 4;
b[2] = 5;
}
let comp: &[i32] = &[4, 2, 5];
assert_eq!(&*mutex.lock().unwrap(), comp);
}
}

View file

@ -0,0 +1,238 @@
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::mpsc::channel;
use crate::sync::{Arc, Condvar, Mutex};
use crate::thread;
struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
#[derive(Eq, PartialEq, Debug)]
struct NonCopy(i32);
#[test]
fn smoke() {
let m = Mutex::new(());
drop(m.lock().unwrap());
drop(m.lock().unwrap());
}
#[test]
fn lots_and_lots() {
const J: u32 = 1000;
const K: u32 = 3;
let m = Arc::new(Mutex::new(0));
fn inc(m: &Mutex<u32>) {
for _ in 0..J {
*m.lock().unwrap() += 1;
}
}
let (tx, rx) = channel();
for _ in 0..K {
let tx2 = tx.clone();
let m2 = m.clone();
thread::spawn(move || {
inc(&m2);
tx2.send(()).unwrap();
});
let tx2 = tx.clone();
let m2 = m.clone();
thread::spawn(move || {
inc(&m2);
tx2.send(()).unwrap();
});
}
drop(tx);
for _ in 0..2 * K {
rx.recv().unwrap();
}
assert_eq!(*m.lock().unwrap(), J * K * 2);
}
#[test]
fn try_lock() {
let m = Mutex::new(());
*m.try_lock().unwrap() = ();
}
#[test]
fn test_into_inner() {
let m = Mutex::new(NonCopy(10));
assert_eq!(m.into_inner().unwrap(), NonCopy(10));
}
#[test]
fn test_into_inner_drop() {
struct Foo(Arc<AtomicUsize>);
impl Drop for Foo {
fn drop(&mut self) {
self.0.fetch_add(1, Ordering::SeqCst);
}
}
let num_drops = Arc::new(AtomicUsize::new(0));
let m = Mutex::new(Foo(num_drops.clone()));
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
{
let _inner = m.into_inner().unwrap();
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
}
assert_eq!(num_drops.load(Ordering::SeqCst), 1);
}
#[test]
fn test_into_inner_poison() {
let m = Arc::new(Mutex::new(NonCopy(10)));
let m2 = m.clone();
let _ = thread::spawn(move || {
let _lock = m2.lock().unwrap();
panic!("test panic in inner thread to poison mutex");
})
.join();
assert!(m.is_poisoned());
match Arc::try_unwrap(m).unwrap().into_inner() {
Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x),
}
}
#[test]
fn test_get_mut() {
let mut m = Mutex::new(NonCopy(10));
*m.get_mut().unwrap() = NonCopy(20);
assert_eq!(m.into_inner().unwrap(), NonCopy(20));
}
#[test]
fn test_get_mut_poison() {
let m = Arc::new(Mutex::new(NonCopy(10)));
let m2 = m.clone();
let _ = thread::spawn(move || {
let _lock = m2.lock().unwrap();
panic!("test panic in inner thread to poison mutex");
})
.join();
assert!(m.is_poisoned());
match Arc::try_unwrap(m).unwrap().get_mut() {
Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x),
}
}
#[test]
fn test_mutex_arc_condvar() {
let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
let packet2 = Packet(packet.0.clone());
let (tx, rx) = channel();
let _t = thread::spawn(move || {
// wait until parent gets in
rx.recv().unwrap();
let &(ref lock, ref cvar) = &*packet2.0;
let mut lock = lock.lock().unwrap();
*lock = true;
cvar.notify_one();
});
let &(ref lock, ref cvar) = &*packet.0;
let mut lock = lock.lock().unwrap();
tx.send(()).unwrap();
assert!(!*lock);
while !*lock {
lock = cvar.wait(lock).unwrap();
}
}
#[test]
fn test_arc_condvar_poison() {
let packet = Packet(Arc::new((Mutex::new(1), Condvar::new())));
let packet2 = Packet(packet.0.clone());
let (tx, rx) = channel();
let _t = thread::spawn(move || -> () {
rx.recv().unwrap();
let &(ref lock, ref cvar) = &*packet2.0;
let _g = lock.lock().unwrap();
cvar.notify_one();
// Parent should fail when it wakes up.
panic!();
});
let &(ref lock, ref cvar) = &*packet.0;
let mut lock = lock.lock().unwrap();
tx.send(()).unwrap();
while *lock == 1 {
match cvar.wait(lock) {
Ok(l) => {
lock = l;
assert_eq!(*lock, 1);
}
Err(..) => break,
}
}
}
#[test]
fn test_mutex_arc_poison() {
let arc = Arc::new(Mutex::new(1));
assert!(!arc.is_poisoned());
let arc2 = arc.clone();
let _ = thread::spawn(move || {
let lock = arc2.lock().unwrap();
assert_eq!(*lock, 2);
})
.join();
assert!(arc.lock().is_err());
assert!(arc.is_poisoned());
}
#[test]
fn test_mutex_arc_nested() {
// Tests nested mutexes and access
// to underlying data.
let arc = Arc::new(Mutex::new(1));
let arc2 = Arc::new(Mutex::new(arc));
let (tx, rx) = channel();
let _t = thread::spawn(move || {
let lock = arc2.lock().unwrap();
let lock2 = lock.lock().unwrap();
assert_eq!(*lock2, 1);
tx.send(()).unwrap();
});
rx.recv().unwrap();
}
#[test]
fn test_mutex_arc_access_in_unwind() {
let arc = Arc::new(Mutex::new(1));
let arc2 = arc.clone();
let _ = thread::spawn(move || -> () {
struct Unwinder {
i: Arc<Mutex<i32>>,
}
impl Drop for Unwinder {
fn drop(&mut self) {
*self.i.lock().unwrap() += 1;
}
}
let _u = Unwinder { i: arc2 };
panic!();
})
.join();
let lock = arc.lock().unwrap();
assert_eq!(*lock, 2);
}
#[test]
fn test_mutex_unsized() {
let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
{
let b = &mut *mutex.lock().unwrap();
b[0] = 4;
b[2] = 5;
}
let comp: &[i32] = &[4, 2, 5];
assert_eq!(&*mutex.lock().unwrap(), comp);
}

View file

@ -84,6 +84,9 @@
// processor. Because both use Acquire ordering such a reordering is not
// allowed, so no need for SeqCst.
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
use crate::cell::Cell;
use crate::fmt;
use crate::marker;
@ -568,123 +571,3 @@ impl OnceState {
self.set_state_on_drop_to.set(POISONED);
}
}
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use super::Once;
use crate::panic;
use crate::sync::mpsc::channel;
use crate::thread;
#[test]
fn smoke_once() {
static O: Once = Once::new();
let mut a = 0;
O.call_once(|| a += 1);
assert_eq!(a, 1);
O.call_once(|| a += 1);
assert_eq!(a, 1);
}
#[test]
fn stampede_once() {
static O: Once = Once::new();
static mut RUN: bool = false;
let (tx, rx) = channel();
for _ in 0..10 {
let tx = tx.clone();
thread::spawn(move || {
for _ in 0..4 {
thread::yield_now()
}
unsafe {
O.call_once(|| {
assert!(!RUN);
RUN = true;
});
assert!(RUN);
}
tx.send(()).unwrap();
});
}
unsafe {
O.call_once(|| {
assert!(!RUN);
RUN = true;
});
assert!(RUN);
}
for _ in 0..10 {
rx.recv().unwrap();
}
}
#[test]
fn poison_bad() {
static O: Once = Once::new();
// poison the once
let t = panic::catch_unwind(|| {
O.call_once(|| panic!());
});
assert!(t.is_err());
// poisoning propagates
let t = panic::catch_unwind(|| {
O.call_once(|| {});
});
assert!(t.is_err());
// we can subvert poisoning, however
let mut called = false;
O.call_once_force(|p| {
called = true;
assert!(p.poisoned())
});
assert!(called);
// once any success happens, we stop propagating the poison
O.call_once(|| {});
}
#[test]
fn wait_for_force_to_finish() {
static O: Once = Once::new();
// poison the once
let t = panic::catch_unwind(|| {
O.call_once(|| panic!());
});
assert!(t.is_err());
// make sure someone's waiting inside the once via a force
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let t1 = thread::spawn(move || {
O.call_once_force(|p| {
assert!(p.poisoned());
tx1.send(()).unwrap();
rx2.recv().unwrap();
});
});
rx1.recv().unwrap();
// put another waiter on the once
let t2 = thread::spawn(|| {
let mut called = false;
O.call_once(|| {
called = true;
});
assert!(!called);
});
tx2.send(()).unwrap();
assert!(t1.join().is_ok());
assert!(t2.join().is_ok());
}
}

View file

@ -0,0 +1,116 @@
use super::Once;
use crate::panic;
use crate::sync::mpsc::channel;
use crate::thread;
#[test]
fn smoke_once() {
static O: Once = Once::new();
let mut a = 0;
O.call_once(|| a += 1);
assert_eq!(a, 1);
O.call_once(|| a += 1);
assert_eq!(a, 1);
}
#[test]
fn stampede_once() {
static O: Once = Once::new();
static mut RUN: bool = false;
let (tx, rx) = channel();
for _ in 0..10 {
let tx = tx.clone();
thread::spawn(move || {
for _ in 0..4 {
thread::yield_now()
}
unsafe {
O.call_once(|| {
assert!(!RUN);
RUN = true;
});
assert!(RUN);
}
tx.send(()).unwrap();
});
}
unsafe {
O.call_once(|| {
assert!(!RUN);
RUN = true;
});
assert!(RUN);
}
for _ in 0..10 {
rx.recv().unwrap();
}
}
#[test]
fn poison_bad() {
static O: Once = Once::new();
// poison the once
let t = panic::catch_unwind(|| {
O.call_once(|| panic!());
});
assert!(t.is_err());
// poisoning propagates
let t = panic::catch_unwind(|| {
O.call_once(|| {});
});
assert!(t.is_err());
// we can subvert poisoning, however
let mut called = false;
O.call_once_force(|p| {
called = true;
assert!(p.poisoned())
});
assert!(called);
// once any success happens, we stop propagating the poison
O.call_once(|| {});
}
#[test]
fn wait_for_force_to_finish() {
static O: Once = Once::new();
// poison the once
let t = panic::catch_unwind(|| {
O.call_once(|| panic!());
});
assert!(t.is_err());
// make sure someone's waiting inside the once via a force
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let t1 = thread::spawn(move || {
O.call_once_force(|p| {
assert!(p.poisoned());
tx1.send(()).unwrap();
rx2.recv().unwrap();
});
});
rx1.recv().unwrap();
// put another waiter on the once
let t2 = thread::spawn(|| {
let mut called = false;
O.call_once(|| {
called = true;
});
assert!(!called);
});
tx2.send(()).unwrap();
assert!(t1.join().is_ok());
assert!(t2.join().is_ok());
}

View file

@ -1,3 +1,6 @@
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::mem;
@ -538,254 +541,3 @@ impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
}
}
}
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::mpsc::channel;
use crate::sync::{Arc, RwLock, TryLockError};
use crate::thread;
use rand::{self, Rng};
#[derive(Eq, PartialEq, Debug)]
struct NonCopy(i32);
#[test]
fn smoke() {
let l = RwLock::new(());
drop(l.read().unwrap());
drop(l.write().unwrap());
drop((l.read().unwrap(), l.read().unwrap()));
drop(l.write().unwrap());
}
#[test]
fn frob() {
const N: u32 = 10;
const M: usize = 1000;
let r = Arc::new(RwLock::new(()));
let (tx, rx) = channel::<()>();
for _ in 0..N {
let tx = tx.clone();
let r = r.clone();
thread::spawn(move || {
let mut rng = rand::thread_rng();
for _ in 0..M {
if rng.gen_bool(1.0 / (N as f64)) {
drop(r.write().unwrap());
} else {
drop(r.read().unwrap());
}
}
drop(tx);
});
}
drop(tx);
let _ = rx.recv();
}
#[test]
fn test_rw_arc_poison_wr() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.write().unwrap();
panic!();
})
.join();
assert!(arc.read().is_err());
}
#[test]
fn test_rw_arc_poison_ww() {
let arc = Arc::new(RwLock::new(1));
assert!(!arc.is_poisoned());
let arc2 = arc.clone();
let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.write().unwrap();
panic!();
})
.join();
assert!(arc.write().is_err());
assert!(arc.is_poisoned());
}
#[test]
fn test_rw_arc_no_poison_rr() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.read().unwrap();
panic!();
})
.join();
let lock = arc.read().unwrap();
assert_eq!(*lock, 1);
}
#[test]
fn test_rw_arc_no_poison_rw() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.read().unwrap();
panic!()
})
.join();
let lock = arc.write().unwrap();
assert_eq!(*lock, 1);
}
#[test]
fn test_rw_arc() {
let arc = Arc::new(RwLock::new(0));
let arc2 = arc.clone();
let (tx, rx) = channel();
thread::spawn(move || {
let mut lock = arc2.write().unwrap();
for _ in 0..10 {
let tmp = *lock;
*lock = -1;
thread::yield_now();
*lock = tmp + 1;
}
tx.send(()).unwrap();
});
// Readers try to catch the writer in the act
let mut children = Vec::new();
for _ in 0..5 {
let arc3 = arc.clone();
children.push(thread::spawn(move || {
let lock = arc3.read().unwrap();
assert!(*lock >= 0);
}));
}
// Wait for children to pass their asserts
for r in children {
assert!(r.join().is_ok());
}
// Wait for writer to finish
rx.recv().unwrap();
let lock = arc.read().unwrap();
assert_eq!(*lock, 10);
}
#[test]
fn test_rw_arc_access_in_unwind() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let _ = thread::spawn(move || -> () {
struct Unwinder {
i: Arc<RwLock<isize>>,
}
impl Drop for Unwinder {
fn drop(&mut self) {
let mut lock = self.i.write().unwrap();
*lock += 1;
}
}
let _u = Unwinder { i: arc2 };
panic!();
})
.join();
let lock = arc.read().unwrap();
assert_eq!(*lock, 2);
}
#[test]
fn test_rwlock_unsized() {
let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
{
let b = &mut *rw.write().unwrap();
b[0] = 4;
b[2] = 5;
}
let comp: &[i32] = &[4, 2, 5];
assert_eq!(&*rw.read().unwrap(), comp);
}
#[test]
fn test_rwlock_try_write() {
let lock = RwLock::new(0isize);
let read_guard = lock.read().unwrap();
let write_result = lock.try_write();
match write_result {
Err(TryLockError::WouldBlock) => (),
Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"),
Err(_) => assert!(false, "unexpected error"),
}
drop(read_guard);
}
#[test]
fn test_into_inner() {
let m = RwLock::new(NonCopy(10));
assert_eq!(m.into_inner().unwrap(), NonCopy(10));
}
#[test]
fn test_into_inner_drop() {
struct Foo(Arc<AtomicUsize>);
impl Drop for Foo {
fn drop(&mut self) {
self.0.fetch_add(1, Ordering::SeqCst);
}
}
let num_drops = Arc::new(AtomicUsize::new(0));
let m = RwLock::new(Foo(num_drops.clone()));
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
{
let _inner = m.into_inner().unwrap();
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
}
assert_eq!(num_drops.load(Ordering::SeqCst), 1);
}
#[test]
fn test_into_inner_poison() {
let m = Arc::new(RwLock::new(NonCopy(10)));
let m2 = m.clone();
let _ = thread::spawn(move || {
let _lock = m2.write().unwrap();
panic!("test panic in inner thread to poison RwLock");
})
.join();
assert!(m.is_poisoned());
match Arc::try_unwrap(m).unwrap().into_inner() {
Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x),
}
}
#[test]
fn test_get_mut() {
let mut m = RwLock::new(NonCopy(10));
*m.get_mut().unwrap() = NonCopy(20);
assert_eq!(m.into_inner().unwrap(), NonCopy(20));
}
#[test]
fn test_get_mut_poison() {
let m = Arc::new(RwLock::new(NonCopy(10)));
let m2 = m.clone();
let _ = thread::spawn(move || {
let _lock = m2.write().unwrap();
panic!("test panic in inner thread to poison RwLock");
})
.join();
assert!(m.is_poisoned());
match Arc::try_unwrap(m).unwrap().get_mut() {
Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x),
}
}
}

View file

@ -0,0 +1,247 @@
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::mpsc::channel;
use crate::sync::{Arc, RwLock, TryLockError};
use crate::thread;
use rand::{self, Rng};
#[derive(Eq, PartialEq, Debug)]
struct NonCopy(i32);
#[test]
fn smoke() {
let l = RwLock::new(());
drop(l.read().unwrap());
drop(l.write().unwrap());
drop((l.read().unwrap(), l.read().unwrap()));
drop(l.write().unwrap());
}
#[test]
fn frob() {
const N: u32 = 10;
const M: usize = 1000;
let r = Arc::new(RwLock::new(()));
let (tx, rx) = channel::<()>();
for _ in 0..N {
let tx = tx.clone();
let r = r.clone();
thread::spawn(move || {
let mut rng = rand::thread_rng();
for _ in 0..M {
if rng.gen_bool(1.0 / (N as f64)) {
drop(r.write().unwrap());
} else {
drop(r.read().unwrap());
}
}
drop(tx);
});
}
drop(tx);
let _ = rx.recv();
}
#[test]
fn test_rw_arc_poison_wr() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.write().unwrap();
panic!();
})
.join();
assert!(arc.read().is_err());
}
#[test]
fn test_rw_arc_poison_ww() {
let arc = Arc::new(RwLock::new(1));
assert!(!arc.is_poisoned());
let arc2 = arc.clone();
let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.write().unwrap();
panic!();
})
.join();
assert!(arc.write().is_err());
assert!(arc.is_poisoned());
}
#[test]
fn test_rw_arc_no_poison_rr() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.read().unwrap();
panic!();
})
.join();
let lock = arc.read().unwrap();
assert_eq!(*lock, 1);
}
#[test]
fn test_rw_arc_no_poison_rw() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.read().unwrap();
panic!()
})
.join();
let lock = arc.write().unwrap();
assert_eq!(*lock, 1);
}
#[test]
fn test_rw_arc() {
let arc = Arc::new(RwLock::new(0));
let arc2 = arc.clone();
let (tx, rx) = channel();
thread::spawn(move || {
let mut lock = arc2.write().unwrap();
for _ in 0..10 {
let tmp = *lock;
*lock = -1;
thread::yield_now();
*lock = tmp + 1;
}
tx.send(()).unwrap();
});
// Readers try to catch the writer in the act
let mut children = Vec::new();
for _ in 0..5 {
let arc3 = arc.clone();
children.push(thread::spawn(move || {
let lock = arc3.read().unwrap();
assert!(*lock >= 0);
}));
}
// Wait for children to pass their asserts
for r in children {
assert!(r.join().is_ok());
}
// Wait for writer to finish
rx.recv().unwrap();
let lock = arc.read().unwrap();
assert_eq!(*lock, 10);
}
#[test]
fn test_rw_arc_access_in_unwind() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let _ = thread::spawn(move || -> () {
struct Unwinder {
i: Arc<RwLock<isize>>,
}
impl Drop for Unwinder {
fn drop(&mut self) {
let mut lock = self.i.write().unwrap();
*lock += 1;
}
}
let _u = Unwinder { i: arc2 };
panic!();
})
.join();
let lock = arc.read().unwrap();
assert_eq!(*lock, 2);
}
#[test]
fn test_rwlock_unsized() {
let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
{
let b = &mut *rw.write().unwrap();
b[0] = 4;
b[2] = 5;
}
let comp: &[i32] = &[4, 2, 5];
assert_eq!(&*rw.read().unwrap(), comp);
}
#[test]
fn test_rwlock_try_write() {
let lock = RwLock::new(0isize);
let read_guard = lock.read().unwrap();
let write_result = lock.try_write();
match write_result {
Err(TryLockError::WouldBlock) => (),
Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"),
Err(_) => assert!(false, "unexpected error"),
}
drop(read_guard);
}
#[test]
fn test_into_inner() {
let m = RwLock::new(NonCopy(10));
assert_eq!(m.into_inner().unwrap(), NonCopy(10));
}
#[test]
fn test_into_inner_drop() {
struct Foo(Arc<AtomicUsize>);
impl Drop for Foo {
fn drop(&mut self) {
self.0.fetch_add(1, Ordering::SeqCst);
}
}
let num_drops = Arc::new(AtomicUsize::new(0));
let m = RwLock::new(Foo(num_drops.clone()));
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
{
let _inner = m.into_inner().unwrap();
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
}
assert_eq!(num_drops.load(Ordering::SeqCst), 1);
}
#[test]
fn test_into_inner_poison() {
let m = Arc::new(RwLock::new(NonCopy(10)));
let m2 = m.clone();
let _ = thread::spawn(move || {
let _lock = m2.write().unwrap();
panic!("test panic in inner thread to poison RwLock");
})
.join();
assert!(m.is_poisoned());
match Arc::try_unwrap(m).unwrap().into_inner() {
Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x),
}
}
#[test]
fn test_get_mut() {
let mut m = RwLock::new(NonCopy(10));
*m.get_mut().unwrap() = NonCopy(20);
assert_eq!(m.into_inner().unwrap(), NonCopy(20));
}
#[test]
fn test_get_mut_poison() {
let m = Arc::new(RwLock::new(NonCopy(10)));
let m2 = m.clone();
let _ = thread::spawn(move || {
let _lock = m2.write().unwrap();
panic!("test panic in inner thread to poison RwLock");
})
.join();
assert!(m.is_poisoned());
match Arc::try_unwrap(m).unwrap().get_mut() {
Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x),
}
}

View file

@ -1,3 +1,5 @@
mod sync_bitset;
use self::sync_bitset::*;
use crate::cell::Cell;
use crate::mem;
@ -125,117 +127,3 @@ impl Tls {
TLS_KEY_IN_USE.clear(key.to_index());
}
}
mod sync_bitset {
use super::{TLS_KEYS_BITSET_SIZE, USIZE_BITS};
use crate::iter::{Enumerate, Peekable};
use crate::slice::Iter;
use crate::sync::atomic::{AtomicUsize, Ordering};
/// A bitset that can be used synchronously.
pub(super) struct SyncBitset([AtomicUsize; TLS_KEYS_BITSET_SIZE]);
pub(super) const SYNC_BITSET_INIT: SyncBitset =
SyncBitset([AtomicUsize::new(0), AtomicUsize::new(0)]);
impl SyncBitset {
pub fn get(&self, index: usize) -> bool {
let (hi, lo) = Self::split(index);
(self.0[hi].load(Ordering::Relaxed) & lo) != 0
}
/// Not atomic.
pub fn iter(&self) -> SyncBitsetIter<'_> {
SyncBitsetIter { iter: self.0.iter().enumerate().peekable(), elem_idx: 0 }
}
pub fn clear(&self, index: usize) {
let (hi, lo) = Self::split(index);
self.0[hi].fetch_and(!lo, Ordering::Relaxed);
}
/// Sets any unset bit. Not atomic. Returns `None` if all bits were
/// observed to be set.
pub fn set(&self) -> Option<usize> {
'elems: for (idx, elem) in self.0.iter().enumerate() {
let mut current = elem.load(Ordering::Relaxed);
loop {
if 0 == !current {
continue 'elems;
}
let trailing_ones = (!current).trailing_zeros() as usize;
match elem.compare_exchange(
current,
current | (1 << trailing_ones),
Ordering::AcqRel,
Ordering::Relaxed,
) {
Ok(_) => return Some(idx * USIZE_BITS + trailing_ones),
Err(previous) => current = previous,
}
}
}
None
}
fn split(index: usize) -> (usize, usize) {
(index / USIZE_BITS, 1 << (index % USIZE_BITS))
}
}
pub(super) struct SyncBitsetIter<'a> {
iter: Peekable<Enumerate<Iter<'a, AtomicUsize>>>,
elem_idx: usize,
}
impl<'a> Iterator for SyncBitsetIter<'a> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
self.iter.peek().cloned().and_then(|(idx, elem)| {
let elem = elem.load(Ordering::Relaxed);
let low_mask = (1 << self.elem_idx) - 1;
let next = elem & !low_mask;
let next_idx = next.trailing_zeros() as usize;
self.elem_idx = next_idx + 1;
if self.elem_idx >= 64 {
self.elem_idx = 0;
self.iter.next();
}
match next_idx {
64 => self.next(),
_ => Some(idx * USIZE_BITS + next_idx),
}
})
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_data(bitset: [usize; 2], bit_indices: &[usize]) {
let set = SyncBitset([AtomicUsize::new(bitset[0]), AtomicUsize::new(bitset[1])]);
assert_eq!(set.iter().collect::<Vec<_>>(), bit_indices);
for &i in bit_indices {
assert!(set.get(i));
}
}
#[test]
fn iter() {
test_data([0b0110_1001, 0], &[0, 3, 5, 6]);
test_data([0x8000_0000_0000_0000, 0x8000_0000_0000_0001], &[63, 64, 127]);
test_data([0, 0], &[]);
}
#[test]
fn set_get_clear() {
let set = SYNC_BITSET_INIT;
let key = set.set().unwrap();
assert!(set.get(key));
set.clear(key);
assert!(!set.get(key));
}
}
}

View file

@ -0,0 +1,85 @@
#[cfg(test)]
mod tests;
use super::{TLS_KEYS_BITSET_SIZE, USIZE_BITS};
use crate::iter::{Enumerate, Peekable};
use crate::slice::Iter;
use crate::sync::atomic::{AtomicUsize, Ordering};
/// A bitset that can be used synchronously.
pub(super) struct SyncBitset([AtomicUsize; TLS_KEYS_BITSET_SIZE]);
pub(super) const SYNC_BITSET_INIT: SyncBitset =
SyncBitset([AtomicUsize::new(0), AtomicUsize::new(0)]);
impl SyncBitset {
pub fn get(&self, index: usize) -> bool {
let (hi, lo) = Self::split(index);
(self.0[hi].load(Ordering::Relaxed) & lo) != 0
}
/// Not atomic.
pub fn iter(&self) -> SyncBitsetIter<'_> {
SyncBitsetIter { iter: self.0.iter().enumerate().peekable(), elem_idx: 0 }
}
pub fn clear(&self, index: usize) {
let (hi, lo) = Self::split(index);
self.0[hi].fetch_and(!lo, Ordering::Relaxed);
}
/// Sets any unset bit. Not atomic. Returns `None` if all bits were
/// observed to be set.
pub fn set(&self) -> Option<usize> {
'elems: for (idx, elem) in self.0.iter().enumerate() {
let mut current = elem.load(Ordering::Relaxed);
loop {
if 0 == !current {
continue 'elems;
}
let trailing_ones = (!current).trailing_zeros() as usize;
match elem.compare_exchange(
current,
current | (1 << trailing_ones),
Ordering::AcqRel,
Ordering::Relaxed,
) {
Ok(_) => return Some(idx * USIZE_BITS + trailing_ones),
Err(previous) => current = previous,
}
}
}
None
}
fn split(index: usize) -> (usize, usize) {
(index / USIZE_BITS, 1 << (index % USIZE_BITS))
}
}
pub(super) struct SyncBitsetIter<'a> {
iter: Peekable<Enumerate<Iter<'a, AtomicUsize>>>,
elem_idx: usize,
}
impl<'a> Iterator for SyncBitsetIter<'a> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
self.iter.peek().cloned().and_then(|(idx, elem)| {
let elem = elem.load(Ordering::Relaxed);
let low_mask = (1 << self.elem_idx) - 1;
let next = elem & !low_mask;
let next_idx = next.trailing_zeros() as usize;
self.elem_idx = next_idx + 1;
if self.elem_idx >= 64 {
self.elem_idx = 0;
self.iter.next();
}
match next_idx {
64 => self.next(),
_ => Some(idx * USIZE_BITS + next_idx),
}
})
}
}

View file

@ -0,0 +1,25 @@
use super::*;
fn test_data(bitset: [usize; 2], bit_indices: &[usize]) {
let set = SyncBitset([AtomicUsize::new(bitset[0]), AtomicUsize::new(bitset[1])]);
assert_eq!(set.iter().collect::<Vec<_>>(), bit_indices);
for &i in bit_indices {
assert!(set.get(i));
}
}
#[test]
fn iter() {
test_data([0b0110_1001, 0], &[0, 3, 5, 6]);
test_data([0x8000_0000_0000_0000, 0x8000_0000_0000_0001], &[63, 64, 127]);
test_data([0, 0], &[]);
}
#[test]
fn set_get_clear() {
let set = SYNC_BITSET_INIT;
let key = set.set().unwrap();
assert!(set.get(key));
set.clear(key);
assert!(!set.get(key));
}

View file

@ -1,3 +1,6 @@
#[cfg(test)]
mod tests;
use crate::num::NonZeroUsize;
use super::waitqueue::{
@ -198,50 +201,3 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 {
(*p).unlock();
return 0;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mem::{self, MaybeUninit};
use core::array::FixedSizeArray;
// Verify that the bytes of initialized RWLock are the same as in
// libunwind. If they change, `src/UnwindRustSgx.h` in libunwind needs to
// be changed too.
#[test]
fn test_c_rwlock_initializer() {
#[rustfmt::skip]
const RWLOCK_INIT: &[u8] = &[
/* 0x00 */ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x10 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x20 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x30 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x40 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x50 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x60 */ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x70 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x80 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
];
#[inline(never)]
fn zero_stack() {
test::black_box(MaybeUninit::<[RWLock; 16]>::zeroed());
}
#[inline(never)]
unsafe fn rwlock_new(init: &mut MaybeUninit<RWLock>) {
init.write(RWLock::new());
}
unsafe {
// try hard to make sure that the padding/unused bytes in RWLock
// get initialized as 0. If the assertion below fails, that might
// just be an issue with the test code and not with the value of
// RWLOCK_INIT.
zero_stack();
let mut init = MaybeUninit::<RWLock>::zeroed();
rwlock_new(&mut init);
assert_eq!(mem::transmute::<_, [u8; 144]>(init.assume_init()).as_slice(), RWLOCK_INIT)
};
}
}

View file

@ -0,0 +1,43 @@
use super::*;
use crate::mem::{self, MaybeUninit};
use core::array::FixedSizeArray;
// Verify that the bytes of initialized RWLock are the same as in
// libunwind. If they change, `src/UnwindRustSgx.h` in libunwind needs to
// be changed too.
#[test]
fn test_c_rwlock_initializer() {
#[rustfmt::skip]
const RWLOCK_INIT: &[u8] = &[
/* 0x00 */ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x10 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x20 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x30 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x40 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x50 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x60 */ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x70 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x80 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
];
#[inline(never)]
fn zero_stack() {
test::black_box(MaybeUninit::<[RWLock; 16]>::zeroed());
}
#[inline(never)]
unsafe fn rwlock_new(init: &mut MaybeUninit<RWLock>) {
init.write(RWLock::new());
}
unsafe {
// try hard to make sure that the padding/unused bytes in RWLock
// get initialized as 0. If the assertion below fails, that might
// just be an issue with the test code and not with the value of
// RWLOCK_INIT.
zero_stack();
let mut init = MaybeUninit::<RWLock>::zeroed();
rwlock_new(&mut init);
assert_eq!(mem::transmute::<_, [u8; 144]>(init.assume_init()).as_slice(), RWLOCK_INIT)
};
}

View file

@ -9,6 +9,18 @@
//! Since userspace may send spurious wake-ups, the wakeup event state is
//! recorded in the enclave. The wakeup event state is protected by a spinlock.
//! The queue and associated wait state are stored in a `WaitVariable`.
#[cfg(test)]
mod tests;
/// A doubly-linked list where callers are in charge of memory allocation
/// of the nodes in the list.
mod unsafe_list;
/// Trivial spinlock-based implementation of `sync::Mutex`.
// FIXME: Perhaps use Intel TSX to avoid locking?
mod spin_mutex;
use crate::num::NonZeroUsize;
use crate::ops::{Deref, DerefMut};
use crate::time::Duration;
@ -231,389 +243,3 @@ impl WaitQueue {
}
}
}
/// A doubly-linked list where callers are in charge of memory allocation
/// of the nodes in the list.
mod unsafe_list {
use crate::mem;
use crate::ptr::NonNull;
pub struct UnsafeListEntry<T> {
next: NonNull<UnsafeListEntry<T>>,
prev: NonNull<UnsafeListEntry<T>>,
value: Option<T>,
}
impl<T> UnsafeListEntry<T> {
fn dummy() -> Self {
UnsafeListEntry { next: NonNull::dangling(), prev: NonNull::dangling(), value: None }
}
pub fn new(value: T) -> Self {
UnsafeListEntry { value: Some(value), ..Self::dummy() }
}
}
pub struct UnsafeList<T> {
head_tail: NonNull<UnsafeListEntry<T>>,
head_tail_entry: Option<UnsafeListEntry<T>>,
}
impl<T> UnsafeList<T> {
pub const fn new() -> Self {
unsafe {
UnsafeList { head_tail: NonNull::new_unchecked(1 as _), head_tail_entry: None }
}
}
unsafe fn init(&mut self) {
if self.head_tail_entry.is_none() {
self.head_tail_entry = Some(UnsafeListEntry::dummy());
self.head_tail = NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap());
self.head_tail.as_mut().next = self.head_tail;
self.head_tail.as_mut().prev = self.head_tail;
}
}
pub fn is_empty(&self) -> bool {
unsafe {
if self.head_tail_entry.is_some() {
let first = self.head_tail.as_ref().next;
if first == self.head_tail {
// ,-------> /---------\ next ---,
// | |head_tail| |
// `--- prev \---------/ <-------`
rtassert!(self.head_tail.as_ref().prev == first);
true
} else {
false
}
} else {
true
}
}
}
/// Pushes an entry onto the back of the list.
///
/// # Safety
///
/// The entry must remain allocated until the entry is removed from the
/// list AND the caller who popped is done using the entry. Special
/// care must be taken in the caller of `push` to ensure unwinding does
/// not destroy the stack frame containing the entry.
pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T {
self.init();
// BEFORE:
// /---------\ next ---> /---------\
// ... |prev_tail| |head_tail| ...
// \---------/ <--- prev \---------/
//
// AFTER:
// /---------\ next ---> /-----\ next ---> /---------\
// ... |prev_tail| |entry| |head_tail| ...
// \---------/ <--- prev \-----/ <--- prev \---------/
let mut entry = NonNull::new_unchecked(entry);
let mut prev_tail = mem::replace(&mut self.head_tail.as_mut().prev, entry);
entry.as_mut().prev = prev_tail;
entry.as_mut().next = self.head_tail;
prev_tail.as_mut().next = entry;
// unwrap ok: always `Some` on non-dummy entries
(*entry.as_ptr()).value.as_ref().unwrap()
}
/// Pops an entry from the front of the list.
///
/// # Safety
///
/// The caller must make sure to synchronize ending the borrow of the
/// return value and deallocation of the containing entry.
pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> {
self.init();
if self.is_empty() {
None
} else {
// BEFORE:
// /---------\ next ---> /-----\ next ---> /------\
// ... |head_tail| |first| |second| ...
// \---------/ <--- prev \-----/ <--- prev \------/
//
// AFTER:
// /---------\ next ---> /------\
// ... |head_tail| |second| ...
// \---------/ <--- prev \------/
let mut first = self.head_tail.as_mut().next;
let mut second = first.as_mut().next;
self.head_tail.as_mut().next = second;
second.as_mut().prev = self.head_tail;
first.as_mut().next = NonNull::dangling();
first.as_mut().prev = NonNull::dangling();
// unwrap ok: always `Some` on non-dummy entries
Some((*first.as_ptr()).value.as_ref().unwrap())
}
}
/// Removes an entry from the list.
///
/// # Safety
///
/// The caller must ensure that `entry` has been pushed onto `self`
/// prior to this call and has not moved since then.
pub unsafe fn remove(&mut self, entry: &mut UnsafeListEntry<T>) {
rtassert!(!self.is_empty());
// BEFORE:
// /----\ next ---> /-----\ next ---> /----\
// ... |prev| |entry| |next| ...
// \----/ <--- prev \-----/ <--- prev \----/
//
// AFTER:
// /----\ next ---> /----\
// ... |prev| |next| ...
// \----/ <--- prev \----/
let mut prev = entry.prev;
let mut next = entry.next;
prev.as_mut().next = next;
next.as_mut().prev = prev;
entry.next = NonNull::dangling();
entry.prev = NonNull::dangling();
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cell::Cell;
unsafe fn assert_empty<T>(list: &mut UnsafeList<T>) {
assert!(list.pop().is_none(), "assertion failed: list is not empty");
}
#[test]
fn init_empty() {
unsafe {
assert_empty(&mut UnsafeList::<i32>::new());
}
}
#[test]
fn push_pop() {
unsafe {
let mut node = UnsafeListEntry::new(1234);
let mut list = UnsafeList::new();
assert_eq!(list.push(&mut node), &1234);
assert_eq!(list.pop().unwrap(), &1234);
assert_empty(&mut list);
}
}
#[test]
fn push_remove() {
unsafe {
let mut node = UnsafeListEntry::new(1234);
let mut list = UnsafeList::new();
assert_eq!(list.push(&mut node), &1234);
list.remove(&mut node);
assert_empty(&mut list);
}
}
#[test]
fn push_remove_pop() {
unsafe {
let mut node1 = UnsafeListEntry::new(11);
let mut node2 = UnsafeListEntry::new(12);
let mut node3 = UnsafeListEntry::new(13);
let mut node4 = UnsafeListEntry::new(14);
let mut node5 = UnsafeListEntry::new(15);
let mut list = UnsafeList::new();
assert_eq!(list.push(&mut node1), &11);
assert_eq!(list.push(&mut node2), &12);
assert_eq!(list.push(&mut node3), &13);
assert_eq!(list.push(&mut node4), &14);
assert_eq!(list.push(&mut node5), &15);
list.remove(&mut node1);
assert_eq!(list.pop().unwrap(), &12);
list.remove(&mut node3);
assert_eq!(list.pop().unwrap(), &14);
list.remove(&mut node5);
assert_empty(&mut list);
assert_eq!(list.push(&mut node1), &11);
assert_eq!(list.pop().unwrap(), &11);
assert_empty(&mut list);
assert_eq!(list.push(&mut node3), &13);
assert_eq!(list.push(&mut node4), &14);
list.remove(&mut node3);
list.remove(&mut node4);
assert_empty(&mut list);
}
}
#[test]
fn complex_pushes_pops() {
unsafe {
let mut node1 = UnsafeListEntry::new(1234);
let mut node2 = UnsafeListEntry::new(4567);
let mut node3 = UnsafeListEntry::new(9999);
let mut node4 = UnsafeListEntry::new(8642);
let mut list = UnsafeList::new();
list.push(&mut node1);
list.push(&mut node2);
assert_eq!(list.pop().unwrap(), &1234);
list.push(&mut node3);
assert_eq!(list.pop().unwrap(), &4567);
assert_eq!(list.pop().unwrap(), &9999);
assert_empty(&mut list);
list.push(&mut node4);
assert_eq!(list.pop().unwrap(), &8642);
assert_empty(&mut list);
}
}
#[test]
fn cell() {
unsafe {
let mut node = UnsafeListEntry::new(Cell::new(0));
let mut list = UnsafeList::new();
let noderef = list.push(&mut node);
assert_eq!(noderef.get(), 0);
list.pop().unwrap().set(1);
assert_empty(&mut list);
assert_eq!(noderef.get(), 1);
}
}
}
}
/// Trivial spinlock-based implementation of `sync::Mutex`.
// FIXME: Perhaps use Intel TSX to avoid locking?
mod spin_mutex {
use crate::cell::UnsafeCell;
use crate::ops::{Deref, DerefMut};
use crate::sync::atomic::{spin_loop_hint, AtomicBool, Ordering};
#[derive(Default)]
pub struct SpinMutex<T> {
value: UnsafeCell<T>,
lock: AtomicBool,
}
unsafe impl<T: Send> Send for SpinMutex<T> {}
unsafe impl<T: Send> Sync for SpinMutex<T> {}
pub struct SpinMutexGuard<'a, T: 'a> {
mutex: &'a SpinMutex<T>,
}
impl<'a, T> !Send for SpinMutexGuard<'a, T> {}
unsafe impl<'a, T: Sync> Sync for SpinMutexGuard<'a, T> {}
impl<T> SpinMutex<T> {
pub const fn new(value: T) -> Self {
SpinMutex { value: UnsafeCell::new(value), lock: AtomicBool::new(false) }
}
#[inline(always)]
pub fn lock(&self) -> SpinMutexGuard<'_, T> {
loop {
match self.try_lock() {
None => {
while self.lock.load(Ordering::Relaxed) {
spin_loop_hint()
}
}
Some(guard) => return guard,
}
}
}
#[inline(always)]
pub fn try_lock(&self) -> Option<SpinMutexGuard<'_, T>> {
if !self.lock.compare_and_swap(false, true, Ordering::Acquire) {
Some(SpinMutexGuard { mutex: self })
} else {
None
}
}
}
/// Lock the Mutex or return false.
pub macro try_lock_or_false($e:expr) {
if let Some(v) = $e.try_lock() { v } else { return false }
}
impl<'a, T> Deref for SpinMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.mutex.value.get() }
}
}
impl<'a, T> DerefMut for SpinMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.mutex.value.get() }
}
}
impl<'a, T> Drop for SpinMutexGuard<'a, T> {
fn drop(&mut self) {
self.mutex.lock.store(false, Ordering::Release)
}
}
#[cfg(test)]
mod tests {
#![allow(deprecated)]
use super::*;
use crate::sync::Arc;
use crate::thread;
use crate::time::Duration;
#[test]
fn sleep() {
let mutex = Arc::new(SpinMutex::<i32>::default());
let mutex2 = mutex.clone();
let guard = mutex.lock();
let t1 = thread::spawn(move || {
*mutex2.lock() = 1;
});
thread::sleep(Duration::from_millis(50));
assert_eq!(*guard, 0);
drop(guard);
t1.join().unwrap();
assert_eq!(*mutex.lock(), 1);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::sync::Arc;
use crate::thread;
#[test]
fn queue() {
let wq = Arc::new(SpinMutex::<WaitVariable<()>>::default());
let wq2 = wq.clone();
let locked = wq.lock();
let t1 = thread::spawn(move || {
// if we obtain the lock, the main thread should be waiting
assert!(WaitQueue::notify_one(wq2.lock()).is_ok());
});
WaitQueue::wait(locked, || {});
t1.join().unwrap();
}
}

View file

@ -0,0 +1,76 @@
#[cfg(test)]
mod tests;
use crate::cell::UnsafeCell;
use crate::ops::{Deref, DerefMut};
use crate::sync::atomic::{spin_loop_hint, AtomicBool, Ordering};
#[derive(Default)]
pub struct SpinMutex<T> {
value: UnsafeCell<T>,
lock: AtomicBool,
}
unsafe impl<T: Send> Send for SpinMutex<T> {}
unsafe impl<T: Send> Sync for SpinMutex<T> {}
pub struct SpinMutexGuard<'a, T: 'a> {
mutex: &'a SpinMutex<T>,
}
impl<'a, T> !Send for SpinMutexGuard<'a, T> {}
unsafe impl<'a, T: Sync> Sync for SpinMutexGuard<'a, T> {}
impl<T> SpinMutex<T> {
pub const fn new(value: T) -> Self {
SpinMutex { value: UnsafeCell::new(value), lock: AtomicBool::new(false) }
}
#[inline(always)]
pub fn lock(&self) -> SpinMutexGuard<'_, T> {
loop {
match self.try_lock() {
None => {
while self.lock.load(Ordering::Relaxed) {
spin_loop_hint()
}
}
Some(guard) => return guard,
}
}
}
#[inline(always)]
pub fn try_lock(&self) -> Option<SpinMutexGuard<'_, T>> {
if !self.lock.compare_and_swap(false, true, Ordering::Acquire) {
Some(SpinMutexGuard { mutex: self })
} else {
None
}
}
}
/// Lock the Mutex or return false.
pub macro try_lock_or_false($e:expr) {
if let Some(v) = $e.try_lock() { v } else { return false }
}
impl<'a, T> Deref for SpinMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.mutex.value.get() }
}
}
impl<'a, T> DerefMut for SpinMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.mutex.value.get() }
}
}
impl<'a, T> Drop for SpinMutexGuard<'a, T> {
fn drop(&mut self) {
self.mutex.lock.store(false, Ordering::Release)
}
}

View file

@ -0,0 +1,23 @@
#![allow(deprecated)]
use super::*;
use crate::sync::Arc;
use crate::thread;
use crate::time::Duration;
#[test]
fn sleep() {
let mutex = Arc::new(SpinMutex::<i32>::default());
let mutex2 = mutex.clone();
let guard = mutex.lock();
let t1 = thread::spawn(move || {
*mutex2.lock() = 1;
});
thread::sleep(Duration::from_millis(50));
assert_eq!(*guard, 0);
drop(guard);
t1.join().unwrap();
assert_eq!(*mutex.lock(), 1);
}

View file

@ -0,0 +1,20 @@
use super::*;
use crate::sync::Arc;
use crate::thread;
#[test]
fn queue() {
let wq = Arc::new(SpinMutex::<WaitVariable<()>>::default());
let wq2 = wq.clone();
let locked = wq.lock();
let t1 = thread::spawn(move || {
// if we obtain the lock, the main thread should be waiting
assert!(WaitQueue::notify_one(wq2.lock()).is_ok());
});
WaitQueue::wait(locked, || {});
t1.join().unwrap();
}

View file

@ -0,0 +1,146 @@
#[cfg(test)]
mod tests;
use crate::mem;
use crate::ptr::NonNull;
pub struct UnsafeListEntry<T> {
next: NonNull<UnsafeListEntry<T>>,
prev: NonNull<UnsafeListEntry<T>>,
value: Option<T>,
}
impl<T> UnsafeListEntry<T> {
fn dummy() -> Self {
UnsafeListEntry { next: NonNull::dangling(), prev: NonNull::dangling(), value: None }
}
pub fn new(value: T) -> Self {
UnsafeListEntry { value: Some(value), ..Self::dummy() }
}
}
pub struct UnsafeList<T> {
head_tail: NonNull<UnsafeListEntry<T>>,
head_tail_entry: Option<UnsafeListEntry<T>>,
}
impl<T> UnsafeList<T> {
pub const fn new() -> Self {
unsafe { UnsafeList { head_tail: NonNull::new_unchecked(1 as _), head_tail_entry: None } }
}
unsafe fn init(&mut self) {
if self.head_tail_entry.is_none() {
self.head_tail_entry = Some(UnsafeListEntry::dummy());
self.head_tail = NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap());
self.head_tail.as_mut().next = self.head_tail;
self.head_tail.as_mut().prev = self.head_tail;
}
}
pub fn is_empty(&self) -> bool {
unsafe {
if self.head_tail_entry.is_some() {
let first = self.head_tail.as_ref().next;
if first == self.head_tail {
// ,-------> /---------\ next ---,
// | |head_tail| |
// `--- prev \---------/ <-------`
rtassert!(self.head_tail.as_ref().prev == first);
true
} else {
false
}
} else {
true
}
}
}
/// Pushes an entry onto the back of the list.
///
/// # Safety
///
/// The entry must remain allocated until the entry is removed from the
/// list AND the caller who popped is done using the entry. Special
/// care must be taken in the caller of `push` to ensure unwinding does
/// not destroy the stack frame containing the entry.
pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T {
self.init();
// BEFORE:
// /---------\ next ---> /---------\
// ... |prev_tail| |head_tail| ...
// \---------/ <--- prev \---------/
//
// AFTER:
// /---------\ next ---> /-----\ next ---> /---------\
// ... |prev_tail| |entry| |head_tail| ...
// \---------/ <--- prev \-----/ <--- prev \---------/
let mut entry = NonNull::new_unchecked(entry);
let mut prev_tail = mem::replace(&mut self.head_tail.as_mut().prev, entry);
entry.as_mut().prev = prev_tail;
entry.as_mut().next = self.head_tail;
prev_tail.as_mut().next = entry;
// unwrap ok: always `Some` on non-dummy entries
(*entry.as_ptr()).value.as_ref().unwrap()
}
/// Pops an entry from the front of the list.
///
/// # Safety
///
/// The caller must make sure to synchronize ending the borrow of the
/// return value and deallocation of the containing entry.
pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> {
self.init();
if self.is_empty() {
None
} else {
// BEFORE:
// /---------\ next ---> /-----\ next ---> /------\
// ... |head_tail| |first| |second| ...
// \---------/ <--- prev \-----/ <--- prev \------/
//
// AFTER:
// /---------\ next ---> /------\
// ... |head_tail| |second| ...
// \---------/ <--- prev \------/
let mut first = self.head_tail.as_mut().next;
let mut second = first.as_mut().next;
self.head_tail.as_mut().next = second;
second.as_mut().prev = self.head_tail;
first.as_mut().next = NonNull::dangling();
first.as_mut().prev = NonNull::dangling();
// unwrap ok: always `Some` on non-dummy entries
Some((*first.as_ptr()).value.as_ref().unwrap())
}
}
/// Removes an entry from the list.
///
/// # Safety
///
/// The caller must ensure that `entry` has been pushed onto `self`
/// prior to this call and has not moved since then.
pub unsafe fn remove(&mut self, entry: &mut UnsafeListEntry<T>) {
rtassert!(!self.is_empty());
// BEFORE:
// /----\ next ---> /-----\ next ---> /----\
// ... |prev| |entry| |next| ...
// \----/ <--- prev \-----/ <--- prev \----/
//
// AFTER:
// /----\ next ---> /----\
// ... |prev| |next| ...
// \----/ <--- prev \----/
let mut prev = entry.prev;
let mut next = entry.next;
prev.as_mut().next = next;
next.as_mut().prev = prev;
entry.next = NonNull::dangling();
entry.prev = NonNull::dangling();
}
}

View file

@ -0,0 +1,103 @@
use super::*;
use crate::cell::Cell;
unsafe fn assert_empty<T>(list: &mut UnsafeList<T>) {
assert!(list.pop().is_none(), "assertion failed: list is not empty");
}
#[test]
fn init_empty() {
unsafe {
assert_empty(&mut UnsafeList::<i32>::new());
}
}
#[test]
fn push_pop() {
unsafe {
let mut node = UnsafeListEntry::new(1234);
let mut list = UnsafeList::new();
assert_eq!(list.push(&mut node), &1234);
assert_eq!(list.pop().unwrap(), &1234);
assert_empty(&mut list);
}
}
#[test]
fn push_remove() {
unsafe {
let mut node = UnsafeListEntry::new(1234);
let mut list = UnsafeList::new();
assert_eq!(list.push(&mut node), &1234);
list.remove(&mut node);
assert_empty(&mut list);
}
}
#[test]
fn push_remove_pop() {
unsafe {
let mut node1 = UnsafeListEntry::new(11);
let mut node2 = UnsafeListEntry::new(12);
let mut node3 = UnsafeListEntry::new(13);
let mut node4 = UnsafeListEntry::new(14);
let mut node5 = UnsafeListEntry::new(15);
let mut list = UnsafeList::new();
assert_eq!(list.push(&mut node1), &11);
assert_eq!(list.push(&mut node2), &12);
assert_eq!(list.push(&mut node3), &13);
assert_eq!(list.push(&mut node4), &14);
assert_eq!(list.push(&mut node5), &15);
list.remove(&mut node1);
assert_eq!(list.pop().unwrap(), &12);
list.remove(&mut node3);
assert_eq!(list.pop().unwrap(), &14);
list.remove(&mut node5);
assert_empty(&mut list);
assert_eq!(list.push(&mut node1), &11);
assert_eq!(list.pop().unwrap(), &11);
assert_empty(&mut list);
assert_eq!(list.push(&mut node3), &13);
assert_eq!(list.push(&mut node4), &14);
list.remove(&mut node3);
list.remove(&mut node4);
assert_empty(&mut list);
}
}
#[test]
fn complex_pushes_pops() {
unsafe {
let mut node1 = UnsafeListEntry::new(1234);
let mut node2 = UnsafeListEntry::new(4567);
let mut node3 = UnsafeListEntry::new(9999);
let mut node4 = UnsafeListEntry::new(8642);
let mut list = UnsafeList::new();
list.push(&mut node1);
list.push(&mut node2);
assert_eq!(list.pop().unwrap(), &1234);
list.push(&mut node3);
assert_eq!(list.pop().unwrap(), &4567);
assert_eq!(list.pop().unwrap(), &9999);
assert_empty(&mut list);
list.push(&mut node4);
assert_eq!(list.pop().unwrap(), &8642);
assert_empty(&mut list);
}
}
#[test]
fn cell() {
unsafe {
let mut node = UnsafeListEntry::new(Cell::new(0));
let mut list = UnsafeList::new();
let noderef = list.push(&mut node);
assert_eq!(noderef.get(), 0);
list.pop().unwrap().set(1);
assert_empty(&mut list);
assert_eq!(noderef.get(), 1);
}
}

View file

@ -2,6 +2,9 @@
//! Unix-specific networking functionality
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
#[cfg(not(unix))]
#[allow(non_camel_case_types)]
@ -1620,382 +1623,3 @@ impl IntoRawFd for UnixDatagram {
self.0.into_inner()
}
}
#[cfg(all(test, not(target_os = "emscripten")))]
mod test {
use crate::io::prelude::*;
use crate::io::{self, ErrorKind};
use crate::sys_common::io::test::tmpdir;
use crate::thread;
use crate::time::Duration;
use super::*;
macro_rules! or_panic {
($e:expr) => {
match $e {
Ok(e) => e,
Err(e) => panic!("{}", e),
}
};
}
#[test]
fn basic() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let msg1 = b"hello";
let msg2 = b"world!";
let listener = or_panic!(UnixListener::bind(&socket_path));
let thread = thread::spawn(move || {
let mut stream = or_panic!(listener.accept()).0;
let mut buf = [0; 5];
or_panic!(stream.read(&mut buf));
assert_eq!(&msg1[..], &buf[..]);
or_panic!(stream.write_all(msg2));
});
let mut stream = or_panic!(UnixStream::connect(&socket_path));
assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname());
or_panic!(stream.write_all(msg1));
let mut buf = vec![];
or_panic!(stream.read_to_end(&mut buf));
assert_eq!(&msg2[..], &buf[..]);
drop(stream);
thread.join().unwrap();
}
#[test]
fn vectored() {
let (mut s1, mut s2) = or_panic!(UnixStream::pair());
let len = or_panic!(s1.write_vectored(&[
IoSlice::new(b"hello"),
IoSlice::new(b" "),
IoSlice::new(b"world!")
],));
assert_eq!(len, 12);
let mut buf1 = [0; 6];
let mut buf2 = [0; 7];
let len = or_panic!(
s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)
);
assert_eq!(len, 12);
assert_eq!(&buf1, b"hello ");
assert_eq!(&buf2, b"world!\0");
}
#[test]
fn pair() {
let msg1 = b"hello";
let msg2 = b"world!";
let (mut s1, mut s2) = or_panic!(UnixStream::pair());
let thread = thread::spawn(move || {
// s1 must be moved in or the test will hang!
let mut buf = [0; 5];
or_panic!(s1.read(&mut buf));
assert_eq!(&msg1[..], &buf[..]);
or_panic!(s1.write_all(msg2));
});
or_panic!(s2.write_all(msg1));
let mut buf = vec![];
or_panic!(s2.read_to_end(&mut buf));
assert_eq!(&msg2[..], &buf[..]);
drop(s2);
thread.join().unwrap();
}
#[test]
fn try_clone() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let msg1 = b"hello";
let msg2 = b"world";
let listener = or_panic!(UnixListener::bind(&socket_path));
let thread = thread::spawn(move || {
let mut stream = or_panic!(listener.accept()).0;
or_panic!(stream.write_all(msg1));
or_panic!(stream.write_all(msg2));
});
let mut stream = or_panic!(UnixStream::connect(&socket_path));
let mut stream2 = or_panic!(stream.try_clone());
let mut buf = [0; 5];
or_panic!(stream.read(&mut buf));
assert_eq!(&msg1[..], &buf[..]);
or_panic!(stream2.read(&mut buf));
assert_eq!(&msg2[..], &buf[..]);
thread.join().unwrap();
}
#[test]
fn iter() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let listener = or_panic!(UnixListener::bind(&socket_path));
let thread = thread::spawn(move || {
for stream in listener.incoming().take(2) {
let mut stream = or_panic!(stream);
let mut buf = [0];
or_panic!(stream.read(&mut buf));
}
});
for _ in 0..2 {
let mut stream = or_panic!(UnixStream::connect(&socket_path));
or_panic!(stream.write_all(&[0]));
}
thread.join().unwrap();
}
#[test]
fn long_path() {
let dir = tmpdir();
let socket_path = dir.path().join(
"asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\
sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf",
);
match UnixStream::connect(&socket_path) {
Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
Err(e) => panic!("unexpected error {}", e),
Ok(_) => panic!("unexpected success"),
}
match UnixListener::bind(&socket_path) {
Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
Err(e) => panic!("unexpected error {}", e),
Ok(_) => panic!("unexpected success"),
}
match UnixDatagram::bind(&socket_path) {
Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
Err(e) => panic!("unexpected error {}", e),
Ok(_) => panic!("unexpected success"),
}
}
#[test]
fn timeouts() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let _listener = or_panic!(UnixListener::bind(&socket_path));
let stream = or_panic!(UnixStream::connect(&socket_path));
let dur = Duration::new(15410, 0);
assert_eq!(None, or_panic!(stream.read_timeout()));
or_panic!(stream.set_read_timeout(Some(dur)));
assert_eq!(Some(dur), or_panic!(stream.read_timeout()));
assert_eq!(None, or_panic!(stream.write_timeout()));
or_panic!(stream.set_write_timeout(Some(dur)));
assert_eq!(Some(dur), or_panic!(stream.write_timeout()));
or_panic!(stream.set_read_timeout(None));
assert_eq!(None, or_panic!(stream.read_timeout()));
or_panic!(stream.set_write_timeout(None));
assert_eq!(None, or_panic!(stream.write_timeout()));
}
#[test]
fn test_read_timeout() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let _listener = or_panic!(UnixListener::bind(&socket_path));
let mut stream = or_panic!(UnixStream::connect(&socket_path));
or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
let mut buf = [0; 10];
let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
assert!(
kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
"unexpected_error: {:?}",
kind
);
}
#[test]
fn test_read_with_timeout() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let listener = or_panic!(UnixListener::bind(&socket_path));
let mut stream = or_panic!(UnixStream::connect(&socket_path));
or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
let mut other_end = or_panic!(listener.accept()).0;
or_panic!(other_end.write_all(b"hello world"));
let mut buf = [0; 11];
or_panic!(stream.read(&mut buf));
assert_eq!(b"hello world", &buf[..]);
let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
assert!(
kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
"unexpected_error: {:?}",
kind
);
}
// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
// when passed zero Durations
#[test]
fn test_unix_stream_timeout_zero_duration() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let listener = or_panic!(UnixListener::bind(&socket_path));
let stream = or_panic!(UnixStream::connect(&socket_path));
let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
drop(listener);
}
#[test]
fn test_unix_datagram() {
let dir = tmpdir();
let path1 = dir.path().join("sock1");
let path2 = dir.path().join("sock2");
let sock1 = or_panic!(UnixDatagram::bind(&path1));
let sock2 = or_panic!(UnixDatagram::bind(&path2));
let msg = b"hello world";
or_panic!(sock1.send_to(msg, &path2));
let mut buf = [0; 11];
or_panic!(sock2.recv_from(&mut buf));
assert_eq!(msg, &buf[..]);
}
#[test]
fn test_unnamed_unix_datagram() {
let dir = tmpdir();
let path1 = dir.path().join("sock1");
let sock1 = or_panic!(UnixDatagram::bind(&path1));
let sock2 = or_panic!(UnixDatagram::unbound());
let msg = b"hello world";
or_panic!(sock2.send_to(msg, &path1));
let mut buf = [0; 11];
let (usize, addr) = or_panic!(sock1.recv_from(&mut buf));
assert_eq!(usize, 11);
assert!(addr.is_unnamed());
assert_eq!(msg, &buf[..]);
}
#[test]
fn test_connect_unix_datagram() {
let dir = tmpdir();
let path1 = dir.path().join("sock1");
let path2 = dir.path().join("sock2");
let bsock1 = or_panic!(UnixDatagram::bind(&path1));
let bsock2 = or_panic!(UnixDatagram::bind(&path2));
let sock = or_panic!(UnixDatagram::unbound());
or_panic!(sock.connect(&path1));
// Check send()
let msg = b"hello there";
or_panic!(sock.send(msg));
let mut buf = [0; 11];
let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf));
assert_eq!(usize, 11);
assert!(addr.is_unnamed());
assert_eq!(msg, &buf[..]);
// Changing default socket works too
or_panic!(sock.connect(&path2));
or_panic!(sock.send(msg));
or_panic!(bsock2.recv_from(&mut buf));
}
#[test]
fn test_unix_datagram_recv() {
let dir = tmpdir();
let path1 = dir.path().join("sock1");
let sock1 = or_panic!(UnixDatagram::bind(&path1));
let sock2 = or_panic!(UnixDatagram::unbound());
or_panic!(sock2.connect(&path1));
let msg = b"hello world";
or_panic!(sock2.send(msg));
let mut buf = [0; 11];
let size = or_panic!(sock1.recv(&mut buf));
assert_eq!(size, 11);
assert_eq!(msg, &buf[..]);
}
#[test]
fn datagram_pair() {
let msg1 = b"hello";
let msg2 = b"world!";
let (s1, s2) = or_panic!(UnixDatagram::pair());
let thread = thread::spawn(move || {
// s1 must be moved in or the test will hang!
let mut buf = [0; 5];
or_panic!(s1.recv(&mut buf));
assert_eq!(&msg1[..], &buf[..]);
or_panic!(s1.send(msg2));
});
or_panic!(s2.send(msg1));
let mut buf = [0; 6];
or_panic!(s2.recv(&mut buf));
assert_eq!(&msg2[..], &buf[..]);
drop(s2);
thread.join().unwrap();
}
// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
// when passed zero Durations
#[test]
fn test_unix_datagram_timeout_zero_duration() {
let dir = tmpdir();
let path = dir.path().join("sock");
let datagram = or_panic!(UnixDatagram::bind(&path));
let result = datagram.set_write_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
let result = datagram.set_read_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
}
#[test]
fn abstract_namespace_not_allowed() {
assert!(UnixStream::connect("\0asdf").is_err());
}
}

View file

@ -0,0 +1,374 @@
use crate::io::prelude::*;
use crate::io::{self, ErrorKind};
use crate::sys_common::io::test::tmpdir;
use crate::thread;
use crate::time::Duration;
use super::*;
macro_rules! or_panic {
($e:expr) => {
match $e {
Ok(e) => e,
Err(e) => panic!("{}", e),
}
};
}
#[test]
fn basic() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let msg1 = b"hello";
let msg2 = b"world!";
let listener = or_panic!(UnixListener::bind(&socket_path));
let thread = thread::spawn(move || {
let mut stream = or_panic!(listener.accept()).0;
let mut buf = [0; 5];
or_panic!(stream.read(&mut buf));
assert_eq!(&msg1[..], &buf[..]);
or_panic!(stream.write_all(msg2));
});
let mut stream = or_panic!(UnixStream::connect(&socket_path));
assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname());
or_panic!(stream.write_all(msg1));
let mut buf = vec![];
or_panic!(stream.read_to_end(&mut buf));
assert_eq!(&msg2[..], &buf[..]);
drop(stream);
thread.join().unwrap();
}
#[test]
fn vectored() {
let (mut s1, mut s2) = or_panic!(UnixStream::pair());
let len = or_panic!(s1.write_vectored(&[
IoSlice::new(b"hello"),
IoSlice::new(b" "),
IoSlice::new(b"world!")
],));
assert_eq!(len, 12);
let mut buf1 = [0; 6];
let mut buf2 = [0; 7];
let len =
or_panic!(s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],));
assert_eq!(len, 12);
assert_eq!(&buf1, b"hello ");
assert_eq!(&buf2, b"world!\0");
}
#[test]
fn pair() {
let msg1 = b"hello";
let msg2 = b"world!";
let (mut s1, mut s2) = or_panic!(UnixStream::pair());
let thread = thread::spawn(move || {
// s1 must be moved in or the test will hang!
let mut buf = [0; 5];
or_panic!(s1.read(&mut buf));
assert_eq!(&msg1[..], &buf[..]);
or_panic!(s1.write_all(msg2));
});
or_panic!(s2.write_all(msg1));
let mut buf = vec![];
or_panic!(s2.read_to_end(&mut buf));
assert_eq!(&msg2[..], &buf[..]);
drop(s2);
thread.join().unwrap();
}
#[test]
fn try_clone() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let msg1 = b"hello";
let msg2 = b"world";
let listener = or_panic!(UnixListener::bind(&socket_path));
let thread = thread::spawn(move || {
let mut stream = or_panic!(listener.accept()).0;
or_panic!(stream.write_all(msg1));
or_panic!(stream.write_all(msg2));
});
let mut stream = or_panic!(UnixStream::connect(&socket_path));
let mut stream2 = or_panic!(stream.try_clone());
let mut buf = [0; 5];
or_panic!(stream.read(&mut buf));
assert_eq!(&msg1[..], &buf[..]);
or_panic!(stream2.read(&mut buf));
assert_eq!(&msg2[..], &buf[..]);
thread.join().unwrap();
}
#[test]
fn iter() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let listener = or_panic!(UnixListener::bind(&socket_path));
let thread = thread::spawn(move || {
for stream in listener.incoming().take(2) {
let mut stream = or_panic!(stream);
let mut buf = [0];
or_panic!(stream.read(&mut buf));
}
});
for _ in 0..2 {
let mut stream = or_panic!(UnixStream::connect(&socket_path));
or_panic!(stream.write_all(&[0]));
}
thread.join().unwrap();
}
#[test]
fn long_path() {
let dir = tmpdir();
let socket_path = dir.path().join(
"asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\
sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf",
);
match UnixStream::connect(&socket_path) {
Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
Err(e) => panic!("unexpected error {}", e),
Ok(_) => panic!("unexpected success"),
}
match UnixListener::bind(&socket_path) {
Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
Err(e) => panic!("unexpected error {}", e),
Ok(_) => panic!("unexpected success"),
}
match UnixDatagram::bind(&socket_path) {
Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
Err(e) => panic!("unexpected error {}", e),
Ok(_) => panic!("unexpected success"),
}
}
#[test]
fn timeouts() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let _listener = or_panic!(UnixListener::bind(&socket_path));
let stream = or_panic!(UnixStream::connect(&socket_path));
let dur = Duration::new(15410, 0);
assert_eq!(None, or_panic!(stream.read_timeout()));
or_panic!(stream.set_read_timeout(Some(dur)));
assert_eq!(Some(dur), or_panic!(stream.read_timeout()));
assert_eq!(None, or_panic!(stream.write_timeout()));
or_panic!(stream.set_write_timeout(Some(dur)));
assert_eq!(Some(dur), or_panic!(stream.write_timeout()));
or_panic!(stream.set_read_timeout(None));
assert_eq!(None, or_panic!(stream.read_timeout()));
or_panic!(stream.set_write_timeout(None));
assert_eq!(None, or_panic!(stream.write_timeout()));
}
#[test]
fn test_read_timeout() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let _listener = or_panic!(UnixListener::bind(&socket_path));
let mut stream = or_panic!(UnixStream::connect(&socket_path));
or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
let mut buf = [0; 10];
let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
assert!(
kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
"unexpected_error: {:?}",
kind
);
}
#[test]
fn test_read_with_timeout() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let listener = or_panic!(UnixListener::bind(&socket_path));
let mut stream = or_panic!(UnixStream::connect(&socket_path));
or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
let mut other_end = or_panic!(listener.accept()).0;
or_panic!(other_end.write_all(b"hello world"));
let mut buf = [0; 11];
or_panic!(stream.read(&mut buf));
assert_eq!(b"hello world", &buf[..]);
let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
assert!(
kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
"unexpected_error: {:?}",
kind
);
}
// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
// when passed zero Durations
#[test]
fn test_unix_stream_timeout_zero_duration() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let listener = or_panic!(UnixListener::bind(&socket_path));
let stream = or_panic!(UnixStream::connect(&socket_path));
let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
drop(listener);
}
#[test]
fn test_unix_datagram() {
let dir = tmpdir();
let path1 = dir.path().join("sock1");
let path2 = dir.path().join("sock2");
let sock1 = or_panic!(UnixDatagram::bind(&path1));
let sock2 = or_panic!(UnixDatagram::bind(&path2));
let msg = b"hello world";
or_panic!(sock1.send_to(msg, &path2));
let mut buf = [0; 11];
or_panic!(sock2.recv_from(&mut buf));
assert_eq!(msg, &buf[..]);
}
#[test]
fn test_unnamed_unix_datagram() {
let dir = tmpdir();
let path1 = dir.path().join("sock1");
let sock1 = or_panic!(UnixDatagram::bind(&path1));
let sock2 = or_panic!(UnixDatagram::unbound());
let msg = b"hello world";
or_panic!(sock2.send_to(msg, &path1));
let mut buf = [0; 11];
let (usize, addr) = or_panic!(sock1.recv_from(&mut buf));
assert_eq!(usize, 11);
assert!(addr.is_unnamed());
assert_eq!(msg, &buf[..]);
}
#[test]
fn test_connect_unix_datagram() {
let dir = tmpdir();
let path1 = dir.path().join("sock1");
let path2 = dir.path().join("sock2");
let bsock1 = or_panic!(UnixDatagram::bind(&path1));
let bsock2 = or_panic!(UnixDatagram::bind(&path2));
let sock = or_panic!(UnixDatagram::unbound());
or_panic!(sock.connect(&path1));
// Check send()
let msg = b"hello there";
or_panic!(sock.send(msg));
let mut buf = [0; 11];
let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf));
assert_eq!(usize, 11);
assert!(addr.is_unnamed());
assert_eq!(msg, &buf[..]);
// Changing default socket works too
or_panic!(sock.connect(&path2));
or_panic!(sock.send(msg));
or_panic!(bsock2.recv_from(&mut buf));
}
#[test]
fn test_unix_datagram_recv() {
let dir = tmpdir();
let path1 = dir.path().join("sock1");
let sock1 = or_panic!(UnixDatagram::bind(&path1));
let sock2 = or_panic!(UnixDatagram::unbound());
or_panic!(sock2.connect(&path1));
let msg = b"hello world";
or_panic!(sock2.send(msg));
let mut buf = [0; 11];
let size = or_panic!(sock1.recv(&mut buf));
assert_eq!(size, 11);
assert_eq!(msg, &buf[..]);
}
#[test]
fn datagram_pair() {
let msg1 = b"hello";
let msg2 = b"world!";
let (s1, s2) = or_panic!(UnixDatagram::pair());
let thread = thread::spawn(move || {
// s1 must be moved in or the test will hang!
let mut buf = [0; 5];
or_panic!(s1.recv(&mut buf));
assert_eq!(&msg1[..], &buf[..]);
or_panic!(s1.send(msg2));
});
or_panic!(s2.send(msg1));
let mut buf = [0; 6];
or_panic!(s2.recv(&mut buf));
assert_eq!(&msg2[..], &buf[..]);
drop(s2);
thread.join().unwrap();
}
// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
// when passed zero Durations
#[test]
fn test_unix_datagram_timeout_zero_duration() {
let dir = tmpdir();
let path = dir.path().join("sock");
let datagram = or_panic!(UnixDatagram::bind(&path));
let result = datagram.set_write_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
let result = datagram.set_read_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
}
#[test]
fn abstract_namespace_not_allowed() {
assert!(UnixStream::connect("\0asdf").is_err());
}

View file

@ -1,5 +1,8 @@
#![unstable(reason = "not public", issue = "none", feature = "fd")]
#[cfg(test)]
mod tests;
use crate::cmp;
use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
use crate::mem;
@ -279,16 +282,3 @@ impl Drop for FileDesc {
let _ = unsafe { libc::close(self.fd) };
}
}
#[cfg(test)]
mod tests {
use super::{FileDesc, IoSlice};
use core::mem::ManuallyDrop;
#[test]
fn limit_vector_count() {
let stdout = ManuallyDrop::new(FileDesc { fd: 1 });
let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>();
assert!(stdout.write_vectored(&bufs).is_ok());
}
}

View file

@ -0,0 +1,9 @@
use super::{FileDesc, IoSlice};
use core::mem::ManuallyDrop;
#[test]
fn limit_vector_count() {
let stdout = ManuallyDrop::new(FileDesc { fd: 1 });
let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>();
assert!(stdout.write_vectored(&bufs).is_ok());
}

View file

@ -2,6 +2,9 @@
#![allow(unused_imports)] // lots of cfg code here
#[cfg(all(test, target_env = "gnu"))]
mod tests;
use crate::os::unix::prelude::*;
use crate::error::Error as StdError;
@ -645,30 +648,3 @@ fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
_ => None,
}
}
#[cfg(all(test, target_env = "gnu"))]
mod test {
use super::*;
#[test]
fn test_glibc_version() {
// This mostly just tests that the weak linkage doesn't panic wildly...
glibc_version();
}
#[test]
fn test_parse_glibc_version() {
let cases = [
("0.0", Some((0, 0))),
("01.+2", Some((1, 2))),
("3.4.5.six", Some((3, 4))),
("1", None),
("1.-2", None),
("1.foo", None),
("foo.1", None),
];
for &(version_str, parsed) in cases.iter() {
assert_eq!(parsed, parse_glibc_version(version_str));
}
}
}

View file

@ -0,0 +1,23 @@
use super::*;
#[test]
fn test_glibc_version() {
// This mostly just tests that the weak linkage doesn't panic wildly...
glibc_version();
}
#[test]
fn test_parse_glibc_version() {
let cases = [
("0.0", Some((0, 0))),
("01.+2", Some((1, 2))),
("3.4.5.six", Some((3, 4))),
("1", None),
("1.-2", None),
("1.foo", None),
("foo.1", None),
];
for &(version_str, parsed) in cases.iter() {
assert_eq!(parsed, parse_glibc_version(version_str));
}
}

View file

@ -1,3 +1,6 @@
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
use crate::os::unix::prelude::*;
use crate::collections::BTreeMap;
@ -399,71 +402,3 @@ impl ExitCode {
self.0 as i32
}
}
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use super::*;
use crate::ffi::OsStr;
use crate::mem;
use crate::ptr;
use crate::sys::cvt;
macro_rules! t {
($e:expr) => {
match $e {
Ok(t) => t,
Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
}
};
}
// See #14232 for more information, but it appears that signal delivery to a
// newly spawned process may just be raced in the macOS, so to prevent this
// test from being flaky we ignore it on macOS.
#[test]
#[cfg_attr(target_os = "macos", ignore)]
// When run under our current QEMU emulation test suite this test fails,
// although the reason isn't very clear as to why. For now this test is
// ignored there.
#[cfg_attr(target_arch = "arm", ignore)]
#[cfg_attr(target_arch = "aarch64", ignore)]
#[cfg_attr(target_arch = "riscv64", ignore)]
fn test_process_mask() {
unsafe {
// Test to make sure that a signal mask does not get inherited.
let mut cmd = Command::new(OsStr::new("cat"));
let mut set = mem::MaybeUninit::<libc::sigset_t>::uninit();
let mut old_set = mem::MaybeUninit::<libc::sigset_t>::uninit();
t!(cvt(sigemptyset(set.as_mut_ptr())));
t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT)));
t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), old_set.as_mut_ptr())));
cmd.stdin(Stdio::MakePipe);
cmd.stdout(Stdio::MakePipe);
let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
let stdin_write = pipes.stdin.take().unwrap();
let stdout_read = pipes.stdout.take().unwrap();
t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut())));
t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
// We need to wait until SIGINT is definitely delivered. The
// easiest way is to write something to cat, and try to read it
// back: if SIGINT is unmasked, it'll get delivered when cat is
// next scheduled.
let _ = stdin_write.write(b"Hello");
drop(stdin_write);
// Either EOF or failure (EPIPE) is okay.
let mut buf = [0; 5];
if let Ok(ret) = stdout_read.read(&mut buf) {
assert_eq!(ret, 0);
}
t!(cat.wait());
}
}
}

View file

@ -0,0 +1,64 @@
use super::*;
use crate::ffi::OsStr;
use crate::mem;
use crate::ptr;
use crate::sys::cvt;
macro_rules! t {
($e:expr) => {
match $e {
Ok(t) => t,
Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
}
};
}
// See #14232 for more information, but it appears that signal delivery to a
// newly spawned process may just be raced in the macOS, so to prevent this
// test from being flaky we ignore it on macOS.
#[test]
#[cfg_attr(target_os = "macos", ignore)]
// When run under our current QEMU emulation test suite this test fails,
// although the reason isn't very clear as to why. For now this test is
// ignored there.
#[cfg_attr(target_arch = "arm", ignore)]
#[cfg_attr(target_arch = "aarch64", ignore)]
#[cfg_attr(target_arch = "riscv64", ignore)]
fn test_process_mask() {
unsafe {
// Test to make sure that a signal mask does not get inherited.
let mut cmd = Command::new(OsStr::new("cat"));
let mut set = mem::MaybeUninit::<libc::sigset_t>::uninit();
let mut old_set = mem::MaybeUninit::<libc::sigset_t>::uninit();
t!(cvt(sigemptyset(set.as_mut_ptr())));
t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT)));
t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), old_set.as_mut_ptr())));
cmd.stdin(Stdio::MakePipe);
cmd.stdout(Stdio::MakePipe);
let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
let stdin_write = pipes.stdin.take().unwrap();
let stdout_read = pipes.stdout.take().unwrap();
t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut())));
t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
// We need to wait until SIGINT is definitely delivered. The
// easiest way is to write something to cat, and try to read it
// back: if SIGINT is unmasked, it'll get delivered when cat is
// next scheduled.
let _ = stdin_write.write(b"Hello");
drop(stdin_write);
// Either EOF or failure (EPIPE) is okay.
let mut buf = [0; 5];
if let Ok(ret) = stdout_read.read(&mut buf) {
assert_eq!(ret, 0);
}
t!(cat.wait());
}
}

View file

@ -1,3 +1,6 @@
#[cfg(all(test, taget_env = "gnu"))]
mod tests;
use crate::cmp;
use crate::ffi::CStr;
use crate::io;
@ -330,30 +333,3 @@ fn on_resolver_failure() {
#[cfg(not(target_env = "gnu"))]
fn on_resolver_failure() {}
#[cfg(all(test, taget_env = "gnu"))]
mod test {
use super::*;
#[test]
fn test_res_init() {
// This mostly just tests that the weak linkage doesn't panic wildly...
res_init_if_glibc_before_2_26().unwrap();
}
#[test]
fn test_parse_glibc_version() {
let cases = [
("0.0", Some((0, 0))),
("01.+2", Some((1, 2))),
("3.4.5.six", Some((3, 4))),
("1", None),
("1.-2", None),
("1.foo", None),
("foo.1", None),
];
for &(version_str, parsed) in cases.iter() {
assert_eq!(parsed, parse_glibc_version(version_str));
}
}
}

View file

@ -0,0 +1,23 @@
use super::*;
#[test]
fn test_res_init() {
// This mostly just tests that the weak linkage doesn't panic wildly...
res_init_if_glibc_before_2_26().unwrap();
}
#[test]
fn test_parse_glibc_version() {
let cases = [
("0.0", Some((0, 0))),
("01.+2", Some((1, 2))),
("3.4.5.six", Some((3, 4))),
("1", None),
("1.-2", None),
("1.foo", None),
("foo.1", None),
];
for &(version_str, parsed) in cases.iter() {
assert_eq!(parsed, parse_glibc_version(version_str));
}
}

View file

@ -1,5 +1,8 @@
#![allow(dead_code)] // runtime init functions not used during testing
#[cfg(test)]
mod tests;
use crate::ffi::OsString;
use crate::fmt;
use crate::os::windows::prelude::*;
@ -198,69 +201,3 @@ impl ExactSizeIterator for Args {
self.parsed_args_list.len()
}
}
#[cfg(test)]
mod tests {
use crate::ffi::OsString;
use crate::sys::windows::args::*;
fn chk(string: &str, parts: &[&str]) {
let mut wide: Vec<u16> = OsString::from(string).encode_wide().collect();
wide.push(0);
let parsed = unsafe {
parse_lp_cmd_line(wide.as_ptr() as *const u16, || OsString::from("TEST.EXE"))
};
let expected: Vec<OsString> = parts.iter().map(|k| OsString::from(k)).collect();
assert_eq!(parsed.as_slice(), expected.as_slice());
}
#[test]
fn empty() {
chk("", &["TEST.EXE"]);
chk("\0", &["TEST.EXE"]);
}
#[test]
fn single_words() {
chk("EXE one_word", &["EXE", "one_word"]);
chk("EXE a", &["EXE", "a"]);
chk("EXE 😅", &["EXE", "😅"]);
chk("EXE 😅🤦", &["EXE", "😅🤦"]);
}
#[test]
fn official_examples() {
chk(r#"EXE "abc" d e"#, &["EXE", "abc", "d", "e"]);
chk(r#"EXE a\\\b d"e f"g h"#, &["EXE", r#"a\\\b"#, "de fg", "h"]);
chk(r#"EXE a\\\"b c d"#, &["EXE", r#"a\"b"#, "c", "d"]);
chk(r#"EXE a\\\\"b c" d e"#, &["EXE", r#"a\\b c"#, "d", "e"]);
}
#[test]
fn whitespace_behavior() {
chk(r#" test"#, &["", "test"]);
chk(r#" test"#, &["", "test"]);
chk(r#" test test2"#, &["", "test", "test2"]);
chk(r#" test test2"#, &["", "test", "test2"]);
chk(r#"test test2 "#, &["test", "test2"]);
chk(r#"test test2 "#, &["test", "test2"]);
chk(r#"test "#, &["test"]);
}
#[test]
fn genius_quotes() {
chk(r#"EXE "" """#, &["EXE", "", ""]);
chk(r#"EXE "" """"#, &["EXE", "", "\""]);
chk(
r#"EXE "this is """all""" in the same argument""#,
&["EXE", "this is \"all\" in the same argument"],
);
chk(r#"EXE "a"""#, &["EXE", "a\""]);
chk(r#"EXE "a"" a"#, &["EXE", "a\"", "a"]);
// quotes cannot be escaped in command names
chk(r#""EXE" check"#, &["EXE", "check"]);
chk(r#""EXE check""#, &["EXE check"]);
chk(r#""EXE """for""" check"#, &["EXE ", r#"for""#, "check"]);
chk(r#""EXE \"for\" check"#, &[r#"EXE \"#, r#"for""#, "check"]);
}
}

View file

@ -0,0 +1,61 @@
use crate::ffi::OsString;
use crate::sys::windows::args::*;
fn chk(string: &str, parts: &[&str]) {
let mut wide: Vec<u16> = OsString::from(string).encode_wide().collect();
wide.push(0);
let parsed =
unsafe { parse_lp_cmd_line(wide.as_ptr() as *const u16, || OsString::from("TEST.EXE")) };
let expected: Vec<OsString> = parts.iter().map(|k| OsString::from(k)).collect();
assert_eq!(parsed.as_slice(), expected.as_slice());
}
#[test]
fn empty() {
chk("", &["TEST.EXE"]);
chk("\0", &["TEST.EXE"]);
}
#[test]
fn single_words() {
chk("EXE one_word", &["EXE", "one_word"]);
chk("EXE a", &["EXE", "a"]);
chk("EXE 😅", &["EXE", "😅"]);
chk("EXE 😅🤦", &["EXE", "😅🤦"]);
}
#[test]
fn official_examples() {
chk(r#"EXE "abc" d e"#, &["EXE", "abc", "d", "e"]);
chk(r#"EXE a\\\b d"e f"g h"#, &["EXE", r#"a\\\b"#, "de fg", "h"]);
chk(r#"EXE a\\\"b c d"#, &["EXE", r#"a\"b"#, "c", "d"]);
chk(r#"EXE a\\\\"b c" d e"#, &["EXE", r#"a\\b c"#, "d", "e"]);
}
#[test]
fn whitespace_behavior() {
chk(r#" test"#, &["", "test"]);
chk(r#" test"#, &["", "test"]);
chk(r#" test test2"#, &["", "test", "test2"]);
chk(r#" test test2"#, &["", "test", "test2"]);
chk(r#"test test2 "#, &["test", "test2"]);
chk(r#"test test2 "#, &["test", "test2"]);
chk(r#"test "#, &["test"]);
}
#[test]
fn genius_quotes() {
chk(r#"EXE "" """#, &["EXE", "", ""]);
chk(r#"EXE "" """"#, &["EXE", "", "\""]);
chk(
r#"EXE "this is """all""" in the same argument""#,
&["EXE", "this is \"all\" in the same argument"],
);
chk(r#"EXE "a"""#, &["EXE", "a\""]);
chk(r#"EXE "a"" a"#, &["EXE", "a\"", "a"]);
// quotes cannot be escaped in command names
chk(r#""EXE" check"#, &["EXE", "check"]);
chk(r#""EXE check""#, &["EXE check"]);
chk(r#""EXE """for""" check"#, &["EXE ", r#"for""#, "check"]);
chk(r#""EXE \"for\" check"#, &[r#"EXE \"#, r#"for""#, "check"]);
}

View file

@ -2,6 +2,9 @@
#![allow(nonstandard_style)]
#[cfg(test)]
mod tests;
use crate::os::windows::prelude::*;
use crate::error::Error as StdError;
@ -328,20 +331,3 @@ pub fn exit(code: i32) -> ! {
pub fn getpid() -> u32 {
unsafe { c::GetCurrentProcessId() as u32 }
}
#[cfg(test)]
mod tests {
use crate::io::Error;
use crate::sys::c;
// tests `error_string` above
#[test]
fn ntstatus_error() {
const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001;
assert!(
!Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _)
.to_string()
.contains("FormatMessageW() returned error")
);
}
}

View file

@ -0,0 +1,13 @@
use crate::io::Error;
use crate::sys::c;
// tests `error_string` above
#[test]
fn ntstatus_error() {
const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001;
assert!(
!Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _)
.to_string()
.contains("FormatMessageW() returned error")
);
}

View file

@ -1,5 +1,8 @@
#![unstable(feature = "process_internals", issue = "none")]
#[cfg(test)]
mod tests;
use crate::borrow::Borrow;
use crate::collections::BTreeMap;
use crate::env;
@ -526,41 +529,3 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
None => Ok((ptr::null(), Vec::new())),
}
}
#[cfg(test)]
mod tests {
use super::make_command_line;
use crate::ffi::{OsStr, OsString};
#[test]
fn test_make_command_line() {
fn test_wrapper(prog: &str, args: &[&str]) -> String {
let command_line = &make_command_line(
OsStr::new(prog),
&args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(),
)
.unwrap();
String::from_utf16(command_line).unwrap()
}
assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"]), "\"prog\" aaa bbb ccc");
assert_eq!(
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]),
"\"C:\\Program Files\\blah\\blah.exe\" aaa"
);
assert_eq!(
test_wrapper("C:\\Program Files\\test", &["aa\"bb"]),
"\"C:\\Program Files\\test\" aa\\\"bb"
);
assert_eq!(test_wrapper("echo", &["a b c"]), "\"echo\" \"a b c\"");
assert_eq!(
test_wrapper("echo", &["\" \\\" \\", "\\"]),
"\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
);
assert_eq!(
test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
"\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
);
}
}

Some files were not shown because too many files have changed in this diff Show more