Also doing fmt inplace as requested.
#![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
}
}
}
-
-#[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);
-}
--- /dev/null
+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);
+}
-// ignore-tidy-filelength
+#[cfg(test)]
+mod tests;
use self::Entry::*;
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),
- }
- }
- }
-}
--- /dev/null
+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),
+ }
+ }
+}
+#[cfg(test)]
+mod tests;
+
use crate::borrow::Borrow;
use crate::collections::TryReserveError;
use crate::fmt;
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));
- }
-}
--- /dev/null
+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));
+}
#![stable(feature = "env", since = "1.0.0")]
+#[cfg(test)]
+mod tests;
+
use crate::error::Error;
use crate::ffi::{OsStr, OsString};
use crate::fmt;
#[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())
- );
- }
-}
--- /dev/null
+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())
+ );
+}
// 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;
})
}
}
-
-#[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),
- }
- }
-}
--- /dev/null
+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),
+ }
+}
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
+#[cfg(test)]
+mod tests;
+
#[cfg(not(test))]
use crate::intrinsics;
#[cfg(not(test))]
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()));
- }
-}
--- /dev/null
+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()));
+}
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
+#[cfg(test)]
+mod tests;
+
#[cfg(not(test))]
use crate::intrinsics;
#[cfg(not(test))]
}
}
}
-
-#[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()));
- }
-}
--- /dev/null
+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()));
+}
#![deny(unsafe_op_in_unsafe_fn)]
+
+#[cfg(test)]
+mod tests;
+
use crate::ascii;
use crate::borrow::{Borrow, Cow};
use crate::cmp::Ordering;
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()..];
- }
-}
--- /dev/null
+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()..];
+}
+#[cfg(test)]
+mod tests;
+
use crate::borrow::{Borrow, Cow};
use crate::cmp;
use crate::fmt;
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);
- }
-}
--- /dev/null
+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);
+}
-// ignore-tidy-filelength
-
//! Filesystem manipulation operations.
//!
//! This module contains basic methods to manipulate the contents of the local
#![stable(feature = "rust1", since = "1.0.0")]
#![deny(unsafe_op_in_unsafe_fn)]
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
+mod tests;
+
use crate::ffi::OsString;
use crate::fmt;
use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
&mut self.inner
}
}
-
-#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
-mod tests {
- use crate::io::prelude::*;
-
- use crate::fs::{self, File, OpenOptions};
- use crate::io::{ErrorKind, SeekFrom};
- use crate::path::Path;
- use crate::str;
- use crate::sys_common::io::test::{tmpdir, TempDir};
- use crate::thread;
-
- use rand::{rngs::StdRng, RngCore, SeedableRng};
-
- #[cfg(unix)]
- use crate::os::unix::fs::symlink as symlink_dir;
- #[cfg(unix)]
- use crate::os::unix::fs::symlink as symlink_file;
- #[cfg(unix)]
- use crate::os::unix::fs::symlink as symlink_junction;
- #[cfg(windows)]
- use crate::os::windows::fs::{symlink_dir, symlink_file};
- #[cfg(windows)]
- use crate::sys::fs::symlink_junction;
-
- macro_rules! check {
- ($e:expr) => {
- match $e {
- Ok(t) => t,
- Err(e) => panic!("{} failed with: {}", stringify!($e), e),
- }
- };
- }
-
- #[cfg(windows)]
- macro_rules! error {
- ($e:expr, $s:expr) => {
- match $e {
- Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
- Err(ref err) => assert!(
- err.raw_os_error() == Some($s),
- format!("`{}` did not have a code of `{}`", err, $s)
- ),
- }
- };
- }
-
- #[cfg(unix)]
- macro_rules! error {
- ($e:expr, $s:expr) => {
- error_contains!($e, $s)
- };
- }
-
- macro_rules! error_contains {
- ($e:expr, $s:expr) => {
- match $e {
- Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
- Err(ref err) => assert!(
- err.to_string().contains($s),
- format!("`{}` did not contain `{}`", err, $s)
- ),
- }
- };
- }
-
- // Several test fail on windows if the user does not have permission to
- // create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
- // disabling these test on Windows, use this function to test whether we
- // have permission, and return otherwise. This way, we still don't run these
- // tests most of the time, but at least we do if the user has the right
- // permissions.
- pub fn got_symlink_permission(tmpdir: &TempDir) -> bool {
- if cfg!(unix) {
- return true;
- }
- let link = tmpdir.join("some_hopefully_unique_link_name");
-
- match symlink_file(r"nonexisting_target", link) {
- Ok(_) => true,
- // ERROR_PRIVILEGE_NOT_HELD = 1314
- Err(ref err) if err.raw_os_error() == Some(1314) => false,
- Err(_) => true,
- }
- }
-
- #[test]
- fn file_test_io_smoke_test() {
- let message = "it's alright. have a good time";
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test.txt");
- {
- let mut write_stream = check!(File::create(filename));
- check!(write_stream.write(message.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
- let mut read_buf = [0; 1028];
- let read_str = match check!(read_stream.read(&mut read_buf)) {
- 0 => panic!("shouldn't happen"),
- n => str::from_utf8(&read_buf[..n]).unwrap().to_string(),
- };
- assert_eq!(read_str, message);
- }
- check!(fs::remove_file(filename));
- }
-
- #[test]
- fn invalid_path_raises() {
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_that_does_not_exist.txt");
- let result = File::open(filename);
-
- #[cfg(all(unix, not(target_os = "vxworks")))]
- error!(result, "No such file or directory");
- #[cfg(target_os = "vxworks")]
- error!(result, "no such file or directory");
- #[cfg(windows)]
- error!(result, 2); // ERROR_FILE_NOT_FOUND
- }
-
- #[test]
- fn file_test_iounlinking_invalid_path_should_raise_condition() {
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
-
- let result = fs::remove_file(filename);
-
- #[cfg(all(unix, not(target_os = "vxworks")))]
- error!(result, "No such file or directory");
- #[cfg(target_os = "vxworks")]
- error!(result, "no such file or directory");
- #[cfg(windows)]
- error!(result, 2); // ERROR_FILE_NOT_FOUND
- }
-
- #[test]
- fn file_test_io_non_positional_read() {
- let message: &str = "ten-four";
- let mut read_mem = [0; 8];
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
- {
- let mut rw_stream = check!(File::create(filename));
- check!(rw_stream.write(message.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
- {
- let read_buf = &mut read_mem[0..4];
- check!(read_stream.read(read_buf));
- }
- {
- let read_buf = &mut read_mem[4..8];
- check!(read_stream.read(read_buf));
- }
- }
- check!(fs::remove_file(filename));
- let read_str = str::from_utf8(&read_mem).unwrap();
- assert_eq!(read_str, message);
- }
-
- #[test]
- fn file_test_io_seek_and_tell_smoke_test() {
- let message = "ten-four";
- let mut read_mem = [0; 4];
- let set_cursor = 4 as u64;
- let tell_pos_pre_read;
- let tell_pos_post_read;
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
- {
- let mut rw_stream = check!(File::create(filename));
- check!(rw_stream.write(message.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
- check!(read_stream.seek(SeekFrom::Start(set_cursor)));
- tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0)));
- check!(read_stream.read(&mut read_mem));
- tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0)));
- }
- check!(fs::remove_file(filename));
- let read_str = str::from_utf8(&read_mem).unwrap();
- assert_eq!(read_str, &message[4..8]);
- assert_eq!(tell_pos_pre_read, set_cursor);
- assert_eq!(tell_pos_post_read, message.len() as u64);
- }
-
- #[test]
- fn file_test_io_seek_and_write() {
- let initial_msg = "food-is-yummy";
- let overwrite_msg = "-the-bar!!";
- let final_msg = "foo-the-bar!!";
- let seek_idx = 3;
- let mut read_mem = [0; 13];
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
- {
- let mut rw_stream = check!(File::create(filename));
- check!(rw_stream.write(initial_msg.as_bytes()));
- check!(rw_stream.seek(SeekFrom::Start(seek_idx)));
- check!(rw_stream.write(overwrite_msg.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
- check!(read_stream.read(&mut read_mem));
- }
- check!(fs::remove_file(filename));
- let read_str = str::from_utf8(&read_mem).unwrap();
- assert!(read_str == final_msg);
- }
-
- #[test]
- fn file_test_io_seek_shakedown() {
- // 01234567890123
- let initial_msg = "qwer-asdf-zxcv";
- let chunk_one: &str = "qwer";
- let chunk_two: &str = "asdf";
- let chunk_three: &str = "zxcv";
- let mut read_mem = [0; 4];
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
- {
- let mut rw_stream = check!(File::create(filename));
- check!(rw_stream.write(initial_msg.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
-
- check!(read_stream.seek(SeekFrom::End(-4)));
- check!(read_stream.read(&mut read_mem));
- assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three);
-
- check!(read_stream.seek(SeekFrom::Current(-9)));
- check!(read_stream.read(&mut read_mem));
- assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two);
-
- check!(read_stream.seek(SeekFrom::Start(0)));
- check!(read_stream.read(&mut read_mem));
- assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one);
- }
- check!(fs::remove_file(filename));
- }
-
- #[test]
- fn file_test_io_eof() {
- let tmpdir = tmpdir();
- let filename = tmpdir.join("file_rt_io_file_test_eof.txt");
- let mut buf = [0; 256];
- {
- let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
- let mut rw = check!(oo.open(&filename));
- assert_eq!(check!(rw.read(&mut buf)), 0);
- assert_eq!(check!(rw.read(&mut buf)), 0);
- }
- check!(fs::remove_file(&filename));
- }
-
- #[test]
- #[cfg(unix)]
- fn file_test_io_read_write_at() {
- use crate::os::unix::fs::FileExt;
-
- let tmpdir = tmpdir();
- let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt");
- let mut buf = [0; 256];
- let write1 = "asdf";
- let write2 = "qwer-";
- let write3 = "-zxcv";
- let content = "qwer-asdf-zxcv";
- {
- let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
- let mut rw = check!(oo.open(&filename));
- assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len());
- assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
- assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len());
- assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
- assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
- assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
- assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0"));
- assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
- assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
- assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
- assert_eq!(check!(rw.read(&mut buf)), write1.len());
- assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
- assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
- assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
- assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
- assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
- assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len());
- assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
- }
- {
- let mut read = check!(File::open(&filename));
- assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
- assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
- assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0);
- assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
- assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
- assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
- assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9);
- assert_eq!(check!(read.read(&mut buf)), write3.len());
- assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
- assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
- assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
- assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
- assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
- assert_eq!(check!(read.read_at(&mut buf, 14)), 0);
- assert_eq!(check!(read.read_at(&mut buf, 15)), 0);
- assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
- }
- check!(fs::remove_file(&filename));
- }
-
- #[test]
- #[cfg(unix)]
- fn set_get_unix_permissions() {
- use crate::os::unix::fs::PermissionsExt;
-
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("set_get_unix_permissions");
- check!(fs::create_dir(filename));
- let mask = 0o7777;
-
- check!(fs::set_permissions(filename, fs::Permissions::from_mode(0)));
- let metadata0 = check!(fs::metadata(filename));
- assert_eq!(mask & metadata0.permissions().mode(), 0);
-
- check!(fs::set_permissions(filename, fs::Permissions::from_mode(0o1777)));
- let metadata1 = check!(fs::metadata(filename));
- #[cfg(all(unix, not(target_os = "vxworks")))]
- assert_eq!(mask & metadata1.permissions().mode(), 0o1777);
- #[cfg(target_os = "vxworks")]
- assert_eq!(mask & metadata1.permissions().mode(), 0o0777);
- }
-
- #[test]
- #[cfg(windows)]
- fn file_test_io_seek_read_write() {
- use crate::os::windows::fs::FileExt;
-
- let tmpdir = tmpdir();
- let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt");
- let mut buf = [0; 256];
- let write1 = "asdf";
- let write2 = "qwer-";
- let write3 = "-zxcv";
- let content = "qwer-asdf-zxcv";
- {
- let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
- let mut rw = check!(oo.open(&filename));
- assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len());
- assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
- assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len());
- assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
- assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
- assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0);
- assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
- assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
- assert_eq!(check!(rw.read(&mut buf)), write1.len());
- assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
- assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
- assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len());
- assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
- assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
- assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len());
- assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14);
- }
- {
- let mut read = check!(File::open(&filename));
- assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
- assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
- assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
- assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
- assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
- assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
- assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
- assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
- assert_eq!(check!(read.read(&mut buf)), write3.len());
- assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
- assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
- assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
- assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
- assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
- assert_eq!(check!(read.seek_read(&mut buf, 14)), 0);
- assert_eq!(check!(read.seek_read(&mut buf, 15)), 0);
- }
- check!(fs::remove_file(&filename));
- }
-
- #[test]
- fn file_test_stat_is_correct_on_is_file() {
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
- {
- let mut opts = OpenOptions::new();
- let mut fs = check!(opts.read(true).write(true).create(true).open(filename));
- let msg = "hw";
- fs.write(msg.as_bytes()).unwrap();
-
- let fstat_res = check!(fs.metadata());
- assert!(fstat_res.is_file());
- }
- let stat_res_fn = check!(fs::metadata(filename));
- assert!(stat_res_fn.is_file());
- let stat_res_meth = check!(filename.metadata());
- assert!(stat_res_meth.is_file());
- check!(fs::remove_file(filename));
- }
-
- #[test]
- fn file_test_stat_is_correct_on_is_dir() {
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_stat_correct_on_is_dir");
- check!(fs::create_dir(filename));
- let stat_res_fn = check!(fs::metadata(filename));
- assert!(stat_res_fn.is_dir());
- let stat_res_meth = check!(filename.metadata());
- assert!(stat_res_meth.is_dir());
- check!(fs::remove_dir(filename));
- }
-
- #[test]
- fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("fileinfo_false_on_dir");
- check!(fs::create_dir(dir));
- assert!(!dir.is_file());
- check!(fs::remove_dir(dir));
- }
-
- #[test]
- fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
- let tmpdir = tmpdir();
- let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
- check!(check!(File::create(file)).write(b"foo"));
- assert!(file.exists());
- check!(fs::remove_file(file));
- assert!(!file.exists());
- }
-
- #[test]
- fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("before_and_after_dir");
- assert!(!dir.exists());
- check!(fs::create_dir(dir));
- assert!(dir.exists());
- assert!(dir.is_dir());
- check!(fs::remove_dir(dir));
- assert!(!dir.exists());
- }
-
- #[test]
- fn file_test_directoryinfo_readdir() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("di_readdir");
- check!(fs::create_dir(dir));
- let prefix = "foo";
- for n in 0..3 {
- let f = dir.join(&format!("{}.txt", n));
- let mut w = check!(File::create(&f));
- let msg_str = format!("{}{}", prefix, n.to_string());
- let msg = msg_str.as_bytes();
- check!(w.write(msg));
- }
- let files = check!(fs::read_dir(dir));
- let mut mem = [0; 4];
- for f in files {
- let f = f.unwrap().path();
- {
- let n = f.file_stem().unwrap();
- check!(check!(File::open(&f)).read(&mut mem));
- let read_str = str::from_utf8(&mem).unwrap();
- let expected = format!("{}{}", prefix, n.to_str().unwrap());
- assert_eq!(expected, read_str);
- }
- check!(fs::remove_file(&f));
- }
- check!(fs::remove_dir(dir));
- }
-
- #[test]
- fn file_create_new_already_exists_error() {
- let tmpdir = tmpdir();
- let file = &tmpdir.join("file_create_new_error_exists");
- check!(fs::File::create(file));
- let e = fs::OpenOptions::new().write(true).create_new(true).open(file).unwrap_err();
- assert_eq!(e.kind(), ErrorKind::AlreadyExists);
- }
-
- #[test]
- fn mkdir_path_already_exists_error() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("mkdir_error_twice");
- check!(fs::create_dir(dir));
- let e = fs::create_dir(dir).unwrap_err();
- assert_eq!(e.kind(), ErrorKind::AlreadyExists);
- }
-
- #[test]
- fn recursive_mkdir() {
- let tmpdir = tmpdir();
- let dir = tmpdir.join("d1/d2");
- check!(fs::create_dir_all(&dir));
- assert!(dir.is_dir())
- }
-
- #[test]
- fn recursive_mkdir_failure() {
- let tmpdir = tmpdir();
- let dir = tmpdir.join("d1");
- let file = dir.join("f1");
-
- check!(fs::create_dir_all(&dir));
- check!(File::create(&file));
-
- let result = fs::create_dir_all(&file);
-
- assert!(result.is_err());
- }
-
- #[test]
- fn concurrent_recursive_mkdir() {
- for _ in 0..100 {
- let dir = tmpdir();
- let mut dir = dir.join("a");
- for _ in 0..40 {
- dir = dir.join("a");
- }
- let mut join = vec![];
- for _ in 0..8 {
- let dir = dir.clone();
- join.push(thread::spawn(move || {
- check!(fs::create_dir_all(&dir));
- }))
- }
-
- // No `Display` on result of `join()`
- join.drain(..).map(|join| join.join().unwrap()).count();
- }
- }
-
- #[test]
- fn recursive_mkdir_slash() {
- check!(fs::create_dir_all(Path::new("/")));
- }
-
- #[test]
- fn recursive_mkdir_dot() {
- check!(fs::create_dir_all(Path::new(".")));
- }
-
- #[test]
- fn recursive_mkdir_empty() {
- check!(fs::create_dir_all(Path::new("")));
- }
-
- #[test]
- fn recursive_rmdir() {
- let tmpdir = tmpdir();
- let d1 = tmpdir.join("d1");
- let dt = d1.join("t");
- let dtt = dt.join("t");
- let d2 = tmpdir.join("d2");
- let canary = d2.join("do_not_delete");
- check!(fs::create_dir_all(&dtt));
- check!(fs::create_dir_all(&d2));
- check!(check!(File::create(&canary)).write(b"foo"));
- check!(symlink_junction(&d2, &dt.join("d2")));
- let _ = symlink_file(&canary, &d1.join("canary"));
- check!(fs::remove_dir_all(&d1));
-
- assert!(!d1.is_dir());
- assert!(canary.exists());
- }
-
- #[test]
- fn recursive_rmdir_of_symlink() {
- // test we do not recursively delete a symlink but only dirs.
- let tmpdir = tmpdir();
- let link = tmpdir.join("d1");
- let dir = tmpdir.join("d2");
- let canary = dir.join("do_not_delete");
- check!(fs::create_dir_all(&dir));
- check!(check!(File::create(&canary)).write(b"foo"));
- check!(symlink_junction(&dir, &link));
- check!(fs::remove_dir_all(&link));
-
- assert!(!link.is_dir());
- assert!(canary.exists());
- }
-
- #[test]
- // only Windows makes a distinction between file and directory symlinks.
- #[cfg(windows)]
- fn recursive_rmdir_of_file_symlink() {
- let tmpdir = tmpdir();
- if !got_symlink_permission(&tmpdir) {
- return;
- };
-
- let f1 = tmpdir.join("f1");
- let f2 = tmpdir.join("f2");
- check!(check!(File::create(&f1)).write(b"foo"));
- check!(symlink_file(&f1, &f2));
- match fs::remove_dir_all(&f2) {
- Ok(..) => panic!("wanted a failure"),
- Err(..) => {}
- }
- }
-
- #[test]
- fn unicode_path_is_dir() {
- assert!(Path::new(".").is_dir());
- assert!(!Path::new("test/stdtest/fs.rs").is_dir());
-
- let tmpdir = tmpdir();
-
- let mut dirpath = tmpdir.path().to_path_buf();
- dirpath.push("test-가一ー你好");
- check!(fs::create_dir(&dirpath));
- assert!(dirpath.is_dir());
-
- let mut filepath = dirpath;
- filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
- check!(File::create(&filepath)); // ignore return; touch only
- assert!(!filepath.is_dir());
- assert!(filepath.exists());
- }
-
- #[test]
- fn unicode_path_exists() {
- assert!(Path::new(".").exists());
- assert!(!Path::new("test/nonexistent-bogus-path").exists());
-
- let tmpdir = tmpdir();
- let unicode = tmpdir.path();
- let unicode = unicode.join("test-각丁ー再见");
- check!(fs::create_dir(&unicode));
- assert!(unicode.exists());
- assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
- }
-
- #[test]
- fn copy_file_does_not_exist() {
- let from = Path::new("test/nonexistent-bogus-path");
- let to = Path::new("test/other-bogus-path");
-
- match fs::copy(&from, &to) {
- Ok(..) => panic!(),
- Err(..) => {
- assert!(!from.exists());
- assert!(!to.exists());
- }
- }
- }
-
- #[test]
- fn copy_src_does_not_exist() {
- let tmpdir = tmpdir();
- let from = Path::new("test/nonexistent-bogus-path");
- let to = tmpdir.join("out.txt");
- check!(check!(File::create(&to)).write(b"hello"));
- assert!(fs::copy(&from, &to).is_err());
- assert!(!from.exists());
- let mut v = Vec::new();
- check!(check!(File::open(&to)).read_to_end(&mut v));
- assert_eq!(v, b"hello");
- }
-
- #[test]
- fn copy_file_ok() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in.txt");
- let out = tmpdir.join("out.txt");
-
- check!(check!(File::create(&input)).write(b"hello"));
- check!(fs::copy(&input, &out));
- let mut v = Vec::new();
- check!(check!(File::open(&out)).read_to_end(&mut v));
- assert_eq!(v, b"hello");
-
- assert_eq!(check!(input.metadata()).permissions(), check!(out.metadata()).permissions());
- }
-
- #[test]
- fn copy_file_dst_dir() {
- let tmpdir = tmpdir();
- let out = tmpdir.join("out");
-
- check!(File::create(&out));
- match fs::copy(&*out, tmpdir.path()) {
- Ok(..) => panic!(),
- Err(..) => {}
- }
- }
-
- #[test]
- fn copy_file_dst_exists() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in");
- let output = tmpdir.join("out");
-
- check!(check!(File::create(&input)).write("foo".as_bytes()));
- check!(check!(File::create(&output)).write("bar".as_bytes()));
- check!(fs::copy(&input, &output));
-
- let mut v = Vec::new();
- check!(check!(File::open(&output)).read_to_end(&mut v));
- assert_eq!(v, b"foo".to_vec());
- }
-
- #[test]
- fn copy_file_src_dir() {
- let tmpdir = tmpdir();
- let out = tmpdir.join("out");
-
- match fs::copy(tmpdir.path(), &out) {
- Ok(..) => panic!(),
- Err(..) => {}
- }
- assert!(!out.exists());
- }
-
- #[test]
- fn copy_file_preserves_perm_bits() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in.txt");
- let out = tmpdir.join("out.txt");
-
- let attr = check!(check!(File::create(&input)).metadata());
- let mut p = attr.permissions();
- p.set_readonly(true);
- check!(fs::set_permissions(&input, p));
- check!(fs::copy(&input, &out));
- assert!(check!(out.metadata()).permissions().readonly());
- check!(fs::set_permissions(&input, attr.permissions()));
- check!(fs::set_permissions(&out, attr.permissions()));
- }
-
- #[test]
- #[cfg(windows)]
- fn copy_file_preserves_streams() {
- let tmp = tmpdir();
- check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes()));
- assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 0);
- assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0);
- let mut v = Vec::new();
- check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v));
- assert_eq!(v, b"carrot".to_vec());
- }
-
- #[test]
- fn copy_file_returns_metadata_len() {
- let tmp = tmpdir();
- let in_path = tmp.join("in.txt");
- let out_path = tmp.join("out.txt");
- check!(check!(File::create(&in_path)).write(b"lettuce"));
- #[cfg(windows)]
- check!(check!(File::create(tmp.join("in.txt:bunny"))).write(b"carrot"));
- let copied_len = check!(fs::copy(&in_path, &out_path));
- assert_eq!(check!(out_path.metadata()).len(), copied_len);
- }
-
- #[test]
- fn copy_file_follows_dst_symlink() {
- let tmp = tmpdir();
- if !got_symlink_permission(&tmp) {
- return;
- };
-
- let in_path = tmp.join("in.txt");
- let out_path = tmp.join("out.txt");
- let out_path_symlink = tmp.join("out_symlink.txt");
-
- check!(fs::write(&in_path, "foo"));
- check!(fs::write(&out_path, "bar"));
- check!(symlink_file(&out_path, &out_path_symlink));
-
- check!(fs::copy(&in_path, &out_path_symlink));
-
- assert!(check!(out_path_symlink.symlink_metadata()).file_type().is_symlink());
- assert_eq!(check!(fs::read(&out_path_symlink)), b"foo".to_vec());
- assert_eq!(check!(fs::read(&out_path)), b"foo".to_vec());
- }
-
- #[test]
- fn symlinks_work() {
- let tmpdir = tmpdir();
- if !got_symlink_permission(&tmpdir) {
- return;
- };
-
- let input = tmpdir.join("in.txt");
- let out = tmpdir.join("out.txt");
-
- check!(check!(File::create(&input)).write("foobar".as_bytes()));
- check!(symlink_file(&input, &out));
- assert!(check!(out.symlink_metadata()).file_type().is_symlink());
- assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len());
- let mut v = Vec::new();
- check!(check!(File::open(&out)).read_to_end(&mut v));
- assert_eq!(v, b"foobar".to_vec());
- }
-
- #[test]
- fn symlink_noexist() {
- // Symlinks can point to things that don't exist
- let tmpdir = tmpdir();
- if !got_symlink_permission(&tmpdir) {
- return;
- };
-
- // Use a relative path for testing. Symlinks get normalized by Windows,
- // so we may not get the same path back for absolute paths
- check!(symlink_file(&"foo", &tmpdir.join("bar")));
- assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))).to_str().unwrap(), "foo");
- }
-
- #[test]
- fn read_link() {
- if cfg!(windows) {
- // directory symlink
- assert_eq!(
- check!(fs::read_link(r"C:\Users\All Users")).to_str().unwrap(),
- r"C:\ProgramData"
- );
- // junction
- assert_eq!(
- check!(fs::read_link(r"C:\Users\Default User")).to_str().unwrap(),
- r"C:\Users\Default"
- );
- // junction with special permissions
- assert_eq!(
- check!(fs::read_link(r"C:\Documents and Settings\")).to_str().unwrap(),
- r"C:\Users"
- );
- }
- let tmpdir = tmpdir();
- let link = tmpdir.join("link");
- if !got_symlink_permission(&tmpdir) {
- return;
- };
- check!(symlink_file(&"foo", &link));
- assert_eq!(check!(fs::read_link(&link)).to_str().unwrap(), "foo");
- }
-
- #[test]
- fn readlink_not_symlink() {
- let tmpdir = tmpdir();
- match fs::read_link(tmpdir.path()) {
- Ok(..) => panic!("wanted a failure"),
- Err(..) => {}
- }
- }
-
- #[test]
- fn links_work() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in.txt");
- let out = tmpdir.join("out.txt");
-
- check!(check!(File::create(&input)).write("foobar".as_bytes()));
- check!(fs::hard_link(&input, &out));
- assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len());
- assert_eq!(check!(fs::metadata(&out)).len(), check!(input.metadata()).len());
- let mut v = Vec::new();
- check!(check!(File::open(&out)).read_to_end(&mut v));
- assert_eq!(v, b"foobar".to_vec());
-
- // can't link to yourself
- match fs::hard_link(&input, &input) {
- Ok(..) => panic!("wanted a failure"),
- Err(..) => {}
- }
- // can't link to something that doesn't exist
- match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
- Ok(..) => panic!("wanted a failure"),
- Err(..) => {}
- }
- }
-
- #[test]
- fn chmod_works() {
- let tmpdir = tmpdir();
- let file = tmpdir.join("in.txt");
-
- check!(File::create(&file));
- let attr = check!(fs::metadata(&file));
- assert!(!attr.permissions().readonly());
- let mut p = attr.permissions();
- p.set_readonly(true);
- check!(fs::set_permissions(&file, p.clone()));
- let attr = check!(fs::metadata(&file));
- assert!(attr.permissions().readonly());
-
- match fs::set_permissions(&tmpdir.join("foo"), p.clone()) {
- Ok(..) => panic!("wanted an error"),
- Err(..) => {}
- }
-
- p.set_readonly(false);
- check!(fs::set_permissions(&file, p));
- }
-
- #[test]
- fn fchmod_works() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("in.txt");
-
- let file = check!(File::create(&path));
- let attr = check!(fs::metadata(&path));
- assert!(!attr.permissions().readonly());
- let mut p = attr.permissions();
- p.set_readonly(true);
- check!(file.set_permissions(p.clone()));
- let attr = check!(fs::metadata(&path));
- assert!(attr.permissions().readonly());
-
- p.set_readonly(false);
- check!(file.set_permissions(p));
- }
-
- #[test]
- fn sync_doesnt_kill_anything() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("in.txt");
-
- let mut file = check!(File::create(&path));
- check!(file.sync_all());
- check!(file.sync_data());
- check!(file.write(b"foo"));
- check!(file.sync_all());
- check!(file.sync_data());
- }
-
- #[test]
- fn truncate_works() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("in.txt");
-
- let mut file = check!(File::create(&path));
- check!(file.write(b"foo"));
- check!(file.sync_all());
-
- // Do some simple things with truncation
- assert_eq!(check!(file.metadata()).len(), 3);
- check!(file.set_len(10));
- assert_eq!(check!(file.metadata()).len(), 10);
- check!(file.write(b"bar"));
- check!(file.sync_all());
- assert_eq!(check!(file.metadata()).len(), 10);
-
- let mut v = Vec::new();
- check!(check!(File::open(&path)).read_to_end(&mut v));
- assert_eq!(v, b"foobar\0\0\0\0".to_vec());
-
- // Truncate to a smaller length, don't seek, and then write something.
- // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
- // past the end of the file).
- check!(file.set_len(2));
- assert_eq!(check!(file.metadata()).len(), 2);
- check!(file.write(b"wut"));
- check!(file.sync_all());
- assert_eq!(check!(file.metadata()).len(), 9);
- let mut v = Vec::new();
- check!(check!(File::open(&path)).read_to_end(&mut v));
- assert_eq!(v, b"fo\0\0\0\0wut".to_vec());
- }
-
- #[test]
- fn open_flavors() {
- use crate::fs::OpenOptions as OO;
- fn c<T: Clone>(t: &T) -> T {
- t.clone()
- }
-
- let tmpdir = tmpdir();
-
- let mut r = OO::new();
- r.read(true);
- let mut w = OO::new();
- w.write(true);
- let mut rw = OO::new();
- rw.read(true).write(true);
- let mut a = OO::new();
- a.append(true);
- let mut ra = OO::new();
- ra.read(true).append(true);
-
- #[cfg(windows)]
- let invalid_options = 87; // ERROR_INVALID_PARAMETER
- #[cfg(all(unix, not(target_os = "vxworks")))]
- let invalid_options = "Invalid argument";
- #[cfg(target_os = "vxworks")]
- let invalid_options = "invalid argument";
-
- // Test various combinations of creation modes and access modes.
- //
- // Allowed:
- // creation mode | read | write | read-write | append | read-append |
- // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:|
- // not set (open existing) | X | X | X | X | X |
- // create | | X | X | X | X |
- // truncate | | X | X | | |
- // create and truncate | | X | X | | |
- // create_new | | X | X | X | X |
- //
- // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it.
-
- // write-only
- check!(c(&w).create_new(true).open(&tmpdir.join("a")));
- check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a")));
- check!(c(&w).truncate(true).open(&tmpdir.join("a")));
- check!(c(&w).create(true).open(&tmpdir.join("a")));
- check!(c(&w).open(&tmpdir.join("a")));
-
- // read-only
- error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options);
- error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options);
- error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options);
- error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options);
- check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only
-
- // read-write
- check!(c(&rw).create_new(true).open(&tmpdir.join("c")));
- check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c")));
- check!(c(&rw).truncate(true).open(&tmpdir.join("c")));
- check!(c(&rw).create(true).open(&tmpdir.join("c")));
- check!(c(&rw).open(&tmpdir.join("c")));
-
- // append
- check!(c(&a).create_new(true).open(&tmpdir.join("d")));
- error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options);
- error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options);
- check!(c(&a).create(true).open(&tmpdir.join("d")));
- check!(c(&a).open(&tmpdir.join("d")));
-
- // read-append
- check!(c(&ra).create_new(true).open(&tmpdir.join("e")));
- error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options);
- error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options);
- check!(c(&ra).create(true).open(&tmpdir.join("e")));
- check!(c(&ra).open(&tmpdir.join("e")));
-
- // Test opening a file without setting an access mode
- let mut blank = OO::new();
- error!(blank.create(true).open(&tmpdir.join("f")), invalid_options);
-
- // Test write works
- check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes()));
-
- // Test write fails for read-only
- check!(r.open(&tmpdir.join("h")));
- {
- let mut f = check!(r.open(&tmpdir.join("h")));
- assert!(f.write("wut".as_bytes()).is_err());
- }
-
- // Test write overwrites
- {
- let mut f = check!(c(&w).open(&tmpdir.join("h")));
- check!(f.write("baz".as_bytes()));
- }
- {
- let mut f = check!(c(&r).open(&tmpdir.join("h")));
- let mut b = vec![0; 6];
- check!(f.read(&mut b));
- assert_eq!(b, "bazbar".as_bytes());
- }
-
- // Test truncate works
- {
- let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
- check!(f.write("foo".as_bytes()));
- }
- assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
-
- // Test append works
- assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
- {
- let mut f = check!(c(&a).open(&tmpdir.join("h")));
- check!(f.write("bar".as_bytes()));
- }
- assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
-
- // Test .append(true) equals .write(true).append(true)
- {
- let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
- check!(f.write("baz".as_bytes()));
- }
- assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9);
- }
-
- #[test]
- fn _assert_send_sync() {
- fn _assert_send_sync<T: Send + Sync>() {}
- _assert_send_sync::<OpenOptions>();
- }
-
- #[test]
- fn binary_file() {
- let mut bytes = [0; 1024];
- StdRng::from_entropy().fill_bytes(&mut bytes);
-
- let tmpdir = tmpdir();
-
- check!(check!(File::create(&tmpdir.join("test"))).write(&bytes));
- let mut v = Vec::new();
- check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v));
- assert!(v == &bytes[..]);
- }
-
- #[test]
- fn write_then_read() {
- let mut bytes = [0; 1024];
- StdRng::from_entropy().fill_bytes(&mut bytes);
-
- let tmpdir = tmpdir();
-
- check!(fs::write(&tmpdir.join("test"), &bytes[..]));
- let v = check!(fs::read(&tmpdir.join("test")));
- assert!(v == &bytes[..]);
-
- check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF]));
- error_contains!(
- fs::read_to_string(&tmpdir.join("not-utf8")),
- "stream did not contain valid UTF-8"
- );
-
- let s = "𐁁𐀓𐀠𐀴𐀍";
- check!(fs::write(&tmpdir.join("utf8"), s.as_bytes()));
- let string = check!(fs::read_to_string(&tmpdir.join("utf8")));
- assert_eq!(string, s);
- }
-
- #[test]
- fn file_try_clone() {
- let tmpdir = tmpdir();
-
- let mut f1 = check!(
- OpenOptions::new().read(true).write(true).create(true).open(&tmpdir.join("test"))
- );
- let mut f2 = check!(f1.try_clone());
-
- check!(f1.write_all(b"hello world"));
- check!(f1.seek(SeekFrom::Start(2)));
-
- let mut buf = vec![];
- check!(f2.read_to_end(&mut buf));
- assert_eq!(buf, b"llo world");
- drop(f2);
-
- check!(f1.write_all(b"!"));
- }
-
- #[test]
- #[cfg(not(windows))]
- fn unlink_readonly() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("file");
- check!(File::create(&path));
- let mut perm = check!(fs::metadata(&path)).permissions();
- perm.set_readonly(true);
- check!(fs::set_permissions(&path, perm));
- check!(fs::remove_file(&path));
- }
-
- #[test]
- fn mkdir_trailing_slash() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("file");
- check!(fs::create_dir_all(&path.join("a/")));
- }
-
- #[test]
- fn canonicalize_works_simple() {
- let tmpdir = tmpdir();
- let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
- let file = tmpdir.join("test");
- File::create(&file).unwrap();
- assert_eq!(fs::canonicalize(&file).unwrap(), file);
- }
-
- #[test]
- fn realpath_works() {
- let tmpdir = tmpdir();
- if !got_symlink_permission(&tmpdir) {
- return;
- };
-
- let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
- let file = tmpdir.join("test");
- let dir = tmpdir.join("test2");
- let link = dir.join("link");
- let linkdir = tmpdir.join("test3");
-
- File::create(&file).unwrap();
- fs::create_dir(&dir).unwrap();
- symlink_file(&file, &link).unwrap();
- symlink_dir(&dir, &linkdir).unwrap();
-
- assert!(link.symlink_metadata().unwrap().file_type().is_symlink());
-
- assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir);
- assert_eq!(fs::canonicalize(&file).unwrap(), file);
- assert_eq!(fs::canonicalize(&link).unwrap(), file);
- assert_eq!(fs::canonicalize(&linkdir).unwrap(), dir);
- assert_eq!(fs::canonicalize(&linkdir.join("link")).unwrap(), file);
- }
-
- #[test]
- fn realpath_works_tricky() {
- let tmpdir = tmpdir();
- if !got_symlink_permission(&tmpdir) {
- return;
- };
-
- let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
- let a = tmpdir.join("a");
- let b = a.join("b");
- let c = b.join("c");
- let d = a.join("d");
- let e = d.join("e");
- let f = a.join("f");
-
- fs::create_dir_all(&b).unwrap();
- fs::create_dir_all(&d).unwrap();
- File::create(&f).unwrap();
- if cfg!(not(windows)) {
- symlink_file("../d/e", &c).unwrap();
- symlink_file("../f", &e).unwrap();
- }
- if cfg!(windows) {
- symlink_file(r"..\d\e", &c).unwrap();
- symlink_file(r"..\f", &e).unwrap();
- }
-
- assert_eq!(fs::canonicalize(&c).unwrap(), f);
- assert_eq!(fs::canonicalize(&e).unwrap(), f);
- }
-
- #[test]
- fn dir_entry_methods() {
- let tmpdir = tmpdir();
-
- fs::create_dir_all(&tmpdir.join("a")).unwrap();
- File::create(&tmpdir.join("b")).unwrap();
-
- for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) {
- let fname = file.file_name();
- match fname.to_str() {
- Some("a") => {
- assert!(file.file_type().unwrap().is_dir());
- assert!(file.metadata().unwrap().is_dir());
- }
- Some("b") => {
- assert!(file.file_type().unwrap().is_file());
- assert!(file.metadata().unwrap().is_file());
- }
- f => panic!("unknown file name: {:?}", f),
- }
- }
- }
-
- #[test]
- fn dir_entry_debug() {
- let tmpdir = tmpdir();
- File::create(&tmpdir.join("b")).unwrap();
- let mut read_dir = tmpdir.path().read_dir().unwrap();
- let dir_entry = read_dir.next().unwrap().unwrap();
- let actual = format!("{:?}", dir_entry);
- let expected = format!("DirEntry({:?})", dir_entry.0.path());
- assert_eq!(actual, expected);
- }
-
- #[test]
- fn read_dir_not_found() {
- let res = fs::read_dir("/path/that/does/not/exist");
- assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound);
- }
-
- #[test]
- fn create_dir_all_with_junctions() {
- let tmpdir = tmpdir();
- let target = tmpdir.join("target");
-
- let junction = tmpdir.join("junction");
- let b = junction.join("a/b");
-
- let link = tmpdir.join("link");
- let d = link.join("c/d");
-
- fs::create_dir(&target).unwrap();
-
- check!(symlink_junction(&target, &junction));
- check!(fs::create_dir_all(&b));
- // the junction itself is not a directory, but `is_dir()` on a Path
- // follows links
- assert!(junction.is_dir());
- assert!(b.exists());
-
- if !got_symlink_permission(&tmpdir) {
- return;
- };
- check!(symlink_dir(&target, &link));
- check!(fs::create_dir_all(&d));
- assert!(link.is_dir());
- assert!(d.exists());
- }
-
- #[test]
- fn metadata_access_times() {
- let tmpdir = tmpdir();
-
- let b = tmpdir.join("b");
- File::create(&b).unwrap();
-
- let a = check!(fs::metadata(&tmpdir.path()));
- let b = check!(fs::metadata(&b));
-
- assert_eq!(check!(a.accessed()), check!(a.accessed()));
- assert_eq!(check!(a.modified()), check!(a.modified()));
- assert_eq!(check!(b.accessed()), check!(b.modified()));
-
- if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
- check!(a.created());
- check!(b.created());
- }
-
- if cfg!(target_os = "linux") {
- // Not always available
- match (a.created(), b.created()) {
- (Ok(t1), Ok(t2)) => assert!(t1 <= t2),
- (Err(e1), Err(e2))
- if e1.kind() == ErrorKind::Other && e2.kind() == ErrorKind::Other => {}
- (a, b) => panic!(
- "creation time must be always supported or not supported: {:?} {:?}",
- a, b,
- ),
- }
- }
- }
-}
--- /dev/null
+use crate::io::prelude::*;
+
+use crate::fs::{self, File, OpenOptions};
+use crate::io::{ErrorKind, SeekFrom};
+use crate::path::Path;
+use crate::str;
+use crate::sys_common::io::test::{tmpdir, TempDir};
+use crate::thread;
+
+use rand::{rngs::StdRng, RngCore, SeedableRng};
+
+#[cfg(unix)]
+use crate::os::unix::fs::symlink as symlink_dir;
+#[cfg(unix)]
+use crate::os::unix::fs::symlink as symlink_file;
+#[cfg(unix)]
+use crate::os::unix::fs::symlink as symlink_junction;
+#[cfg(windows)]
+use crate::os::windows::fs::{symlink_dir, symlink_file};
+#[cfg(windows)]
+use crate::sys::fs::symlink_junction;
+
+macro_rules! check {
+ ($e:expr) => {
+ match $e {
+ Ok(t) => t,
+ Err(e) => panic!("{} failed with: {}", stringify!($e), e),
+ }
+ };
+}
+
+#[cfg(windows)]
+macro_rules! error {
+ ($e:expr, $s:expr) => {
+ match $e {
+ Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
+ Err(ref err) => assert!(
+ err.raw_os_error() == Some($s),
+ format!("`{}` did not have a code of `{}`", err, $s)
+ ),
+ }
+ };
+}
+
+#[cfg(unix)]
+macro_rules! error {
+ ($e:expr, $s:expr) => {
+ error_contains!($e, $s)
+ };
+}
+
+macro_rules! error_contains {
+ ($e:expr, $s:expr) => {
+ match $e {
+ Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
+ Err(ref err) => {
+ assert!(err.to_string().contains($s), format!("`{}` did not contain `{}`", err, $s))
+ }
+ }
+ };
+}
+
+// Several test fail on windows if the user does not have permission to
+// create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
+// disabling these test on Windows, use this function to test whether we
+// have permission, and return otherwise. This way, we still don't run these
+// tests most of the time, but at least we do if the user has the right
+// permissions.
+pub fn got_symlink_permission(tmpdir: &TempDir) -> bool {
+ if cfg!(unix) {
+ return true;
+ }
+ let link = tmpdir.join("some_hopefully_unique_link_name");
+
+ match symlink_file(r"nonexisting_target", link) {
+ Ok(_) => true,
+ // ERROR_PRIVILEGE_NOT_HELD = 1314
+ Err(ref err) if err.raw_os_error() == Some(1314) => false,
+ Err(_) => true,
+ }
+}
+
+#[test]
+fn file_test_io_smoke_test() {
+ let message = "it's alright. have a good time";
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test.txt");
+ {
+ let mut write_stream = check!(File::create(filename));
+ check!(write_stream.write(message.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ let mut read_buf = [0; 1028];
+ let read_str = match check!(read_stream.read(&mut read_buf)) {
+ 0 => panic!("shouldn't happen"),
+ n => str::from_utf8(&read_buf[..n]).unwrap().to_string(),
+ };
+ assert_eq!(read_str, message);
+ }
+ check!(fs::remove_file(filename));
+}
+
+#[test]
+fn invalid_path_raises() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_that_does_not_exist.txt");
+ let result = File::open(filename);
+
+ #[cfg(all(unix, not(target_os = "vxworks")))]
+ error!(result, "No such file or directory");
+ #[cfg(target_os = "vxworks")]
+ error!(result, "no such file or directory");
+ #[cfg(windows)]
+ error!(result, 2); // ERROR_FILE_NOT_FOUND
+}
+
+#[test]
+fn file_test_iounlinking_invalid_path_should_raise_condition() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
+
+ let result = fs::remove_file(filename);
+
+ #[cfg(all(unix, not(target_os = "vxworks")))]
+ error!(result, "No such file or directory");
+ #[cfg(target_os = "vxworks")]
+ error!(result, "no such file or directory");
+ #[cfg(windows)]
+ error!(result, 2); // ERROR_FILE_NOT_FOUND
+}
+
+#[test]
+fn file_test_io_non_positional_read() {
+ let message: &str = "ten-four";
+ let mut read_mem = [0; 8];
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(message.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ {
+ let read_buf = &mut read_mem[0..4];
+ check!(read_stream.read(read_buf));
+ }
+ {
+ let read_buf = &mut read_mem[4..8];
+ check!(read_stream.read(read_buf));
+ }
+ }
+ check!(fs::remove_file(filename));
+ let read_str = str::from_utf8(&read_mem).unwrap();
+ assert_eq!(read_str, message);
+}
+
+#[test]
+fn file_test_io_seek_and_tell_smoke_test() {
+ let message = "ten-four";
+ let mut read_mem = [0; 4];
+ let set_cursor = 4 as u64;
+ let tell_pos_pre_read;
+ let tell_pos_post_read;
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(message.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ check!(read_stream.seek(SeekFrom::Start(set_cursor)));
+ tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0)));
+ check!(read_stream.read(&mut read_mem));
+ tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0)));
+ }
+ check!(fs::remove_file(filename));
+ let read_str = str::from_utf8(&read_mem).unwrap();
+ assert_eq!(read_str, &message[4..8]);
+ assert_eq!(tell_pos_pre_read, set_cursor);
+ assert_eq!(tell_pos_post_read, message.len() as u64);
+}
+
+#[test]
+fn file_test_io_seek_and_write() {
+ let initial_msg = "food-is-yummy";
+ let overwrite_msg = "-the-bar!!";
+ let final_msg = "foo-the-bar!!";
+ let seek_idx = 3;
+ let mut read_mem = [0; 13];
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(initial_msg.as_bytes()));
+ check!(rw_stream.seek(SeekFrom::Start(seek_idx)));
+ check!(rw_stream.write(overwrite_msg.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ check!(read_stream.read(&mut read_mem));
+ }
+ check!(fs::remove_file(filename));
+ let read_str = str::from_utf8(&read_mem).unwrap();
+ assert!(read_str == final_msg);
+}
+
+#[test]
+fn file_test_io_seek_shakedown() {
+ // 01234567890123
+ let initial_msg = "qwer-asdf-zxcv";
+ let chunk_one: &str = "qwer";
+ let chunk_two: &str = "asdf";
+ let chunk_three: &str = "zxcv";
+ let mut read_mem = [0; 4];
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(initial_msg.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+
+ check!(read_stream.seek(SeekFrom::End(-4)));
+ check!(read_stream.read(&mut read_mem));
+ assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three);
+
+ check!(read_stream.seek(SeekFrom::Current(-9)));
+ check!(read_stream.read(&mut read_mem));
+ assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two);
+
+ check!(read_stream.seek(SeekFrom::Start(0)));
+ check!(read_stream.read(&mut read_mem));
+ assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one);
+ }
+ check!(fs::remove_file(filename));
+}
+
+#[test]
+fn file_test_io_eof() {
+ let tmpdir = tmpdir();
+ let filename = tmpdir.join("file_rt_io_file_test_eof.txt");
+ let mut buf = [0; 256];
+ {
+ let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+ let mut rw = check!(oo.open(&filename));
+ assert_eq!(check!(rw.read(&mut buf)), 0);
+ assert_eq!(check!(rw.read(&mut buf)), 0);
+ }
+ check!(fs::remove_file(&filename));
+}
+
+#[test]
+#[cfg(unix)]
+fn file_test_io_read_write_at() {
+ use crate::os::unix::fs::FileExt;
+
+ let tmpdir = tmpdir();
+ let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt");
+ let mut buf = [0; 256];
+ let write1 = "asdf";
+ let write2 = "qwer-";
+ let write3 = "-zxcv";
+ let content = "qwer-asdf-zxcv";
+ {
+ let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+ let mut rw = check!(oo.open(&filename));
+ assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
+ assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len());
+ assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
+ assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
+ assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0"));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
+ assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
+ assert_eq!(check!(rw.read(&mut buf)), write1.len());
+ assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
+ assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ }
+ {
+ let mut read = check!(File::open(&filename));
+ assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0);
+ assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
+ assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(read.read(&mut buf)), write3.len());
+ assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.read_at(&mut buf, 14)), 0);
+ assert_eq!(check!(read.read_at(&mut buf, 15)), 0);
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ }
+ check!(fs::remove_file(&filename));
+}
+
+#[test]
+#[cfg(unix)]
+fn set_get_unix_permissions() {
+ use crate::os::unix::fs::PermissionsExt;
+
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("set_get_unix_permissions");
+ check!(fs::create_dir(filename));
+ let mask = 0o7777;
+
+ check!(fs::set_permissions(filename, fs::Permissions::from_mode(0)));
+ let metadata0 = check!(fs::metadata(filename));
+ assert_eq!(mask & metadata0.permissions().mode(), 0);
+
+ check!(fs::set_permissions(filename, fs::Permissions::from_mode(0o1777)));
+ let metadata1 = check!(fs::metadata(filename));
+ #[cfg(all(unix, not(target_os = "vxworks")))]
+ assert_eq!(mask & metadata1.permissions().mode(), 0o1777);
+ #[cfg(target_os = "vxworks")]
+ assert_eq!(mask & metadata1.permissions().mode(), 0o0777);
+}
+
+#[test]
+#[cfg(windows)]
+fn file_test_io_seek_read_write() {
+ use crate::os::windows::fs::FileExt;
+
+ let tmpdir = tmpdir();
+ let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt");
+ let mut buf = [0; 256];
+ let write1 = "asdf";
+ let write2 = "qwer-";
+ let write3 = "-zxcv";
+ let content = "qwer-asdf-zxcv";
+ {
+ let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+ let mut rw = check!(oo.open(&filename));
+ assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len());
+ assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0);
+ assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
+ assert_eq!(check!(rw.read(&mut buf)), write1.len());
+ assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len());
+ assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
+ assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14);
+ }
+ {
+ let mut read = check!(File::open(&filename));
+ assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
+ assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
+ assert_eq!(check!(read.read(&mut buf)), write3.len());
+ assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.seek_read(&mut buf, 14)), 0);
+ assert_eq!(check!(read.seek_read(&mut buf, 15)), 0);
+ }
+ check!(fs::remove_file(&filename));
+}
+
+#[test]
+fn file_test_stat_is_correct_on_is_file() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
+ {
+ let mut opts = OpenOptions::new();
+ let mut fs = check!(opts.read(true).write(true).create(true).open(filename));
+ let msg = "hw";
+ fs.write(msg.as_bytes()).unwrap();
+
+ let fstat_res = check!(fs.metadata());
+ assert!(fstat_res.is_file());
+ }
+ let stat_res_fn = check!(fs::metadata(filename));
+ assert!(stat_res_fn.is_file());
+ let stat_res_meth = check!(filename.metadata());
+ assert!(stat_res_meth.is_file());
+ check!(fs::remove_file(filename));
+}
+
+#[test]
+fn file_test_stat_is_correct_on_is_dir() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_stat_correct_on_is_dir");
+ check!(fs::create_dir(filename));
+ let stat_res_fn = check!(fs::metadata(filename));
+ assert!(stat_res_fn.is_dir());
+ let stat_res_meth = check!(filename.metadata());
+ assert!(stat_res_meth.is_dir());
+ check!(fs::remove_dir(filename));
+}
+
+#[test]
+fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("fileinfo_false_on_dir");
+ check!(fs::create_dir(dir));
+ assert!(!dir.is_file());
+ check!(fs::remove_dir(dir));
+}
+
+#[test]
+fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
+ let tmpdir = tmpdir();
+ let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
+ check!(check!(File::create(file)).write(b"foo"));
+ assert!(file.exists());
+ check!(fs::remove_file(file));
+ assert!(!file.exists());
+}
+
+#[test]
+fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("before_and_after_dir");
+ assert!(!dir.exists());
+ check!(fs::create_dir(dir));
+ assert!(dir.exists());
+ assert!(dir.is_dir());
+ check!(fs::remove_dir(dir));
+ assert!(!dir.exists());
+}
+
+#[test]
+fn file_test_directoryinfo_readdir() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("di_readdir");
+ check!(fs::create_dir(dir));
+ let prefix = "foo";
+ for n in 0..3 {
+ let f = dir.join(&format!("{}.txt", n));
+ let mut w = check!(File::create(&f));
+ let msg_str = format!("{}{}", prefix, n.to_string());
+ let msg = msg_str.as_bytes();
+ check!(w.write(msg));
+ }
+ let files = check!(fs::read_dir(dir));
+ let mut mem = [0; 4];
+ for f in files {
+ let f = f.unwrap().path();
+ {
+ let n = f.file_stem().unwrap();
+ check!(check!(File::open(&f)).read(&mut mem));
+ let read_str = str::from_utf8(&mem).unwrap();
+ let expected = format!("{}{}", prefix, n.to_str().unwrap());
+ assert_eq!(expected, read_str);
+ }
+ check!(fs::remove_file(&f));
+ }
+ check!(fs::remove_dir(dir));
+}
+
+#[test]
+fn file_create_new_already_exists_error() {
+ let tmpdir = tmpdir();
+ let file = &tmpdir.join("file_create_new_error_exists");
+ check!(fs::File::create(file));
+ let e = fs::OpenOptions::new().write(true).create_new(true).open(file).unwrap_err();
+ assert_eq!(e.kind(), ErrorKind::AlreadyExists);
+}
+
+#[test]
+fn mkdir_path_already_exists_error() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("mkdir_error_twice");
+ check!(fs::create_dir(dir));
+ let e = fs::create_dir(dir).unwrap_err();
+ assert_eq!(e.kind(), ErrorKind::AlreadyExists);
+}
+
+#[test]
+fn recursive_mkdir() {
+ let tmpdir = tmpdir();
+ let dir = tmpdir.join("d1/d2");
+ check!(fs::create_dir_all(&dir));
+ assert!(dir.is_dir())
+}
+
+#[test]
+fn recursive_mkdir_failure() {
+ let tmpdir = tmpdir();
+ let dir = tmpdir.join("d1");
+ let file = dir.join("f1");
+
+ check!(fs::create_dir_all(&dir));
+ check!(File::create(&file));
+
+ let result = fs::create_dir_all(&file);
+
+ assert!(result.is_err());
+}
+
+#[test]
+fn concurrent_recursive_mkdir() {
+ for _ in 0..100 {
+ let dir = tmpdir();
+ let mut dir = dir.join("a");
+ for _ in 0..40 {
+ dir = dir.join("a");
+ }
+ let mut join = vec![];
+ for _ in 0..8 {
+ let dir = dir.clone();
+ join.push(thread::spawn(move || {
+ check!(fs::create_dir_all(&dir));
+ }))
+ }
+
+ // No `Display` on result of `join()`
+ join.drain(..).map(|join| join.join().unwrap()).count();
+ }
+}
+
+#[test]
+fn recursive_mkdir_slash() {
+ check!(fs::create_dir_all(Path::new("/")));
+}
+
+#[test]
+fn recursive_mkdir_dot() {
+ check!(fs::create_dir_all(Path::new(".")));
+}
+
+#[test]
+fn recursive_mkdir_empty() {
+ check!(fs::create_dir_all(Path::new("")));
+}
+
+#[test]
+fn recursive_rmdir() {
+ let tmpdir = tmpdir();
+ let d1 = tmpdir.join("d1");
+ let dt = d1.join("t");
+ let dtt = dt.join("t");
+ let d2 = tmpdir.join("d2");
+ let canary = d2.join("do_not_delete");
+ check!(fs::create_dir_all(&dtt));
+ check!(fs::create_dir_all(&d2));
+ check!(check!(File::create(&canary)).write(b"foo"));
+ check!(symlink_junction(&d2, &dt.join("d2")));
+ let _ = symlink_file(&canary, &d1.join("canary"));
+ check!(fs::remove_dir_all(&d1));
+
+ assert!(!d1.is_dir());
+ assert!(canary.exists());
+}
+
+#[test]
+fn recursive_rmdir_of_symlink() {
+ // test we do not recursively delete a symlink but only dirs.
+ let tmpdir = tmpdir();
+ let link = tmpdir.join("d1");
+ let dir = tmpdir.join("d2");
+ let canary = dir.join("do_not_delete");
+ check!(fs::create_dir_all(&dir));
+ check!(check!(File::create(&canary)).write(b"foo"));
+ check!(symlink_junction(&dir, &link));
+ check!(fs::remove_dir_all(&link));
+
+ assert!(!link.is_dir());
+ assert!(canary.exists());
+}
+
+#[test]
+// only Windows makes a distinction between file and directory symlinks.
+#[cfg(windows)]
+fn recursive_rmdir_of_file_symlink() {
+ let tmpdir = tmpdir();
+ if !got_symlink_permission(&tmpdir) {
+ return;
+ };
+
+ let f1 = tmpdir.join("f1");
+ let f2 = tmpdir.join("f2");
+ check!(check!(File::create(&f1)).write(b"foo"));
+ check!(symlink_file(&f1, &f2));
+ match fs::remove_dir_all(&f2) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+}
+
+#[test]
+fn unicode_path_is_dir() {
+ assert!(Path::new(".").is_dir());
+ assert!(!Path::new("test/stdtest/fs.rs").is_dir());
+
+ let tmpdir = tmpdir();
+
+ let mut dirpath = tmpdir.path().to_path_buf();
+ dirpath.push("test-가一ー你好");
+ check!(fs::create_dir(&dirpath));
+ assert!(dirpath.is_dir());
+
+ let mut filepath = dirpath;
+ filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
+ check!(File::create(&filepath)); // ignore return; touch only
+ assert!(!filepath.is_dir());
+ assert!(filepath.exists());
+}
+
+#[test]
+fn unicode_path_exists() {
+ assert!(Path::new(".").exists());
+ assert!(!Path::new("test/nonexistent-bogus-path").exists());
+
+ let tmpdir = tmpdir();
+ let unicode = tmpdir.path();
+ let unicode = unicode.join("test-각丁ー再见");
+ check!(fs::create_dir(&unicode));
+ assert!(unicode.exists());
+ assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
+}
+
+#[test]
+fn copy_file_does_not_exist() {
+ let from = Path::new("test/nonexistent-bogus-path");
+ let to = Path::new("test/other-bogus-path");
+
+ match fs::copy(&from, &to) {
+ Ok(..) => panic!(),
+ Err(..) => {
+ assert!(!from.exists());
+ assert!(!to.exists());
+ }
+ }
+}
+
+#[test]
+fn copy_src_does_not_exist() {
+ let tmpdir = tmpdir();
+ let from = Path::new("test/nonexistent-bogus-path");
+ let to = tmpdir.join("out.txt");
+ check!(check!(File::create(&to)).write(b"hello"));
+ assert!(fs::copy(&from, &to).is_err());
+ assert!(!from.exists());
+ let mut v = Vec::new();
+ check!(check!(File::open(&to)).read_to_end(&mut v));
+ assert_eq!(v, b"hello");
+}
+
+#[test]
+fn copy_file_ok() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ check!(check!(File::create(&input)).write(b"hello"));
+ check!(fs::copy(&input, &out));
+ let mut v = Vec::new();
+ check!(check!(File::open(&out)).read_to_end(&mut v));
+ assert_eq!(v, b"hello");
+
+ assert_eq!(check!(input.metadata()).permissions(), check!(out.metadata()).permissions());
+}
+
+#[test]
+fn copy_file_dst_dir() {
+ let tmpdir = tmpdir();
+ let out = tmpdir.join("out");
+
+ check!(File::create(&out));
+ match fs::copy(&*out, tmpdir.path()) {
+ Ok(..) => panic!(),
+ Err(..) => {}
+ }
+}
+
+#[test]
+fn copy_file_dst_exists() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in");
+ let output = tmpdir.join("out");
+
+ check!(check!(File::create(&input)).write("foo".as_bytes()));
+ check!(check!(File::create(&output)).write("bar".as_bytes()));
+ check!(fs::copy(&input, &output));
+
+ let mut v = Vec::new();
+ check!(check!(File::open(&output)).read_to_end(&mut v));
+ assert_eq!(v, b"foo".to_vec());
+}
+
+#[test]
+fn copy_file_src_dir() {
+ let tmpdir = tmpdir();
+ let out = tmpdir.join("out");
+
+ match fs::copy(tmpdir.path(), &out) {
+ Ok(..) => panic!(),
+ Err(..) => {}
+ }
+ assert!(!out.exists());
+}
+
+#[test]
+fn copy_file_preserves_perm_bits() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ let attr = check!(check!(File::create(&input)).metadata());
+ let mut p = attr.permissions();
+ p.set_readonly(true);
+ check!(fs::set_permissions(&input, p));
+ check!(fs::copy(&input, &out));
+ assert!(check!(out.metadata()).permissions().readonly());
+ check!(fs::set_permissions(&input, attr.permissions()));
+ check!(fs::set_permissions(&out, attr.permissions()));
+}
+
+#[test]
+#[cfg(windows)]
+fn copy_file_preserves_streams() {
+ let tmp = tmpdir();
+ check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes()));
+ assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 0);
+ assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0);
+ let mut v = Vec::new();
+ check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v));
+ assert_eq!(v, b"carrot".to_vec());
+}
+
+#[test]
+fn copy_file_returns_metadata_len() {
+ let tmp = tmpdir();
+ let in_path = tmp.join("in.txt");
+ let out_path = tmp.join("out.txt");
+ check!(check!(File::create(&in_path)).write(b"lettuce"));
+ #[cfg(windows)]
+ check!(check!(File::create(tmp.join("in.txt:bunny"))).write(b"carrot"));
+ let copied_len = check!(fs::copy(&in_path, &out_path));
+ assert_eq!(check!(out_path.metadata()).len(), copied_len);
+}
+
+#[test]
+fn copy_file_follows_dst_symlink() {
+ let tmp = tmpdir();
+ if !got_symlink_permission(&tmp) {
+ return;
+ };
+
+ let in_path = tmp.join("in.txt");
+ let out_path = tmp.join("out.txt");
+ let out_path_symlink = tmp.join("out_symlink.txt");
+
+ check!(fs::write(&in_path, "foo"));
+ check!(fs::write(&out_path, "bar"));
+ check!(symlink_file(&out_path, &out_path_symlink));
+
+ check!(fs::copy(&in_path, &out_path_symlink));
+
+ assert!(check!(out_path_symlink.symlink_metadata()).file_type().is_symlink());
+ assert_eq!(check!(fs::read(&out_path_symlink)), b"foo".to_vec());
+ assert_eq!(check!(fs::read(&out_path)), b"foo".to_vec());
+}
+
+#[test]
+fn symlinks_work() {
+ let tmpdir = tmpdir();
+ if !got_symlink_permission(&tmpdir) {
+ return;
+ };
+
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ check!(check!(File::create(&input)).write("foobar".as_bytes()));
+ check!(symlink_file(&input, &out));
+ assert!(check!(out.symlink_metadata()).file_type().is_symlink());
+ assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len());
+ let mut v = Vec::new();
+ check!(check!(File::open(&out)).read_to_end(&mut v));
+ assert_eq!(v, b"foobar".to_vec());
+}
+
+#[test]
+fn symlink_noexist() {
+ // Symlinks can point to things that don't exist
+ let tmpdir = tmpdir();
+ if !got_symlink_permission(&tmpdir) {
+ return;
+ };
+
+ // Use a relative path for testing. Symlinks get normalized by Windows,
+ // so we may not get the same path back for absolute paths
+ check!(symlink_file(&"foo", &tmpdir.join("bar")));
+ assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))).to_str().unwrap(), "foo");
+}
+
+#[test]
+fn read_link() {
+ if cfg!(windows) {
+ // directory symlink
+ assert_eq!(
+ check!(fs::read_link(r"C:\Users\All Users")).to_str().unwrap(),
+ r"C:\ProgramData"
+ );
+ // junction
+ assert_eq!(
+ check!(fs::read_link(r"C:\Users\Default User")).to_str().unwrap(),
+ r"C:\Users\Default"
+ );
+ // junction with special permissions
+ assert_eq!(
+ check!(fs::read_link(r"C:\Documents and Settings\")).to_str().unwrap(),
+ r"C:\Users"
+ );
+ }
+ let tmpdir = tmpdir();
+ let link = tmpdir.join("link");
+ if !got_symlink_permission(&tmpdir) {
+ return;
+ };
+ check!(symlink_file(&"foo", &link));
+ assert_eq!(check!(fs::read_link(&link)).to_str().unwrap(), "foo");
+}
+
+#[test]
+fn readlink_not_symlink() {
+ let tmpdir = tmpdir();
+ match fs::read_link(tmpdir.path()) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+}
+
+#[test]
+fn links_work() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ check!(check!(File::create(&input)).write("foobar".as_bytes()));
+ check!(fs::hard_link(&input, &out));
+ assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len());
+ assert_eq!(check!(fs::metadata(&out)).len(), check!(input.metadata()).len());
+ let mut v = Vec::new();
+ check!(check!(File::open(&out)).read_to_end(&mut v));
+ assert_eq!(v, b"foobar".to_vec());
+
+ // can't link to yourself
+ match fs::hard_link(&input, &input) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+ // can't link to something that doesn't exist
+ match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+}
+
+#[test]
+fn chmod_works() {
+ let tmpdir = tmpdir();
+ let file = tmpdir.join("in.txt");
+
+ check!(File::create(&file));
+ let attr = check!(fs::metadata(&file));
+ assert!(!attr.permissions().readonly());
+ let mut p = attr.permissions();
+ p.set_readonly(true);
+ check!(fs::set_permissions(&file, p.clone()));
+ let attr = check!(fs::metadata(&file));
+ assert!(attr.permissions().readonly());
+
+ match fs::set_permissions(&tmpdir.join("foo"), p.clone()) {
+ Ok(..) => panic!("wanted an error"),
+ Err(..) => {}
+ }
+
+ p.set_readonly(false);
+ check!(fs::set_permissions(&file, p));
+}
+
+#[test]
+fn fchmod_works() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("in.txt");
+
+ let file = check!(File::create(&path));
+ let attr = check!(fs::metadata(&path));
+ assert!(!attr.permissions().readonly());
+ let mut p = attr.permissions();
+ p.set_readonly(true);
+ check!(file.set_permissions(p.clone()));
+ let attr = check!(fs::metadata(&path));
+ assert!(attr.permissions().readonly());
+
+ p.set_readonly(false);
+ check!(file.set_permissions(p));
+}
+
+#[test]
+fn sync_doesnt_kill_anything() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("in.txt");
+
+ let mut file = check!(File::create(&path));
+ check!(file.sync_all());
+ check!(file.sync_data());
+ check!(file.write(b"foo"));
+ check!(file.sync_all());
+ check!(file.sync_data());
+}
+
+#[test]
+fn truncate_works() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("in.txt");
+
+ let mut file = check!(File::create(&path));
+ check!(file.write(b"foo"));
+ check!(file.sync_all());
+
+ // Do some simple things with truncation
+ assert_eq!(check!(file.metadata()).len(), 3);
+ check!(file.set_len(10));
+ assert_eq!(check!(file.metadata()).len(), 10);
+ check!(file.write(b"bar"));
+ check!(file.sync_all());
+ assert_eq!(check!(file.metadata()).len(), 10);
+
+ let mut v = Vec::new();
+ check!(check!(File::open(&path)).read_to_end(&mut v));
+ assert_eq!(v, b"foobar\0\0\0\0".to_vec());
+
+ // Truncate to a smaller length, don't seek, and then write something.
+ // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
+ // past the end of the file).
+ check!(file.set_len(2));
+ assert_eq!(check!(file.metadata()).len(), 2);
+ check!(file.write(b"wut"));
+ check!(file.sync_all());
+ assert_eq!(check!(file.metadata()).len(), 9);
+ let mut v = Vec::new();
+ check!(check!(File::open(&path)).read_to_end(&mut v));
+ assert_eq!(v, b"fo\0\0\0\0wut".to_vec());
+}
+
+#[test]
+fn open_flavors() {
+ use crate::fs::OpenOptions as OO;
+ fn c<T: Clone>(t: &T) -> T {
+ t.clone()
+ }
+
+ let tmpdir = tmpdir();
+
+ let mut r = OO::new();
+ r.read(true);
+ let mut w = OO::new();
+ w.write(true);
+ let mut rw = OO::new();
+ rw.read(true).write(true);
+ let mut a = OO::new();
+ a.append(true);
+ let mut ra = OO::new();
+ ra.read(true).append(true);
+
+ #[cfg(windows)]
+ let invalid_options = 87; // ERROR_INVALID_PARAMETER
+ #[cfg(all(unix, not(target_os = "vxworks")))]
+ let invalid_options = "Invalid argument";
+ #[cfg(target_os = "vxworks")]
+ let invalid_options = "invalid argument";
+
+ // Test various combinations of creation modes and access modes.
+ //
+ // Allowed:
+ // creation mode | read | write | read-write | append | read-append |
+ // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:|
+ // not set (open existing) | X | X | X | X | X |
+ // create | | X | X | X | X |
+ // truncate | | X | X | | |
+ // create and truncate | | X | X | | |
+ // create_new | | X | X | X | X |
+ //
+ // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it.
+
+ // write-only
+ check!(c(&w).create_new(true).open(&tmpdir.join("a")));
+ check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a")));
+ check!(c(&w).truncate(true).open(&tmpdir.join("a")));
+ check!(c(&w).create(true).open(&tmpdir.join("a")));
+ check!(c(&w).open(&tmpdir.join("a")));
+
+ // read-only
+ error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options);
+ error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options);
+ error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options);
+ error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options);
+ check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only
+
+ // read-write
+ check!(c(&rw).create_new(true).open(&tmpdir.join("c")));
+ check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c")));
+ check!(c(&rw).truncate(true).open(&tmpdir.join("c")));
+ check!(c(&rw).create(true).open(&tmpdir.join("c")));
+ check!(c(&rw).open(&tmpdir.join("c")));
+
+ // append
+ check!(c(&a).create_new(true).open(&tmpdir.join("d")));
+ error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options);
+ error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options);
+ check!(c(&a).create(true).open(&tmpdir.join("d")));
+ check!(c(&a).open(&tmpdir.join("d")));
+
+ // read-append
+ check!(c(&ra).create_new(true).open(&tmpdir.join("e")));
+ error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options);
+ error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options);
+ check!(c(&ra).create(true).open(&tmpdir.join("e")));
+ check!(c(&ra).open(&tmpdir.join("e")));
+
+ // Test opening a file without setting an access mode
+ let mut blank = OO::new();
+ error!(blank.create(true).open(&tmpdir.join("f")), invalid_options);
+
+ // Test write works
+ check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes()));
+
+ // Test write fails for read-only
+ check!(r.open(&tmpdir.join("h")));
+ {
+ let mut f = check!(r.open(&tmpdir.join("h")));
+ assert!(f.write("wut".as_bytes()).is_err());
+ }
+
+ // Test write overwrites
+ {
+ let mut f = check!(c(&w).open(&tmpdir.join("h")));
+ check!(f.write("baz".as_bytes()));
+ }
+ {
+ let mut f = check!(c(&r).open(&tmpdir.join("h")));
+ let mut b = vec![0; 6];
+ check!(f.read(&mut b));
+ assert_eq!(b, "bazbar".as_bytes());
+ }
+
+ // Test truncate works
+ {
+ let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
+ check!(f.write("foo".as_bytes()));
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
+
+ // Test append works
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
+ {
+ let mut f = check!(c(&a).open(&tmpdir.join("h")));
+ check!(f.write("bar".as_bytes()));
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
+
+ // Test .append(true) equals .write(true).append(true)
+ {
+ let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
+ check!(f.write("baz".as_bytes()));
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9);
+}
+
+#[test]
+fn _assert_send_sync() {
+ fn _assert_send_sync<T: Send + Sync>() {}
+ _assert_send_sync::<OpenOptions>();
+}
+
+#[test]
+fn binary_file() {
+ let mut bytes = [0; 1024];
+ StdRng::from_entropy().fill_bytes(&mut bytes);
+
+ let tmpdir = tmpdir();
+
+ check!(check!(File::create(&tmpdir.join("test"))).write(&bytes));
+ let mut v = Vec::new();
+ check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v));
+ assert!(v == &bytes[..]);
+}
+
+#[test]
+fn write_then_read() {
+ let mut bytes = [0; 1024];
+ StdRng::from_entropy().fill_bytes(&mut bytes);
+
+ let tmpdir = tmpdir();
+
+ check!(fs::write(&tmpdir.join("test"), &bytes[..]));
+ let v = check!(fs::read(&tmpdir.join("test")));
+ assert!(v == &bytes[..]);
+
+ check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF]));
+ error_contains!(
+ fs::read_to_string(&tmpdir.join("not-utf8")),
+ "stream did not contain valid UTF-8"
+ );
+
+ let s = "𐁁𐀓𐀠𐀴𐀍";
+ check!(fs::write(&tmpdir.join("utf8"), s.as_bytes()));
+ let string = check!(fs::read_to_string(&tmpdir.join("utf8")));
+ assert_eq!(string, s);
+}
+
+#[test]
+fn file_try_clone() {
+ let tmpdir = tmpdir();
+
+ let mut f1 =
+ check!(OpenOptions::new().read(true).write(true).create(true).open(&tmpdir.join("test")));
+ let mut f2 = check!(f1.try_clone());
+
+ check!(f1.write_all(b"hello world"));
+ check!(f1.seek(SeekFrom::Start(2)));
+
+ let mut buf = vec![];
+ check!(f2.read_to_end(&mut buf));
+ assert_eq!(buf, b"llo world");
+ drop(f2);
+
+ check!(f1.write_all(b"!"));
+}
+
+#[test]
+#[cfg(not(windows))]
+fn unlink_readonly() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("file");
+ check!(File::create(&path));
+ let mut perm = check!(fs::metadata(&path)).permissions();
+ perm.set_readonly(true);
+ check!(fs::set_permissions(&path, perm));
+ check!(fs::remove_file(&path));
+}
+
+#[test]
+fn mkdir_trailing_slash() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("file");
+ check!(fs::create_dir_all(&path.join("a/")));
+}
+
+#[test]
+fn canonicalize_works_simple() {
+ let tmpdir = tmpdir();
+ let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
+ let file = tmpdir.join("test");
+ File::create(&file).unwrap();
+ assert_eq!(fs::canonicalize(&file).unwrap(), file);
+}
+
+#[test]
+fn realpath_works() {
+ let tmpdir = tmpdir();
+ if !got_symlink_permission(&tmpdir) {
+ return;
+ };
+
+ let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
+ let file = tmpdir.join("test");
+ let dir = tmpdir.join("test2");
+ let link = dir.join("link");
+ let linkdir = tmpdir.join("test3");
+
+ File::create(&file).unwrap();
+ fs::create_dir(&dir).unwrap();
+ symlink_file(&file, &link).unwrap();
+ symlink_dir(&dir, &linkdir).unwrap();
+
+ assert!(link.symlink_metadata().unwrap().file_type().is_symlink());
+
+ assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir);
+ assert_eq!(fs::canonicalize(&file).unwrap(), file);
+ assert_eq!(fs::canonicalize(&link).unwrap(), file);
+ assert_eq!(fs::canonicalize(&linkdir).unwrap(), dir);
+ assert_eq!(fs::canonicalize(&linkdir.join("link")).unwrap(), file);
+}
+
+#[test]
+fn realpath_works_tricky() {
+ let tmpdir = tmpdir();
+ if !got_symlink_permission(&tmpdir) {
+ return;
+ };
+
+ let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
+ let a = tmpdir.join("a");
+ let b = a.join("b");
+ let c = b.join("c");
+ let d = a.join("d");
+ let e = d.join("e");
+ let f = a.join("f");
+
+ fs::create_dir_all(&b).unwrap();
+ fs::create_dir_all(&d).unwrap();
+ File::create(&f).unwrap();
+ if cfg!(not(windows)) {
+ symlink_file("../d/e", &c).unwrap();
+ symlink_file("../f", &e).unwrap();
+ }
+ if cfg!(windows) {
+ symlink_file(r"..\d\e", &c).unwrap();
+ symlink_file(r"..\f", &e).unwrap();
+ }
+
+ assert_eq!(fs::canonicalize(&c).unwrap(), f);
+ assert_eq!(fs::canonicalize(&e).unwrap(), f);
+}
+
+#[test]
+fn dir_entry_methods() {
+ let tmpdir = tmpdir();
+
+ fs::create_dir_all(&tmpdir.join("a")).unwrap();
+ File::create(&tmpdir.join("b")).unwrap();
+
+ for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) {
+ let fname = file.file_name();
+ match fname.to_str() {
+ Some("a") => {
+ assert!(file.file_type().unwrap().is_dir());
+ assert!(file.metadata().unwrap().is_dir());
+ }
+ Some("b") => {
+ assert!(file.file_type().unwrap().is_file());
+ assert!(file.metadata().unwrap().is_file());
+ }
+ f => panic!("unknown file name: {:?}", f),
+ }
+ }
+}
+
+#[test]
+fn dir_entry_debug() {
+ let tmpdir = tmpdir();
+ File::create(&tmpdir.join("b")).unwrap();
+ let mut read_dir = tmpdir.path().read_dir().unwrap();
+ let dir_entry = read_dir.next().unwrap().unwrap();
+ let actual = format!("{:?}", dir_entry);
+ let expected = format!("DirEntry({:?})", dir_entry.0.path());
+ assert_eq!(actual, expected);
+}
+
+#[test]
+fn read_dir_not_found() {
+ let res = fs::read_dir("/path/that/does/not/exist");
+ assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound);
+}
+
+#[test]
+fn create_dir_all_with_junctions() {
+ let tmpdir = tmpdir();
+ let target = tmpdir.join("target");
+
+ let junction = tmpdir.join("junction");
+ let b = junction.join("a/b");
+
+ let link = tmpdir.join("link");
+ let d = link.join("c/d");
+
+ fs::create_dir(&target).unwrap();
+
+ check!(symlink_junction(&target, &junction));
+ check!(fs::create_dir_all(&b));
+ // the junction itself is not a directory, but `is_dir()` on a Path
+ // follows links
+ assert!(junction.is_dir());
+ assert!(b.exists());
+
+ if !got_symlink_permission(&tmpdir) {
+ return;
+ };
+ check!(symlink_dir(&target, &link));
+ check!(fs::create_dir_all(&d));
+ assert!(link.is_dir());
+ assert!(d.exists());
+}
+
+#[test]
+fn metadata_access_times() {
+ let tmpdir = tmpdir();
+
+ let b = tmpdir.join("b");
+ File::create(&b).unwrap();
+
+ let a = check!(fs::metadata(&tmpdir.path()));
+ let b = check!(fs::metadata(&b));
+
+ assert_eq!(check!(a.accessed()), check!(a.accessed()));
+ assert_eq!(check!(a.modified()), check!(a.modified()));
+ assert_eq!(check!(b.accessed()), check!(b.modified()));
+
+ if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
+ check!(a.created());
+ check!(b.created());
+ }
+
+ if cfg!(target_os = "linux") {
+ // Not always available
+ match (a.created(), b.created()) {
+ (Ok(t1), Ok(t2)) => assert!(t1 <= t2),
+ (Err(e1), Err(e2))
+ if e1.kind() == ErrorKind::Other && e2.kind() == ErrorKind::Other => {}
+ (a, b) => {
+ panic!("creation time must be always supported or not supported: {:?} {:?}", a, b,)
+ }
+ }
+ }
+}
//! Buffering wrappers for I/O traits
+#[cfg(test)]
+mod tests;
+
use crate::io::prelude::*;
use crate::cmp;
.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())]);
- }
-}
--- /dev/null
+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())]);
+}
+#[cfg(test)]
+mod tests;
+
use crate::io::prelude::*;
use crate::cmp;
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()));
- }
-}
--- /dev/null
+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()));
+}
+#[cfg(test)]
+mod tests;
+
use crate::convert::From;
use crate::error;
use crate::fmt;
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();
- }
-}
--- /dev/null
+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();
+}
+#[cfg(test)]
+mod tests;
+
use crate::cmp;
use crate::fmt;
use crate::io::{
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);
- }
- })
- }
-}
--- /dev/null
+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);
+ }
+ })
+}
#![stable(feature = "rust1", since = "1.0.0")]
+#[cfg(test)]
+mod tests;
+
use crate::cmp;
use crate::fmt;
use crate::memchr;
}
}
}
-
-#[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);
- }
- }
- }
-}
#![cfg_attr(test, allow(unused))]
+#[cfg(test)]
+mod tests;
+
use crate::io::prelude::*;
use crate::cell::RefCell;
#[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();
- }
-}
--- /dev/null
+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();
+}
--- /dev/null
+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);
+ }
+ }
+}
#![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;
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);
- }
-}
--- /dev/null
+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);
+}
//! Lazy values and one-time initialization of static data.
+#[cfg(test)]
+mod tests;
+
use crate::{
cell::{Cell, UnsafeCell},
fmt,
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();
- }
- }
-}
--- /dev/null
+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();
+ }
+}
// 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
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..]));
- }
- }
-}
--- /dev/null
+// 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..]));
+ }
+}
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
use crate::cmp::Ordering;
use crate::convert::TryInto;
use crate::fmt;
(&**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());
- }
-}
--- /dev/null
+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());
+}
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;
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());
- }
-}
--- /dev/null
+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());
+}
//! 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};
"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());
- }
-}
--- /dev/null
+// 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());
+}
#![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;
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();
- }
-}
--- /dev/null
+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();
+}
+#[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};
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),
- }
- })
- }
-}
--- /dev/null
+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),
+ }
+ })
+}
#![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")]
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));
- });
- }
-}
--- /dev/null
+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));
+ });
+}
--- /dev/null
+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);
+}
#![stable(feature = "raw_os", since = "1.1.0")]
+#[cfg(test)]
+#[allow(unused_imports)]
+mod tests;
+
#[doc(include = "char.md")]
#[cfg(any(
all(
#[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);
- }
-}
--- /dev/null
+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);
+}
-// ignore-tidy-filelength
-
//! Cross-platform path manipulation.
//!
//! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`]
#![stable(feature = "rust1", since = "1.0.0")]
+#[cfg(test)]
+mod tests;
+
use crate::borrow::{Borrow, Cow};
use crate::cmp;
use crate::error::Error;
"prefix not found"
}
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- use crate::rc::Rc;
- use crate::sync::Arc;
-
- macro_rules! t(
- ($path:expr, iter: $iter:expr) => (
- {
- let path = Path::new($path);
-
- // Forward iteration
- let comps = path.iter()
- .map(|p| p.to_string_lossy().into_owned())
- .collect::<Vec<String>>();
- let exp: &[&str] = &$iter;
- let exps = exp.iter().map(|s| s.to_string()).collect::<Vec<String>>();
- assert!(comps == exps, "iter: Expected {:?}, found {:?}",
- exps, comps);
-
- // Reverse iteration
- let comps = Path::new($path).iter().rev()
- .map(|p| p.to_string_lossy().into_owned())
- .collect::<Vec<String>>();
- let exps = exps.into_iter().rev().collect::<Vec<String>>();
- assert!(comps == exps, "iter().rev(): Expected {:?}, found {:?}",
- exps, comps);
- }
- );
-
- ($path:expr, has_root: $has_root:expr, is_absolute: $is_absolute:expr) => (
- {
- let path = Path::new($path);
-
- let act_root = path.has_root();
- assert!(act_root == $has_root, "has_root: Expected {:?}, found {:?}",
- $has_root, act_root);
-
- let act_abs = path.is_absolute();
- assert!(act_abs == $is_absolute, "is_absolute: Expected {:?}, found {:?}",
- $is_absolute, act_abs);
- }
- );
-
- ($path:expr, parent: $parent:expr, file_name: $file:expr) => (
- {
- let path = Path::new($path);
-
- let parent = path.parent().map(|p| p.to_str().unwrap());
- let exp_parent: Option<&str> = $parent;
- assert!(parent == exp_parent, "parent: Expected {:?}, found {:?}",
- exp_parent, parent);
-
- let file = path.file_name().map(|p| p.to_str().unwrap());
- let exp_file: Option<&str> = $file;
- assert!(file == exp_file, "file_name: Expected {:?}, found {:?}",
- exp_file, file);
- }
- );
-
- ($path:expr, file_stem: $file_stem:expr, extension: $extension:expr) => (
- {
- let path = Path::new($path);
-
- let stem = path.file_stem().map(|p| p.to_str().unwrap());
- let exp_stem: Option<&str> = $file_stem;
- assert!(stem == exp_stem, "file_stem: Expected {:?}, found {:?}",
- exp_stem, stem);
-
- let ext = path.extension().map(|p| p.to_str().unwrap());
- let exp_ext: Option<&str> = $extension;
- assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}",
- exp_ext, ext);
- }
- );
-
- ($path:expr, iter: $iter:expr,
- has_root: $has_root:expr, is_absolute: $is_absolute:expr,
- parent: $parent:expr, file_name: $file:expr,
- file_stem: $file_stem:expr, extension: $extension:expr) => (
- {
- t!($path, iter: $iter);
- t!($path, has_root: $has_root, is_absolute: $is_absolute);
- t!($path, parent: $parent, file_name: $file);
- t!($path, file_stem: $file_stem, extension: $extension);
- }
- );
- );
-
- #[test]
- fn into() {
- use crate::borrow::Cow;
-
- let static_path = Path::new("/home/foo");
- let static_cow_path: Cow<'static, Path> = static_path.into();
- let pathbuf = PathBuf::from("/home/foo");
-
- {
- let path: &Path = &pathbuf;
- let borrowed_cow_path: Cow<'_, Path> = path.into();
-
- assert_eq!(static_cow_path, borrowed_cow_path);
- }
-
- let owned_cow_path: Cow<'static, Path> = pathbuf.into();
-
- assert_eq!(static_cow_path, owned_cow_path);
- }
-
- #[test]
- #[cfg(unix)]
- pub fn test_decompositions_unix() {
- t!("",
- iter: [],
- has_root: false,
- is_absolute: false,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("foo",
- iter: ["foo"],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("/",
- iter: ["/"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("/foo",
- iter: ["/", "foo"],
- has_root: true,
- is_absolute: true,
- parent: Some("/"),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("foo/",
- iter: ["foo"],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("/foo/",
- iter: ["/", "foo"],
- has_root: true,
- is_absolute: true,
- parent: Some("/"),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("foo/bar",
- iter: ["foo", "bar"],
- has_root: false,
- is_absolute: false,
- parent: Some("foo"),
- file_name: Some("bar"),
- file_stem: Some("bar"),
- extension: None
- );
-
- t!("/foo/bar",
- iter: ["/", "foo", "bar"],
- has_root: true,
- is_absolute: true,
- parent: Some("/foo"),
- file_name: Some("bar"),
- file_stem: Some("bar"),
- extension: None
- );
-
- t!("///foo///",
- iter: ["/", "foo"],
- has_root: true,
- is_absolute: true,
- parent: Some("/"),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("///foo///bar",
- iter: ["/", "foo", "bar"],
- has_root: true,
- is_absolute: true,
- parent: Some("///foo"),
- file_name: Some("bar"),
- file_stem: Some("bar"),
- extension: None
- );
-
- t!("./.",
- iter: ["."],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("/..",
- iter: ["/", ".."],
- has_root: true,
- is_absolute: true,
- parent: Some("/"),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("../",
- iter: [".."],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("foo/.",
- iter: ["foo"],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("foo/..",
- iter: ["foo", ".."],
- has_root: false,
- is_absolute: false,
- parent: Some("foo"),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("foo/./",
- iter: ["foo"],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("foo/./bar",
- iter: ["foo", "bar"],
- has_root: false,
- is_absolute: false,
- parent: Some("foo"),
- file_name: Some("bar"),
- file_stem: Some("bar"),
- extension: None
- );
-
- t!("foo/../",
- iter: ["foo", ".."],
- has_root: false,
- is_absolute: false,
- parent: Some("foo"),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("foo/../bar",
- iter: ["foo", "..", "bar"],
- has_root: false,
- is_absolute: false,
- parent: Some("foo/.."),
- file_name: Some("bar"),
- file_stem: Some("bar"),
- extension: None
- );
-
- t!("./a",
- iter: [".", "a"],
- has_root: false,
- is_absolute: false,
- parent: Some("."),
- file_name: Some("a"),
- file_stem: Some("a"),
- extension: None
- );
-
- t!(".",
- iter: ["."],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("./",
- iter: ["."],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("a/b",
- iter: ["a", "b"],
- has_root: false,
- is_absolute: false,
- parent: Some("a"),
- file_name: Some("b"),
- file_stem: Some("b"),
- extension: None
- );
-
- t!("a//b",
- iter: ["a", "b"],
- has_root: false,
- is_absolute: false,
- parent: Some("a"),
- file_name: Some("b"),
- file_stem: Some("b"),
- extension: None
- );
-
- t!("a/./b",
- iter: ["a", "b"],
- has_root: false,
- is_absolute: false,
- parent: Some("a"),
- file_name: Some("b"),
- file_stem: Some("b"),
- extension: None
- );
-
- t!("a/b/c",
- iter: ["a", "b", "c"],
- has_root: false,
- is_absolute: false,
- parent: Some("a/b"),
- file_name: Some("c"),
- file_stem: Some("c"),
- extension: None
- );
-
- t!(".foo",
- iter: [".foo"],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: Some(".foo"),
- file_stem: Some(".foo"),
- extension: None
- );
- }
-
- #[test]
- #[cfg(windows)]
- pub fn test_decompositions_windows() {
- t!("",
- iter: [],
- has_root: false,
- is_absolute: false,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("foo",
- iter: ["foo"],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("/",
- iter: ["\\"],
- has_root: true,
- is_absolute: false,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("\\",
- iter: ["\\"],
- has_root: true,
- is_absolute: false,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("c:",
- iter: ["c:"],
- has_root: false,
- is_absolute: false,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("c:\\",
- iter: ["c:", "\\"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("c:/",
- iter: ["c:", "\\"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("/foo",
- iter: ["\\", "foo"],
- has_root: true,
- is_absolute: false,
- parent: Some("/"),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("foo/",
- iter: ["foo"],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("/foo/",
- iter: ["\\", "foo"],
- has_root: true,
- is_absolute: false,
- parent: Some("/"),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("foo/bar",
- iter: ["foo", "bar"],
- has_root: false,
- is_absolute: false,
- parent: Some("foo"),
- file_name: Some("bar"),
- file_stem: Some("bar"),
- extension: None
- );
-
- t!("/foo/bar",
- iter: ["\\", "foo", "bar"],
- has_root: true,
- is_absolute: false,
- parent: Some("/foo"),
- file_name: Some("bar"),
- file_stem: Some("bar"),
- extension: None
- );
-
- t!("///foo///",
- iter: ["\\", "foo"],
- has_root: true,
- is_absolute: false,
- parent: Some("/"),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("///foo///bar",
- iter: ["\\", "foo", "bar"],
- has_root: true,
- is_absolute: false,
- parent: Some("///foo"),
- file_name: Some("bar"),
- file_stem: Some("bar"),
- extension: None
- );
-
- t!("./.",
- iter: ["."],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("/..",
- iter: ["\\", ".."],
- has_root: true,
- is_absolute: false,
- parent: Some("/"),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("../",
- iter: [".."],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("foo/.",
- iter: ["foo"],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("foo/..",
- iter: ["foo", ".."],
- has_root: false,
- is_absolute: false,
- parent: Some("foo"),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("foo/./",
- iter: ["foo"],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: Some("foo"),
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("foo/./bar",
- iter: ["foo", "bar"],
- has_root: false,
- is_absolute: false,
- parent: Some("foo"),
- file_name: Some("bar"),
- file_stem: Some("bar"),
- extension: None
- );
-
- t!("foo/../",
- iter: ["foo", ".."],
- has_root: false,
- is_absolute: false,
- parent: Some("foo"),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("foo/../bar",
- iter: ["foo", "..", "bar"],
- has_root: false,
- is_absolute: false,
- parent: Some("foo/.."),
- file_name: Some("bar"),
- file_stem: Some("bar"),
- extension: None
- );
-
- t!("./a",
- iter: [".", "a"],
- has_root: false,
- is_absolute: false,
- parent: Some("."),
- file_name: Some("a"),
- file_stem: Some("a"),
- extension: None
- );
-
- t!(".",
- iter: ["."],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("./",
- iter: ["."],
- has_root: false,
- is_absolute: false,
- parent: Some(""),
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("a/b",
- iter: ["a", "b"],
- has_root: false,
- is_absolute: false,
- parent: Some("a"),
- file_name: Some("b"),
- file_stem: Some("b"),
- extension: None
- );
-
- t!("a//b",
- iter: ["a", "b"],
- has_root: false,
- is_absolute: false,
- parent: Some("a"),
- file_name: Some("b"),
- file_stem: Some("b"),
- extension: None
- );
-
- t!("a/./b",
- iter: ["a", "b"],
- has_root: false,
- is_absolute: false,
- parent: Some("a"),
- file_name: Some("b"),
- file_stem: Some("b"),
- extension: None
- );
-
- t!("a/b/c",
- iter: ["a", "b", "c"],
- has_root: false,
- is_absolute: false,
- parent: Some("a/b"),
- file_name: Some("c"),
- file_stem: Some("c"),
- extension: None);
-
- t!("a\\b\\c",
- iter: ["a", "b", "c"],
- has_root: false,
- is_absolute: false,
- parent: Some("a\\b"),
- file_name: Some("c"),
- file_stem: Some("c"),
- extension: None
- );
-
- t!("\\a",
- iter: ["\\", "a"],
- has_root: true,
- is_absolute: false,
- parent: Some("\\"),
- file_name: Some("a"),
- file_stem: Some("a"),
- extension: None
- );
-
- t!("c:\\foo.txt",
- iter: ["c:", "\\", "foo.txt"],
- has_root: true,
- is_absolute: true,
- parent: Some("c:\\"),
- file_name: Some("foo.txt"),
- file_stem: Some("foo"),
- extension: Some("txt")
- );
-
- t!("\\\\server\\share\\foo.txt",
- iter: ["\\\\server\\share", "\\", "foo.txt"],
- has_root: true,
- is_absolute: true,
- parent: Some("\\\\server\\share\\"),
- file_name: Some("foo.txt"),
- file_stem: Some("foo"),
- extension: Some("txt")
- );
-
- t!("\\\\server\\share",
- iter: ["\\\\server\\share", "\\"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("\\\\server",
- iter: ["\\", "server"],
- has_root: true,
- is_absolute: false,
- parent: Some("\\"),
- file_name: Some("server"),
- file_stem: Some("server"),
- extension: None
- );
-
- t!("\\\\?\\bar\\foo.txt",
- iter: ["\\\\?\\bar", "\\", "foo.txt"],
- has_root: true,
- is_absolute: true,
- parent: Some("\\\\?\\bar\\"),
- file_name: Some("foo.txt"),
- file_stem: Some("foo"),
- extension: Some("txt")
- );
-
- t!("\\\\?\\bar",
- iter: ["\\\\?\\bar"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("\\\\?\\",
- iter: ["\\\\?\\"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("\\\\?\\UNC\\server\\share\\foo.txt",
- iter: ["\\\\?\\UNC\\server\\share", "\\", "foo.txt"],
- has_root: true,
- is_absolute: true,
- parent: Some("\\\\?\\UNC\\server\\share\\"),
- file_name: Some("foo.txt"),
- file_stem: Some("foo"),
- extension: Some("txt")
- );
-
- t!("\\\\?\\UNC\\server",
- iter: ["\\\\?\\UNC\\server"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("\\\\?\\UNC\\",
- iter: ["\\\\?\\UNC\\"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("\\\\?\\C:\\foo.txt",
- iter: ["\\\\?\\C:", "\\", "foo.txt"],
- has_root: true,
- is_absolute: true,
- parent: Some("\\\\?\\C:\\"),
- file_name: Some("foo.txt"),
- file_stem: Some("foo"),
- extension: Some("txt")
- );
-
- t!("\\\\?\\C:\\",
- iter: ["\\\\?\\C:", "\\"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("\\\\?\\C:",
- iter: ["\\\\?\\C:"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("\\\\?\\foo/bar",
- iter: ["\\\\?\\foo/bar"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("\\\\?\\C:/foo",
- iter: ["\\\\?\\C:/foo"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("\\\\.\\foo\\bar",
- iter: ["\\\\.\\foo", "\\", "bar"],
- has_root: true,
- is_absolute: true,
- parent: Some("\\\\.\\foo\\"),
- file_name: Some("bar"),
- file_stem: Some("bar"),
- extension: None
- );
-
- t!("\\\\.\\foo",
- iter: ["\\\\.\\foo", "\\"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("\\\\.\\foo/bar",
- iter: ["\\\\.\\foo/bar", "\\"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("\\\\.\\foo\\bar/baz",
- iter: ["\\\\.\\foo", "\\", "bar", "baz"],
- has_root: true,
- is_absolute: true,
- parent: Some("\\\\.\\foo\\bar"),
- file_name: Some("baz"),
- file_stem: Some("baz"),
- extension: None
- );
-
- t!("\\\\.\\",
- iter: ["\\\\.\\", "\\"],
- has_root: true,
- is_absolute: true,
- parent: None,
- file_name: None,
- file_stem: None,
- extension: None
- );
-
- t!("\\\\?\\a\\b\\",
- iter: ["\\\\?\\a", "\\", "b"],
- has_root: true,
- is_absolute: true,
- parent: Some("\\\\?\\a\\"),
- file_name: Some("b"),
- file_stem: Some("b"),
- extension: None
- );
- }
-
- #[test]
- pub fn test_stem_ext() {
- t!("foo",
- file_stem: Some("foo"),
- extension: None
- );
-
- t!("foo.",
- file_stem: Some("foo"),
- extension: Some("")
- );
-
- t!(".foo",
- file_stem: Some(".foo"),
- extension: None
- );
-
- t!("foo.txt",
- file_stem: Some("foo"),
- extension: Some("txt")
- );
-
- t!("foo.bar.txt",
- file_stem: Some("foo.bar"),
- extension: Some("txt")
- );
-
- t!("foo.bar.",
- file_stem: Some("foo.bar"),
- extension: Some("")
- );
-
- t!(".", file_stem: None, extension: None);
-
- t!("..", file_stem: None, extension: None);
-
- t!("", file_stem: None, extension: None);
- }
-
- #[test]
- pub fn test_push() {
- macro_rules! tp(
- ($path:expr, $push:expr, $expected:expr) => ( {
- let mut actual = PathBuf::from($path);
- actual.push($push);
- assert!(actual.to_str() == Some($expected),
- "pushing {:?} onto {:?}: Expected {:?}, got {:?}",
- $push, $path, $expected, actual.to_str().unwrap());
- });
- );
-
- if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
- tp!("", "foo", "foo");
- tp!("foo", "bar", "foo/bar");
- tp!("foo/", "bar", "foo/bar");
- tp!("foo//", "bar", "foo//bar");
- tp!("foo/.", "bar", "foo/./bar");
- tp!("foo./.", "bar", "foo././bar");
- tp!("foo", "", "foo/");
- tp!("foo", ".", "foo/.");
- tp!("foo", "..", "foo/..");
- tp!("foo", "/", "/");
- tp!("/foo/bar", "/", "/");
- tp!("/foo/bar", "/baz", "/baz");
- tp!("/foo/bar", "./baz", "/foo/bar/./baz");
- } else {
- tp!("", "foo", "foo");
- tp!("foo", "bar", r"foo\bar");
- tp!("foo/", "bar", r"foo/bar");
- tp!(r"foo\", "bar", r"foo\bar");
- tp!("foo//", "bar", r"foo//bar");
- tp!(r"foo\\", "bar", r"foo\\bar");
- tp!("foo/.", "bar", r"foo/.\bar");
- tp!("foo./.", "bar", r"foo./.\bar");
- tp!(r"foo\.", "bar", r"foo\.\bar");
- tp!(r"foo.\.", "bar", r"foo.\.\bar");
- tp!("foo", "", "foo\\");
- tp!("foo", ".", r"foo\.");
- tp!("foo", "..", r"foo\..");
- tp!("foo", "/", "/");
- tp!("foo", r"\", r"\");
- tp!("/foo/bar", "/", "/");
- tp!(r"\foo\bar", r"\", r"\");
- tp!("/foo/bar", "/baz", "/baz");
- tp!("/foo/bar", r"\baz", r"\baz");
- tp!("/foo/bar", "./baz", r"/foo/bar\./baz");
- tp!("/foo/bar", r".\baz", r"/foo/bar\.\baz");
-
- tp!("c:\\", "windows", "c:\\windows");
- tp!("c:", "windows", "c:windows");
-
- tp!("a\\b\\c", "d", "a\\b\\c\\d");
- tp!("\\a\\b\\c", "d", "\\a\\b\\c\\d");
- tp!("a\\b", "c\\d", "a\\b\\c\\d");
- tp!("a\\b", "\\c\\d", "\\c\\d");
- tp!("a\\b", ".", "a\\b\\.");
- tp!("a\\b", "..\\c", "a\\b\\..\\c");
- tp!("a\\b", "C:a.txt", "C:a.txt");
- tp!("a\\b", "C:\\a.txt", "C:\\a.txt");
- tp!("C:\\a", "C:\\b.txt", "C:\\b.txt");
- tp!("C:\\a\\b\\c", "C:d", "C:d");
- tp!("C:a\\b\\c", "C:d", "C:d");
- tp!("C:", r"a\b\c", r"C:a\b\c");
- tp!("C:", r"..\a", r"C:..\a");
- tp!("\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar");
- tp!("\\\\server\\share\\foo", "C:baz", "C:baz");
- tp!("\\\\?\\C:\\a\\b", "C:c\\d", "C:c\\d");
- tp!("\\\\?\\C:a\\b", "C:c\\d", "C:c\\d");
- tp!("\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d");
- tp!("\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz");
- tp!("\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar");
- tp!("\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a");
- tp!("\\\\?\\UNC\\server\\share", "C:a", "C:a");
-
- // Note: modified from old path API
- tp!("\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\foo");
-
- tp!("C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share");
- tp!("\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz");
- tp!("\\\\.\\foo\\bar", "C:a", "C:a");
- // again, not sure about the following, but I'm assuming \\.\ should be verbatim
- tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar");
-
- tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one
- }
- }
-
- #[test]
- pub fn test_pop() {
- macro_rules! tp(
- ($path:expr, $expected:expr, $output:expr) => ( {
- let mut actual = PathBuf::from($path);
- let output = actual.pop();
- assert!(actual.to_str() == Some($expected) && output == $output,
- "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
- $path, $expected, $output,
- actual.to_str().unwrap(), output);
- });
- );
-
- tp!("", "", false);
- tp!("/", "/", false);
- tp!("foo", "", true);
- tp!(".", "", true);
- tp!("/foo", "/", true);
- tp!("/foo/bar", "/foo", true);
- tp!("foo/bar", "foo", true);
- tp!("foo/.", "", true);
- tp!("foo//bar", "foo", true);
-
- if cfg!(windows) {
- tp!("a\\b\\c", "a\\b", true);
- tp!("\\a", "\\", true);
- tp!("\\", "\\", false);
-
- tp!("C:\\a\\b", "C:\\a", true);
- tp!("C:\\a", "C:\\", true);
- tp!("C:\\", "C:\\", false);
- tp!("C:a\\b", "C:a", true);
- tp!("C:a", "C:", true);
- tp!("C:", "C:", false);
- tp!("\\\\server\\share\\a\\b", "\\\\server\\share\\a", true);
- tp!("\\\\server\\share\\a", "\\\\server\\share\\", true);
- tp!("\\\\server\\share", "\\\\server\\share", false);
- tp!("\\\\?\\a\\b\\c", "\\\\?\\a\\b", true);
- tp!("\\\\?\\a\\b", "\\\\?\\a\\", true);
- tp!("\\\\?\\a", "\\\\?\\a", false);
- tp!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true);
- tp!("\\\\?\\C:\\a", "\\\\?\\C:\\", true);
- tp!("\\\\?\\C:\\", "\\\\?\\C:\\", false);
- tp!("\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true);
- tp!("\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share\\", true);
- tp!("\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false);
- tp!("\\\\.\\a\\b\\c", "\\\\.\\a\\b", true);
- tp!("\\\\.\\a\\b", "\\\\.\\a\\", true);
- tp!("\\\\.\\a", "\\\\.\\a", false);
-
- tp!("\\\\?\\a\\b\\", "\\\\?\\a\\", true);
- }
- }
-
- #[test]
- pub fn test_set_file_name() {
- macro_rules! tfn(
- ($path:expr, $file:expr, $expected:expr) => ( {
- let mut p = PathBuf::from($path);
- p.set_file_name($file);
- assert!(p.to_str() == Some($expected),
- "setting file name of {:?} to {:?}: Expected {:?}, got {:?}",
- $path, $file, $expected,
- p.to_str().unwrap());
- });
- );
-
- tfn!("foo", "foo", "foo");
- tfn!("foo", "bar", "bar");
- tfn!("foo", "", "");
- tfn!("", "foo", "foo");
- if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
- tfn!(".", "foo", "./foo");
- tfn!("foo/", "bar", "bar");
- tfn!("foo/.", "bar", "bar");
- tfn!("..", "foo", "../foo");
- tfn!("foo/..", "bar", "foo/../bar");
- tfn!("/", "foo", "/foo");
- } else {
- tfn!(".", "foo", r".\foo");
- tfn!(r"foo\", "bar", r"bar");
- tfn!(r"foo\.", "bar", r"bar");
- tfn!("..", "foo", r"..\foo");
- tfn!(r"foo\..", "bar", r"foo\..\bar");
- tfn!(r"\", "foo", r"\foo");
- }
- }
-
- #[test]
- pub fn test_set_extension() {
- macro_rules! tfe(
- ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( {
- let mut p = PathBuf::from($path);
- let output = p.set_extension($ext);
- assert!(p.to_str() == Some($expected) && output == $output,
- "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
- $path, $ext, $expected, $output,
- p.to_str().unwrap(), output);
- });
- );
-
- tfe!("foo", "txt", "foo.txt", true);
- tfe!("foo.bar", "txt", "foo.txt", true);
- tfe!("foo.bar.baz", "txt", "foo.bar.txt", true);
- tfe!(".test", "txt", ".test.txt", true);
- tfe!("foo.txt", "", "foo", true);
- tfe!("foo", "", "foo", true);
- tfe!("", "foo", "", false);
- tfe!(".", "foo", ".", false);
- tfe!("foo/", "bar", "foo.bar", true);
- tfe!("foo/.", "bar", "foo.bar", true);
- tfe!("..", "foo", "..", false);
- tfe!("foo/..", "bar", "foo/..", false);
- tfe!("/", "foo", "/", false);
- }
-
- #[test]
- fn test_eq_receivers() {
- use crate::borrow::Cow;
-
- let borrowed: &Path = Path::new("foo/bar");
- let mut owned: PathBuf = PathBuf::new();
- owned.push("foo");
- owned.push("bar");
- let borrowed_cow: Cow<'_, Path> = borrowed.into();
- let owned_cow: Cow<'_, Path> = owned.clone().into();
-
- macro_rules! t {
- ($($current:expr),+) => {
- $(
- assert_eq!($current, borrowed);
- assert_eq!($current, owned);
- assert_eq!($current, borrowed_cow);
- assert_eq!($current, owned_cow);
- )+
- }
- }
-
- t!(borrowed, owned, borrowed_cow, owned_cow);
- }
-
- #[test]
- pub fn test_compare() {
- use crate::collections::hash_map::DefaultHasher;
- use crate::hash::{Hash, Hasher};
-
- fn hash<T: Hash>(t: T) -> u64 {
- let mut s = DefaultHasher::new();
- t.hash(&mut s);
- s.finish()
- }
-
- macro_rules! tc(
- ($path1:expr, $path2:expr, eq: $eq:expr,
- starts_with: $starts_with:expr, ends_with: $ends_with:expr,
- relative_from: $relative_from:expr) => ({
- let path1 = Path::new($path1);
- let path2 = Path::new($path2);
-
- let eq = path1 == path2;
- assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}",
- $path1, $path2, $eq, eq);
- assert!($eq == (hash(path1) == hash(path2)),
- "{:?} == {:?}, expected {:?}, got {} and {}",
- $path1, $path2, $eq, hash(path1), hash(path2));
-
- let starts_with = path1.starts_with(path2);
- assert!(starts_with == $starts_with,
- "{:?}.starts_with({:?}), expected {:?}, got {:?}", $path1, $path2,
- $starts_with, starts_with);
-
- let ends_with = path1.ends_with(path2);
- assert!(ends_with == $ends_with,
- "{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2,
- $ends_with, ends_with);
-
- let relative_from = path1.strip_prefix(path2)
- .map(|p| p.to_str().unwrap())
- .ok();
- let exp: Option<&str> = $relative_from;
- assert!(relative_from == exp,
- "{:?}.strip_prefix({:?}), expected {:?}, got {:?}",
- $path1, $path2, exp, relative_from);
- });
- );
-
- tc!("", "",
- eq: true,
- starts_with: true,
- ends_with: true,
- relative_from: Some("")
- );
-
- tc!("foo", "",
- eq: false,
- starts_with: true,
- ends_with: true,
- relative_from: Some("foo")
- );
-
- tc!("", "foo",
- eq: false,
- starts_with: false,
- ends_with: false,
- relative_from: None
- );
-
- tc!("foo", "foo",
- eq: true,
- starts_with: true,
- ends_with: true,
- relative_from: Some("")
- );
-
- tc!("foo/", "foo",
- eq: true,
- starts_with: true,
- ends_with: true,
- relative_from: Some("")
- );
-
- tc!("foo/bar", "foo",
- eq: false,
- starts_with: true,
- ends_with: false,
- relative_from: Some("bar")
- );
-
- tc!("foo/bar/baz", "foo/bar",
- eq: false,
- starts_with: true,
- ends_with: false,
- relative_from: Some("baz")
- );
-
- tc!("foo/bar", "foo/bar/baz",
- eq: false,
- starts_with: false,
- ends_with: false,
- relative_from: None
- );
-
- tc!("./foo/bar/", ".",
- eq: false,
- starts_with: true,
- ends_with: false,
- relative_from: Some("foo/bar")
- );
-
- if cfg!(windows) {
- tc!(r"C:\src\rust\cargo-test\test\Cargo.toml",
- r"c:\src\rust\cargo-test\test",
- eq: false,
- starts_with: true,
- ends_with: false,
- relative_from: Some("Cargo.toml")
- );
-
- tc!(r"c:\foo", r"C:\foo",
- eq: true,
- starts_with: true,
- ends_with: true,
- relative_from: Some("")
- );
- }
- }
-
- #[test]
- fn test_components_debug() {
- let path = Path::new("/tmp");
-
- let mut components = path.components();
-
- let expected = "Components([RootDir, Normal(\"tmp\")])";
- let actual = format!("{:?}", components);
- assert_eq!(expected, actual);
-
- let _ = components.next().unwrap();
- let expected = "Components([Normal(\"tmp\")])";
- let actual = format!("{:?}", components);
- assert_eq!(expected, actual);
-
- let _ = components.next().unwrap();
- let expected = "Components([])";
- let actual = format!("{:?}", components);
- assert_eq!(expected, actual);
- }
-
- #[cfg(unix)]
- #[test]
- fn test_iter_debug() {
- let path = Path::new("/tmp");
-
- let mut iter = path.iter();
-
- let expected = "Iter([\"/\", \"tmp\"])";
- let actual = format!("{:?}", iter);
- assert_eq!(expected, actual);
-
- let _ = iter.next().unwrap();
- let expected = "Iter([\"tmp\"])";
- let actual = format!("{:?}", iter);
- assert_eq!(expected, actual);
-
- let _ = iter.next().unwrap();
- let expected = "Iter([])";
- let actual = format!("{:?}", iter);
- assert_eq!(expected, actual);
- }
-
- #[test]
- fn into_boxed() {
- let orig: &str = "some/sort/of/path";
- let path = Path::new(orig);
- let boxed: Box<Path> = Box::from(path);
- let path_buf = path.to_owned().into_boxed_path().into_path_buf();
- assert_eq!(path, &*boxed);
- assert_eq!(&*boxed, &*path_buf);
- assert_eq!(&*path_buf, path);
- }
-
- #[test]
- fn test_clone_into() {
- let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious");
- let path = Path::new("short");
- path.clone_into(&mut path_buf);
- assert_eq!(path, path_buf);
- assert!(path_buf.into_os_string().capacity() >= 15);
- }
-
- #[test]
- fn display_format_flags() {
- assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b");
- assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b");
- }
-
- #[test]
- fn into_rc() {
- let orig = "hello/world";
- let path = Path::new(orig);
- let rc: Rc<Path> = Rc::from(path);
- let arc: Arc<Path> = Arc::from(path);
-
- assert_eq!(&*rc, path);
- assert_eq!(&*arc, path);
-
- let rc2: Rc<Path> = Rc::from(path.to_owned());
- let arc2: Arc<Path> = Arc::from(path.to_owned());
-
- assert_eq!(&*rc2, path);
- assert_eq!(&*arc2, path);
- }
-}
--- /dev/null
+use super::*;
+
+use crate::rc::Rc;
+use crate::sync::Arc;
+
+macro_rules! t(
+ ($path:expr, iter: $iter:expr) => (
+ {
+ let path = Path::new($path);
+
+ // Forward iteration
+ let comps = path.iter()
+ .map(|p| p.to_string_lossy().into_owned())
+ .collect::<Vec<String>>();
+ let exp: &[&str] = &$iter;
+ let exps = exp.iter().map(|s| s.to_string()).collect::<Vec<String>>();
+ assert!(comps == exps, "iter: Expected {:?}, found {:?}",
+ exps, comps);
+
+ // Reverse iteration
+ let comps = Path::new($path).iter().rev()
+ .map(|p| p.to_string_lossy().into_owned())
+ .collect::<Vec<String>>();
+ let exps = exps.into_iter().rev().collect::<Vec<String>>();
+ assert!(comps == exps, "iter().rev(): Expected {:?}, found {:?}",
+ exps, comps);
+ }
+ );
+
+ ($path:expr, has_root: $has_root:expr, is_absolute: $is_absolute:expr) => (
+ {
+ let path = Path::new($path);
+
+ let act_root = path.has_root();
+ assert!(act_root == $has_root, "has_root: Expected {:?}, found {:?}",
+ $has_root, act_root);
+
+ let act_abs = path.is_absolute();
+ assert!(act_abs == $is_absolute, "is_absolute: Expected {:?}, found {:?}",
+ $is_absolute, act_abs);
+ }
+ );
+
+ ($path:expr, parent: $parent:expr, file_name: $file:expr) => (
+ {
+ let path = Path::new($path);
+
+ let parent = path.parent().map(|p| p.to_str().unwrap());
+ let exp_parent: Option<&str> = $parent;
+ assert!(parent == exp_parent, "parent: Expected {:?}, found {:?}",
+ exp_parent, parent);
+
+ let file = path.file_name().map(|p| p.to_str().unwrap());
+ let exp_file: Option<&str> = $file;
+ assert!(file == exp_file, "file_name: Expected {:?}, found {:?}",
+ exp_file, file);
+ }
+ );
+
+ ($path:expr, file_stem: $file_stem:expr, extension: $extension:expr) => (
+ {
+ let path = Path::new($path);
+
+ let stem = path.file_stem().map(|p| p.to_str().unwrap());
+ let exp_stem: Option<&str> = $file_stem;
+ assert!(stem == exp_stem, "file_stem: Expected {:?}, found {:?}",
+ exp_stem, stem);
+
+ let ext = path.extension().map(|p| p.to_str().unwrap());
+ let exp_ext: Option<&str> = $extension;
+ assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}",
+ exp_ext, ext);
+ }
+ );
+
+ ($path:expr, iter: $iter:expr,
+ has_root: $has_root:expr, is_absolute: $is_absolute:expr,
+ parent: $parent:expr, file_name: $file:expr,
+ file_stem: $file_stem:expr, extension: $extension:expr) => (
+ {
+ t!($path, iter: $iter);
+ t!($path, has_root: $has_root, is_absolute: $is_absolute);
+ t!($path, parent: $parent, file_name: $file);
+ t!($path, file_stem: $file_stem, extension: $extension);
+ }
+ );
+);
+
+#[test]
+fn into() {
+ use crate::borrow::Cow;
+
+ let static_path = Path::new("/home/foo");
+ let static_cow_path: Cow<'static, Path> = static_path.into();
+ let pathbuf = PathBuf::from("/home/foo");
+
+ {
+ let path: &Path = &pathbuf;
+ let borrowed_cow_path: Cow<'_, Path> = path.into();
+
+ assert_eq!(static_cow_path, borrowed_cow_path);
+ }
+
+ let owned_cow_path: Cow<'static, Path> = pathbuf.into();
+
+ assert_eq!(static_cow_path, owned_cow_path);
+}
+
+#[test]
+#[cfg(unix)]
+pub fn test_decompositions_unix() {
+ t!("",
+ iter: [],
+ has_root: false,
+ is_absolute: false,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("/",
+ iter: ["/"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("/foo",
+ iter: ["/", "foo"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("/"),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("/foo/",
+ iter: ["/", "foo"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("/"),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/bar",
+ iter: ["foo", "bar"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("/foo/bar",
+ iter: ["/", "foo", "bar"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("/foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("///foo///",
+ iter: ["/", "foo"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("/"),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("///foo///bar",
+ iter: ["/", "foo", "bar"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("///foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("./.",
+ iter: ["."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("/..",
+ iter: ["/", ".."],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("/"),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("../",
+ iter: [".."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo/.",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/..",
+ iter: ["foo", ".."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo/./",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/./bar",
+ iter: ["foo", "bar"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("foo/../",
+ iter: ["foo", ".."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo/../bar",
+ iter: ["foo", "..", "bar"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo/.."),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("./a",
+ iter: [".", "a"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("."),
+ file_name: Some("a"),
+ file_stem: Some("a"),
+ extension: None
+ );
+
+ t!(".",
+ iter: ["."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("./",
+ iter: ["."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("a/b",
+ iter: ["a", "b"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+
+ t!("a//b",
+ iter: ["a", "b"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+
+ t!("a/./b",
+ iter: ["a", "b"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+
+ t!("a/b/c",
+ iter: ["a", "b", "c"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a/b"),
+ file_name: Some("c"),
+ file_stem: Some("c"),
+ extension: None
+ );
+
+ t!(".foo",
+ iter: [".foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some(".foo"),
+ file_stem: Some(".foo"),
+ extension: None
+ );
+}
+
+#[test]
+#[cfg(windows)]
+pub fn test_decompositions_windows() {
+ t!("",
+ iter: [],
+ has_root: false,
+ is_absolute: false,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("/",
+ iter: ["\\"],
+ has_root: true,
+ is_absolute: false,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\",
+ iter: ["\\"],
+ has_root: true,
+ is_absolute: false,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("c:",
+ iter: ["c:"],
+ has_root: false,
+ is_absolute: false,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("c:\\",
+ iter: ["c:", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("c:/",
+ iter: ["c:", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("/foo",
+ iter: ["\\", "foo"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("/"),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("/foo/",
+ iter: ["\\", "foo"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("/"),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/bar",
+ iter: ["foo", "bar"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("/foo/bar",
+ iter: ["\\", "foo", "bar"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("/foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("///foo///",
+ iter: ["\\", "foo"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("/"),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("///foo///bar",
+ iter: ["\\", "foo", "bar"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("///foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("./.",
+ iter: ["."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("/..",
+ iter: ["\\", ".."],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("/"),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("../",
+ iter: [".."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo/.",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/..",
+ iter: ["foo", ".."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo/./",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/./bar",
+ iter: ["foo", "bar"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("foo/../",
+ iter: ["foo", ".."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo/../bar",
+ iter: ["foo", "..", "bar"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo/.."),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("./a",
+ iter: [".", "a"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("."),
+ file_name: Some("a"),
+ file_stem: Some("a"),
+ extension: None
+ );
+
+ t!(".",
+ iter: ["."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("./",
+ iter: ["."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("a/b",
+ iter: ["a", "b"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+
+ t!("a//b",
+ iter: ["a", "b"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+
+ t!("a/./b",
+ iter: ["a", "b"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+
+ t!("a/b/c",
+ iter: ["a", "b", "c"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a/b"),
+ file_name: Some("c"),
+ file_stem: Some("c"),
+ extension: None);
+
+ t!("a\\b\\c",
+ iter: ["a", "b", "c"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a\\b"),
+ file_name: Some("c"),
+ file_stem: Some("c"),
+ extension: None
+ );
+
+ t!("\\a",
+ iter: ["\\", "a"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("\\"),
+ file_name: Some("a"),
+ file_stem: Some("a"),
+ extension: None
+ );
+
+ t!("c:\\foo.txt",
+ iter: ["c:", "\\", "foo.txt"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("c:\\"),
+ file_name: Some("foo.txt"),
+ file_stem: Some("foo"),
+ extension: Some("txt")
+ );
+
+ t!("\\\\server\\share\\foo.txt",
+ iter: ["\\\\server\\share", "\\", "foo.txt"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\server\\share\\"),
+ file_name: Some("foo.txt"),
+ file_stem: Some("foo"),
+ extension: Some("txt")
+ );
+
+ t!("\\\\server\\share",
+ iter: ["\\\\server\\share", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\server",
+ iter: ["\\", "server"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("\\"),
+ file_name: Some("server"),
+ file_stem: Some("server"),
+ extension: None
+ );
+
+ t!("\\\\?\\bar\\foo.txt",
+ iter: ["\\\\?\\bar", "\\", "foo.txt"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\?\\bar\\"),
+ file_name: Some("foo.txt"),
+ file_stem: Some("foo"),
+ extension: Some("txt")
+ );
+
+ t!("\\\\?\\bar",
+ iter: ["\\\\?\\bar"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\?\\",
+ iter: ["\\\\?\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\?\\UNC\\server\\share\\foo.txt",
+ iter: ["\\\\?\\UNC\\server\\share", "\\", "foo.txt"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\?\\UNC\\server\\share\\"),
+ file_name: Some("foo.txt"),
+ file_stem: Some("foo"),
+ extension: Some("txt")
+ );
+
+ t!("\\\\?\\UNC\\server",
+ iter: ["\\\\?\\UNC\\server"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\?\\UNC\\",
+ iter: ["\\\\?\\UNC\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\?\\C:\\foo.txt",
+ iter: ["\\\\?\\C:", "\\", "foo.txt"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\?\\C:\\"),
+ file_name: Some("foo.txt"),
+ file_stem: Some("foo"),
+ extension: Some("txt")
+ );
+
+ t!("\\\\?\\C:\\",
+ iter: ["\\\\?\\C:", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\?\\C:",
+ iter: ["\\\\?\\C:"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\?\\foo/bar",
+ iter: ["\\\\?\\foo/bar"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\?\\C:/foo",
+ iter: ["\\\\?\\C:/foo"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\.\\foo\\bar",
+ iter: ["\\\\.\\foo", "\\", "bar"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\.\\foo\\"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("\\\\.\\foo",
+ iter: ["\\\\.\\foo", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\.\\foo/bar",
+ iter: ["\\\\.\\foo/bar", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\.\\foo\\bar/baz",
+ iter: ["\\\\.\\foo", "\\", "bar", "baz"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\.\\foo\\bar"),
+ file_name: Some("baz"),
+ file_stem: Some("baz"),
+ extension: None
+ );
+
+ t!("\\\\.\\",
+ iter: ["\\\\.\\", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\?\\a\\b\\",
+ iter: ["\\\\?\\a", "\\", "b"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\?\\a\\"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+}
+
+#[test]
+pub fn test_stem_ext() {
+ t!("foo",
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo.",
+ file_stem: Some("foo"),
+ extension: Some("")
+ );
+
+ t!(".foo",
+ file_stem: Some(".foo"),
+ extension: None
+ );
+
+ t!("foo.txt",
+ file_stem: Some("foo"),
+ extension: Some("txt")
+ );
+
+ t!("foo.bar.txt",
+ file_stem: Some("foo.bar"),
+ extension: Some("txt")
+ );
+
+ t!("foo.bar.",
+ file_stem: Some("foo.bar"),
+ extension: Some("")
+ );
+
+ t!(".", file_stem: None, extension: None);
+
+ t!("..", file_stem: None, extension: None);
+
+ t!("", file_stem: None, extension: None);
+}
+
+#[test]
+pub fn test_push() {
+ macro_rules! tp(
+ ($path:expr, $push:expr, $expected:expr) => ( {
+ let mut actual = PathBuf::from($path);
+ actual.push($push);
+ assert!(actual.to_str() == Some($expected),
+ "pushing {:?} onto {:?}: Expected {:?}, got {:?}",
+ $push, $path, $expected, actual.to_str().unwrap());
+ });
+ );
+
+ if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
+ tp!("", "foo", "foo");
+ tp!("foo", "bar", "foo/bar");
+ tp!("foo/", "bar", "foo/bar");
+ tp!("foo//", "bar", "foo//bar");
+ tp!("foo/.", "bar", "foo/./bar");
+ tp!("foo./.", "bar", "foo././bar");
+ tp!("foo", "", "foo/");
+ tp!("foo", ".", "foo/.");
+ tp!("foo", "..", "foo/..");
+ tp!("foo", "/", "/");
+ tp!("/foo/bar", "/", "/");
+ tp!("/foo/bar", "/baz", "/baz");
+ tp!("/foo/bar", "./baz", "/foo/bar/./baz");
+ } else {
+ tp!("", "foo", "foo");
+ tp!("foo", "bar", r"foo\bar");
+ tp!("foo/", "bar", r"foo/bar");
+ tp!(r"foo\", "bar", r"foo\bar");
+ tp!("foo//", "bar", r"foo//bar");
+ tp!(r"foo\\", "bar", r"foo\\bar");
+ tp!("foo/.", "bar", r"foo/.\bar");
+ tp!("foo./.", "bar", r"foo./.\bar");
+ tp!(r"foo\.", "bar", r"foo\.\bar");
+ tp!(r"foo.\.", "bar", r"foo.\.\bar");
+ tp!("foo", "", "foo\\");
+ tp!("foo", ".", r"foo\.");
+ tp!("foo", "..", r"foo\..");
+ tp!("foo", "/", "/");
+ tp!("foo", r"\", r"\");
+ tp!("/foo/bar", "/", "/");
+ tp!(r"\foo\bar", r"\", r"\");
+ tp!("/foo/bar", "/baz", "/baz");
+ tp!("/foo/bar", r"\baz", r"\baz");
+ tp!("/foo/bar", "./baz", r"/foo/bar\./baz");
+ tp!("/foo/bar", r".\baz", r"/foo/bar\.\baz");
+
+ tp!("c:\\", "windows", "c:\\windows");
+ tp!("c:", "windows", "c:windows");
+
+ tp!("a\\b\\c", "d", "a\\b\\c\\d");
+ tp!("\\a\\b\\c", "d", "\\a\\b\\c\\d");
+ tp!("a\\b", "c\\d", "a\\b\\c\\d");
+ tp!("a\\b", "\\c\\d", "\\c\\d");
+ tp!("a\\b", ".", "a\\b\\.");
+ tp!("a\\b", "..\\c", "a\\b\\..\\c");
+ tp!("a\\b", "C:a.txt", "C:a.txt");
+ tp!("a\\b", "C:\\a.txt", "C:\\a.txt");
+ tp!("C:\\a", "C:\\b.txt", "C:\\b.txt");
+ tp!("C:\\a\\b\\c", "C:d", "C:d");
+ tp!("C:a\\b\\c", "C:d", "C:d");
+ tp!("C:", r"a\b\c", r"C:a\b\c");
+ tp!("C:", r"..\a", r"C:..\a");
+ tp!("\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar");
+ tp!("\\\\server\\share\\foo", "C:baz", "C:baz");
+ tp!("\\\\?\\C:\\a\\b", "C:c\\d", "C:c\\d");
+ tp!("\\\\?\\C:a\\b", "C:c\\d", "C:c\\d");
+ tp!("\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d");
+ tp!("\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz");
+ tp!("\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar");
+ tp!("\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a");
+ tp!("\\\\?\\UNC\\server\\share", "C:a", "C:a");
+
+ // Note: modified from old path API
+ tp!("\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\foo");
+
+ tp!("C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share");
+ tp!("\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz");
+ tp!("\\\\.\\foo\\bar", "C:a", "C:a");
+ // again, not sure about the following, but I'm assuming \\.\ should be verbatim
+ tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar");
+
+ tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one
+ }
+}
+
+#[test]
+pub fn test_pop() {
+ macro_rules! tp(
+ ($path:expr, $expected:expr, $output:expr) => ( {
+ let mut actual = PathBuf::from($path);
+ let output = actual.pop();
+ assert!(actual.to_str() == Some($expected) && output == $output,
+ "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
+ $path, $expected, $output,
+ actual.to_str().unwrap(), output);
+ });
+ );
+
+ tp!("", "", false);
+ tp!("/", "/", false);
+ tp!("foo", "", true);
+ tp!(".", "", true);
+ tp!("/foo", "/", true);
+ tp!("/foo/bar", "/foo", true);
+ tp!("foo/bar", "foo", true);
+ tp!("foo/.", "", true);
+ tp!("foo//bar", "foo", true);
+
+ if cfg!(windows) {
+ tp!("a\\b\\c", "a\\b", true);
+ tp!("\\a", "\\", true);
+ tp!("\\", "\\", false);
+
+ tp!("C:\\a\\b", "C:\\a", true);
+ tp!("C:\\a", "C:\\", true);
+ tp!("C:\\", "C:\\", false);
+ tp!("C:a\\b", "C:a", true);
+ tp!("C:a", "C:", true);
+ tp!("C:", "C:", false);
+ tp!("\\\\server\\share\\a\\b", "\\\\server\\share\\a", true);
+ tp!("\\\\server\\share\\a", "\\\\server\\share\\", true);
+ tp!("\\\\server\\share", "\\\\server\\share", false);
+ tp!("\\\\?\\a\\b\\c", "\\\\?\\a\\b", true);
+ tp!("\\\\?\\a\\b", "\\\\?\\a\\", true);
+ tp!("\\\\?\\a", "\\\\?\\a", false);
+ tp!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true);
+ tp!("\\\\?\\C:\\a", "\\\\?\\C:\\", true);
+ tp!("\\\\?\\C:\\", "\\\\?\\C:\\", false);
+ tp!("\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true);
+ tp!("\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share\\", true);
+ tp!("\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false);
+ tp!("\\\\.\\a\\b\\c", "\\\\.\\a\\b", true);
+ tp!("\\\\.\\a\\b", "\\\\.\\a\\", true);
+ tp!("\\\\.\\a", "\\\\.\\a", false);
+
+ tp!("\\\\?\\a\\b\\", "\\\\?\\a\\", true);
+ }
+}
+
+#[test]
+pub fn test_set_file_name() {
+ macro_rules! tfn(
+ ($path:expr, $file:expr, $expected:expr) => ( {
+ let mut p = PathBuf::from($path);
+ p.set_file_name($file);
+ assert!(p.to_str() == Some($expected),
+ "setting file name of {:?} to {:?}: Expected {:?}, got {:?}",
+ $path, $file, $expected,
+ p.to_str().unwrap());
+ });
+ );
+
+ tfn!("foo", "foo", "foo");
+ tfn!("foo", "bar", "bar");
+ tfn!("foo", "", "");
+ tfn!("", "foo", "foo");
+ if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
+ tfn!(".", "foo", "./foo");
+ tfn!("foo/", "bar", "bar");
+ tfn!("foo/.", "bar", "bar");
+ tfn!("..", "foo", "../foo");
+ tfn!("foo/..", "bar", "foo/../bar");
+ tfn!("/", "foo", "/foo");
+ } else {
+ tfn!(".", "foo", r".\foo");
+ tfn!(r"foo\", "bar", r"bar");
+ tfn!(r"foo\.", "bar", r"bar");
+ tfn!("..", "foo", r"..\foo");
+ tfn!(r"foo\..", "bar", r"foo\..\bar");
+ tfn!(r"\", "foo", r"\foo");
+ }
+}
+
+#[test]
+pub fn test_set_extension() {
+ macro_rules! tfe(
+ ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( {
+ let mut p = PathBuf::from($path);
+ let output = p.set_extension($ext);
+ assert!(p.to_str() == Some($expected) && output == $output,
+ "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
+ $path, $ext, $expected, $output,
+ p.to_str().unwrap(), output);
+ });
+ );
+
+ tfe!("foo", "txt", "foo.txt", true);
+ tfe!("foo.bar", "txt", "foo.txt", true);
+ tfe!("foo.bar.baz", "txt", "foo.bar.txt", true);
+ tfe!(".test", "txt", ".test.txt", true);
+ tfe!("foo.txt", "", "foo", true);
+ tfe!("foo", "", "foo", true);
+ tfe!("", "foo", "", false);
+ tfe!(".", "foo", ".", false);
+ tfe!("foo/", "bar", "foo.bar", true);
+ tfe!("foo/.", "bar", "foo.bar", true);
+ tfe!("..", "foo", "..", false);
+ tfe!("foo/..", "bar", "foo/..", false);
+ tfe!("/", "foo", "/", false);
+}
+
+#[test]
+fn test_eq_receivers() {
+ use crate::borrow::Cow;
+
+ let borrowed: &Path = Path::new("foo/bar");
+ let mut owned: PathBuf = PathBuf::new();
+ owned.push("foo");
+ owned.push("bar");
+ let borrowed_cow: Cow<'_, Path> = borrowed.into();
+ let owned_cow: Cow<'_, Path> = owned.clone().into();
+
+ macro_rules! t {
+ ($($current:expr),+) => {
+ $(
+ assert_eq!($current, borrowed);
+ assert_eq!($current, owned);
+ assert_eq!($current, borrowed_cow);
+ assert_eq!($current, owned_cow);
+ )+
+ }
+ }
+
+ t!(borrowed, owned, borrowed_cow, owned_cow);
+}
+
+#[test]
+pub fn test_compare() {
+ use crate::collections::hash_map::DefaultHasher;
+ use crate::hash::{Hash, Hasher};
+
+ fn hash<T: Hash>(t: T) -> u64 {
+ let mut s = DefaultHasher::new();
+ t.hash(&mut s);
+ s.finish()
+ }
+
+ macro_rules! tc(
+ ($path1:expr, $path2:expr, eq: $eq:expr,
+ starts_with: $starts_with:expr, ends_with: $ends_with:expr,
+ relative_from: $relative_from:expr) => ({
+ let path1 = Path::new($path1);
+ let path2 = Path::new($path2);
+
+ let eq = path1 == path2;
+ assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}",
+ $path1, $path2, $eq, eq);
+ assert!($eq == (hash(path1) == hash(path2)),
+ "{:?} == {:?}, expected {:?}, got {} and {}",
+ $path1, $path2, $eq, hash(path1), hash(path2));
+
+ let starts_with = path1.starts_with(path2);
+ assert!(starts_with == $starts_with,
+ "{:?}.starts_with({:?}), expected {:?}, got {:?}", $path1, $path2,
+ $starts_with, starts_with);
+
+ let ends_with = path1.ends_with(path2);
+ assert!(ends_with == $ends_with,
+ "{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2,
+ $ends_with, ends_with);
+
+ let relative_from = path1.strip_prefix(path2)
+ .map(|p| p.to_str().unwrap())
+ .ok();
+ let exp: Option<&str> = $relative_from;
+ assert!(relative_from == exp,
+ "{:?}.strip_prefix({:?}), expected {:?}, got {:?}",
+ $path1, $path2, exp, relative_from);
+ });
+ );
+
+ tc!("", "",
+ eq: true,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("")
+ );
+
+ tc!("foo", "",
+ eq: false,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("foo")
+ );
+
+ tc!("", "foo",
+ eq: false,
+ starts_with: false,
+ ends_with: false,
+ relative_from: None
+ );
+
+ tc!("foo", "foo",
+ eq: true,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("")
+ );
+
+ tc!("foo/", "foo",
+ eq: true,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("")
+ );
+
+ tc!("foo/bar", "foo",
+ eq: false,
+ starts_with: true,
+ ends_with: false,
+ relative_from: Some("bar")
+ );
+
+ tc!("foo/bar/baz", "foo/bar",
+ eq: false,
+ starts_with: true,
+ ends_with: false,
+ relative_from: Some("baz")
+ );
+
+ tc!("foo/bar", "foo/bar/baz",
+ eq: false,
+ starts_with: false,
+ ends_with: false,
+ relative_from: None
+ );
+
+ tc!("./foo/bar/", ".",
+ eq: false,
+ starts_with: true,
+ ends_with: false,
+ relative_from: Some("foo/bar")
+ );
+
+ if cfg!(windows) {
+ tc!(r"C:\src\rust\cargo-test\test\Cargo.toml",
+ r"c:\src\rust\cargo-test\test",
+ eq: false,
+ starts_with: true,
+ ends_with: false,
+ relative_from: Some("Cargo.toml")
+ );
+
+ tc!(r"c:\foo", r"C:\foo",
+ eq: true,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("")
+ );
+ }
+}
+
+#[test]
+fn test_components_debug() {
+ let path = Path::new("/tmp");
+
+ let mut components = path.components();
+
+ let expected = "Components([RootDir, Normal(\"tmp\")])";
+ let actual = format!("{:?}", components);
+ assert_eq!(expected, actual);
+
+ let _ = components.next().unwrap();
+ let expected = "Components([Normal(\"tmp\")])";
+ let actual = format!("{:?}", components);
+ assert_eq!(expected, actual);
+
+ let _ = components.next().unwrap();
+ let expected = "Components([])";
+ let actual = format!("{:?}", components);
+ assert_eq!(expected, actual);
+}
+
+#[cfg(unix)]
+#[test]
+fn test_iter_debug() {
+ let path = Path::new("/tmp");
+
+ let mut iter = path.iter();
+
+ let expected = "Iter([\"/\", \"tmp\"])";
+ let actual = format!("{:?}", iter);
+ assert_eq!(expected, actual);
+
+ let _ = iter.next().unwrap();
+ let expected = "Iter([\"tmp\"])";
+ let actual = format!("{:?}", iter);
+ assert_eq!(expected, actual);
+
+ let _ = iter.next().unwrap();
+ let expected = "Iter([])";
+ let actual = format!("{:?}", iter);
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn into_boxed() {
+ let orig: &str = "some/sort/of/path";
+ let path = Path::new(orig);
+ let boxed: Box<Path> = Box::from(path);
+ let path_buf = path.to_owned().into_boxed_path().into_path_buf();
+ assert_eq!(path, &*boxed);
+ assert_eq!(&*boxed, &*path_buf);
+ assert_eq!(&*path_buf, path);
+}
+
+#[test]
+fn test_clone_into() {
+ let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious");
+ let path = Path::new("short");
+ path.clone_into(&mut path_buf);
+ assert_eq!(path, path_buf);
+ assert!(path_buf.into_os_string().capacity() >= 15);
+}
+
+#[test]
+fn display_format_flags() {
+ assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b");
+ assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b");
+}
+
+#[test]
+fn into_rc() {
+ let orig = "hello/world";
+ let path = Path::new(orig);
+ let rc: Rc<Path> = Rc::from(path);
+ let arc: Arc<Path> = Arc::from(path);
+
+ assert_eq!(&*rc, path);
+ assert_eq!(&*arc, path);
+
+ let rc2: Rc<Path> = Rc::from(path.to_owned());
+ let arc2: Arc<Path> = Arc::from(path.to_owned());
+
+ assert_eq!(&*rc2, path);
+ assert_eq!(&*arc2, path);
+}
#![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;
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(""))
- }
-}
--- /dev/null
+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(""))
+}
+#[cfg(test)]
+mod tests;
+
use crate::fmt;
use crate::sync::{Condvar, Mutex};
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);
- }
-}
--- /dev/null
+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);
+}
+#[cfg(test)]
+mod tests;
+
use crate::fmt;
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::{mutex, MutexGuard, PoisonError};
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();
- }
-}
--- /dev/null
+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();
+}
#![stable(feature = "rust1", since = "1.0.0")]
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod sync_tests;
+
// A description of how Rust's channel implementation works
//
// Channels are supposed to be the basic building block for all other
}
}
}
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests {
- 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)));
- }
-}
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod sync_tests {
- 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()
- }
- }
-}
// 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;
}
}
}
-
-#[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();
- }
- }
-}
--- /dev/null
+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();
+ }
+}
// 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;
}
}
}
-
-#[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();
- }
- }
-}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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()
+ }
+}
--- /dev/null
+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)));
+}
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::mem;
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);
- }
-}
--- /dev/null
+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);
+}
// 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;
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());
- }
-}
--- /dev/null
+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());
+}
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::mem;
}
}
}
-
-#[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),
- }
- }
-}
--- /dev/null
+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),
+ }
+}
+mod sync_bitset;
+
use self::sync_bitset::*;
use crate::cell::Cell;
use crate::mem;
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));
- }
- }
-}
--- /dev/null
+#[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),
+ }
+ })
+ }
+}
--- /dev/null
+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));
+}
+#[cfg(test)]
+mod tests;
+
use crate::num::NonZeroUsize;
use super::waitqueue::{
(*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)
- };
- }
-}
--- /dev/null
+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)
+ };
+}
//! 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;
}
}
}
-
-/// 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();
- }
-}
--- /dev/null
+#[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)
+ }
+}
--- /dev/null
+#![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);
+}
--- /dev/null
+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();
+}
--- /dev/null
+#[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();
+ }
+}
--- /dev/null
+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);
+ }
+}
//! 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)]
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());
- }
-}
--- /dev/null
+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());
+}
#![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;
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());
- }
-}
--- /dev/null
+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());
+}
#![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;
_ => 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));
- }
- }
-}
--- /dev/null
+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));
+ }
+}
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
use crate::os::unix::prelude::*;
use crate::collections::BTreeMap;
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());
- }
- }
-}
--- /dev/null
+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());
+ }
+}
+#[cfg(all(test, taget_env = "gnu"))]
+mod tests;
+
use crate::cmp;
use crate::ffi::CStr;
use crate::io;
#[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));
- }
- }
-}
--- /dev/null
+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));
+ }
+}
#![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::*;
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"]);
- }
-}
--- /dev/null
+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"]);
+}
#![allow(nonstandard_style)]
+#[cfg(test)]
+mod tests;
+
use crate::os::windows::prelude::*;
use crate::error::Error as StdError;
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")
- );
- }
-}
--- /dev/null
+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")
+ );
+}
#![unstable(feature = "process_internals", issue = "none")]
+#[cfg(test)]
+mod tests;
+
use crate::borrow::Borrow;
use crate::collections::BTreeMap;
use crate::env;
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}\""
- );
- }
-}
--- /dev/null
+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}\""
+ );
+}
#![allow(dead_code)]
+#[cfg(test)]
+mod tests;
+
use crate::fmt::{Formatter, Result, Write};
use core::str::lossy::{Utf8Lossy, Utf8LossyChunk};
}
f.write_str("\"")
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::fmt::{Debug, Formatter, Result};
-
- #[test]
- fn smoke() {
- struct Helper<'a>(&'a [u8]);
-
- impl Debug for Helper<'_> {
- fn fmt(&self, f: &mut Formatter<'_>) -> Result {
- debug_fmt_bytestring(self.0, f)
- }
- }
-
- let input = b"\xF0hello,\tworld";
- let expected = r#""\xF0hello,\tworld""#;
- let output = format!("{:?}", Helper(input));
-
- assert!(output == expected);
- }
-}
--- /dev/null
+use super::*;
+use crate::fmt::{Debug, Formatter, Result};
+
+#[test]
+fn smoke() {
+ struct Helper<'a>(&'a [u8]);
+
+ impl Debug for Helper<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ debug_fmt_bytestring(self.0, f)
+ }
+ }
+
+ let input = b"\xF0hello,\tworld";
+ let expected = r#""\xF0hello,\tworld""#;
+ let output = format!("{:?}", Helper(input));
+
+ assert!(output == expected);
+}
#![allow(missing_docs)]
#![allow(missing_debug_implementations)]
+#[cfg(test)]
+mod tests;
+
use crate::sync::Once;
use crate::sys;
// r < denom, so (denom*numer) is the upper bound of (r*numer)
q * numer + r * numer / denom
}
-
-#[test]
-fn test_muldiv() {
- assert_eq!(mul_div_u64(1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000);
-}
+#[cfg(test)]
+mod tests;
+
use crate::cmp;
use crate::convert::{TryFrom, TryInto};
use crate::ffi::CString;
res.field(name, &self.inner.as_inner()).finish()
}
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::collections::HashMap;
-
- #[test]
- fn no_lookup_host_duplicates() {
- let mut addrs = HashMap::new();
- let lh = match LookupHost::try_from(("localhost", 0)) {
- Ok(lh) => lh,
- Err(e) => panic!("couldn't resolve `localhost': {}", e),
- };
- for sa in lh {
- *addrs.entry(sa).or_insert(0) += 1;
- }
- assert_eq!(
- addrs.iter().filter(|&(_, &v)| v > 1).collect::<Vec<_>>(),
- vec![],
- "There should be no duplicate localhost entries"
- );
- }
-}
--- /dev/null
+use super::*;
+use crate::collections::HashMap;
+
+#[test]
+fn no_lookup_host_duplicates() {
+ let mut addrs = HashMap::new();
+ let lh = match LookupHost::try_from(("localhost", 0)) {
+ Ok(lh) => lh,
+ Err(e) => panic!("couldn't resolve `localhost': {}", e),
+ };
+ for sa in lh {
+ *addrs.entry(sa).or_insert(0) += 1;
+ }
+ assert_eq!(
+ addrs.iter().filter(|&(_, &v)| v > 1).collect::<Vec<_>>(),
+ vec![],
+ "There should be no duplicate localhost entries"
+ );
+}
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
use crate::fmt;
use crate::marker;
use crate::ops::Deref;
}
}
}
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests {
- use crate::cell::RefCell;
- use crate::sync::Arc;
- use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
- use crate::thread;
-
- #[test]
- fn smoke() {
- let m = unsafe {
- let m = ReentrantMutex::new(());
- m.init();
- m
- };
- {
- let a = m.lock();
- {
- let b = m.lock();
- {
- let c = m.lock();
- assert_eq!(*c, ());
- }
- assert_eq!(*b, ());
- }
- assert_eq!(*a, ());
- }
- }
-
- #[test]
- fn is_mutex() {
- let m = unsafe {
- let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
- m.init();
- m
- };
- let m2 = m.clone();
- let lock = m.lock();
- let child = thread::spawn(move || {
- let lock = m2.lock();
- assert_eq!(*lock.borrow(), 4950);
- });
- for i in 0..100 {
- let lock = m.lock();
- *lock.borrow_mut() += i;
- }
- drop(lock);
- child.join().unwrap();
- }
-
- #[test]
- fn trylock_works() {
- let m = unsafe {
- let m = Arc::new(ReentrantMutex::new(()));
- m.init();
- m
- };
- let m2 = m.clone();
- let _lock = m.try_lock();
- let _lock2 = m.try_lock();
- thread::spawn(move || {
- let lock = m2.try_lock();
- assert!(lock.is_none());
- })
- .join()
- .unwrap();
- let _lock3 = m.try_lock();
- }
-
- pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
- impl Drop for Answer<'_> {
- fn drop(&mut self) {
- *self.0.borrow_mut() = 42;
- }
- }
-}
--- /dev/null
+use crate::cell::RefCell;
+use crate::sync::Arc;
+use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
+use crate::thread;
+
+#[test]
+fn smoke() {
+ let m = unsafe {
+ let m = ReentrantMutex::new(());
+ m.init();
+ m
+ };
+ {
+ let a = m.lock();
+ {
+ let b = m.lock();
+ {
+ let c = m.lock();
+ assert_eq!(*c, ());
+ }
+ assert_eq!(*b, ());
+ }
+ assert_eq!(*a, ());
+ }
+}
+
+#[test]
+fn is_mutex() {
+ let m = unsafe {
+ let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
+ m.init();
+ m
+ };
+ let m2 = m.clone();
+ let lock = m.lock();
+ let child = thread::spawn(move || {
+ let lock = m2.lock();
+ assert_eq!(*lock.borrow(), 4950);
+ });
+ for i in 0..100 {
+ let lock = m.lock();
+ *lock.borrow_mut() += i;
+ }
+ drop(lock);
+ child.join().unwrap();
+}
+
+#[test]
+fn trylock_works() {
+ let m = unsafe {
+ let m = Arc::new(ReentrantMutex::new(()));
+ m.init();
+ m
+ };
+ let m2 = m.clone();
+ let _lock = m.try_lock();
+ let _lock2 = m.try_lock();
+ thread::spawn(move || {
+ let lock = m2.try_lock();
+ assert!(lock.is_none());
+ })
+ .join()
+ .unwrap();
+ let _lock3 = m.try_lock();
+}
+
+pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
+impl Drop for Answer<'_> {
+ fn drop(&mut self) {
+ *self.0.borrow_mut() = 42;
+ }
+}
--- /dev/null
+use super::mul_div_u64;
+
+#[test]
+fn test_muldiv() {
+ assert_eq!(mul_div_u64(1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000);
+}
#![unstable(feature = "thread_local_internals", issue = "none")]
#![allow(dead_code)] // sys isn't exported yet
+#[cfg(test)]
+mod tests;
+
use crate::sync::atomic::{self, AtomicUsize, Ordering};
use crate::sys::thread_local_key as imp;
use crate::sys_common::mutex::Mutex;
// unsafe { imp::destroy(self.key) }
}
}
-
-#[cfg(test)]
-mod tests {
- use super::{Key, StaticKey};
-
- fn assert_sync<T: Sync>() {}
- fn assert_send<T: Send>() {}
-
- #[test]
- fn smoke() {
- assert_sync::<Key>();
- assert_send::<Key>();
-
- let k1 = Key::new(None);
- let k2 = Key::new(None);
- assert!(k1.get().is_null());
- assert!(k2.get().is_null());
- k1.set(1 as *mut _);
- k2.set(2 as *mut _);
- assert_eq!(k1.get() as usize, 1);
- assert_eq!(k2.get() as usize, 2);
- }
-
- #[test]
- fn statik() {
- static K1: StaticKey = StaticKey::new(None);
- static K2: StaticKey = StaticKey::new(None);
-
- unsafe {
- assert!(K1.get().is_null());
- assert!(K2.get().is_null());
- K1.set(1 as *mut _);
- K2.set(2 as *mut _);
- assert_eq!(K1.get() as usize, 1);
- assert_eq!(K2.get() as usize, 2);
- }
- }
-}
--- /dev/null
+use super::{Key, StaticKey};
+
+fn assert_sync<T: Sync>() {}
+fn assert_send<T: Send>() {}
+
+#[test]
+fn smoke() {
+ assert_sync::<Key>();
+ assert_send::<Key>();
+
+ let k1 = Key::new(None);
+ let k2 = Key::new(None);
+ assert!(k1.get().is_null());
+ assert!(k2.get().is_null());
+ k1.set(1 as *mut _);
+ k2.set(2 as *mut _);
+ assert_eq!(k1.get() as usize, 1);
+ assert_eq!(k2.get() as usize, 2);
+}
+
+#[test]
+fn statik() {
+ static K1: StaticKey = StaticKey::new(None);
+ static K2: StaticKey = StaticKey::new(None);
+
+ unsafe {
+ assert!(K1.get().is_null());
+ assert!(K2.get().is_null());
+ K1.set(1 as *mut _);
+ K2.set(2 as *mut _);
+ assert_eq!(K1.get() as usize, 1);
+ assert_eq!(K2.get() as usize, 2);
+ }
+}
// unix (it's mostly used on windows), so don't worry about dead code here.
#![allow(dead_code)]
+#[cfg(test)]
+mod tests;
+
use core::str::next_code_point;
use crate::borrow::Cow;
0xfeu8.hash(state)
}
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::borrow::Cow;
-
- #[test]
- fn code_point_from_u32() {
- assert!(CodePoint::from_u32(0).is_some());
- assert!(CodePoint::from_u32(0xD800).is_some());
- assert!(CodePoint::from_u32(0x10FFFF).is_some());
- assert!(CodePoint::from_u32(0x110000).is_none());
- }
-
- #[test]
- fn code_point_to_u32() {
- fn c(value: u32) -> CodePoint {
- CodePoint::from_u32(value).unwrap()
- }
- assert_eq!(c(0).to_u32(), 0);
- assert_eq!(c(0xD800).to_u32(), 0xD800);
- assert_eq!(c(0x10FFFF).to_u32(), 0x10FFFF);
- }
-
- #[test]
- fn code_point_from_char() {
- assert_eq!(CodePoint::from_char('a').to_u32(), 0x61);
- assert_eq!(CodePoint::from_char('💩').to_u32(), 0x1F4A9);
- }
-
- #[test]
- fn code_point_to_string() {
- assert_eq!(format!("{:?}", CodePoint::from_char('a')), "U+0061");
- assert_eq!(format!("{:?}", CodePoint::from_char('💩')), "U+1F4A9");
- }
-
- #[test]
- fn code_point_to_char() {
- fn c(value: u32) -> CodePoint {
- CodePoint::from_u32(value).unwrap()
- }
- assert_eq!(c(0x61).to_char(), Some('a'));
- assert_eq!(c(0x1F4A9).to_char(), Some('💩'));
- assert_eq!(c(0xD800).to_char(), None);
- }
-
- #[test]
- fn code_point_to_char_lossy() {
- fn c(value: u32) -> CodePoint {
- CodePoint::from_u32(value).unwrap()
- }
- assert_eq!(c(0x61).to_char_lossy(), 'a');
- assert_eq!(c(0x1F4A9).to_char_lossy(), '💩');
- assert_eq!(c(0xD800).to_char_lossy(), '\u{FFFD}');
- }
-
- #[test]
- fn wtf8buf_new() {
- assert_eq!(Wtf8Buf::new().bytes, b"");
- }
-
- #[test]
- fn wtf8buf_from_str() {
- assert_eq!(Wtf8Buf::from_str("").bytes, b"");
- assert_eq!(Wtf8Buf::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
- }
-
- #[test]
- fn wtf8buf_from_string() {
- assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b"");
- assert_eq!(
- Wtf8Buf::from_string(String::from("aé 💩")).bytes,
- b"a\xC3\xA9 \xF0\x9F\x92\xA9"
- );
- }
-
- #[test]
- fn wtf8buf_from_wide() {
- assert_eq!(Wtf8Buf::from_wide(&[]).bytes, b"");
- assert_eq!(
- Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]).bytes,
- b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9"
- );
- }
-
- #[test]
- fn wtf8buf_push_str() {
- let mut string = Wtf8Buf::new();
- assert_eq!(string.bytes, b"");
- string.push_str("aé 💩");
- assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
- }
-
- #[test]
- fn wtf8buf_push_char() {
- let mut string = Wtf8Buf::from_str("aé ");
- assert_eq!(string.bytes, b"a\xC3\xA9 ");
- string.push_char('💩');
- assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
- }
-
- #[test]
- fn wtf8buf_push() {
- let mut string = Wtf8Buf::from_str("aé ");
- assert_eq!(string.bytes, b"a\xC3\xA9 ");
- string.push(CodePoint::from_char('💩'));
- assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
-
- fn c(value: u32) -> CodePoint {
- CodePoint::from_u32(value).unwrap()
- }
-
- let mut string = Wtf8Buf::new();
- string.push(c(0xD83D)); // lead
- string.push(c(0xDCA9)); // trail
- assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic!
-
- let mut string = Wtf8Buf::new();
- string.push(c(0xD83D)); // lead
- string.push(c(0x20)); // not surrogate
- string.push(c(0xDCA9)); // trail
- assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
-
- let mut string = Wtf8Buf::new();
- string.push(c(0xD800)); // lead
- string.push(c(0xDBFF)); // lead
- assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF");
-
- let mut string = Wtf8Buf::new();
- string.push(c(0xD800)); // lead
- string.push(c(0xE000)); // not surrogate
- assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80");
-
- let mut string = Wtf8Buf::new();
- string.push(c(0xD7FF)); // not surrogate
- string.push(c(0xDC00)); // trail
- assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80");
-
- let mut string = Wtf8Buf::new();
- string.push(c(0x61)); // not surrogate, < 3 bytes
- string.push(c(0xDC00)); // trail
- assert_eq!(string.bytes, b"\x61\xED\xB0\x80");
-
- let mut string = Wtf8Buf::new();
- string.push(c(0xDC00)); // trail
- assert_eq!(string.bytes, b"\xED\xB0\x80");
- }
-
- #[test]
- fn wtf8buf_push_wtf8() {
- let mut string = Wtf8Buf::from_str("aé");
- assert_eq!(string.bytes, b"a\xC3\xA9");
- string.push_wtf8(Wtf8::from_str(" 💩"));
- assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
-
- fn w(v: &[u8]) -> &Wtf8 {
- unsafe { Wtf8::from_bytes_unchecked(v) }
- }
-
- let mut string = Wtf8Buf::new();
- string.push_wtf8(w(b"\xED\xA0\xBD")); // lead
- string.push_wtf8(w(b"\xED\xB2\xA9")); // trail
- assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic!
-
- let mut string = Wtf8Buf::new();
- string.push_wtf8(w(b"\xED\xA0\xBD")); // lead
- string.push_wtf8(w(b" ")); // not surrogate
- string.push_wtf8(w(b"\xED\xB2\xA9")); // trail
- assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
-
- let mut string = Wtf8Buf::new();
- string.push_wtf8(w(b"\xED\xA0\x80")); // lead
- string.push_wtf8(w(b"\xED\xAF\xBF")); // lead
- assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF");
-
- let mut string = Wtf8Buf::new();
- string.push_wtf8(w(b"\xED\xA0\x80")); // lead
- string.push_wtf8(w(b"\xEE\x80\x80")); // not surrogate
- assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80");
-
- let mut string = Wtf8Buf::new();
- string.push_wtf8(w(b"\xED\x9F\xBF")); // not surrogate
- string.push_wtf8(w(b"\xED\xB0\x80")); // trail
- assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80");
-
- let mut string = Wtf8Buf::new();
- string.push_wtf8(w(b"a")); // not surrogate, < 3 bytes
- string.push_wtf8(w(b"\xED\xB0\x80")); // trail
- assert_eq!(string.bytes, b"\x61\xED\xB0\x80");
-
- let mut string = Wtf8Buf::new();
- string.push_wtf8(w(b"\xED\xB0\x80")); // trail
- assert_eq!(string.bytes, b"\xED\xB0\x80");
- }
-
- #[test]
- fn wtf8buf_truncate() {
- let mut string = Wtf8Buf::from_str("aé");
- string.truncate(1);
- assert_eq!(string.bytes, b"a");
- }
-
- #[test]
- #[should_panic]
- fn wtf8buf_truncate_fail_code_point_boundary() {
- let mut string = Wtf8Buf::from_str("aé");
- string.truncate(2);
- }
-
- #[test]
- #[should_panic]
- fn wtf8buf_truncate_fail_longer() {
- let mut string = Wtf8Buf::from_str("aé");
- string.truncate(4);
- }
-
- #[test]
- fn wtf8buf_into_string() {
- let mut string = Wtf8Buf::from_str("aé 💩");
- assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩")));
- string.push(CodePoint::from_u32(0xD800).unwrap());
- assert_eq!(string.clone().into_string(), Err(string));
- }
-
- #[test]
- fn wtf8buf_into_string_lossy() {
- let mut string = Wtf8Buf::from_str("aé 💩");
- assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩"));
- string.push(CodePoint::from_u32(0xD800).unwrap());
- assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�"));
- }
-
- #[test]
- fn wtf8buf_from_iterator() {
- fn f(values: &[u32]) -> Wtf8Buf {
- values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::<Wtf8Buf>()
- }
- assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
-
- assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!
- assert_eq!(f(&[0xD83D, 0x20, 0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
- assert_eq!(f(&[0xD800, 0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF");
- assert_eq!(f(&[0xD800, 0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80");
- assert_eq!(f(&[0xD7FF, 0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80");
- assert_eq!(f(&[0x61, 0xDC00]).bytes, b"\x61\xED\xB0\x80");
- assert_eq!(f(&[0xDC00]).bytes, b"\xED\xB0\x80");
- }
-
- #[test]
- fn wtf8buf_extend() {
- fn e(initial: &[u32], extended: &[u32]) -> Wtf8Buf {
- fn c(value: &u32) -> CodePoint {
- CodePoint::from_u32(*value).unwrap()
- }
- let mut string = initial.iter().map(c).collect::<Wtf8Buf>();
- string.extend(extended.iter().map(c));
- string
- }
-
- assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
-
- assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!
- assert_eq!(e(&[0xD83D, 0x20], &[0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
- assert_eq!(e(&[0xD800], &[0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF");
- assert_eq!(e(&[0xD800], &[0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80");
- assert_eq!(e(&[0xD7FF], &[0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80");
- assert_eq!(e(&[0x61], &[0xDC00]).bytes, b"\x61\xED\xB0\x80");
- assert_eq!(e(&[], &[0xDC00]).bytes, b"\xED\xB0\x80");
- }
-
- #[test]
- fn wtf8buf_show() {
- let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r");
- string.push(CodePoint::from_u32(0xD800).unwrap());
- assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\"");
- }
-
- #[test]
- fn wtf8buf_as_slice() {
- assert_eq!(Wtf8Buf::from_str("aé").as_slice(), Wtf8::from_str("aé"));
- }
-
- #[test]
- fn wtf8buf_show_str() {
- let text = "a\té 💩\r";
- let string = Wtf8Buf::from_str(text);
- assert_eq!(format!("{:?}", text), format!("{:?}", string));
- }
-
- #[test]
- fn wtf8_from_str() {
- assert_eq!(&Wtf8::from_str("").bytes, b"");
- assert_eq!(&Wtf8::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
- }
-
- #[test]
- fn wtf8_len() {
- assert_eq!(Wtf8::from_str("").len(), 0);
- assert_eq!(Wtf8::from_str("aé 💩").len(), 8);
- }
-
- #[test]
- fn wtf8_slice() {
- assert_eq!(&Wtf8::from_str("aé 💩")[1..4].bytes, b"\xC3\xA9 ");
- }
-
- #[test]
- #[should_panic]
- fn wtf8_slice_not_code_point_boundary() {
- &Wtf8::from_str("aé 💩")[2..4];
- }
-
- #[test]
- fn wtf8_slice_from() {
- assert_eq!(&Wtf8::from_str("aé 💩")[1..].bytes, b"\xC3\xA9 \xF0\x9F\x92\xA9");
- }
-
- #[test]
- #[should_panic]
- fn wtf8_slice_from_not_code_point_boundary() {
- &Wtf8::from_str("aé 💩")[2..];
- }
-
- #[test]
- fn wtf8_slice_to() {
- assert_eq!(&Wtf8::from_str("aé 💩")[..4].bytes, b"a\xC3\xA9 ");
- }
-
- #[test]
- #[should_panic]
- fn wtf8_slice_to_not_code_point_boundary() {
- &Wtf8::from_str("aé 💩")[5..];
- }
-
- #[test]
- fn wtf8_ascii_byte_at() {
- let slice = Wtf8::from_str("aé 💩");
- assert_eq!(slice.ascii_byte_at(0), b'a');
- assert_eq!(slice.ascii_byte_at(1), b'\xFF');
- assert_eq!(slice.ascii_byte_at(2), b'\xFF');
- assert_eq!(slice.ascii_byte_at(3), b' ');
- assert_eq!(slice.ascii_byte_at(4), b'\xFF');
- }
-
- #[test]
- fn wtf8_code_points() {
- fn c(value: u32) -> CodePoint {
- CodePoint::from_u32(value).unwrap()
- }
- fn cp(string: &Wtf8Buf) -> Vec<Option<char>> {
- string.code_points().map(|c| c.to_char()).collect::<Vec<_>>()
- }
- let mut string = Wtf8Buf::from_str("é ");
- assert_eq!(cp(&string), [Some('é'), Some(' ')]);
- string.push(c(0xD83D));
- assert_eq!(cp(&string), [Some('é'), Some(' '), None]);
- string.push(c(0xDCA9));
- assert_eq!(cp(&string), [Some('é'), Some(' '), Some('💩')]);
- }
-
- #[test]
- fn wtf8_as_str() {
- assert_eq!(Wtf8::from_str("").as_str(), Some(""));
- assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩"));
- let mut string = Wtf8Buf::new();
- string.push(CodePoint::from_u32(0xD800).unwrap());
- assert_eq!(string.as_str(), None);
- }
-
- #[test]
- fn wtf8_to_string_lossy() {
- assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed(""));
- assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩"));
- let mut string = Wtf8Buf::from_str("aé 💩");
- string.push(CodePoint::from_u32(0xD800).unwrap());
- let expected: Cow<'_, str> = Cow::Owned(String::from("aé 💩�"));
- assert_eq!(string.to_string_lossy(), expected);
- }
-
- #[test]
- fn wtf8_display() {
- fn d(b: &[u8]) -> String {
- (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string()
- }
-
- assert_eq!("", d("".as_bytes()));
- assert_eq!("aé 💩", d("aé 💩".as_bytes()));
-
- let mut string = Wtf8Buf::from_str("aé 💩");
- string.push(CodePoint::from_u32(0xD800).unwrap());
- assert_eq!("aé 💩�", d(string.as_inner()));
- }
-
- #[test]
- fn wtf8_encode_wide() {
- let mut string = Wtf8Buf::from_str("aé ");
- string.push(CodePoint::from_u32(0xD83D).unwrap());
- string.push_char('💩');
- assert_eq!(
- string.encode_wide().collect::<Vec<_>>(),
- vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]
- );
- }
-}
--- /dev/null
+use super::*;
+use crate::borrow::Cow;
+
+#[test]
+fn code_point_from_u32() {
+ assert!(CodePoint::from_u32(0).is_some());
+ assert!(CodePoint::from_u32(0xD800).is_some());
+ assert!(CodePoint::from_u32(0x10FFFF).is_some());
+ assert!(CodePoint::from_u32(0x110000).is_none());
+}
+
+#[test]
+fn code_point_to_u32() {
+ fn c(value: u32) -> CodePoint {
+ CodePoint::from_u32(value).unwrap()
+ }
+ assert_eq!(c(0).to_u32(), 0);
+ assert_eq!(c(0xD800).to_u32(), 0xD800);
+ assert_eq!(c(0x10FFFF).to_u32(), 0x10FFFF);
+}
+
+#[test]
+fn code_point_from_char() {
+ assert_eq!(CodePoint::from_char('a').to_u32(), 0x61);
+ assert_eq!(CodePoint::from_char('💩').to_u32(), 0x1F4A9);
+}
+
+#[test]
+fn code_point_to_string() {
+ assert_eq!(format!("{:?}", CodePoint::from_char('a')), "U+0061");
+ assert_eq!(format!("{:?}", CodePoint::from_char('💩')), "U+1F4A9");
+}
+
+#[test]
+fn code_point_to_char() {
+ fn c(value: u32) -> CodePoint {
+ CodePoint::from_u32(value).unwrap()
+ }
+ assert_eq!(c(0x61).to_char(), Some('a'));
+ assert_eq!(c(0x1F4A9).to_char(), Some('💩'));
+ assert_eq!(c(0xD800).to_char(), None);
+}
+
+#[test]
+fn code_point_to_char_lossy() {
+ fn c(value: u32) -> CodePoint {
+ CodePoint::from_u32(value).unwrap()
+ }
+ assert_eq!(c(0x61).to_char_lossy(), 'a');
+ assert_eq!(c(0x1F4A9).to_char_lossy(), '💩');
+ assert_eq!(c(0xD800).to_char_lossy(), '\u{FFFD}');
+}
+
+#[test]
+fn wtf8buf_new() {
+ assert_eq!(Wtf8Buf::new().bytes, b"");
+}
+
+#[test]
+fn wtf8buf_from_str() {
+ assert_eq!(Wtf8Buf::from_str("").bytes, b"");
+ assert_eq!(Wtf8Buf::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+}
+
+#[test]
+fn wtf8buf_from_string() {
+ assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b"");
+ assert_eq!(Wtf8Buf::from_string(String::from("aé 💩")).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+}
+
+#[test]
+fn wtf8buf_from_wide() {
+ assert_eq!(Wtf8Buf::from_wide(&[]).bytes, b"");
+ assert_eq!(
+ Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]).bytes,
+ b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9"
+ );
+}
+
+#[test]
+fn wtf8buf_push_str() {
+ let mut string = Wtf8Buf::new();
+ assert_eq!(string.bytes, b"");
+ string.push_str("aé 💩");
+ assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+}
+
+#[test]
+fn wtf8buf_push_char() {
+ let mut string = Wtf8Buf::from_str("aé ");
+ assert_eq!(string.bytes, b"a\xC3\xA9 ");
+ string.push_char('💩');
+ assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+}
+
+#[test]
+fn wtf8buf_push() {
+ let mut string = Wtf8Buf::from_str("aé ");
+ assert_eq!(string.bytes, b"a\xC3\xA9 ");
+ string.push(CodePoint::from_char('💩'));
+ assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+
+ fn c(value: u32) -> CodePoint {
+ CodePoint::from_u32(value).unwrap()
+ }
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD83D)); // lead
+ string.push(c(0xDCA9)); // trail
+ assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic!
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD83D)); // lead
+ string.push(c(0x20)); // not surrogate
+ string.push(c(0xDCA9)); // trail
+ assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD800)); // lead
+ string.push(c(0xDBFF)); // lead
+ assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD800)); // lead
+ string.push(c(0xE000)); // not surrogate
+ assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD7FF)); // not surrogate
+ string.push(c(0xDC00)); // trail
+ assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0x61)); // not surrogate, < 3 bytes
+ string.push(c(0xDC00)); // trail
+ assert_eq!(string.bytes, b"\x61\xED\xB0\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xDC00)); // trail
+ assert_eq!(string.bytes, b"\xED\xB0\x80");
+}
+
+#[test]
+fn wtf8buf_push_wtf8() {
+ let mut string = Wtf8Buf::from_str("aé");
+ assert_eq!(string.bytes, b"a\xC3\xA9");
+ string.push_wtf8(Wtf8::from_str(" 💩"));
+ assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+
+ fn w(v: &[u8]) -> &Wtf8 {
+ unsafe { Wtf8::from_bytes_unchecked(v) }
+ }
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xA0\xBD")); // lead
+ string.push_wtf8(w(b"\xED\xB2\xA9")); // trail
+ assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic!
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xA0\xBD")); // lead
+ string.push_wtf8(w(b" ")); // not surrogate
+ string.push_wtf8(w(b"\xED\xB2\xA9")); // trail
+ assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xA0\x80")); // lead
+ string.push_wtf8(w(b"\xED\xAF\xBF")); // lead
+ assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xA0\x80")); // lead
+ string.push_wtf8(w(b"\xEE\x80\x80")); // not surrogate
+ assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\x9F\xBF")); // not surrogate
+ string.push_wtf8(w(b"\xED\xB0\x80")); // trail
+ assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"a")); // not surrogate, < 3 bytes
+ string.push_wtf8(w(b"\xED\xB0\x80")); // trail
+ assert_eq!(string.bytes, b"\x61\xED\xB0\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xB0\x80")); // trail
+ assert_eq!(string.bytes, b"\xED\xB0\x80");
+}
+
+#[test]
+fn wtf8buf_truncate() {
+ let mut string = Wtf8Buf::from_str("aé");
+ string.truncate(1);
+ assert_eq!(string.bytes, b"a");
+}
+
+#[test]
+#[should_panic]
+fn wtf8buf_truncate_fail_code_point_boundary() {
+ let mut string = Wtf8Buf::from_str("aé");
+ string.truncate(2);
+}
+
+#[test]
+#[should_panic]
+fn wtf8buf_truncate_fail_longer() {
+ let mut string = Wtf8Buf::from_str("aé");
+ string.truncate(4);
+}
+
+#[test]
+fn wtf8buf_into_string() {
+ let mut string = Wtf8Buf::from_str("aé 💩");
+ assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩")));
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!(string.clone().into_string(), Err(string));
+}
+
+#[test]
+fn wtf8buf_into_string_lossy() {
+ let mut string = Wtf8Buf::from_str("aé 💩");
+ assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩"));
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�"));
+}
+
+#[test]
+fn wtf8buf_from_iterator() {
+ fn f(values: &[u32]) -> Wtf8Buf {
+ values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::<Wtf8Buf>()
+ }
+ assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+
+ assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!
+ assert_eq!(f(&[0xD83D, 0x20, 0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
+ assert_eq!(f(&[0xD800, 0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF");
+ assert_eq!(f(&[0xD800, 0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80");
+ assert_eq!(f(&[0xD7FF, 0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80");
+ assert_eq!(f(&[0x61, 0xDC00]).bytes, b"\x61\xED\xB0\x80");
+ assert_eq!(f(&[0xDC00]).bytes, b"\xED\xB0\x80");
+}
+
+#[test]
+fn wtf8buf_extend() {
+ fn e(initial: &[u32], extended: &[u32]) -> Wtf8Buf {
+ fn c(value: &u32) -> CodePoint {
+ CodePoint::from_u32(*value).unwrap()
+ }
+ let mut string = initial.iter().map(c).collect::<Wtf8Buf>();
+ string.extend(extended.iter().map(c));
+ string
+ }
+
+ assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+
+ assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!
+ assert_eq!(e(&[0xD83D, 0x20], &[0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
+ assert_eq!(e(&[0xD800], &[0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF");
+ assert_eq!(e(&[0xD800], &[0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80");
+ assert_eq!(e(&[0xD7FF], &[0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80");
+ assert_eq!(e(&[0x61], &[0xDC00]).bytes, b"\x61\xED\xB0\x80");
+ assert_eq!(e(&[], &[0xDC00]).bytes, b"\xED\xB0\x80");
+}
+
+#[test]
+fn wtf8buf_show() {
+ let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r");
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\"");
+}
+
+#[test]
+fn wtf8buf_as_slice() {
+ assert_eq!(Wtf8Buf::from_str("aé").as_slice(), Wtf8::from_str("aé"));
+}
+
+#[test]
+fn wtf8buf_show_str() {
+ let text = "a\té 💩\r";
+ let string = Wtf8Buf::from_str(text);
+ assert_eq!(format!("{:?}", text), format!("{:?}", string));
+}
+
+#[test]
+fn wtf8_from_str() {
+ assert_eq!(&Wtf8::from_str("").bytes, b"");
+ assert_eq!(&Wtf8::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+}
+
+#[test]
+fn wtf8_len() {
+ assert_eq!(Wtf8::from_str("").len(), 0);
+ assert_eq!(Wtf8::from_str("aé 💩").len(), 8);
+}
+
+#[test]
+fn wtf8_slice() {
+ assert_eq!(&Wtf8::from_str("aé 💩")[1..4].bytes, b"\xC3\xA9 ");
+}
+
+#[test]
+#[should_panic]
+fn wtf8_slice_not_code_point_boundary() {
+ &Wtf8::from_str("aé 💩")[2..4];
+}
+
+#[test]
+fn wtf8_slice_from() {
+ assert_eq!(&Wtf8::from_str("aé 💩")[1..].bytes, b"\xC3\xA9 \xF0\x9F\x92\xA9");
+}
+
+#[test]
+#[should_panic]
+fn wtf8_slice_from_not_code_point_boundary() {
+ &Wtf8::from_str("aé 💩")[2..];
+}
+
+#[test]
+fn wtf8_slice_to() {
+ assert_eq!(&Wtf8::from_str("aé 💩")[..4].bytes, b"a\xC3\xA9 ");
+}
+
+#[test]
+#[should_panic]
+fn wtf8_slice_to_not_code_point_boundary() {
+ &Wtf8::from_str("aé 💩")[5..];
+}
+
+#[test]
+fn wtf8_ascii_byte_at() {
+ let slice = Wtf8::from_str("aé 💩");
+ assert_eq!(slice.ascii_byte_at(0), b'a');
+ assert_eq!(slice.ascii_byte_at(1), b'\xFF');
+ assert_eq!(slice.ascii_byte_at(2), b'\xFF');
+ assert_eq!(slice.ascii_byte_at(3), b' ');
+ assert_eq!(slice.ascii_byte_at(4), b'\xFF');
+}
+
+#[test]
+fn wtf8_code_points() {
+ fn c(value: u32) -> CodePoint {
+ CodePoint::from_u32(value).unwrap()
+ }
+ fn cp(string: &Wtf8Buf) -> Vec<Option<char>> {
+ string.code_points().map(|c| c.to_char()).collect::<Vec<_>>()
+ }
+ let mut string = Wtf8Buf::from_str("é ");
+ assert_eq!(cp(&string), [Some('é'), Some(' ')]);
+ string.push(c(0xD83D));
+ assert_eq!(cp(&string), [Some('é'), Some(' '), None]);
+ string.push(c(0xDCA9));
+ assert_eq!(cp(&string), [Some('é'), Some(' '), Some('💩')]);
+}
+
+#[test]
+fn wtf8_as_str() {
+ assert_eq!(Wtf8::from_str("").as_str(), Some(""));
+ assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩"));
+ let mut string = Wtf8Buf::new();
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!(string.as_str(), None);
+}
+
+#[test]
+fn wtf8_to_string_lossy() {
+ assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed(""));
+ assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩"));
+ let mut string = Wtf8Buf::from_str("aé 💩");
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ let expected: Cow<'_, str> = Cow::Owned(String::from("aé 💩�"));
+ assert_eq!(string.to_string_lossy(), expected);
+}
+
+#[test]
+fn wtf8_display() {
+ fn d(b: &[u8]) -> String {
+ (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string()
+ }
+
+ assert_eq!("", d("".as_bytes()));
+ assert_eq!("aé 💩", d("aé 💩".as_bytes()));
+
+ let mut string = Wtf8Buf::from_str("aé 💩");
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!("aé 💩�", d(string.as_inner()));
+}
+
+#[test]
+fn wtf8_encode_wide() {
+ let mut string = Wtf8Buf::from_str("aé ");
+ string.push(CodePoint::from_u32(0xD83D).unwrap());
+ string.push_char('💩');
+ assert_eq!(
+ string.encode_wide().collect::<Vec<_>>(),
+ vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]
+ );
+}
#![unstable(feature = "thread_local_internals", issue = "none")]
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
+#[cfg(test)]
+mod dynamic_tests;
+
use crate::error::Error;
use crate::fmt;
key.os.set(ptr::null_mut());
}
}
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests {
- use crate::cell::{Cell, UnsafeCell};
- use crate::sync::mpsc::{channel, Sender};
- use crate::thread;
-
- struct Foo(Sender<()>);
-
- impl Drop for Foo {
- fn drop(&mut self) {
- let Foo(ref s) = *self;
- s.send(()).unwrap();
- }
- }
-
- #[test]
- fn smoke_no_dtor() {
- thread_local!(static FOO: Cell<i32> = Cell::new(1));
-
- FOO.with(|f| {
- assert_eq!(f.get(), 1);
- f.set(2);
- });
- let (tx, rx) = channel();
- let _t = thread::spawn(move || {
- FOO.with(|f| {
- assert_eq!(f.get(), 1);
- });
- tx.send(()).unwrap();
- });
- rx.recv().unwrap();
-
- FOO.with(|f| {
- assert_eq!(f.get(), 2);
- });
- }
-
- #[test]
- fn states() {
- struct Foo;
- impl Drop for Foo {
- fn drop(&mut self) {
- assert!(FOO.try_with(|_| ()).is_err());
- }
- }
- thread_local!(static FOO: Foo = Foo);
-
- thread::spawn(|| {
- assert!(FOO.try_with(|_| ()).is_ok());
- })
- .join()
- .ok()
- .expect("thread panicked");
- }
-
- #[test]
- fn smoke_dtor() {
- thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
-
- let (tx, rx) = channel();
- let _t = thread::spawn(move || unsafe {
- let mut tx = Some(tx);
- FOO.with(|f| {
- *f.get() = Some(Foo(tx.take().unwrap()));
- });
- });
- rx.recv().unwrap();
- }
-
- #[test]
- fn circular() {
- struct S1;
- struct S2;
- thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
- thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell::new(None));
- static mut HITS: u32 = 0;
-
- impl Drop for S1 {
- fn drop(&mut self) {
- unsafe {
- HITS += 1;
- if K2.try_with(|_| ()).is_err() {
- assert_eq!(HITS, 3);
- } else {
- if HITS == 1 {
- K2.with(|s| *s.get() = Some(S2));
- } else {
- assert_eq!(HITS, 3);
- }
- }
- }
- }
- }
- impl Drop for S2 {
- fn drop(&mut self) {
- unsafe {
- HITS += 1;
- assert!(K1.try_with(|_| ()).is_ok());
- assert_eq!(HITS, 2);
- K1.with(|s| *s.get() = Some(S1));
- }
- }
- }
-
- thread::spawn(move || {
- drop(S1);
- })
- .join()
- .ok()
- .expect("thread panicked");
- }
-
- #[test]
- fn self_referential() {
- struct S1;
- thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
-
- impl Drop for S1 {
- fn drop(&mut self) {
- assert!(K1.try_with(|_| ()).is_err());
- }
- }
-
- thread::spawn(move || unsafe {
- K1.with(|s| *s.get() = Some(S1));
- })
- .join()
- .ok()
- .expect("thread panicked");
- }
-
- // Note that this test will deadlock if TLS destructors aren't run (this
- // requires the destructor to be run to pass the test).
- #[test]
- fn dtors_in_dtors_in_dtors() {
- struct S1(Sender<()>);
- thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
- thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
-
- impl Drop for S1 {
- fn drop(&mut self) {
- let S1(ref tx) = *self;
- unsafe {
- let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone())));
- }
- }
- }
-
- let (tx, rx) = channel();
- let _t = thread::spawn(move || unsafe {
- let mut tx = Some(tx);
- K1.with(|s| *s.get() = Some(S1(tx.take().unwrap())));
- });
- rx.recv().unwrap();
- }
-}
-
-#[cfg(test)]
-mod dynamic_tests {
- use crate::cell::RefCell;
- use crate::collections::HashMap;
-
- #[test]
- fn smoke() {
- fn square(i: i32) -> i32 {
- i * i
- }
- thread_local!(static FOO: i32 = square(3));
-
- FOO.with(|f| {
- assert_eq!(*f, 9);
- });
- }
-
- #[test]
- fn hashmap() {
- fn map() -> RefCell<HashMap<i32, i32>> {
- let mut m = HashMap::new();
- m.insert(1, 2);
- RefCell::new(m)
- }
- thread_local!(static FOO: RefCell<HashMap<i32, i32>> = map());
-
- FOO.with(|map| {
- assert_eq!(map.borrow()[&1], 2);
- });
- }
-
- #[test]
- fn refcell_vec() {
- thread_local!(static FOO: RefCell<Vec<u32>> = RefCell::new(vec![1, 2, 3]));
-
- FOO.with(|vec| {
- assert_eq!(vec.borrow().len(), 3);
- vec.borrow_mut().push(4);
- assert_eq!(vec.borrow()[3], 4);
- });
- }
-}
--- /dev/null
+use crate::cell::RefCell;
+use crate::collections::HashMap;
+use crate::thread_local;
+
+#[test]
+fn smoke() {
+ fn square(i: i32) -> i32 {
+ i * i
+ }
+ thread_local!(static FOO: i32 = square(3));
+
+ FOO.with(|f| {
+ assert_eq!(*f, 9);
+ });
+}
+
+#[test]
+fn hashmap() {
+ fn map() -> RefCell<HashMap<i32, i32>> {
+ let mut m = HashMap::new();
+ m.insert(1, 2);
+ RefCell::new(m)
+ }
+ thread_local!(static FOO: RefCell<HashMap<i32, i32>> = map());
+
+ FOO.with(|map| {
+ assert_eq!(map.borrow()[&1], 2);
+ });
+}
+
+#[test]
+fn refcell_vec() {
+ thread_local!(static FOO: RefCell<Vec<u32>> = RefCell::new(vec![1, 2, 3]));
+
+ FOO.with(|vec| {
+ assert_eq!(vec.borrow().len(), 3);
+ vec.borrow_mut().push(4);
+ assert_eq!(vec.borrow()[3], 4);
+ });
+}
--- /dev/null
+use crate::cell::{Cell, UnsafeCell};
+use crate::sync::mpsc::{channel, Sender};
+use crate::thread;
+use crate::thread_local;
+
+struct Foo(Sender<()>);
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ let Foo(ref s) = *self;
+ s.send(()).unwrap();
+ }
+}
+
+#[test]
+fn smoke_no_dtor() {
+ thread_local!(static FOO: Cell<i32> = Cell::new(1));
+
+ FOO.with(|f| {
+ assert_eq!(f.get(), 1);
+ f.set(2);
+ });
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move || {
+ FOO.with(|f| {
+ assert_eq!(f.get(), 1);
+ });
+ tx.send(()).unwrap();
+ });
+ rx.recv().unwrap();
+
+ FOO.with(|f| {
+ assert_eq!(f.get(), 2);
+ });
+}
+
+#[test]
+fn states() {
+ struct Foo;
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ assert!(FOO.try_with(|_| ()).is_err());
+ }
+ }
+ thread_local!(static FOO: Foo = Foo);
+
+ thread::spawn(|| {
+ assert!(FOO.try_with(|_| ()).is_ok());
+ })
+ .join()
+ .ok()
+ .expect("thread panicked");
+}
+
+#[test]
+fn smoke_dtor() {
+ thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
+
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move || unsafe {
+ let mut tx = Some(tx);
+ FOO.with(|f| {
+ *f.get() = Some(Foo(tx.take().unwrap()));
+ });
+ });
+ rx.recv().unwrap();
+}
+
+#[test]
+fn circular() {
+ struct S1;
+ struct S2;
+ thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+ thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell::new(None));
+ static mut HITS: u32 = 0;
+
+ impl Drop for S1 {
+ fn drop(&mut self) {
+ unsafe {
+ HITS += 1;
+ if K2.try_with(|_| ()).is_err() {
+ assert_eq!(HITS, 3);
+ } else {
+ if HITS == 1 {
+ K2.with(|s| *s.get() = Some(S2));
+ } else {
+ assert_eq!(HITS, 3);
+ }
+ }
+ }
+ }
+ }
+ impl Drop for S2 {
+ fn drop(&mut self) {
+ unsafe {
+ HITS += 1;
+ assert!(K1.try_with(|_| ()).is_ok());
+ assert_eq!(HITS, 2);
+ K1.with(|s| *s.get() = Some(S1));
+ }
+ }
+ }
+
+ thread::spawn(move || {
+ drop(S1);
+ })
+ .join()
+ .ok()
+ .expect("thread panicked");
+}
+
+#[test]
+fn self_referential() {
+ struct S1;
+ thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+
+ impl Drop for S1 {
+ fn drop(&mut self) {
+ assert!(K1.try_with(|_| ()).is_err());
+ }
+ }
+
+ thread::spawn(move || unsafe {
+ K1.with(|s| *s.get() = Some(S1));
+ })
+ .join()
+ .ok()
+ .expect("thread panicked");
+}
+
+// Note that this test will deadlock if TLS destructors aren't run (this
+// requires the destructor to be run to pass the test).
+#[test]
+fn dtors_in_dtors_in_dtors() {
+ struct S1(Sender<()>);
+ thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+ thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
+
+ impl Drop for S1 {
+ fn drop(&mut self) {
+ let S1(ref tx) = *self;
+ unsafe {
+ let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone())));
+ }
+ }
+ }
+
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move || unsafe {
+ let mut tx = Some(tx);
+ K1.with(|s| *s.get() = Some(S1(tx.take().unwrap())));
+ });
+ rx.recv().unwrap();
+}
#![stable(feature = "rust1", since = "1.0.0")]
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
use crate::any::Any;
use crate::cell::UnsafeCell;
use crate::ffi::{CStr, CString};
_assert_both::<JoinHandle<()>>();
_assert_both::<Thread>();
}
-
-////////////////////////////////////////////////////////////////////////////////
-// Tests
-////////////////////////////////////////////////////////////////////////////////
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests {
- use super::Builder;
- use crate::any::Any;
- use crate::mem;
- use crate::result;
- use crate::sync::mpsc::{channel, Sender};
- use crate::thread::{self, ThreadId};
- use crate::time::Duration;
-
- // !!! These tests are dangerous. If something is buggy, they will hang, !!!
- // !!! instead of exiting cleanly. This might wedge the buildbots. !!!
-
- #[test]
- fn test_unnamed_thread() {
- thread::spawn(move || {
- assert!(thread::current().name().is_none());
- })
- .join()
- .ok()
- .expect("thread panicked");
- }
-
- #[test]
- fn test_named_thread() {
- Builder::new()
- .name("ada lovelace".to_string())
- .spawn(move || {
- assert!(thread::current().name().unwrap() == "ada lovelace".to_string());
- })
- .unwrap()
- .join()
- .unwrap();
- }
-
- #[test]
- #[should_panic]
- fn test_invalid_named_thread() {
- let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {});
- }
-
- #[test]
- fn test_run_basic() {
- let (tx, rx) = channel();
- thread::spawn(move || {
- tx.send(()).unwrap();
- });
- rx.recv().unwrap();
- }
-
- #[test]
- fn test_join_panic() {
- match thread::spawn(move || panic!()).join() {
- result::Result::Err(_) => (),
- result::Result::Ok(()) => panic!(),
- }
- }
-
- #[test]
- fn test_spawn_sched() {
- let (tx, rx) = channel();
-
- fn f(i: i32, tx: Sender<()>) {
- let tx = tx.clone();
- thread::spawn(move || {
- if i == 0 {
- tx.send(()).unwrap();
- } else {
- f(i - 1, tx);
- }
- });
- }
- f(10, tx);
- rx.recv().unwrap();
- }
-
- #[test]
- fn test_spawn_sched_childs_on_default_sched() {
- let (tx, rx) = channel();
-
- thread::spawn(move || {
- thread::spawn(move || {
- tx.send(()).unwrap();
- });
- });
-
- rx.recv().unwrap();
- }
-
- fn avoid_copying_the_body<F>(spawnfn: F)
- where
- F: FnOnce(Box<dyn Fn() + Send>),
- {
- let (tx, rx) = channel();
-
- let x: Box<_> = box 1;
- let x_in_parent = (&*x) as *const i32 as usize;
-
- spawnfn(Box::new(move || {
- let x_in_child = (&*x) as *const i32 as usize;
- tx.send(x_in_child).unwrap();
- }));
-
- let x_in_child = rx.recv().unwrap();
- assert_eq!(x_in_parent, x_in_child);
- }
-
- #[test]
- fn test_avoid_copying_the_body_spawn() {
- avoid_copying_the_body(|v| {
- thread::spawn(move || v());
- });
- }
-
- #[test]
- fn test_avoid_copying_the_body_thread_spawn() {
- avoid_copying_the_body(|f| {
- thread::spawn(move || {
- f();
- });
- })
- }
-
- #[test]
- fn test_avoid_copying_the_body_join() {
- avoid_copying_the_body(|f| {
- let _ = thread::spawn(move || f()).join();
- })
- }
-
- #[test]
- fn test_child_doesnt_ref_parent() {
- // If the child refcounts the parent thread, this will stack overflow when
- // climbing the thread tree to dereference each ancestor. (See #1789)
- // (well, it would if the constant were 8000+ - I lowered it to be more
- // valgrind-friendly. try this at home, instead..!)
- const GENERATIONS: u32 = 16;
- fn child_no(x: u32) -> Box<dyn Fn() + Send> {
- return Box::new(move || {
- if x < GENERATIONS {
- thread::spawn(move || child_no(x + 1)());
- }
- });
- }
- thread::spawn(|| child_no(0)());
- }
-
- #[test]
- fn test_simple_newsched_spawn() {
- thread::spawn(move || {});
- }
-
- #[test]
- fn test_try_panic_message_static_str() {
- match thread::spawn(move || {
- panic!("static string");
- })
- .join()
- {
- Err(e) => {
- type T = &'static str;
- assert!(e.is::<T>());
- assert_eq!(*e.downcast::<T>().unwrap(), "static string");
- }
- Ok(()) => panic!(),
- }
- }
-
- #[test]
- fn test_try_panic_message_owned_str() {
- match thread::spawn(move || {
- panic!("owned string".to_string());
- })
- .join()
- {
- Err(e) => {
- type T = String;
- assert!(e.is::<T>());
- assert_eq!(*e.downcast::<T>().unwrap(), "owned string".to_string());
- }
- Ok(()) => panic!(),
- }
- }
-
- #[test]
- fn test_try_panic_message_any() {
- match thread::spawn(move || {
- panic!(box 413u16 as Box<dyn Any + Send>);
- })
- .join()
- {
- Err(e) => {
- type T = Box<dyn Any + Send>;
- assert!(e.is::<T>());
- let any = e.downcast::<T>().unwrap();
- assert!(any.is::<u16>());
- assert_eq!(*any.downcast::<u16>().unwrap(), 413);
- }
- Ok(()) => panic!(),
- }
- }
-
- #[test]
- fn test_try_panic_message_unit_struct() {
- struct Juju;
-
- match thread::spawn(move || panic!(Juju)).join() {
- Err(ref e) if e.is::<Juju>() => {}
- Err(_) | Ok(()) => panic!(),
- }
- }
-
- #[test]
- fn test_park_timeout_unpark_before() {
- for _ in 0..10 {
- thread::current().unpark();
- thread::park_timeout(Duration::from_millis(u32::MAX as u64));
- }
- }
-
- #[test]
- fn test_park_timeout_unpark_not_called() {
- for _ in 0..10 {
- thread::park_timeout(Duration::from_millis(10));
- }
- }
-
- #[test]
- fn test_park_timeout_unpark_called_other_thread() {
- for _ in 0..10 {
- let th = thread::current();
-
- let _guard = thread::spawn(move || {
- super::sleep(Duration::from_millis(50));
- th.unpark();
- });
-
- thread::park_timeout(Duration::from_millis(u32::MAX as u64));
- }
- }
-
- #[test]
- fn sleep_ms_smoke() {
- thread::sleep(Duration::from_millis(2));
- }
-
- #[test]
- fn test_size_of_option_thread_id() {
- assert_eq!(mem::size_of::<Option<ThreadId>>(), mem::size_of::<ThreadId>());
- }
-
- #[test]
- fn test_thread_id_equal() {
- assert!(thread::current().id() == thread::current().id());
- }
-
- #[test]
- fn test_thread_id_not_equal() {
- let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap();
- assert!(thread::current().id() != spawned_id);
- }
-
- // NOTE: the corresponding test for stderr is in ui/thread-stderr, due
- // to the test harness apparently interfering with stderr configuration.
-}
--- /dev/null
+use super::Builder;
+use crate::any::Any;
+use crate::mem;
+use crate::result;
+use crate::sync::mpsc::{channel, Sender};
+use crate::thread::{self, ThreadId};
+use crate::time::Duration;
+
+// !!! These tests are dangerous. If something is buggy, they will hang, !!!
+// !!! instead of exiting cleanly. This might wedge the buildbots. !!!
+
+#[test]
+fn test_unnamed_thread() {
+ thread::spawn(move || {
+ assert!(thread::current().name().is_none());
+ })
+ .join()
+ .ok()
+ .expect("thread panicked");
+}
+
+#[test]
+fn test_named_thread() {
+ Builder::new()
+ .name("ada lovelace".to_string())
+ .spawn(move || {
+ assert!(thread::current().name().unwrap() == "ada lovelace".to_string());
+ })
+ .unwrap()
+ .join()
+ .unwrap();
+}
+
+#[test]
+#[should_panic]
+fn test_invalid_named_thread() {
+ let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {});
+}
+
+#[test]
+fn test_run_basic() {
+ let (tx, rx) = channel();
+ thread::spawn(move || {
+ tx.send(()).unwrap();
+ });
+ rx.recv().unwrap();
+}
+
+#[test]
+fn test_join_panic() {
+ match thread::spawn(move || panic!()).join() {
+ result::Result::Err(_) => (),
+ result::Result::Ok(()) => panic!(),
+ }
+}
+
+#[test]
+fn test_spawn_sched() {
+ let (tx, rx) = channel();
+
+ fn f(i: i32, tx: Sender<()>) {
+ let tx = tx.clone();
+ thread::spawn(move || {
+ if i == 0 {
+ tx.send(()).unwrap();
+ } else {
+ f(i - 1, tx);
+ }
+ });
+ }
+ f(10, tx);
+ rx.recv().unwrap();
+}
+
+#[test]
+fn test_spawn_sched_childs_on_default_sched() {
+ let (tx, rx) = channel();
+
+ thread::spawn(move || {
+ thread::spawn(move || {
+ tx.send(()).unwrap();
+ });
+ });
+
+ rx.recv().unwrap();
+}
+
+fn avoid_copying_the_body<F>(spawnfn: F)
+where
+ F: FnOnce(Box<dyn Fn() + Send>),
+{
+ let (tx, rx) = channel();
+
+ let x: Box<_> = box 1;
+ let x_in_parent = (&*x) as *const i32 as usize;
+
+ spawnfn(Box::new(move || {
+ let x_in_child = (&*x) as *const i32 as usize;
+ tx.send(x_in_child).unwrap();
+ }));
+
+ let x_in_child = rx.recv().unwrap();
+ assert_eq!(x_in_parent, x_in_child);
+}
+
+#[test]
+fn test_avoid_copying_the_body_spawn() {
+ avoid_copying_the_body(|v| {
+ thread::spawn(move || v());
+ });
+}
+
+#[test]
+fn test_avoid_copying_the_body_thread_spawn() {
+ avoid_copying_the_body(|f| {
+ thread::spawn(move || {
+ f();
+ });
+ })
+}
+
+#[test]
+fn test_avoid_copying_the_body_join() {
+ avoid_copying_the_body(|f| {
+ let _ = thread::spawn(move || f()).join();
+ })
+}
+
+#[test]
+fn test_child_doesnt_ref_parent() {
+ // If the child refcounts the parent thread, this will stack overflow when
+ // climbing the thread tree to dereference each ancestor. (See #1789)
+ // (well, it would if the constant were 8000+ - I lowered it to be more
+ // valgrind-friendly. try this at home, instead..!)
+ const GENERATIONS: u32 = 16;
+ fn child_no(x: u32) -> Box<dyn Fn() + Send> {
+ return Box::new(move || {
+ if x < GENERATIONS {
+ thread::spawn(move || child_no(x + 1)());
+ }
+ });
+ }
+ thread::spawn(|| child_no(0)());
+}
+
+#[test]
+fn test_simple_newsched_spawn() {
+ thread::spawn(move || {});
+}
+
+#[test]
+fn test_try_panic_message_static_str() {
+ match thread::spawn(move || {
+ panic!("static string");
+ })
+ .join()
+ {
+ Err(e) => {
+ type T = &'static str;
+ assert!(e.is::<T>());
+ assert_eq!(*e.downcast::<T>().unwrap(), "static string");
+ }
+ Ok(()) => panic!(),
+ }
+}
+
+#[test]
+fn test_try_panic_message_owned_str() {
+ match thread::spawn(move || {
+ panic!("owned string".to_string());
+ })
+ .join()
+ {
+ Err(e) => {
+ type T = String;
+ assert!(e.is::<T>());
+ assert_eq!(*e.downcast::<T>().unwrap(), "owned string".to_string());
+ }
+ Ok(()) => panic!(),
+ }
+}
+
+#[test]
+fn test_try_panic_message_any() {
+ match thread::spawn(move || {
+ panic!(box 413u16 as Box<dyn Any + Send>);
+ })
+ .join()
+ {
+ Err(e) => {
+ type T = Box<dyn Any + Send>;
+ assert!(e.is::<T>());
+ let any = e.downcast::<T>().unwrap();
+ assert!(any.is::<u16>());
+ assert_eq!(*any.downcast::<u16>().unwrap(), 413);
+ }
+ Ok(()) => panic!(),
+ }
+}
+
+#[test]
+fn test_try_panic_message_unit_struct() {
+ struct Juju;
+
+ match thread::spawn(move || panic!(Juju)).join() {
+ Err(ref e) if e.is::<Juju>() => {}
+ Err(_) | Ok(()) => panic!(),
+ }
+}
+
+#[test]
+fn test_park_timeout_unpark_before() {
+ for _ in 0..10 {
+ thread::current().unpark();
+ thread::park_timeout(Duration::from_millis(u32::MAX as u64));
+ }
+}
+
+#[test]
+fn test_park_timeout_unpark_not_called() {
+ for _ in 0..10 {
+ thread::park_timeout(Duration::from_millis(10));
+ }
+}
+
+#[test]
+fn test_park_timeout_unpark_called_other_thread() {
+ for _ in 0..10 {
+ let th = thread::current();
+
+ let _guard = thread::spawn(move || {
+ super::sleep(Duration::from_millis(50));
+ th.unpark();
+ });
+
+ thread::park_timeout(Duration::from_millis(u32::MAX as u64));
+ }
+}
+
+#[test]
+fn sleep_ms_smoke() {
+ thread::sleep(Duration::from_millis(2));
+}
+
+#[test]
+fn test_size_of_option_thread_id() {
+ assert_eq!(mem::size_of::<Option<ThreadId>>(), mem::size_of::<ThreadId>());
+}
+
+#[test]
+fn test_thread_id_equal() {
+ assert!(thread::current().id() == thread::current().id());
+}
+
+#[test]
+fn test_thread_id_not_equal() {
+ let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap();
+ assert!(thread::current().id() != spawned_id);
+}
+
+// NOTE: the corresponding test for stderr is in ui/thread-stderr, due
+// to the test harness apparently interfering with stderr configuration.
#![stable(feature = "time", since = "1.3.0")]
+#[cfg(test)]
+mod tests;
+
use crate::cmp;
use crate::error::Error;
use crate::fmt;
SystemTime(time)
}
}
-
-#[cfg(test)]
-mod tests {
- use super::{Duration, Instant, SystemTime, UNIX_EPOCH};
-
- macro_rules! assert_almost_eq {
- ($a:expr, $b:expr) => {{
- let (a, b) = ($a, $b);
- if a != b {
- let (a, b) = if a > b { (a, b) } else { (b, a) };
- assert!(a - Duration::new(0, 1000) <= b, "{:?} is not almost equal to {:?}", a, b);
- }
- }};
- }
-
- #[test]
- fn instant_monotonic() {
- let a = Instant::now();
- let b = Instant::now();
- assert!(b >= a);
- }
-
- #[test]
- fn instant_elapsed() {
- let a = Instant::now();
- a.elapsed();
- }
-
- #[test]
- fn instant_math() {
- let a = Instant::now();
- let b = Instant::now();
- println!("a: {:?}", a);
- println!("b: {:?}", b);
- let dur = b.duration_since(a);
- println!("dur: {:?}", dur);
- assert_almost_eq!(b - dur, a);
- assert_almost_eq!(a + dur, b);
-
- let second = Duration::new(1, 0);
- assert_almost_eq!(a - second + second, a);
- assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
-
- // checked_add_duration will not panic on overflow
- let mut maybe_t = Some(Instant::now());
- let max_duration = Duration::from_secs(u64::MAX);
- // in case `Instant` can store `>= now + max_duration`.
- for _ in 0..2 {
- maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration));
- }
- assert_eq!(maybe_t, None);
-
- // checked_add_duration calculates the right time and will work for another year
- let year = Duration::from_secs(60 * 60 * 24 * 365);
- assert_eq!(a + year, a.checked_add(year).unwrap());
- }
-
- #[test]
- fn instant_math_is_associative() {
- let now = Instant::now();
- let offset = Duration::from_millis(5);
- // Changing the order of instant math shouldn't change the results,
- // especially when the expression reduces to X + identity.
- assert_eq!((now + offset) - now, (now - now) + offset);
- }
-
- #[test]
- #[should_panic]
- fn instant_duration_since_panic() {
- let a = Instant::now();
- (a - Duration::new(1, 0)).duration_since(a);
- }
-
- #[test]
- fn instant_checked_duration_since_nopanic() {
- let now = Instant::now();
- let earlier = now - Duration::new(1, 0);
- let later = now + Duration::new(1, 0);
- assert_eq!(earlier.checked_duration_since(now), None);
- assert_eq!(later.checked_duration_since(now), Some(Duration::new(1, 0)));
- assert_eq!(now.checked_duration_since(now), Some(Duration::new(0, 0)));
- }
-
- #[test]
- fn instant_saturating_duration_since_nopanic() {
- let a = Instant::now();
- let ret = (a - Duration::new(1, 0)).saturating_duration_since(a);
- assert_eq!(ret, Duration::new(0, 0));
- }
-
- #[test]
- fn system_time_math() {
- let a = SystemTime::now();
- let b = SystemTime::now();
- match b.duration_since(a) {
- Ok(dur) if dur == Duration::new(0, 0) => {
- assert_almost_eq!(a, b);
- }
- Ok(dur) => {
- assert!(b > a);
- assert_almost_eq!(b - dur, a);
- assert_almost_eq!(a + dur, b);
- }
- Err(dur) => {
- let dur = dur.duration();
- assert!(a > b);
- assert_almost_eq!(b + dur, a);
- assert_almost_eq!(a - dur, b);
- }
- }
-
- let second = Duration::new(1, 0);
- assert_almost_eq!(a.duration_since(a - second).unwrap(), second);
- assert_almost_eq!(a.duration_since(a + second).unwrap_err().duration(), second);
-
- assert_almost_eq!(a - second + second, a);
- assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
-
- let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0);
- let one_second_from_epoch2 =
- UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000);
- assert_eq!(one_second_from_epoch, one_second_from_epoch2);
-
- // checked_add_duration will not panic on overflow
- let mut maybe_t = Some(SystemTime::UNIX_EPOCH);
- let max_duration = Duration::from_secs(u64::MAX);
- // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`.
- for _ in 0..2 {
- maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration));
- }
- assert_eq!(maybe_t, None);
-
- // checked_add_duration calculates the right time and will work for another year
- let year = Duration::from_secs(60 * 60 * 24 * 365);
- assert_eq!(a + year, a.checked_add(year).unwrap());
- }
-
- #[test]
- fn system_time_elapsed() {
- let a = SystemTime::now();
- drop(a.elapsed());
- }
-
- #[test]
- fn since_epoch() {
- let ts = SystemTime::now();
- let a = ts.duration_since(UNIX_EPOCH + Duration::new(1, 0)).unwrap();
- let b = ts.duration_since(UNIX_EPOCH).unwrap();
- assert!(b > a);
- assert_eq!(b - a, Duration::new(1, 0));
-
- let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30;
-
- // Right now for CI this test is run in an emulator, and apparently the
- // aarch64 emulator's sense of time is that we're still living in the
- // 70s. This is also true for riscv (also qemu)
- //
- // Otherwise let's assume that we're all running computers later than
- // 2000.
- if !cfg!(target_arch = "aarch64") && !cfg!(target_arch = "riscv64") {
- assert!(a > thirty_years);
- }
-
- // let's assume that we're all running computers earlier than 2090.
- // Should give us ~70 years to fix this!
- let hundred_twenty_years = thirty_years * 4;
- assert!(a < hundred_twenty_years);
- }
-}
--- /dev/null
+use super::{Duration, Instant, SystemTime, UNIX_EPOCH};
+
+macro_rules! assert_almost_eq {
+ ($a:expr, $b:expr) => {{
+ let (a, b) = ($a, $b);
+ if a != b {
+ let (a, b) = if a > b { (a, b) } else { (b, a) };
+ assert!(a - Duration::new(0, 1000) <= b, "{:?} is not almost equal to {:?}", a, b);
+ }
+ }};
+}
+
+#[test]
+fn instant_monotonic() {
+ let a = Instant::now();
+ let b = Instant::now();
+ assert!(b >= a);
+}
+
+#[test]
+fn instant_elapsed() {
+ let a = Instant::now();
+ a.elapsed();
+}
+
+#[test]
+fn instant_math() {
+ let a = Instant::now();
+ let b = Instant::now();
+ println!("a: {:?}", a);
+ println!("b: {:?}", b);
+ let dur = b.duration_since(a);
+ println!("dur: {:?}", dur);
+ assert_almost_eq!(b - dur, a);
+ assert_almost_eq!(a + dur, b);
+
+ let second = Duration::new(1, 0);
+ assert_almost_eq!(a - second + second, a);
+ assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
+
+ // checked_add_duration will not panic on overflow
+ let mut maybe_t = Some(Instant::now());
+ let max_duration = Duration::from_secs(u64::MAX);
+ // in case `Instant` can store `>= now + max_duration`.
+ for _ in 0..2 {
+ maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration));
+ }
+ assert_eq!(maybe_t, None);
+
+ // checked_add_duration calculates the right time and will work for another year
+ let year = Duration::from_secs(60 * 60 * 24 * 365);
+ assert_eq!(a + year, a.checked_add(year).unwrap());
+}
+
+#[test]
+fn instant_math_is_associative() {
+ let now = Instant::now();
+ let offset = Duration::from_millis(5);
+ // Changing the order of instant math shouldn't change the results,
+ // especially when the expression reduces to X + identity.
+ assert_eq!((now + offset) - now, (now - now) + offset);
+}
+
+#[test]
+#[should_panic]
+fn instant_duration_since_panic() {
+ let a = Instant::now();
+ (a - Duration::new(1, 0)).duration_since(a);
+}
+
+#[test]
+fn instant_checked_duration_since_nopanic() {
+ let now = Instant::now();
+ let earlier = now - Duration::new(1, 0);
+ let later = now + Duration::new(1, 0);
+ assert_eq!(earlier.checked_duration_since(now), None);
+ assert_eq!(later.checked_duration_since(now), Some(Duration::new(1, 0)));
+ assert_eq!(now.checked_duration_since(now), Some(Duration::new(0, 0)));
+}
+
+#[test]
+fn instant_saturating_duration_since_nopanic() {
+ let a = Instant::now();
+ let ret = (a - Duration::new(1, 0)).saturating_duration_since(a);
+ assert_eq!(ret, Duration::new(0, 0));
+}
+
+#[test]
+fn system_time_math() {
+ let a = SystemTime::now();
+ let b = SystemTime::now();
+ match b.duration_since(a) {
+ Ok(dur) if dur == Duration::new(0, 0) => {
+ assert_almost_eq!(a, b);
+ }
+ Ok(dur) => {
+ assert!(b > a);
+ assert_almost_eq!(b - dur, a);
+ assert_almost_eq!(a + dur, b);
+ }
+ Err(dur) => {
+ let dur = dur.duration();
+ assert!(a > b);
+ assert_almost_eq!(b + dur, a);
+ assert_almost_eq!(a - dur, b);
+ }
+ }
+
+ let second = Duration::new(1, 0);
+ assert_almost_eq!(a.duration_since(a - second).unwrap(), second);
+ assert_almost_eq!(a.duration_since(a + second).unwrap_err().duration(), second);
+
+ assert_almost_eq!(a - second + second, a);
+ assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
+
+ let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0);
+ let one_second_from_epoch2 =
+ UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000);
+ assert_eq!(one_second_from_epoch, one_second_from_epoch2);
+
+ // checked_add_duration will not panic on overflow
+ let mut maybe_t = Some(SystemTime::UNIX_EPOCH);
+ let max_duration = Duration::from_secs(u64::MAX);
+ // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`.
+ for _ in 0..2 {
+ maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration));
+ }
+ assert_eq!(maybe_t, None);
+
+ // checked_add_duration calculates the right time and will work for another year
+ let year = Duration::from_secs(60 * 60 * 24 * 365);
+ assert_eq!(a + year, a.checked_add(year).unwrap());
+}
+
+#[test]
+fn system_time_elapsed() {
+ let a = SystemTime::now();
+ drop(a.elapsed());
+}
+
+#[test]
+fn since_epoch() {
+ let ts = SystemTime::now();
+ let a = ts.duration_since(UNIX_EPOCH + Duration::new(1, 0)).unwrap();
+ let b = ts.duration_since(UNIX_EPOCH).unwrap();
+ assert!(b > a);
+ assert_eq!(b - a, Duration::new(1, 0));
+
+ let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30;
+
+ // Right now for CI this test is run in an emulator, and apparently the
+ // aarch64 emulator's sense of time is that we're still living in the
+ // 70s. This is also true for riscv (also qemu)
+ //
+ // Otherwise let's assume that we're all running computers later than
+ // 2000.
+ if !cfg!(target_arch = "aarch64") && !cfg!(target_arch = "riscv64") {
+ assert!(a > thirty_years);
+ }
+
+ // let's assume that we're all running computers earlier than 2090.
+ // Should give us ~70 years to fix this!
+ let hundred_twenty_years = thirty_years * 4;
+ assert!(a < hundred_twenty_years);
+}