]> git.lizzy.rs Git - rust.git/commitdiff
std: move "mod tests/benches" to separate files
authorLzu Tao <taolzu@gmail.com>
Thu, 27 Aug 2020 13:45:01 +0000 (13:45 +0000)
committerLzu Tao <taolzu@gmail.com>
Mon, 31 Aug 2020 02:56:59 +0000 (02:56 +0000)
Also doing fmt inplace as requested.

120 files changed:
library/std/src/backtrace.rs
library/std/src/backtrace/tests.rs [new file with mode: 0644]
library/std/src/collections/hash/map.rs
library/std/src/collections/hash/map/tests.rs [new file with mode: 0644]
library/std/src/collections/hash/set.rs
library/std/src/collections/hash/set/tests.rs [new file with mode: 0644]
library/std/src/env.rs
library/std/src/env/tests.rs [new file with mode: 0644]
library/std/src/error.rs
library/std/src/error/tests.rs [new file with mode: 0644]
library/std/src/f32.rs
library/std/src/f32/tests.rs [new file with mode: 0644]
library/std/src/f64.rs
library/std/src/f64/tests.rs [new file with mode: 0644]
library/std/src/ffi/c_str.rs
library/std/src/ffi/c_str/tests.rs [new file with mode: 0644]
library/std/src/ffi/os_str.rs
library/std/src/ffi/os_str/tests.rs [new file with mode: 0644]
library/std/src/fs.rs
library/std/src/fs/tests.rs [new file with mode: 0644]
library/std/src/io/buffered.rs
library/std/src/io/buffered/tests.rs [new file with mode: 0644]
library/std/src/io/cursor.rs
library/std/src/io/cursor/tests.rs [new file with mode: 0644]
library/std/src/io/error.rs
library/std/src/io/error/tests.rs [new file with mode: 0644]
library/std/src/io/impls.rs
library/std/src/io/impls/tests.rs [new file with mode: 0644]
library/std/src/io/mod.rs
library/std/src/io/stdio.rs
library/std/src/io/stdio/tests.rs [new file with mode: 0644]
library/std/src/io/tests.rs [new file with mode: 0644]
library/std/src/io/util.rs
library/std/src/io/util/tests.rs [new file with mode: 0644]
library/std/src/lazy.rs
library/std/src/lazy/tests.rs [new file with mode: 0644]
library/std/src/memchr.rs
library/std/src/memchr/tests.rs [new file with mode: 0644]
library/std/src/net/addr.rs
library/std/src/net/addr/tests.rs [new file with mode: 0644]
library/std/src/net/ip.rs
library/std/src/net/ip/tests.rs [new file with mode: 0644]
library/std/src/net/parser.rs
library/std/src/net/parser/tests.rs [new file with mode: 0644]
library/std/src/net/tcp.rs
library/std/src/net/tcp/tests.rs [new file with mode: 0644]
library/std/src/net/udp.rs
library/std/src/net/udp/tests.rs [new file with mode: 0644]
library/std/src/num.rs
library/std/src/num/benches.rs [new file with mode: 0644]
library/std/src/num/tests.rs [new file with mode: 0644]
library/std/src/os/raw/mod.rs
library/std/src/os/raw/tests.rs [new file with mode: 0644]
library/std/src/path.rs
library/std/src/path/tests.rs [new file with mode: 0644]
library/std/src/process.rs
library/std/src/process/tests.rs [new file with mode: 0644]
library/std/src/sync/barrier.rs
library/std/src/sync/barrier/tests.rs [new file with mode: 0644]
library/std/src/sync/condvar.rs
library/std/src/sync/condvar/tests.rs [new file with mode: 0644]
library/std/src/sync/mpsc/mod.rs
library/std/src/sync/mpsc/mpsc_queue.rs
library/std/src/sync/mpsc/mpsc_queue/tests.rs [new file with mode: 0644]
library/std/src/sync/mpsc/spsc_queue.rs
library/std/src/sync/mpsc/spsc_queue/tests.rs [new file with mode: 0644]
library/std/src/sync/mpsc/sync_tests.rs [new file with mode: 0644]
library/std/src/sync/mpsc/tests.rs [new file with mode: 0644]
library/std/src/sync/mutex.rs
library/std/src/sync/mutex/tests.rs [new file with mode: 0644]
library/std/src/sync/once.rs
library/std/src/sync/once/tests.rs [new file with mode: 0644]
library/std/src/sync/rwlock.rs
library/std/src/sync/rwlock/tests.rs [new file with mode: 0644]
library/std/src/sys/sgx/abi/tls.rs
library/std/src/sys/sgx/abi/tls/sync_bitset.rs [new file with mode: 0644]
library/std/src/sys/sgx/abi/tls/sync_bitset/tests.rs [new file with mode: 0644]
library/std/src/sys/sgx/rwlock.rs
library/std/src/sys/sgx/rwlock/tests.rs [new file with mode: 0644]
library/std/src/sys/sgx/waitqueue.rs
library/std/src/sys/sgx/waitqueue/spin_mutex.rs [new file with mode: 0644]
library/std/src/sys/sgx/waitqueue/spin_mutex/tests.rs [new file with mode: 0644]
library/std/src/sys/sgx/waitqueue/tests.rs [new file with mode: 0644]
library/std/src/sys/sgx/waitqueue/unsafe_list.rs [new file with mode: 0644]
library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs [new file with mode: 0644]
library/std/src/sys/unix/ext/net.rs
library/std/src/sys/unix/ext/net/tests.rs [new file with mode: 0644]
library/std/src/sys/unix/fd.rs
library/std/src/sys/unix/fd/tests.rs [new file with mode: 0644]
library/std/src/sys/unix/os.rs
library/std/src/sys/unix/os/tests.rs [new file with mode: 0644]
library/std/src/sys/unix/process/process_common.rs
library/std/src/sys/unix/process/process_common/tests.rs [new file with mode: 0644]
library/std/src/sys/vxworks/net.rs
library/std/src/sys/vxworks/net/tests.rs [new file with mode: 0644]
library/std/src/sys/windows/args.rs
library/std/src/sys/windows/args/tests.rs [new file with mode: 0644]
library/std/src/sys/windows/os.rs
library/std/src/sys/windows/os/tests.rs [new file with mode: 0644]
library/std/src/sys/windows/process.rs
library/std/src/sys/windows/process/tests.rs [new file with mode: 0644]
library/std/src/sys_common/bytestring.rs
library/std/src/sys_common/bytestring/tests.rs [new file with mode: 0644]
library/std/src/sys_common/mod.rs
library/std/src/sys_common/net.rs
library/std/src/sys_common/net/tests.rs [new file with mode: 0644]
library/std/src/sys_common/remutex.rs
library/std/src/sys_common/remutex/tests.rs [new file with mode: 0644]
library/std/src/sys_common/tests.rs [new file with mode: 0644]
library/std/src/sys_common/thread_local_key.rs
library/std/src/sys_common/thread_local_key/tests.rs [new file with mode: 0644]
library/std/src/sys_common/wtf8.rs
library/std/src/sys_common/wtf8/tests.rs [new file with mode: 0644]
library/std/src/thread/local.rs
library/std/src/thread/local/dynamic_tests.rs [new file with mode: 0644]
library/std/src/thread/local/tests.rs [new file with mode: 0644]
library/std/src/thread/mod.rs
library/std/src/thread/tests.rs [new file with mode: 0644]
library/std/src/time.rs
library/std/src/time/tests.rs [new file with mode: 0644]

index 09f83ea5fca81c5eb42c2fa9dfd4218933699c1e..cc29e1c0b05229953da2d09827849fbf0e63c245 100644 (file)
@@ -66,6 +66,9 @@
 
 #![unstable(feature = "backtrace", issue = "53487")]
 
+#[cfg(test)]
+mod tests;
+
 // NB: A note on resolution of a backtrace:
 //
 // Backtraces primarily happen in two steps, one is where we actually capture
@@ -438,55 +441,3 @@ fn ip(&self) -> *mut c_void {
         }
     }
 }
-
-#[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);
-}
diff --git a/library/std/src/backtrace/tests.rs b/library/std/src/backtrace/tests.rs
new file mode 100644 (file)
index 0000000..287359c
--- /dev/null
@@ -0,0 +1,53 @@
+use super::*;
+
+#[test]
+fn test_debug() {
+    let backtrace = Backtrace {
+        inner: Inner::Captured(Mutex::new(Capture {
+            actual_start: 1,
+            resolved: true,
+            frames: vec![
+                BacktraceFrame {
+                    frame: RawFrame::Fake,
+                    symbols: vec![BacktraceSymbol {
+                        name: Some(b"std::backtrace::Backtrace::create".to_vec()),
+                        filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())),
+                        lineno: Some(100),
+                    }],
+                },
+                BacktraceFrame {
+                    frame: RawFrame::Fake,
+                    symbols: vec![BacktraceSymbol {
+                        name: Some(b"__rust_maybe_catch_panic".to_vec()),
+                        filename: None,
+                        lineno: None,
+                    }],
+                },
+                BacktraceFrame {
+                    frame: RawFrame::Fake,
+                    symbols: vec![
+                        BacktraceSymbol {
+                            name: Some(b"std::rt::lang_start_internal".to_vec()),
+                            filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())),
+                            lineno: Some(300),
+                        },
+                        BacktraceSymbol {
+                            name: Some(b"std::rt::lang_start".to_vec()),
+                            filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())),
+                            lineno: Some(400),
+                        },
+                    ],
+                },
+            ],
+        })),
+    };
+
+    #[rustfmt::skip]
+    let expected = "Backtrace [\
+    \n    { fn: \"__rust_maybe_catch_panic\" },\
+    \n    { fn: \"std::rt::lang_start_internal\", file: \"rust/rt.rs\", line: 300 },\
+    \n    { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },\
+    \n]";
+
+    assert_eq!(format!("{:#?}", backtrace), expected);
+}
index 70f7214e2f1d78d3c5f2e1d3a5c798f43fe5ecf3..77cc5b93dbb5029a16f76db73c7a0c44efb00d08 100644 (file)
@@ -1,4 +1,5 @@
-// ignore-tidy-filelength
+#[cfg(test)]
+mod tests;
 
 use self::Entry::*;
 
@@ -2754,933 +2755,3 @@ fn drain<'new>(
         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),
-            }
-        }
-    }
-}
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
new file mode 100644 (file)
index 0000000..4283d80
--- /dev/null
@@ -0,0 +1,926 @@
+use super::Entry::{Occupied, Vacant};
+use super::HashMap;
+use super::RandomState;
+use crate::cell::RefCell;
+use rand::{thread_rng, Rng};
+use realstd::collections::TryReserveError::*;
+
+// https://github.com/rust-lang/rust/issues/62301
+fn _assert_hashmap_is_unwind_safe() {
+    fn assert_unwind_safe<T: crate::panic::UnwindSafe>() {}
+    assert_unwind_safe::<HashMap<(), crate::cell::UnsafeCell<()>>>();
+}
+
+#[test]
+fn test_zero_capacities() {
+    type HM = HashMap<i32, i32>;
+
+    let m = HM::new();
+    assert_eq!(m.capacity(), 0);
+
+    let m = HM::default();
+    assert_eq!(m.capacity(), 0);
+
+    let m = HM::with_hasher(RandomState::new());
+    assert_eq!(m.capacity(), 0);
+
+    let m = HM::with_capacity(0);
+    assert_eq!(m.capacity(), 0);
+
+    let m = HM::with_capacity_and_hasher(0, RandomState::new());
+    assert_eq!(m.capacity(), 0);
+
+    let mut m = HM::new();
+    m.insert(1, 1);
+    m.insert(2, 2);
+    m.remove(&1);
+    m.remove(&2);
+    m.shrink_to_fit();
+    assert_eq!(m.capacity(), 0);
+
+    let mut m = HM::new();
+    m.reserve(0);
+    assert_eq!(m.capacity(), 0);
+}
+
+#[test]
+fn test_create_capacity_zero() {
+    let mut m = HashMap::with_capacity(0);
+
+    assert!(m.insert(1, 1).is_none());
+
+    assert!(m.contains_key(&1));
+    assert!(!m.contains_key(&0));
+}
+
+#[test]
+fn test_insert() {
+    let mut m = HashMap::new();
+    assert_eq!(m.len(), 0);
+    assert!(m.insert(1, 2).is_none());
+    assert_eq!(m.len(), 1);
+    assert!(m.insert(2, 4).is_none());
+    assert_eq!(m.len(), 2);
+    assert_eq!(*m.get(&1).unwrap(), 2);
+    assert_eq!(*m.get(&2).unwrap(), 4);
+}
+
+#[test]
+fn test_clone() {
+    let mut m = HashMap::new();
+    assert_eq!(m.len(), 0);
+    assert!(m.insert(1, 2).is_none());
+    assert_eq!(m.len(), 1);
+    assert!(m.insert(2, 4).is_none());
+    assert_eq!(m.len(), 2);
+    let m2 = m.clone();
+    assert_eq!(*m2.get(&1).unwrap(), 2);
+    assert_eq!(*m2.get(&2).unwrap(), 4);
+    assert_eq!(m2.len(), 2);
+}
+
+thread_local! { static DROP_VECTOR: RefCell<Vec<i32>> = RefCell::new(Vec::new()) }
+
+#[derive(Hash, PartialEq, Eq)]
+struct Droppable {
+    k: usize,
+}
+
+impl Droppable {
+    fn new(k: usize) -> Droppable {
+        DROP_VECTOR.with(|slot| {
+            slot.borrow_mut()[k] += 1;
+        });
+
+        Droppable { k }
+    }
+}
+
+impl Drop for Droppable {
+    fn drop(&mut self) {
+        DROP_VECTOR.with(|slot| {
+            slot.borrow_mut()[self.k] -= 1;
+        });
+    }
+}
+
+impl Clone for Droppable {
+    fn clone(&self) -> Droppable {
+        Droppable::new(self.k)
+    }
+}
+
+#[test]
+fn test_drops() {
+    DROP_VECTOR.with(|slot| {
+        *slot.borrow_mut() = vec![0; 200];
+    });
+
+    {
+        let mut m = HashMap::new();
+
+        DROP_VECTOR.with(|v| {
+            for i in 0..200 {
+                assert_eq!(v.borrow()[i], 0);
+            }
+        });
+
+        for i in 0..100 {
+            let d1 = Droppable::new(i);
+            let d2 = Droppable::new(i + 100);
+            m.insert(d1, d2);
+        }
+
+        DROP_VECTOR.with(|v| {
+            for i in 0..200 {
+                assert_eq!(v.borrow()[i], 1);
+            }
+        });
+
+        for i in 0..50 {
+            let k = Droppable::new(i);
+            let v = m.remove(&k);
+
+            assert!(v.is_some());
+
+            DROP_VECTOR.with(|v| {
+                assert_eq!(v.borrow()[i], 1);
+                assert_eq!(v.borrow()[i + 100], 1);
+            });
+        }
+
+        DROP_VECTOR.with(|v| {
+            for i in 0..50 {
+                assert_eq!(v.borrow()[i], 0);
+                assert_eq!(v.borrow()[i + 100], 0);
+            }
+
+            for i in 50..100 {
+                assert_eq!(v.borrow()[i], 1);
+                assert_eq!(v.borrow()[i + 100], 1);
+            }
+        });
+    }
+
+    DROP_VECTOR.with(|v| {
+        for i in 0..200 {
+            assert_eq!(v.borrow()[i], 0);
+        }
+    });
+}
+
+#[test]
+fn test_into_iter_drops() {
+    DROP_VECTOR.with(|v| {
+        *v.borrow_mut() = vec![0; 200];
+    });
+
+    let hm = {
+        let mut hm = HashMap::new();
+
+        DROP_VECTOR.with(|v| {
+            for i in 0..200 {
+                assert_eq!(v.borrow()[i], 0);
+            }
+        });
+
+        for i in 0..100 {
+            let d1 = Droppable::new(i);
+            let d2 = Droppable::new(i + 100);
+            hm.insert(d1, d2);
+        }
+
+        DROP_VECTOR.with(|v| {
+            for i in 0..200 {
+                assert_eq!(v.borrow()[i], 1);
+            }
+        });
+
+        hm
+    };
+
+    // By the way, ensure that cloning doesn't screw up the dropping.
+    drop(hm.clone());
+
+    {
+        let mut half = hm.into_iter().take(50);
+
+        DROP_VECTOR.with(|v| {
+            for i in 0..200 {
+                assert_eq!(v.borrow()[i], 1);
+            }
+        });
+
+        for _ in half.by_ref() {}
+
+        DROP_VECTOR.with(|v| {
+            let nk = (0..100).filter(|&i| v.borrow()[i] == 1).count();
+
+            let nv = (0..100).filter(|&i| v.borrow()[i + 100] == 1).count();
+
+            assert_eq!(nk, 50);
+            assert_eq!(nv, 50);
+        });
+    };
+
+    DROP_VECTOR.with(|v| {
+        for i in 0..200 {
+            assert_eq!(v.borrow()[i], 0);
+        }
+    });
+}
+
+#[test]
+fn test_empty_remove() {
+    let mut m: HashMap<i32, bool> = HashMap::new();
+    assert_eq!(m.remove(&0), None);
+}
+
+#[test]
+fn test_empty_entry() {
+    let mut m: HashMap<i32, bool> = HashMap::new();
+    match m.entry(0) {
+        Occupied(_) => panic!(),
+        Vacant(_) => {}
+    }
+    assert!(*m.entry(0).or_insert(true));
+    assert_eq!(m.len(), 1);
+}
+
+#[test]
+fn test_empty_iter() {
+    let mut m: HashMap<i32, bool> = HashMap::new();
+    assert_eq!(m.drain().next(), None);
+    assert_eq!(m.keys().next(), None);
+    assert_eq!(m.values().next(), None);
+    assert_eq!(m.values_mut().next(), None);
+    assert_eq!(m.iter().next(), None);
+    assert_eq!(m.iter_mut().next(), None);
+    assert_eq!(m.len(), 0);
+    assert!(m.is_empty());
+    assert_eq!(m.into_iter().next(), None);
+}
+
+#[test]
+fn test_lots_of_insertions() {
+    let mut m = HashMap::new();
+
+    // Try this a few times to make sure we never screw up the hashmap's
+    // internal state.
+    for _ in 0..10 {
+        assert!(m.is_empty());
+
+        for i in 1..1001 {
+            assert!(m.insert(i, i).is_none());
+
+            for j in 1..=i {
+                let r = m.get(&j);
+                assert_eq!(r, Some(&j));
+            }
+
+            for j in i + 1..1001 {
+                let r = m.get(&j);
+                assert_eq!(r, None);
+            }
+        }
+
+        for i in 1001..2001 {
+            assert!(!m.contains_key(&i));
+        }
+
+        // remove forwards
+        for i in 1..1001 {
+            assert!(m.remove(&i).is_some());
+
+            for j in 1..=i {
+                assert!(!m.contains_key(&j));
+            }
+
+            for j in i + 1..1001 {
+                assert!(m.contains_key(&j));
+            }
+        }
+
+        for i in 1..1001 {
+            assert!(!m.contains_key(&i));
+        }
+
+        for i in 1..1001 {
+            assert!(m.insert(i, i).is_none());
+        }
+
+        // remove backwards
+        for i in (1..1001).rev() {
+            assert!(m.remove(&i).is_some());
+
+            for j in i..1001 {
+                assert!(!m.contains_key(&j));
+            }
+
+            for j in 1..i {
+                assert!(m.contains_key(&j));
+            }
+        }
+    }
+}
+
+#[test]
+fn test_find_mut() {
+    let mut m = HashMap::new();
+    assert!(m.insert(1, 12).is_none());
+    assert!(m.insert(2, 8).is_none());
+    assert!(m.insert(5, 14).is_none());
+    let new = 100;
+    match m.get_mut(&5) {
+        None => panic!(),
+        Some(x) => *x = new,
+    }
+    assert_eq!(m.get(&5), Some(&new));
+}
+
+#[test]
+fn test_insert_overwrite() {
+    let mut m = HashMap::new();
+    assert!(m.insert(1, 2).is_none());
+    assert_eq!(*m.get(&1).unwrap(), 2);
+    assert!(!m.insert(1, 3).is_none());
+    assert_eq!(*m.get(&1).unwrap(), 3);
+}
+
+#[test]
+fn test_insert_conflicts() {
+    let mut m = HashMap::with_capacity(4);
+    assert!(m.insert(1, 2).is_none());
+    assert!(m.insert(5, 3).is_none());
+    assert!(m.insert(9, 4).is_none());
+    assert_eq!(*m.get(&9).unwrap(), 4);
+    assert_eq!(*m.get(&5).unwrap(), 3);
+    assert_eq!(*m.get(&1).unwrap(), 2);
+}
+
+#[test]
+fn test_conflict_remove() {
+    let mut m = HashMap::with_capacity(4);
+    assert!(m.insert(1, 2).is_none());
+    assert_eq!(*m.get(&1).unwrap(), 2);
+    assert!(m.insert(5, 3).is_none());
+    assert_eq!(*m.get(&1).unwrap(), 2);
+    assert_eq!(*m.get(&5).unwrap(), 3);
+    assert!(m.insert(9, 4).is_none());
+    assert_eq!(*m.get(&1).unwrap(), 2);
+    assert_eq!(*m.get(&5).unwrap(), 3);
+    assert_eq!(*m.get(&9).unwrap(), 4);
+    assert!(m.remove(&1).is_some());
+    assert_eq!(*m.get(&9).unwrap(), 4);
+    assert_eq!(*m.get(&5).unwrap(), 3);
+}
+
+#[test]
+fn test_is_empty() {
+    let mut m = HashMap::with_capacity(4);
+    assert!(m.insert(1, 2).is_none());
+    assert!(!m.is_empty());
+    assert!(m.remove(&1).is_some());
+    assert!(m.is_empty());
+}
+
+#[test]
+fn test_remove() {
+    let mut m = HashMap::new();
+    m.insert(1, 2);
+    assert_eq!(m.remove(&1), Some(2));
+    assert_eq!(m.remove(&1), None);
+}
+
+#[test]
+fn test_remove_entry() {
+    let mut m = HashMap::new();
+    m.insert(1, 2);
+    assert_eq!(m.remove_entry(&1), Some((1, 2)));
+    assert_eq!(m.remove(&1), None);
+}
+
+#[test]
+fn test_iterate() {
+    let mut m = HashMap::with_capacity(4);
+    for i in 0..32 {
+        assert!(m.insert(i, i * 2).is_none());
+    }
+    assert_eq!(m.len(), 32);
+
+    let mut observed: u32 = 0;
+
+    for (k, v) in &m {
+        assert_eq!(*v, *k * 2);
+        observed |= 1 << *k;
+    }
+    assert_eq!(observed, 0xFFFF_FFFF);
+}
+
+#[test]
+fn test_keys() {
+    let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+    let map: HashMap<_, _> = vec.into_iter().collect();
+    let keys: Vec<_> = map.keys().cloned().collect();
+    assert_eq!(keys.len(), 3);
+    assert!(keys.contains(&1));
+    assert!(keys.contains(&2));
+    assert!(keys.contains(&3));
+}
+
+#[test]
+fn test_values() {
+    let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+    let map: HashMap<_, _> = vec.into_iter().collect();
+    let values: Vec<_> = map.values().cloned().collect();
+    assert_eq!(values.len(), 3);
+    assert!(values.contains(&'a'));
+    assert!(values.contains(&'b'));
+    assert!(values.contains(&'c'));
+}
+
+#[test]
+fn test_values_mut() {
+    let vec = vec![(1, 1), (2, 2), (3, 3)];
+    let mut map: HashMap<_, _> = vec.into_iter().collect();
+    for value in map.values_mut() {
+        *value = (*value) * 2
+    }
+    let values: Vec<_> = map.values().cloned().collect();
+    assert_eq!(values.len(), 3);
+    assert!(values.contains(&2));
+    assert!(values.contains(&4));
+    assert!(values.contains(&6));
+}
+
+#[test]
+fn test_into_keys() {
+    let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+    let map: HashMap<_, _> = vec.into_iter().collect();
+    let keys: Vec<_> = map.into_keys().collect();
+
+    assert_eq!(keys.len(), 3);
+    assert!(keys.contains(&1));
+    assert!(keys.contains(&2));
+    assert!(keys.contains(&3));
+}
+
+#[test]
+fn test_into_values() {
+    let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+    let map: HashMap<_, _> = vec.into_iter().collect();
+    let values: Vec<_> = map.into_values().collect();
+
+    assert_eq!(values.len(), 3);
+    assert!(values.contains(&'a'));
+    assert!(values.contains(&'b'));
+    assert!(values.contains(&'c'));
+}
+
+#[test]
+fn test_find() {
+    let mut m = HashMap::new();
+    assert!(m.get(&1).is_none());
+    m.insert(1, 2);
+    match m.get(&1) {
+        None => panic!(),
+        Some(v) => assert_eq!(*v, 2),
+    }
+}
+
+#[test]
+fn test_eq() {
+    let mut m1 = HashMap::new();
+    m1.insert(1, 2);
+    m1.insert(2, 3);
+    m1.insert(3, 4);
+
+    let mut m2 = HashMap::new();
+    m2.insert(1, 2);
+    m2.insert(2, 3);
+
+    assert!(m1 != m2);
+
+    m2.insert(3, 4);
+
+    assert_eq!(m1, m2);
+}
+
+#[test]
+fn test_show() {
+    let mut map = HashMap::new();
+    let empty: HashMap<i32, i32> = HashMap::new();
+
+    map.insert(1, 2);
+    map.insert(3, 4);
+
+    let map_str = format!("{:?}", map);
+
+    assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}");
+    assert_eq!(format!("{:?}", empty), "{}");
+}
+
+#[test]
+fn test_reserve_shrink_to_fit() {
+    let mut m = HashMap::new();
+    m.insert(0, 0);
+    m.remove(&0);
+    assert!(m.capacity() >= m.len());
+    for i in 0..128 {
+        m.insert(i, i);
+    }
+    m.reserve(256);
+
+    let usable_cap = m.capacity();
+    for i in 128..(128 + 256) {
+        m.insert(i, i);
+        assert_eq!(m.capacity(), usable_cap);
+    }
+
+    for i in 100..(128 + 256) {
+        assert_eq!(m.remove(&i), Some(i));
+    }
+    m.shrink_to_fit();
+
+    assert_eq!(m.len(), 100);
+    assert!(!m.is_empty());
+    assert!(m.capacity() >= m.len());
+
+    for i in 0..100 {
+        assert_eq!(m.remove(&i), Some(i));
+    }
+    m.shrink_to_fit();
+    m.insert(0, 0);
+
+    assert_eq!(m.len(), 1);
+    assert!(m.capacity() >= m.len());
+    assert_eq!(m.remove(&0), Some(0));
+}
+
+#[test]
+fn test_from_iter() {
+    let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+    let map: HashMap<_, _> = xs.iter().cloned().collect();
+
+    for &(k, v) in &xs {
+        assert_eq!(map.get(&k), Some(&v));
+    }
+
+    assert_eq!(map.iter().len(), xs.len() - 1);
+}
+
+#[test]
+fn test_size_hint() {
+    let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+    let map: HashMap<_, _> = xs.iter().cloned().collect();
+
+    let mut iter = map.iter();
+
+    for _ in iter.by_ref().take(3) {}
+
+    assert_eq!(iter.size_hint(), (3, Some(3)));
+}
+
+#[test]
+fn test_iter_len() {
+    let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+    let map: HashMap<_, _> = xs.iter().cloned().collect();
+
+    let mut iter = map.iter();
+
+    for _ in iter.by_ref().take(3) {}
+
+    assert_eq!(iter.len(), 3);
+}
+
+#[test]
+fn test_mut_size_hint() {
+    let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+    let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+
+    let mut iter = map.iter_mut();
+
+    for _ in iter.by_ref().take(3) {}
+
+    assert_eq!(iter.size_hint(), (3, Some(3)));
+}
+
+#[test]
+fn test_iter_mut_len() {
+    let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+    let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+
+    let mut iter = map.iter_mut();
+
+    for _ in iter.by_ref().take(3) {}
+
+    assert_eq!(iter.len(), 3);
+}
+
+#[test]
+fn test_index() {
+    let mut map = HashMap::new();
+
+    map.insert(1, 2);
+    map.insert(2, 1);
+    map.insert(3, 4);
+
+    assert_eq!(map[&2], 1);
+}
+
+#[test]
+#[should_panic]
+fn test_index_nonexistent() {
+    let mut map = HashMap::new();
+
+    map.insert(1, 2);
+    map.insert(2, 1);
+    map.insert(3, 4);
+
+    map[&4];
+}
+
+#[test]
+fn test_entry() {
+    let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
+
+    let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+
+    // Existing key (insert)
+    match map.entry(1) {
+        Vacant(_) => unreachable!(),
+        Occupied(mut view) => {
+            assert_eq!(view.get(), &10);
+            assert_eq!(view.insert(100), 10);
+        }
+    }
+    assert_eq!(map.get(&1).unwrap(), &100);
+    assert_eq!(map.len(), 6);
+
+    // Existing key (update)
+    match map.entry(2) {
+        Vacant(_) => unreachable!(),
+        Occupied(mut view) => {
+            let v = view.get_mut();
+            let new_v = (*v) * 10;
+            *v = new_v;
+        }
+    }
+    assert_eq!(map.get(&2).unwrap(), &200);
+    assert_eq!(map.len(), 6);
+
+    // Existing key (take)
+    match map.entry(3) {
+        Vacant(_) => unreachable!(),
+        Occupied(view) => {
+            assert_eq!(view.remove(), 30);
+        }
+    }
+    assert_eq!(map.get(&3), None);
+    assert_eq!(map.len(), 5);
+
+    // Inexistent key (insert)
+    match map.entry(10) {
+        Occupied(_) => unreachable!(),
+        Vacant(view) => {
+            assert_eq!(*view.insert(1000), 1000);
+        }
+    }
+    assert_eq!(map.get(&10).unwrap(), &1000);
+    assert_eq!(map.len(), 6);
+}
+
+#[test]
+fn test_entry_take_doesnt_corrupt() {
+    #![allow(deprecated)] //rand
+    // Test for #19292
+    fn check(m: &HashMap<i32, ()>) {
+        for k in m.keys() {
+            assert!(m.contains_key(k), "{} is in keys() but not in the map?", k);
+        }
+    }
+
+    let mut m = HashMap::new();
+    let mut rng = thread_rng();
+
+    // Populate the map with some items.
+    for _ in 0..50 {
+        let x = rng.gen_range(-10, 10);
+        m.insert(x, ());
+    }
+
+    for _ in 0..1000 {
+        let x = rng.gen_range(-10, 10);
+        match m.entry(x) {
+            Vacant(_) => {}
+            Occupied(e) => {
+                e.remove();
+            }
+        }
+
+        check(&m);
+    }
+}
+
+#[test]
+fn test_extend_ref() {
+    let mut a = HashMap::new();
+    a.insert(1, "one");
+    let mut b = HashMap::new();
+    b.insert(2, "two");
+    b.insert(3, "three");
+
+    a.extend(&b);
+
+    assert_eq!(a.len(), 3);
+    assert_eq!(a[&1], "one");
+    assert_eq!(a[&2], "two");
+    assert_eq!(a[&3], "three");
+}
+
+#[test]
+fn test_capacity_not_less_than_len() {
+    let mut a = HashMap::new();
+    let mut item = 0;
+
+    for _ in 0..116 {
+        a.insert(item, 0);
+        item += 1;
+    }
+
+    assert!(a.capacity() > a.len());
+
+    let free = a.capacity() - a.len();
+    for _ in 0..free {
+        a.insert(item, 0);
+        item += 1;
+    }
+
+    assert_eq!(a.len(), a.capacity());
+
+    // Insert at capacity should cause allocation.
+    a.insert(item, 0);
+    assert!(a.capacity() > a.len());
+}
+
+#[test]
+fn test_occupied_entry_key() {
+    let mut a = HashMap::new();
+    let key = "hello there";
+    let value = "value goes here";
+    assert!(a.is_empty());
+    a.insert(key.clone(), value.clone());
+    assert_eq!(a.len(), 1);
+    assert_eq!(a[key], value);
+
+    match a.entry(key.clone()) {
+        Vacant(_) => panic!(),
+        Occupied(e) => assert_eq!(key, *e.key()),
+    }
+    assert_eq!(a.len(), 1);
+    assert_eq!(a[key], value);
+}
+
+#[test]
+fn test_vacant_entry_key() {
+    let mut a = HashMap::new();
+    let key = "hello there";
+    let value = "value goes here";
+
+    assert!(a.is_empty());
+    match a.entry(key.clone()) {
+        Occupied(_) => panic!(),
+        Vacant(e) => {
+            assert_eq!(key, *e.key());
+            e.insert(value.clone());
+        }
+    }
+    assert_eq!(a.len(), 1);
+    assert_eq!(a[key], value);
+}
+
+#[test]
+fn test_retain() {
+    let mut map: HashMap<i32, i32> = (0..100).map(|x| (x, x * 10)).collect();
+
+    map.retain(|&k, _| k % 2 == 0);
+    assert_eq!(map.len(), 50);
+    assert_eq!(map[&2], 20);
+    assert_eq!(map[&4], 40);
+    assert_eq!(map[&6], 60);
+}
+
+#[test]
+fn test_try_reserve() {
+    let mut empty_bytes: HashMap<u8, u8> = HashMap::new();
+
+    const MAX_USIZE: usize = usize::MAX;
+
+    if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) {
+    } else {
+        panic!("usize::MAX should trigger an overflow!");
+    }
+
+    if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) {
+    } else {
+        panic!("usize::MAX / 8 should trigger an OOM!")
+    }
+}
+
+#[test]
+fn test_raw_entry() {
+    use super::RawEntryMut::{Occupied, Vacant};
+
+    let xs = [(1i32, 10i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
+
+    let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+
+    let compute_hash = |map: &HashMap<i32, i32>, k: i32| -> u64 {
+        use core::hash::{BuildHasher, Hash, Hasher};
+
+        let mut hasher = map.hasher().build_hasher();
+        k.hash(&mut hasher);
+        hasher.finish()
+    };
+
+    // Existing key (insert)
+    match map.raw_entry_mut().from_key(&1) {
+        Vacant(_) => unreachable!(),
+        Occupied(mut view) => {
+            assert_eq!(view.get(), &10);
+            assert_eq!(view.insert(100), 10);
+        }
+    }
+    let hash1 = compute_hash(&map, 1);
+    assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100));
+    assert_eq!(map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), (&1, &100));
+    assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), (&1, &100));
+    assert_eq!(map.len(), 6);
+
+    // Existing key (update)
+    match map.raw_entry_mut().from_key(&2) {
+        Vacant(_) => unreachable!(),
+        Occupied(mut view) => {
+            let v = view.get_mut();
+            let new_v = (*v) * 10;
+            *v = new_v;
+        }
+    }
+    let hash2 = compute_hash(&map, 2);
+    assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200));
+    assert_eq!(map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), (&2, &200));
+    assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), (&2, &200));
+    assert_eq!(map.len(), 6);
+
+    // Existing key (take)
+    let hash3 = compute_hash(&map, 3);
+    match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) {
+        Vacant(_) => unreachable!(),
+        Occupied(view) => {
+            assert_eq!(view.remove_entry(), (3, 30));
+        }
+    }
+    assert_eq!(map.raw_entry().from_key(&3), None);
+    assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None);
+    assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None);
+    assert_eq!(map.len(), 5);
+
+    // Nonexistent key (insert)
+    match map.raw_entry_mut().from_key(&10) {
+        Occupied(_) => unreachable!(),
+        Vacant(view) => {
+            assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000));
+        }
+    }
+    assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000));
+    assert_eq!(map.len(), 6);
+
+    // Ensure all lookup methods produce equivalent results.
+    for k in 0..12 {
+        let hash = compute_hash(&map, k);
+        let v = map.get(&k).cloned();
+        let kv = v.as_ref().map(|v| (&k, v));
+
+        assert_eq!(map.raw_entry().from_key(&k), kv);
+        assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv);
+        assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv);
+
+        match map.raw_entry_mut().from_key(&k) {
+            Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
+            Vacant(_) => assert_eq!(v, None),
+        }
+        match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) {
+            Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
+            Vacant(_) => assert_eq!(v, None),
+        }
+        match map.raw_entry_mut().from_hash(hash, |q| *q == k) {
+            Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
+            Vacant(_) => assert_eq!(v, None),
+        }
+    }
+}
index 10bf917daea4680534d685b4ba7678b98974d6f3..8c39725ef3550011917ca3a93c62ee5297246463 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(test)]
+mod tests;
+
 use crate::borrow::Borrow;
 use crate::collections::TryReserveError;
 use crate::fmt;
@@ -1579,422 +1582,3 @@ fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
         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));
-    }
-}
diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs
new file mode 100644 (file)
index 0000000..3582390
--- /dev/null
@@ -0,0 +1,415 @@
+use super::super::map::RandomState;
+use super::HashSet;
+
+#[test]
+fn test_zero_capacities() {
+    type HS = HashSet<i32>;
+
+    let s = HS::new();
+    assert_eq!(s.capacity(), 0);
+
+    let s = HS::default();
+    assert_eq!(s.capacity(), 0);
+
+    let s = HS::with_hasher(RandomState::new());
+    assert_eq!(s.capacity(), 0);
+
+    let s = HS::with_capacity(0);
+    assert_eq!(s.capacity(), 0);
+
+    let s = HS::with_capacity_and_hasher(0, RandomState::new());
+    assert_eq!(s.capacity(), 0);
+
+    let mut s = HS::new();
+    s.insert(1);
+    s.insert(2);
+    s.remove(&1);
+    s.remove(&2);
+    s.shrink_to_fit();
+    assert_eq!(s.capacity(), 0);
+
+    let mut s = HS::new();
+    s.reserve(0);
+    assert_eq!(s.capacity(), 0);
+}
+
+#[test]
+fn test_disjoint() {
+    let mut xs = HashSet::new();
+    let mut ys = HashSet::new();
+    assert!(xs.is_disjoint(&ys));
+    assert!(ys.is_disjoint(&xs));
+    assert!(xs.insert(5));
+    assert!(ys.insert(11));
+    assert!(xs.is_disjoint(&ys));
+    assert!(ys.is_disjoint(&xs));
+    assert!(xs.insert(7));
+    assert!(xs.insert(19));
+    assert!(xs.insert(4));
+    assert!(ys.insert(2));
+    assert!(ys.insert(-11));
+    assert!(xs.is_disjoint(&ys));
+    assert!(ys.is_disjoint(&xs));
+    assert!(ys.insert(7));
+    assert!(!xs.is_disjoint(&ys));
+    assert!(!ys.is_disjoint(&xs));
+}
+
+#[test]
+fn test_subset_and_superset() {
+    let mut a = HashSet::new();
+    assert!(a.insert(0));
+    assert!(a.insert(5));
+    assert!(a.insert(11));
+    assert!(a.insert(7));
+
+    let mut b = HashSet::new();
+    assert!(b.insert(0));
+    assert!(b.insert(7));
+    assert!(b.insert(19));
+    assert!(b.insert(250));
+    assert!(b.insert(11));
+    assert!(b.insert(200));
+
+    assert!(!a.is_subset(&b));
+    assert!(!a.is_superset(&b));
+    assert!(!b.is_subset(&a));
+    assert!(!b.is_superset(&a));
+
+    assert!(b.insert(5));
+
+    assert!(a.is_subset(&b));
+    assert!(!a.is_superset(&b));
+    assert!(!b.is_subset(&a));
+    assert!(b.is_superset(&a));
+}
+
+#[test]
+fn test_iterate() {
+    let mut a = HashSet::new();
+    for i in 0..32 {
+        assert!(a.insert(i));
+    }
+    let mut observed: u32 = 0;
+    for k in &a {
+        observed |= 1 << *k;
+    }
+    assert_eq!(observed, 0xFFFF_FFFF);
+}
+
+#[test]
+fn test_intersection() {
+    let mut a = HashSet::new();
+    let mut b = HashSet::new();
+    assert!(a.intersection(&b).next().is_none());
+
+    assert!(a.insert(11));
+    assert!(a.insert(1));
+    assert!(a.insert(3));
+    assert!(a.insert(77));
+    assert!(a.insert(103));
+    assert!(a.insert(5));
+    assert!(a.insert(-5));
+
+    assert!(b.insert(2));
+    assert!(b.insert(11));
+    assert!(b.insert(77));
+    assert!(b.insert(-9));
+    assert!(b.insert(-42));
+    assert!(b.insert(5));
+    assert!(b.insert(3));
+
+    let mut i = 0;
+    let expected = [3, 5, 11, 77];
+    for x in a.intersection(&b) {
+        assert!(expected.contains(x));
+        i += 1
+    }
+    assert_eq!(i, expected.len());
+
+    assert!(a.insert(9)); // make a bigger than b
+
+    i = 0;
+    for x in a.intersection(&b) {
+        assert!(expected.contains(x));
+        i += 1
+    }
+    assert_eq!(i, expected.len());
+
+    i = 0;
+    for x in b.intersection(&a) {
+        assert!(expected.contains(x));
+        i += 1
+    }
+    assert_eq!(i, expected.len());
+}
+
+#[test]
+fn test_difference() {
+    let mut a = HashSet::new();
+    let mut b = HashSet::new();
+
+    assert!(a.insert(1));
+    assert!(a.insert(3));
+    assert!(a.insert(5));
+    assert!(a.insert(9));
+    assert!(a.insert(11));
+
+    assert!(b.insert(3));
+    assert!(b.insert(9));
+
+    let mut i = 0;
+    let expected = [1, 5, 11];
+    for x in a.difference(&b) {
+        assert!(expected.contains(x));
+        i += 1
+    }
+    assert_eq!(i, expected.len());
+}
+
+#[test]
+fn test_symmetric_difference() {
+    let mut a = HashSet::new();
+    let mut b = HashSet::new();
+
+    assert!(a.insert(1));
+    assert!(a.insert(3));
+    assert!(a.insert(5));
+    assert!(a.insert(9));
+    assert!(a.insert(11));
+
+    assert!(b.insert(-2));
+    assert!(b.insert(3));
+    assert!(b.insert(9));
+    assert!(b.insert(14));
+    assert!(b.insert(22));
+
+    let mut i = 0;
+    let expected = [-2, 1, 5, 11, 14, 22];
+    for x in a.symmetric_difference(&b) {
+        assert!(expected.contains(x));
+        i += 1
+    }
+    assert_eq!(i, expected.len());
+}
+
+#[test]
+fn test_union() {
+    let mut a = HashSet::new();
+    let mut b = HashSet::new();
+    assert!(a.union(&b).next().is_none());
+    assert!(b.union(&a).next().is_none());
+
+    assert!(a.insert(1));
+    assert!(a.insert(3));
+    assert!(a.insert(11));
+    assert!(a.insert(16));
+    assert!(a.insert(19));
+    assert!(a.insert(24));
+
+    assert!(b.insert(-2));
+    assert!(b.insert(1));
+    assert!(b.insert(5));
+    assert!(b.insert(9));
+    assert!(b.insert(13));
+    assert!(b.insert(19));
+
+    let mut i = 0;
+    let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24];
+    for x in a.union(&b) {
+        assert!(expected.contains(x));
+        i += 1
+    }
+    assert_eq!(i, expected.len());
+
+    assert!(a.insert(9)); // make a bigger than b
+    assert!(a.insert(5));
+
+    i = 0;
+    for x in a.union(&b) {
+        assert!(expected.contains(x));
+        i += 1
+    }
+    assert_eq!(i, expected.len());
+
+    i = 0;
+    for x in b.union(&a) {
+        assert!(expected.contains(x));
+        i += 1
+    }
+    assert_eq!(i, expected.len());
+}
+
+#[test]
+fn test_from_iter() {
+    let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9];
+
+    let set: HashSet<_> = xs.iter().cloned().collect();
+
+    for x in &xs {
+        assert!(set.contains(x));
+    }
+
+    assert_eq!(set.iter().len(), xs.len() - 1);
+}
+
+#[test]
+fn test_move_iter() {
+    let hs = {
+        let mut hs = HashSet::new();
+
+        hs.insert('a');
+        hs.insert('b');
+
+        hs
+    };
+
+    let v = hs.into_iter().collect::<Vec<char>>();
+    assert!(v == ['a', 'b'] || v == ['b', 'a']);
+}
+
+#[test]
+fn test_eq() {
+    // These constants once happened to expose a bug in insert().
+    // I'm keeping them around to prevent a regression.
+    let mut s1 = HashSet::new();
+
+    s1.insert(1);
+    s1.insert(2);
+    s1.insert(3);
+
+    let mut s2 = HashSet::new();
+
+    s2.insert(1);
+    s2.insert(2);
+
+    assert!(s1 != s2);
+
+    s2.insert(3);
+
+    assert_eq!(s1, s2);
+}
+
+#[test]
+fn test_show() {
+    let mut set = HashSet::new();
+    let empty = HashSet::<i32>::new();
+
+    set.insert(1);
+    set.insert(2);
+
+    let set_str = format!("{:?}", set);
+
+    assert!(set_str == "{1, 2}" || set_str == "{2, 1}");
+    assert_eq!(format!("{:?}", empty), "{}");
+}
+
+#[test]
+fn test_trivial_drain() {
+    let mut s = HashSet::<i32>::new();
+    for _ in s.drain() {}
+    assert!(s.is_empty());
+    drop(s);
+
+    let mut s = HashSet::<i32>::new();
+    drop(s.drain());
+    assert!(s.is_empty());
+}
+
+#[test]
+fn test_drain() {
+    let mut s: HashSet<_> = (1..100).collect();
+
+    // try this a bunch of times to make sure we don't screw up internal state.
+    for _ in 0..20 {
+        assert_eq!(s.len(), 99);
+
+        {
+            let mut last_i = 0;
+            let mut d = s.drain();
+            for (i, x) in d.by_ref().take(50).enumerate() {
+                last_i = i;
+                assert!(x != 0);
+            }
+            assert_eq!(last_i, 49);
+        }
+
+        for _ in &s {
+            panic!("s should be empty!");
+        }
+
+        // reset to try again.
+        s.extend(1..100);
+    }
+}
+
+#[test]
+fn test_replace() {
+    use crate::hash;
+
+    #[derive(Debug)]
+    struct Foo(&'static str, i32);
+
+    impl PartialEq for Foo {
+        fn eq(&self, other: &Self) -> bool {
+            self.0 == other.0
+        }
+    }
+
+    impl Eq for Foo {}
+
+    impl hash::Hash for Foo {
+        fn hash<H: hash::Hasher>(&self, h: &mut H) {
+            self.0.hash(h);
+        }
+    }
+
+    let mut s = HashSet::new();
+    assert_eq!(s.replace(Foo("a", 1)), None);
+    assert_eq!(s.len(), 1);
+    assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1)));
+    assert_eq!(s.len(), 1);
+
+    let mut it = s.iter();
+    assert_eq!(it.next(), Some(&Foo("a", 2)));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_extend_ref() {
+    let mut a = HashSet::new();
+    a.insert(1);
+
+    a.extend(&[2, 3, 4]);
+
+    assert_eq!(a.len(), 4);
+    assert!(a.contains(&1));
+    assert!(a.contains(&2));
+    assert!(a.contains(&3));
+    assert!(a.contains(&4));
+
+    let mut b = HashSet::new();
+    b.insert(5);
+    b.insert(6);
+
+    a.extend(&b);
+
+    assert_eq!(a.len(), 6);
+    assert!(a.contains(&1));
+    assert!(a.contains(&2));
+    assert!(a.contains(&3));
+    assert!(a.contains(&4));
+    assert!(a.contains(&5));
+    assert!(a.contains(&6));
+}
+
+#[test]
+fn test_retain() {
+    let xs = [1, 2, 3, 4, 5, 6];
+    let mut set: HashSet<i32> = xs.iter().cloned().collect();
+    set.retain(|&k| k % 2 == 0);
+    assert_eq!(set.len(), 3);
+    assert!(set.contains(&2));
+    assert!(set.contains(&4));
+    assert!(set.contains(&6));
+}
index 387c588f4a061d18f7e1879202ac9f9ce0790395..d38911ba0db90b0801c462704f7869f4a1e66e55 100644 (file)
@@ -10,6 +10,9 @@
 
 #![stable(feature = "env", since = "1.0.0")]
 
+#[cfg(test)]
+mod tests;
+
 use crate::error::Error;
 use crate::ffi::{OsStr, OsString};
 use crate::fmt;
@@ -944,112 +947,3 @@ pub mod consts {
     #[stable(feature = "env", since = "1.0.0")]
     pub const EXE_EXTENSION: &str = os::EXE_EXTENSION;
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    use crate::path::Path;
-
-    #[test]
-    #[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
-    fn test_self_exe_path() {
-        let path = current_exe();
-        assert!(path.is_ok());
-        let path = path.unwrap();
-
-        // Hard to test this function
-        assert!(path.is_absolute());
-    }
-
-    #[test]
-    fn test() {
-        assert!((!Path::new("test-path").is_absolute()));
-
-        #[cfg(not(target_env = "sgx"))]
-        current_dir().unwrap();
-    }
-
-    #[test]
-    #[cfg(windows)]
-    fn split_paths_windows() {
-        use crate::path::PathBuf;
-
-        fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
-            split_paths(unparsed).collect::<Vec<_>>()
-                == parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
-        }
-
-        assert!(check_parse("", &mut [""]));
-        assert!(check_parse(r#""""#, &mut [""]));
-        assert!(check_parse(";;", &mut ["", "", ""]));
-        assert!(check_parse(r"c:\", &mut [r"c:\"]));
-        assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
-        assert!(check_parse(r"c:\;c:\Program Files\", &mut [r"c:\", r"c:\Program Files\"]));
-        assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
-        assert!(check_parse(
-            r#"c:\;c:\"foo;bar"\;c:\baz"#,
-            &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]
-        ));
-    }
-
-    #[test]
-    #[cfg(unix)]
-    fn split_paths_unix() {
-        use crate::path::PathBuf;
-
-        fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
-            split_paths(unparsed).collect::<Vec<_>>()
-                == parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
-        }
-
-        assert!(check_parse("", &mut [""]));
-        assert!(check_parse("::", &mut ["", "", ""]));
-        assert!(check_parse("/", &mut ["/"]));
-        assert!(check_parse("/:", &mut ["/", ""]));
-        assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
-    }
-
-    #[test]
-    #[cfg(unix)]
-    fn join_paths_unix() {
-        use crate::ffi::OsStr;
-
-        fn test_eq(input: &[&str], output: &str) -> bool {
-            &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output)
-        }
-
-        assert!(test_eq(&[], ""));
-        assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], "/bin:/usr/bin:/usr/local/bin"));
-        assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], ":/bin:::/usr/bin:"));
-        assert!(join_paths(["/te:st"].iter().cloned()).is_err());
-    }
-
-    #[test]
-    #[cfg(windows)]
-    fn join_paths_windows() {
-        use crate::ffi::OsStr;
-
-        fn test_eq(input: &[&str], output: &str) -> bool {
-            &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output)
-        }
-
-        assert!(test_eq(&[], ""));
-        assert!(test_eq(&[r"c:\windows", r"c:\"], r"c:\windows;c:\"));
-        assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], r";c:\windows;;;c:\;"));
-        assert!(test_eq(&[r"c:\te;st", r"c:\"], r#""c:\te;st";c:\"#));
-        assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err());
-    }
-
-    #[test]
-    fn args_debug() {
-        assert_eq!(
-            format!("Args {{ inner: {:?} }}", args().collect::<Vec<_>>()),
-            format!("{:?}", args())
-        );
-        assert_eq!(
-            format!("ArgsOs {{ inner: {:?} }}", args_os().collect::<Vec<_>>()),
-            format!("{:?}", args_os())
-        );
-    }
-}
diff --git a/library/std/src/env/tests.rs b/library/std/src/env/tests.rs
new file mode 100644 (file)
index 0000000..94cace0
--- /dev/null
@@ -0,0 +1,102 @@
+use super::*;
+
+use crate::path::Path;
+
+#[test]
+#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
+fn test_self_exe_path() {
+    let path = current_exe();
+    assert!(path.is_ok());
+    let path = path.unwrap();
+
+    // Hard to test this function
+    assert!(path.is_absolute());
+}
+
+#[test]
+fn test() {
+    assert!((!Path::new("test-path").is_absolute()));
+
+    #[cfg(not(target_env = "sgx"))]
+    current_dir().unwrap();
+}
+
+#[test]
+#[cfg(windows)]
+fn split_paths_windows() {
+    use crate::path::PathBuf;
+
+    fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
+        split_paths(unparsed).collect::<Vec<_>>()
+            == parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
+    }
+
+    assert!(check_parse("", &mut [""]));
+    assert!(check_parse(r#""""#, &mut [""]));
+    assert!(check_parse(";;", &mut ["", "", ""]));
+    assert!(check_parse(r"c:\", &mut [r"c:\"]));
+    assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
+    assert!(check_parse(r"c:\;c:\Program Files\", &mut [r"c:\", r"c:\Program Files\"]));
+    assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
+    assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#, &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
+}
+
+#[test]
+#[cfg(unix)]
+fn split_paths_unix() {
+    use crate::path::PathBuf;
+
+    fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
+        split_paths(unparsed).collect::<Vec<_>>()
+            == parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
+    }
+
+    assert!(check_parse("", &mut [""]));
+    assert!(check_parse("::", &mut ["", "", ""]));
+    assert!(check_parse("/", &mut ["/"]));
+    assert!(check_parse("/:", &mut ["/", ""]));
+    assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
+}
+
+#[test]
+#[cfg(unix)]
+fn join_paths_unix() {
+    use crate::ffi::OsStr;
+
+    fn test_eq(input: &[&str], output: &str) -> bool {
+        &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output)
+    }
+
+    assert!(test_eq(&[], ""));
+    assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], "/bin:/usr/bin:/usr/local/bin"));
+    assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], ":/bin:::/usr/bin:"));
+    assert!(join_paths(["/te:st"].iter().cloned()).is_err());
+}
+
+#[test]
+#[cfg(windows)]
+fn join_paths_windows() {
+    use crate::ffi::OsStr;
+
+    fn test_eq(input: &[&str], output: &str) -> bool {
+        &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output)
+    }
+
+    assert!(test_eq(&[], ""));
+    assert!(test_eq(&[r"c:\windows", r"c:\"], r"c:\windows;c:\"));
+    assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], r";c:\windows;;;c:\;"));
+    assert!(test_eq(&[r"c:\te;st", r"c:\"], r#""c:\te;st";c:\"#));
+    assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err());
+}
+
+#[test]
+fn args_debug() {
+    assert_eq!(
+        format!("Args {{ inner: {:?} }}", args().collect::<Vec<_>>()),
+        format!("{:?}", args())
+    );
+    assert_eq!(
+        format!("ArgsOs {{ inner: {:?} }}", args_os().collect::<Vec<_>>()),
+        format!("{:?}", args_os())
+    );
+}
index d3b0f8ceb68a64e8b8981cb840f6cf9f0bbd116b..8da033439768e08b550b9607594e5bb459daaf56 100644 (file)
@@ -13,6 +13,9 @@
 // coherence challenge (e.g., specialization, neg impls, etc) we can
 // reconsider what crate these items belong in.
 
+#[cfg(test)]
+mod tests;
+
 use core::array;
 use core::convert::Infallible;
 
@@ -738,44 +741,3 @@ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>
         })
     }
 }
-
-#[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),
-        }
-    }
-}
diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs
new file mode 100644 (file)
index 0000000..66d6924
--- /dev/null
@@ -0,0 +1,37 @@
+use super::Error;
+use crate::fmt;
+
+#[derive(Debug, PartialEq)]
+struct A;
+#[derive(Debug, PartialEq)]
+struct B;
+
+impl fmt::Display for A {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "A")
+    }
+}
+impl fmt::Display for B {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "B")
+    }
+}
+
+impl Error for A {}
+impl Error for B {}
+
+#[test]
+fn downcasting() {
+    let mut a = A;
+    let a = &mut a as &mut (dyn Error + 'static);
+    assert_eq!(a.downcast_ref::<A>(), Some(&A));
+    assert_eq!(a.downcast_ref::<B>(), None);
+    assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
+    assert_eq!(a.downcast_mut::<B>(), None);
+
+    let a: Box<dyn Error> = Box::new(A);
+    match a.downcast::<B>() {
+        Ok(..) => panic!("expected error"),
+        Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
+    }
+}
index c905bcf5e3db4255819b3c952eb5277012042add..59c2da5273bded106154c46223e9bf011243a3d3 100644 (file)
@@ -11,6 +11,9 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 #![allow(missing_docs)]
 
+#[cfg(test)]
+mod tests;
+
 #[cfg(not(test))]
 use crate::intrinsics;
 #[cfg(not(test))]
@@ -909,766 +912,3 @@ pub fn clamp(self, min: f32, max: f32) -> f32 {
         x
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use crate::f32::consts;
-    use crate::num::FpCategory as Fp;
-    use crate::num::*;
-
-    #[test]
-    fn test_num_f32() {
-        test_num(10f32, 2f32);
-    }
-
-    #[test]
-    fn test_min_nan() {
-        assert_eq!(f32::NAN.min(2.0), 2.0);
-        assert_eq!(2.0f32.min(f32::NAN), 2.0);
-    }
-
-    #[test]
-    fn test_max_nan() {
-        assert_eq!(f32::NAN.max(2.0), 2.0);
-        assert_eq!(2.0f32.max(f32::NAN), 2.0);
-    }
-
-    #[test]
-    fn test_nan() {
-        let nan: f32 = f32::NAN;
-        assert!(nan.is_nan());
-        assert!(!nan.is_infinite());
-        assert!(!nan.is_finite());
-        assert!(!nan.is_normal());
-        assert!(nan.is_sign_positive());
-        assert!(!nan.is_sign_negative());
-        assert_eq!(Fp::Nan, nan.classify());
-    }
-
-    #[test]
-    fn test_infinity() {
-        let inf: f32 = f32::INFINITY;
-        assert!(inf.is_infinite());
-        assert!(!inf.is_finite());
-        assert!(inf.is_sign_positive());
-        assert!(!inf.is_sign_negative());
-        assert!(!inf.is_nan());
-        assert!(!inf.is_normal());
-        assert_eq!(Fp::Infinite, inf.classify());
-    }
-
-    #[test]
-    fn test_neg_infinity() {
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert!(neg_inf.is_infinite());
-        assert!(!neg_inf.is_finite());
-        assert!(!neg_inf.is_sign_positive());
-        assert!(neg_inf.is_sign_negative());
-        assert!(!neg_inf.is_nan());
-        assert!(!neg_inf.is_normal());
-        assert_eq!(Fp::Infinite, neg_inf.classify());
-    }
-
-    #[test]
-    fn test_zero() {
-        let zero: f32 = 0.0f32;
-        assert_eq!(0.0, zero);
-        assert!(!zero.is_infinite());
-        assert!(zero.is_finite());
-        assert!(zero.is_sign_positive());
-        assert!(!zero.is_sign_negative());
-        assert!(!zero.is_nan());
-        assert!(!zero.is_normal());
-        assert_eq!(Fp::Zero, zero.classify());
-    }
-
-    #[test]
-    fn test_neg_zero() {
-        let neg_zero: f32 = -0.0;
-        assert_eq!(0.0, neg_zero);
-        assert!(!neg_zero.is_infinite());
-        assert!(neg_zero.is_finite());
-        assert!(!neg_zero.is_sign_positive());
-        assert!(neg_zero.is_sign_negative());
-        assert!(!neg_zero.is_nan());
-        assert!(!neg_zero.is_normal());
-        assert_eq!(Fp::Zero, neg_zero.classify());
-    }
-
-    #[test]
-    fn test_one() {
-        let one: f32 = 1.0f32;
-        assert_eq!(1.0, one);
-        assert!(!one.is_infinite());
-        assert!(one.is_finite());
-        assert!(one.is_sign_positive());
-        assert!(!one.is_sign_negative());
-        assert!(!one.is_nan());
-        assert!(one.is_normal());
-        assert_eq!(Fp::Normal, one.classify());
-    }
-
-    #[test]
-    fn test_is_nan() {
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert!(nan.is_nan());
-        assert!(!0.0f32.is_nan());
-        assert!(!5.3f32.is_nan());
-        assert!(!(-10.732f32).is_nan());
-        assert!(!inf.is_nan());
-        assert!(!neg_inf.is_nan());
-    }
-
-    #[test]
-    fn test_is_infinite() {
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert!(!nan.is_infinite());
-        assert!(inf.is_infinite());
-        assert!(neg_inf.is_infinite());
-        assert!(!0.0f32.is_infinite());
-        assert!(!42.8f32.is_infinite());
-        assert!(!(-109.2f32).is_infinite());
-    }
-
-    #[test]
-    fn test_is_finite() {
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert!(!nan.is_finite());
-        assert!(!inf.is_finite());
-        assert!(!neg_inf.is_finite());
-        assert!(0.0f32.is_finite());
-        assert!(42.8f32.is_finite());
-        assert!((-109.2f32).is_finite());
-    }
-
-    #[test]
-    fn test_is_normal() {
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        let zero: f32 = 0.0f32;
-        let neg_zero: f32 = -0.0;
-        assert!(!nan.is_normal());
-        assert!(!inf.is_normal());
-        assert!(!neg_inf.is_normal());
-        assert!(!zero.is_normal());
-        assert!(!neg_zero.is_normal());
-        assert!(1f32.is_normal());
-        assert!(1e-37f32.is_normal());
-        assert!(!1e-38f32.is_normal());
-    }
-
-    #[test]
-    fn test_classify() {
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        let zero: f32 = 0.0f32;
-        let neg_zero: f32 = -0.0;
-        assert_eq!(nan.classify(), Fp::Nan);
-        assert_eq!(inf.classify(), Fp::Infinite);
-        assert_eq!(neg_inf.classify(), Fp::Infinite);
-        assert_eq!(zero.classify(), Fp::Zero);
-        assert_eq!(neg_zero.classify(), Fp::Zero);
-        assert_eq!(1f32.classify(), Fp::Normal);
-        assert_eq!(1e-37f32.classify(), Fp::Normal);
-        assert_eq!(1e-38f32.classify(), Fp::Subnormal);
-    }
-
-    #[test]
-    fn test_floor() {
-        assert_approx_eq!(1.0f32.floor(), 1.0f32);
-        assert_approx_eq!(1.3f32.floor(), 1.0f32);
-        assert_approx_eq!(1.5f32.floor(), 1.0f32);
-        assert_approx_eq!(1.7f32.floor(), 1.0f32);
-        assert_approx_eq!(0.0f32.floor(), 0.0f32);
-        assert_approx_eq!((-0.0f32).floor(), -0.0f32);
-        assert_approx_eq!((-1.0f32).floor(), -1.0f32);
-        assert_approx_eq!((-1.3f32).floor(), -2.0f32);
-        assert_approx_eq!((-1.5f32).floor(), -2.0f32);
-        assert_approx_eq!((-1.7f32).floor(), -2.0f32);
-    }
-
-    #[test]
-    fn test_ceil() {
-        assert_approx_eq!(1.0f32.ceil(), 1.0f32);
-        assert_approx_eq!(1.3f32.ceil(), 2.0f32);
-        assert_approx_eq!(1.5f32.ceil(), 2.0f32);
-        assert_approx_eq!(1.7f32.ceil(), 2.0f32);
-        assert_approx_eq!(0.0f32.ceil(), 0.0f32);
-        assert_approx_eq!((-0.0f32).ceil(), -0.0f32);
-        assert_approx_eq!((-1.0f32).ceil(), -1.0f32);
-        assert_approx_eq!((-1.3f32).ceil(), -1.0f32);
-        assert_approx_eq!((-1.5f32).ceil(), -1.0f32);
-        assert_approx_eq!((-1.7f32).ceil(), -1.0f32);
-    }
-
-    #[test]
-    fn test_round() {
-        assert_approx_eq!(1.0f32.round(), 1.0f32);
-        assert_approx_eq!(1.3f32.round(), 1.0f32);
-        assert_approx_eq!(1.5f32.round(), 2.0f32);
-        assert_approx_eq!(1.7f32.round(), 2.0f32);
-        assert_approx_eq!(0.0f32.round(), 0.0f32);
-        assert_approx_eq!((-0.0f32).round(), -0.0f32);
-        assert_approx_eq!((-1.0f32).round(), -1.0f32);
-        assert_approx_eq!((-1.3f32).round(), -1.0f32);
-        assert_approx_eq!((-1.5f32).round(), -2.0f32);
-        assert_approx_eq!((-1.7f32).round(), -2.0f32);
-    }
-
-    #[test]
-    fn test_trunc() {
-        assert_approx_eq!(1.0f32.trunc(), 1.0f32);
-        assert_approx_eq!(1.3f32.trunc(), 1.0f32);
-        assert_approx_eq!(1.5f32.trunc(), 1.0f32);
-        assert_approx_eq!(1.7f32.trunc(), 1.0f32);
-        assert_approx_eq!(0.0f32.trunc(), 0.0f32);
-        assert_approx_eq!((-0.0f32).trunc(), -0.0f32);
-        assert_approx_eq!((-1.0f32).trunc(), -1.0f32);
-        assert_approx_eq!((-1.3f32).trunc(), -1.0f32);
-        assert_approx_eq!((-1.5f32).trunc(), -1.0f32);
-        assert_approx_eq!((-1.7f32).trunc(), -1.0f32);
-    }
-
-    #[test]
-    fn test_fract() {
-        assert_approx_eq!(1.0f32.fract(), 0.0f32);
-        assert_approx_eq!(1.3f32.fract(), 0.3f32);
-        assert_approx_eq!(1.5f32.fract(), 0.5f32);
-        assert_approx_eq!(1.7f32.fract(), 0.7f32);
-        assert_approx_eq!(0.0f32.fract(), 0.0f32);
-        assert_approx_eq!((-0.0f32).fract(), -0.0f32);
-        assert_approx_eq!((-1.0f32).fract(), -0.0f32);
-        assert_approx_eq!((-1.3f32).fract(), -0.3f32);
-        assert_approx_eq!((-1.5f32).fract(), -0.5f32);
-        assert_approx_eq!((-1.7f32).fract(), -0.7f32);
-    }
-
-    #[test]
-    fn test_abs() {
-        assert_eq!(f32::INFINITY.abs(), f32::INFINITY);
-        assert_eq!(1f32.abs(), 1f32);
-        assert_eq!(0f32.abs(), 0f32);
-        assert_eq!((-0f32).abs(), 0f32);
-        assert_eq!((-1f32).abs(), 1f32);
-        assert_eq!(f32::NEG_INFINITY.abs(), f32::INFINITY);
-        assert_eq!((1f32 / f32::NEG_INFINITY).abs(), 0f32);
-        assert!(f32::NAN.abs().is_nan());
-    }
-
-    #[test]
-    fn test_signum() {
-        assert_eq!(f32::INFINITY.signum(), 1f32);
-        assert_eq!(1f32.signum(), 1f32);
-        assert_eq!(0f32.signum(), 1f32);
-        assert_eq!((-0f32).signum(), -1f32);
-        assert_eq!((-1f32).signum(), -1f32);
-        assert_eq!(f32::NEG_INFINITY.signum(), -1f32);
-        assert_eq!((1f32 / f32::NEG_INFINITY).signum(), -1f32);
-        assert!(f32::NAN.signum().is_nan());
-    }
-
-    #[test]
-    fn test_is_sign_positive() {
-        assert!(f32::INFINITY.is_sign_positive());
-        assert!(1f32.is_sign_positive());
-        assert!(0f32.is_sign_positive());
-        assert!(!(-0f32).is_sign_positive());
-        assert!(!(-1f32).is_sign_positive());
-        assert!(!f32::NEG_INFINITY.is_sign_positive());
-        assert!(!(1f32 / f32::NEG_INFINITY).is_sign_positive());
-        assert!(f32::NAN.is_sign_positive());
-        assert!(!(-f32::NAN).is_sign_positive());
-    }
-
-    #[test]
-    fn test_is_sign_negative() {
-        assert!(!f32::INFINITY.is_sign_negative());
-        assert!(!1f32.is_sign_negative());
-        assert!(!0f32.is_sign_negative());
-        assert!((-0f32).is_sign_negative());
-        assert!((-1f32).is_sign_negative());
-        assert!(f32::NEG_INFINITY.is_sign_negative());
-        assert!((1f32 / f32::NEG_INFINITY).is_sign_negative());
-        assert!(!f32::NAN.is_sign_negative());
-        assert!((-f32::NAN).is_sign_negative());
-    }
-
-    #[test]
-    fn test_mul_add() {
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05);
-        assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65);
-        assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2);
-        assert_approx_eq!(3.4f32.mul_add(-0.0, 5.6), 5.6);
-        assert!(nan.mul_add(7.8, 9.0).is_nan());
-        assert_eq!(inf.mul_add(7.8, 9.0), inf);
-        assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
-        assert_eq!(8.9f32.mul_add(inf, 3.2), inf);
-        assert_eq!((-3.2f32).mul_add(2.4, neg_inf), neg_inf);
-    }
-
-    #[test]
-    fn test_recip() {
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert_eq!(1.0f32.recip(), 1.0);
-        assert_eq!(2.0f32.recip(), 0.5);
-        assert_eq!((-0.4f32).recip(), -2.5);
-        assert_eq!(0.0f32.recip(), inf);
-        assert!(nan.recip().is_nan());
-        assert_eq!(inf.recip(), 0.0);
-        assert_eq!(neg_inf.recip(), 0.0);
-    }
-
-    #[test]
-    fn test_powi() {
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert_eq!(1.0f32.powi(1), 1.0);
-        assert_approx_eq!((-3.1f32).powi(2), 9.61);
-        assert_approx_eq!(5.9f32.powi(-2), 0.028727);
-        assert_eq!(8.3f32.powi(0), 1.0);
-        assert!(nan.powi(2).is_nan());
-        assert_eq!(inf.powi(3), inf);
-        assert_eq!(neg_inf.powi(2), inf);
-    }
-
-    #[test]
-    fn test_powf() {
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert_eq!(1.0f32.powf(1.0), 1.0);
-        assert_approx_eq!(3.4f32.powf(4.5), 246.408218);
-        assert_approx_eq!(2.7f32.powf(-3.2), 0.041652);
-        assert_approx_eq!((-3.1f32).powf(2.0), 9.61);
-        assert_approx_eq!(5.9f32.powf(-2.0), 0.028727);
-        assert_eq!(8.3f32.powf(0.0), 1.0);
-        assert!(nan.powf(2.0).is_nan());
-        assert_eq!(inf.powf(2.0), inf);
-        assert_eq!(neg_inf.powf(3.0), neg_inf);
-    }
-
-    #[test]
-    fn test_sqrt_domain() {
-        assert!(f32::NAN.sqrt().is_nan());
-        assert!(f32::NEG_INFINITY.sqrt().is_nan());
-        assert!((-1.0f32).sqrt().is_nan());
-        assert_eq!((-0.0f32).sqrt(), -0.0);
-        assert_eq!(0.0f32.sqrt(), 0.0);
-        assert_eq!(1.0f32.sqrt(), 1.0);
-        assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY);
-    }
-
-    #[test]
-    fn test_exp() {
-        assert_eq!(1.0, 0.0f32.exp());
-        assert_approx_eq!(2.718282, 1.0f32.exp());
-        assert_approx_eq!(148.413162, 5.0f32.exp());
-
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        let nan: f32 = f32::NAN;
-        assert_eq!(inf, inf.exp());
-        assert_eq!(0.0, neg_inf.exp());
-        assert!(nan.exp().is_nan());
-    }
-
-    #[test]
-    fn test_exp2() {
-        assert_eq!(32.0, 5.0f32.exp2());
-        assert_eq!(1.0, 0.0f32.exp2());
-
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        let nan: f32 = f32::NAN;
-        assert_eq!(inf, inf.exp2());
-        assert_eq!(0.0, neg_inf.exp2());
-        assert!(nan.exp2().is_nan());
-    }
-
-    #[test]
-    fn test_ln() {
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert_approx_eq!(1.0f32.exp().ln(), 1.0);
-        assert!(nan.ln().is_nan());
-        assert_eq!(inf.ln(), inf);
-        assert!(neg_inf.ln().is_nan());
-        assert!((-2.3f32).ln().is_nan());
-        assert_eq!((-0.0f32).ln(), neg_inf);
-        assert_eq!(0.0f32.ln(), neg_inf);
-        assert_approx_eq!(4.0f32.ln(), 1.386294);
-    }
-
-    #[test]
-    fn test_log() {
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert_eq!(10.0f32.log(10.0), 1.0);
-        assert_approx_eq!(2.3f32.log(3.5), 0.664858);
-        assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0);
-        assert!(1.0f32.log(1.0).is_nan());
-        assert!(1.0f32.log(-13.9).is_nan());
-        assert!(nan.log(2.3).is_nan());
-        assert_eq!(inf.log(10.0), inf);
-        assert!(neg_inf.log(8.8).is_nan());
-        assert!((-2.3f32).log(0.1).is_nan());
-        assert_eq!((-0.0f32).log(2.0), neg_inf);
-        assert_eq!(0.0f32.log(7.0), neg_inf);
-    }
-
-    #[test]
-    fn test_log2() {
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert_approx_eq!(10.0f32.log2(), 3.321928);
-        assert_approx_eq!(2.3f32.log2(), 1.201634);
-        assert_approx_eq!(1.0f32.exp().log2(), 1.442695);
-        assert!(nan.log2().is_nan());
-        assert_eq!(inf.log2(), inf);
-        assert!(neg_inf.log2().is_nan());
-        assert!((-2.3f32).log2().is_nan());
-        assert_eq!((-0.0f32).log2(), neg_inf);
-        assert_eq!(0.0f32.log2(), neg_inf);
-    }
-
-    #[test]
-    fn test_log10() {
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert_eq!(10.0f32.log10(), 1.0);
-        assert_approx_eq!(2.3f32.log10(), 0.361728);
-        assert_approx_eq!(1.0f32.exp().log10(), 0.434294);
-        assert_eq!(1.0f32.log10(), 0.0);
-        assert!(nan.log10().is_nan());
-        assert_eq!(inf.log10(), inf);
-        assert!(neg_inf.log10().is_nan());
-        assert!((-2.3f32).log10().is_nan());
-        assert_eq!((-0.0f32).log10(), neg_inf);
-        assert_eq!(0.0f32.log10(), neg_inf);
-    }
-
-    #[test]
-    fn test_to_degrees() {
-        let pi: f32 = consts::PI;
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert_eq!(0.0f32.to_degrees(), 0.0);
-        assert_approx_eq!((-5.8f32).to_degrees(), -332.315521);
-        assert_eq!(pi.to_degrees(), 180.0);
-        assert!(nan.to_degrees().is_nan());
-        assert_eq!(inf.to_degrees(), inf);
-        assert_eq!(neg_inf.to_degrees(), neg_inf);
-        assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703);
-    }
-
-    #[test]
-    fn test_to_radians() {
-        let pi: f32 = consts::PI;
-        let nan: f32 = f32::NAN;
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        assert_eq!(0.0f32.to_radians(), 0.0);
-        assert_approx_eq!(154.6f32.to_radians(), 2.698279);
-        assert_approx_eq!((-332.31f32).to_radians(), -5.799903);
-        assert_eq!(180.0f32.to_radians(), pi);
-        assert!(nan.to_radians().is_nan());
-        assert_eq!(inf.to_radians(), inf);
-        assert_eq!(neg_inf.to_radians(), neg_inf);
-    }
-
-    #[test]
-    fn test_asinh() {
-        assert_eq!(0.0f32.asinh(), 0.0f32);
-        assert_eq!((-0.0f32).asinh(), -0.0f32);
-
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        let nan: f32 = f32::NAN;
-        assert_eq!(inf.asinh(), inf);
-        assert_eq!(neg_inf.asinh(), neg_inf);
-        assert!(nan.asinh().is_nan());
-        assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271
-        assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
-        assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
-        // regression test for the catastrophic cancellation fixed in 72486
-        assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32);
-    }
-
-    #[test]
-    fn test_acosh() {
-        assert_eq!(1.0f32.acosh(), 0.0f32);
-        assert!(0.999f32.acosh().is_nan());
-
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        let nan: f32 = f32::NAN;
-        assert_eq!(inf.acosh(), inf);
-        assert!(neg_inf.acosh().is_nan());
-        assert!(nan.acosh().is_nan());
-        assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32);
-        assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32);
-    }
-
-    #[test]
-    fn test_atanh() {
-        assert_eq!(0.0f32.atanh(), 0.0f32);
-        assert_eq!((-0.0f32).atanh(), -0.0f32);
-
-        let inf32: f32 = f32::INFINITY;
-        let neg_inf32: f32 = f32::NEG_INFINITY;
-        assert_eq!(1.0f32.atanh(), inf32);
-        assert_eq!((-1.0f32).atanh(), neg_inf32);
-
-        assert!(2f64.atanh().atanh().is_nan());
-        assert!((-2f64).atanh().atanh().is_nan());
-
-        let inf64: f32 = f32::INFINITY;
-        let neg_inf64: f32 = f32::NEG_INFINITY;
-        let nan32: f32 = f32::NAN;
-        assert!(inf64.atanh().is_nan());
-        assert!(neg_inf64.atanh().is_nan());
-        assert!(nan32.atanh().is_nan());
-
-        assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32);
-        assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32);
-    }
-
-    #[test]
-    fn test_real_consts() {
-        use super::consts;
-
-        let pi: f32 = consts::PI;
-        let frac_pi_2: f32 = consts::FRAC_PI_2;
-        let frac_pi_3: f32 = consts::FRAC_PI_3;
-        let frac_pi_4: f32 = consts::FRAC_PI_4;
-        let frac_pi_6: f32 = consts::FRAC_PI_6;
-        let frac_pi_8: f32 = consts::FRAC_PI_8;
-        let frac_1_pi: f32 = consts::FRAC_1_PI;
-        let frac_2_pi: f32 = consts::FRAC_2_PI;
-        let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI;
-        let sqrt2: f32 = consts::SQRT_2;
-        let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2;
-        let e: f32 = consts::E;
-        let log2_e: f32 = consts::LOG2_E;
-        let log10_e: f32 = consts::LOG10_E;
-        let ln_2: f32 = consts::LN_2;
-        let ln_10: f32 = consts::LN_10;
-
-        assert_approx_eq!(frac_pi_2, pi / 2f32);
-        assert_approx_eq!(frac_pi_3, pi / 3f32);
-        assert_approx_eq!(frac_pi_4, pi / 4f32);
-        assert_approx_eq!(frac_pi_6, pi / 6f32);
-        assert_approx_eq!(frac_pi_8, pi / 8f32);
-        assert_approx_eq!(frac_1_pi, 1f32 / pi);
-        assert_approx_eq!(frac_2_pi, 2f32 / pi);
-        assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt());
-        assert_approx_eq!(sqrt2, 2f32.sqrt());
-        assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt());
-        assert_approx_eq!(log2_e, e.log2());
-        assert_approx_eq!(log10_e, e.log10());
-        assert_approx_eq!(ln_2, 2f32.ln());
-        assert_approx_eq!(ln_10, 10f32.ln());
-    }
-
-    #[test]
-    fn test_float_bits_conv() {
-        assert_eq!((1f32).to_bits(), 0x3f800000);
-        assert_eq!((12.5f32).to_bits(), 0x41480000);
-        assert_eq!((1337f32).to_bits(), 0x44a72000);
-        assert_eq!((-14.25f32).to_bits(), 0xc1640000);
-        assert_approx_eq!(f32::from_bits(0x3f800000), 1.0);
-        assert_approx_eq!(f32::from_bits(0x41480000), 12.5);
-        assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0);
-        assert_approx_eq!(f32::from_bits(0xc1640000), -14.25);
-
-        // Check that NaNs roundtrip their bits regardless of signaling-ness
-        // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
-        let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA;
-        let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555;
-        assert!(f32::from_bits(masked_nan1).is_nan());
-        assert!(f32::from_bits(masked_nan2).is_nan());
-
-        assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1);
-        assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2);
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_clamp_min_greater_than_max() {
-        let _ = 1.0f32.clamp(3.0, 1.0);
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_clamp_min_is_nan() {
-        let _ = 1.0f32.clamp(f32::NAN, 1.0);
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_clamp_max_is_nan() {
-        let _ = 1.0f32.clamp(3.0, f32::NAN);
-    }
-
-    #[test]
-    fn test_total_cmp() {
-        use core::cmp::Ordering;
-
-        fn quiet_bit_mask() -> u32 {
-            1 << (f32::MANTISSA_DIGITS - 2)
-        }
-
-        fn min_subnorm() -> f32 {
-            f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0)
-        }
-
-        fn max_subnorm() -> f32 {
-            f32::MIN_POSITIVE - min_subnorm()
-        }
-
-        fn q_nan() -> f32 {
-            f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask())
-        }
-
-        fn s_nan() -> f32 {
-            f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42)
-        }
-
-        assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan()));
-        assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan()));
-        assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY));
-        assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX));
-        assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5));
-        assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0));
-        assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5));
-        assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5));
-        assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE));
-        assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm()));
-        assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm()));
-        assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0));
-        assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0));
-        assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm()));
-        assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm()));
-        assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE));
-        assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5));
-        assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0));
-        assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5));
-        assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5));
-        assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX));
-        assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY));
-        assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan()));
-        assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan()));
-
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
-        assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX));
-        assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5));
-        assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5));
-        assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0));
-        assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5));
-        assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm()));
-        assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm()));
-        assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0));
-        assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0));
-        assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm()));
-        assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm()));
-        assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5));
-        assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0));
-        assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5));
-        assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5));
-        assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX));
-        assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY));
-        assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan()));
-        assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan()));
-
-        assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan()));
-        assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan()));
-        assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY));
-        assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX));
-        assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5));
-        assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5));
-        assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0));
-        assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5));
-        assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE));
-        assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm()));
-        assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm()));
-        assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0));
-        assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0));
-        assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm()));
-        assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm()));
-        assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE));
-        assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5));
-        assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0));
-        assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5));
-        assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5));
-        assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX));
-        assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY));
-        assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan()));
-
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm()));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm()));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm()));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm()));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan()));
-
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm()));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm()));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm()));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm()));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
-    }
-}
diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs
new file mode 100644 (file)
index 0000000..0d4b865
--- /dev/null
@@ -0,0 +1,759 @@
+use crate::f32::consts;
+use crate::num::FpCategory as Fp;
+use crate::num::*;
+
+#[test]
+fn test_num_f32() {
+    test_num(10f32, 2f32);
+}
+
+#[test]
+fn test_min_nan() {
+    assert_eq!(f32::NAN.min(2.0), 2.0);
+    assert_eq!(2.0f32.min(f32::NAN), 2.0);
+}
+
+#[test]
+fn test_max_nan() {
+    assert_eq!(f32::NAN.max(2.0), 2.0);
+    assert_eq!(2.0f32.max(f32::NAN), 2.0);
+}
+
+#[test]
+fn test_nan() {
+    let nan: f32 = f32::NAN;
+    assert!(nan.is_nan());
+    assert!(!nan.is_infinite());
+    assert!(!nan.is_finite());
+    assert!(!nan.is_normal());
+    assert!(nan.is_sign_positive());
+    assert!(!nan.is_sign_negative());
+    assert_eq!(Fp::Nan, nan.classify());
+}
+
+#[test]
+fn test_infinity() {
+    let inf: f32 = f32::INFINITY;
+    assert!(inf.is_infinite());
+    assert!(!inf.is_finite());
+    assert!(inf.is_sign_positive());
+    assert!(!inf.is_sign_negative());
+    assert!(!inf.is_nan());
+    assert!(!inf.is_normal());
+    assert_eq!(Fp::Infinite, inf.classify());
+}
+
+#[test]
+fn test_neg_infinity() {
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert!(neg_inf.is_infinite());
+    assert!(!neg_inf.is_finite());
+    assert!(!neg_inf.is_sign_positive());
+    assert!(neg_inf.is_sign_negative());
+    assert!(!neg_inf.is_nan());
+    assert!(!neg_inf.is_normal());
+    assert_eq!(Fp::Infinite, neg_inf.classify());
+}
+
+#[test]
+fn test_zero() {
+    let zero: f32 = 0.0f32;
+    assert_eq!(0.0, zero);
+    assert!(!zero.is_infinite());
+    assert!(zero.is_finite());
+    assert!(zero.is_sign_positive());
+    assert!(!zero.is_sign_negative());
+    assert!(!zero.is_nan());
+    assert!(!zero.is_normal());
+    assert_eq!(Fp::Zero, zero.classify());
+}
+
+#[test]
+fn test_neg_zero() {
+    let neg_zero: f32 = -0.0;
+    assert_eq!(0.0, neg_zero);
+    assert!(!neg_zero.is_infinite());
+    assert!(neg_zero.is_finite());
+    assert!(!neg_zero.is_sign_positive());
+    assert!(neg_zero.is_sign_negative());
+    assert!(!neg_zero.is_nan());
+    assert!(!neg_zero.is_normal());
+    assert_eq!(Fp::Zero, neg_zero.classify());
+}
+
+#[test]
+fn test_one() {
+    let one: f32 = 1.0f32;
+    assert_eq!(1.0, one);
+    assert!(!one.is_infinite());
+    assert!(one.is_finite());
+    assert!(one.is_sign_positive());
+    assert!(!one.is_sign_negative());
+    assert!(!one.is_nan());
+    assert!(one.is_normal());
+    assert_eq!(Fp::Normal, one.classify());
+}
+
+#[test]
+fn test_is_nan() {
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert!(nan.is_nan());
+    assert!(!0.0f32.is_nan());
+    assert!(!5.3f32.is_nan());
+    assert!(!(-10.732f32).is_nan());
+    assert!(!inf.is_nan());
+    assert!(!neg_inf.is_nan());
+}
+
+#[test]
+fn test_is_infinite() {
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert!(!nan.is_infinite());
+    assert!(inf.is_infinite());
+    assert!(neg_inf.is_infinite());
+    assert!(!0.0f32.is_infinite());
+    assert!(!42.8f32.is_infinite());
+    assert!(!(-109.2f32).is_infinite());
+}
+
+#[test]
+fn test_is_finite() {
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert!(!nan.is_finite());
+    assert!(!inf.is_finite());
+    assert!(!neg_inf.is_finite());
+    assert!(0.0f32.is_finite());
+    assert!(42.8f32.is_finite());
+    assert!((-109.2f32).is_finite());
+}
+
+#[test]
+fn test_is_normal() {
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    let zero: f32 = 0.0f32;
+    let neg_zero: f32 = -0.0;
+    assert!(!nan.is_normal());
+    assert!(!inf.is_normal());
+    assert!(!neg_inf.is_normal());
+    assert!(!zero.is_normal());
+    assert!(!neg_zero.is_normal());
+    assert!(1f32.is_normal());
+    assert!(1e-37f32.is_normal());
+    assert!(!1e-38f32.is_normal());
+}
+
+#[test]
+fn test_classify() {
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    let zero: f32 = 0.0f32;
+    let neg_zero: f32 = -0.0;
+    assert_eq!(nan.classify(), Fp::Nan);
+    assert_eq!(inf.classify(), Fp::Infinite);
+    assert_eq!(neg_inf.classify(), Fp::Infinite);
+    assert_eq!(zero.classify(), Fp::Zero);
+    assert_eq!(neg_zero.classify(), Fp::Zero);
+    assert_eq!(1f32.classify(), Fp::Normal);
+    assert_eq!(1e-37f32.classify(), Fp::Normal);
+    assert_eq!(1e-38f32.classify(), Fp::Subnormal);
+}
+
+#[test]
+fn test_floor() {
+    assert_approx_eq!(1.0f32.floor(), 1.0f32);
+    assert_approx_eq!(1.3f32.floor(), 1.0f32);
+    assert_approx_eq!(1.5f32.floor(), 1.0f32);
+    assert_approx_eq!(1.7f32.floor(), 1.0f32);
+    assert_approx_eq!(0.0f32.floor(), 0.0f32);
+    assert_approx_eq!((-0.0f32).floor(), -0.0f32);
+    assert_approx_eq!((-1.0f32).floor(), -1.0f32);
+    assert_approx_eq!((-1.3f32).floor(), -2.0f32);
+    assert_approx_eq!((-1.5f32).floor(), -2.0f32);
+    assert_approx_eq!((-1.7f32).floor(), -2.0f32);
+}
+
+#[test]
+fn test_ceil() {
+    assert_approx_eq!(1.0f32.ceil(), 1.0f32);
+    assert_approx_eq!(1.3f32.ceil(), 2.0f32);
+    assert_approx_eq!(1.5f32.ceil(), 2.0f32);
+    assert_approx_eq!(1.7f32.ceil(), 2.0f32);
+    assert_approx_eq!(0.0f32.ceil(), 0.0f32);
+    assert_approx_eq!((-0.0f32).ceil(), -0.0f32);
+    assert_approx_eq!((-1.0f32).ceil(), -1.0f32);
+    assert_approx_eq!((-1.3f32).ceil(), -1.0f32);
+    assert_approx_eq!((-1.5f32).ceil(), -1.0f32);
+    assert_approx_eq!((-1.7f32).ceil(), -1.0f32);
+}
+
+#[test]
+fn test_round() {
+    assert_approx_eq!(1.0f32.round(), 1.0f32);
+    assert_approx_eq!(1.3f32.round(), 1.0f32);
+    assert_approx_eq!(1.5f32.round(), 2.0f32);
+    assert_approx_eq!(1.7f32.round(), 2.0f32);
+    assert_approx_eq!(0.0f32.round(), 0.0f32);
+    assert_approx_eq!((-0.0f32).round(), -0.0f32);
+    assert_approx_eq!((-1.0f32).round(), -1.0f32);
+    assert_approx_eq!((-1.3f32).round(), -1.0f32);
+    assert_approx_eq!((-1.5f32).round(), -2.0f32);
+    assert_approx_eq!((-1.7f32).round(), -2.0f32);
+}
+
+#[test]
+fn test_trunc() {
+    assert_approx_eq!(1.0f32.trunc(), 1.0f32);
+    assert_approx_eq!(1.3f32.trunc(), 1.0f32);
+    assert_approx_eq!(1.5f32.trunc(), 1.0f32);
+    assert_approx_eq!(1.7f32.trunc(), 1.0f32);
+    assert_approx_eq!(0.0f32.trunc(), 0.0f32);
+    assert_approx_eq!((-0.0f32).trunc(), -0.0f32);
+    assert_approx_eq!((-1.0f32).trunc(), -1.0f32);
+    assert_approx_eq!((-1.3f32).trunc(), -1.0f32);
+    assert_approx_eq!((-1.5f32).trunc(), -1.0f32);
+    assert_approx_eq!((-1.7f32).trunc(), -1.0f32);
+}
+
+#[test]
+fn test_fract() {
+    assert_approx_eq!(1.0f32.fract(), 0.0f32);
+    assert_approx_eq!(1.3f32.fract(), 0.3f32);
+    assert_approx_eq!(1.5f32.fract(), 0.5f32);
+    assert_approx_eq!(1.7f32.fract(), 0.7f32);
+    assert_approx_eq!(0.0f32.fract(), 0.0f32);
+    assert_approx_eq!((-0.0f32).fract(), -0.0f32);
+    assert_approx_eq!((-1.0f32).fract(), -0.0f32);
+    assert_approx_eq!((-1.3f32).fract(), -0.3f32);
+    assert_approx_eq!((-1.5f32).fract(), -0.5f32);
+    assert_approx_eq!((-1.7f32).fract(), -0.7f32);
+}
+
+#[test]
+fn test_abs() {
+    assert_eq!(f32::INFINITY.abs(), f32::INFINITY);
+    assert_eq!(1f32.abs(), 1f32);
+    assert_eq!(0f32.abs(), 0f32);
+    assert_eq!((-0f32).abs(), 0f32);
+    assert_eq!((-1f32).abs(), 1f32);
+    assert_eq!(f32::NEG_INFINITY.abs(), f32::INFINITY);
+    assert_eq!((1f32 / f32::NEG_INFINITY).abs(), 0f32);
+    assert!(f32::NAN.abs().is_nan());
+}
+
+#[test]
+fn test_signum() {
+    assert_eq!(f32::INFINITY.signum(), 1f32);
+    assert_eq!(1f32.signum(), 1f32);
+    assert_eq!(0f32.signum(), 1f32);
+    assert_eq!((-0f32).signum(), -1f32);
+    assert_eq!((-1f32).signum(), -1f32);
+    assert_eq!(f32::NEG_INFINITY.signum(), -1f32);
+    assert_eq!((1f32 / f32::NEG_INFINITY).signum(), -1f32);
+    assert!(f32::NAN.signum().is_nan());
+}
+
+#[test]
+fn test_is_sign_positive() {
+    assert!(f32::INFINITY.is_sign_positive());
+    assert!(1f32.is_sign_positive());
+    assert!(0f32.is_sign_positive());
+    assert!(!(-0f32).is_sign_positive());
+    assert!(!(-1f32).is_sign_positive());
+    assert!(!f32::NEG_INFINITY.is_sign_positive());
+    assert!(!(1f32 / f32::NEG_INFINITY).is_sign_positive());
+    assert!(f32::NAN.is_sign_positive());
+    assert!(!(-f32::NAN).is_sign_positive());
+}
+
+#[test]
+fn test_is_sign_negative() {
+    assert!(!f32::INFINITY.is_sign_negative());
+    assert!(!1f32.is_sign_negative());
+    assert!(!0f32.is_sign_negative());
+    assert!((-0f32).is_sign_negative());
+    assert!((-1f32).is_sign_negative());
+    assert!(f32::NEG_INFINITY.is_sign_negative());
+    assert!((1f32 / f32::NEG_INFINITY).is_sign_negative());
+    assert!(!f32::NAN.is_sign_negative());
+    assert!((-f32::NAN).is_sign_negative());
+}
+
+#[test]
+fn test_mul_add() {
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05);
+    assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65);
+    assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2);
+    assert_approx_eq!(3.4f32.mul_add(-0.0, 5.6), 5.6);
+    assert!(nan.mul_add(7.8, 9.0).is_nan());
+    assert_eq!(inf.mul_add(7.8, 9.0), inf);
+    assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
+    assert_eq!(8.9f32.mul_add(inf, 3.2), inf);
+    assert_eq!((-3.2f32).mul_add(2.4, neg_inf), neg_inf);
+}
+
+#[test]
+fn test_recip() {
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert_eq!(1.0f32.recip(), 1.0);
+    assert_eq!(2.0f32.recip(), 0.5);
+    assert_eq!((-0.4f32).recip(), -2.5);
+    assert_eq!(0.0f32.recip(), inf);
+    assert!(nan.recip().is_nan());
+    assert_eq!(inf.recip(), 0.0);
+    assert_eq!(neg_inf.recip(), 0.0);
+}
+
+#[test]
+fn test_powi() {
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert_eq!(1.0f32.powi(1), 1.0);
+    assert_approx_eq!((-3.1f32).powi(2), 9.61);
+    assert_approx_eq!(5.9f32.powi(-2), 0.028727);
+    assert_eq!(8.3f32.powi(0), 1.0);
+    assert!(nan.powi(2).is_nan());
+    assert_eq!(inf.powi(3), inf);
+    assert_eq!(neg_inf.powi(2), inf);
+}
+
+#[test]
+fn test_powf() {
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert_eq!(1.0f32.powf(1.0), 1.0);
+    assert_approx_eq!(3.4f32.powf(4.5), 246.408218);
+    assert_approx_eq!(2.7f32.powf(-3.2), 0.041652);
+    assert_approx_eq!((-3.1f32).powf(2.0), 9.61);
+    assert_approx_eq!(5.9f32.powf(-2.0), 0.028727);
+    assert_eq!(8.3f32.powf(0.0), 1.0);
+    assert!(nan.powf(2.0).is_nan());
+    assert_eq!(inf.powf(2.0), inf);
+    assert_eq!(neg_inf.powf(3.0), neg_inf);
+}
+
+#[test]
+fn test_sqrt_domain() {
+    assert!(f32::NAN.sqrt().is_nan());
+    assert!(f32::NEG_INFINITY.sqrt().is_nan());
+    assert!((-1.0f32).sqrt().is_nan());
+    assert_eq!((-0.0f32).sqrt(), -0.0);
+    assert_eq!(0.0f32.sqrt(), 0.0);
+    assert_eq!(1.0f32.sqrt(), 1.0);
+    assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY);
+}
+
+#[test]
+fn test_exp() {
+    assert_eq!(1.0, 0.0f32.exp());
+    assert_approx_eq!(2.718282, 1.0f32.exp());
+    assert_approx_eq!(148.413162, 5.0f32.exp());
+
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    let nan: f32 = f32::NAN;
+    assert_eq!(inf, inf.exp());
+    assert_eq!(0.0, neg_inf.exp());
+    assert!(nan.exp().is_nan());
+}
+
+#[test]
+fn test_exp2() {
+    assert_eq!(32.0, 5.0f32.exp2());
+    assert_eq!(1.0, 0.0f32.exp2());
+
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    let nan: f32 = f32::NAN;
+    assert_eq!(inf, inf.exp2());
+    assert_eq!(0.0, neg_inf.exp2());
+    assert!(nan.exp2().is_nan());
+}
+
+#[test]
+fn test_ln() {
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert_approx_eq!(1.0f32.exp().ln(), 1.0);
+    assert!(nan.ln().is_nan());
+    assert_eq!(inf.ln(), inf);
+    assert!(neg_inf.ln().is_nan());
+    assert!((-2.3f32).ln().is_nan());
+    assert_eq!((-0.0f32).ln(), neg_inf);
+    assert_eq!(0.0f32.ln(), neg_inf);
+    assert_approx_eq!(4.0f32.ln(), 1.386294);
+}
+
+#[test]
+fn test_log() {
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert_eq!(10.0f32.log(10.0), 1.0);
+    assert_approx_eq!(2.3f32.log(3.5), 0.664858);
+    assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0);
+    assert!(1.0f32.log(1.0).is_nan());
+    assert!(1.0f32.log(-13.9).is_nan());
+    assert!(nan.log(2.3).is_nan());
+    assert_eq!(inf.log(10.0), inf);
+    assert!(neg_inf.log(8.8).is_nan());
+    assert!((-2.3f32).log(0.1).is_nan());
+    assert_eq!((-0.0f32).log(2.0), neg_inf);
+    assert_eq!(0.0f32.log(7.0), neg_inf);
+}
+
+#[test]
+fn test_log2() {
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert_approx_eq!(10.0f32.log2(), 3.321928);
+    assert_approx_eq!(2.3f32.log2(), 1.201634);
+    assert_approx_eq!(1.0f32.exp().log2(), 1.442695);
+    assert!(nan.log2().is_nan());
+    assert_eq!(inf.log2(), inf);
+    assert!(neg_inf.log2().is_nan());
+    assert!((-2.3f32).log2().is_nan());
+    assert_eq!((-0.0f32).log2(), neg_inf);
+    assert_eq!(0.0f32.log2(), neg_inf);
+}
+
+#[test]
+fn test_log10() {
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert_eq!(10.0f32.log10(), 1.0);
+    assert_approx_eq!(2.3f32.log10(), 0.361728);
+    assert_approx_eq!(1.0f32.exp().log10(), 0.434294);
+    assert_eq!(1.0f32.log10(), 0.0);
+    assert!(nan.log10().is_nan());
+    assert_eq!(inf.log10(), inf);
+    assert!(neg_inf.log10().is_nan());
+    assert!((-2.3f32).log10().is_nan());
+    assert_eq!((-0.0f32).log10(), neg_inf);
+    assert_eq!(0.0f32.log10(), neg_inf);
+}
+
+#[test]
+fn test_to_degrees() {
+    let pi: f32 = consts::PI;
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert_eq!(0.0f32.to_degrees(), 0.0);
+    assert_approx_eq!((-5.8f32).to_degrees(), -332.315521);
+    assert_eq!(pi.to_degrees(), 180.0);
+    assert!(nan.to_degrees().is_nan());
+    assert_eq!(inf.to_degrees(), inf);
+    assert_eq!(neg_inf.to_degrees(), neg_inf);
+    assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703);
+}
+
+#[test]
+fn test_to_radians() {
+    let pi: f32 = consts::PI;
+    let nan: f32 = f32::NAN;
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    assert_eq!(0.0f32.to_radians(), 0.0);
+    assert_approx_eq!(154.6f32.to_radians(), 2.698279);
+    assert_approx_eq!((-332.31f32).to_radians(), -5.799903);
+    assert_eq!(180.0f32.to_radians(), pi);
+    assert!(nan.to_radians().is_nan());
+    assert_eq!(inf.to_radians(), inf);
+    assert_eq!(neg_inf.to_radians(), neg_inf);
+}
+
+#[test]
+fn test_asinh() {
+    assert_eq!(0.0f32.asinh(), 0.0f32);
+    assert_eq!((-0.0f32).asinh(), -0.0f32);
+
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    let nan: f32 = f32::NAN;
+    assert_eq!(inf.asinh(), inf);
+    assert_eq!(neg_inf.asinh(), neg_inf);
+    assert!(nan.asinh().is_nan());
+    assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271
+    assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
+    assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
+    // regression test for the catastrophic cancellation fixed in 72486
+    assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32);
+}
+
+#[test]
+fn test_acosh() {
+    assert_eq!(1.0f32.acosh(), 0.0f32);
+    assert!(0.999f32.acosh().is_nan());
+
+    let inf: f32 = f32::INFINITY;
+    let neg_inf: f32 = f32::NEG_INFINITY;
+    let nan: f32 = f32::NAN;
+    assert_eq!(inf.acosh(), inf);
+    assert!(neg_inf.acosh().is_nan());
+    assert!(nan.acosh().is_nan());
+    assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32);
+    assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32);
+}
+
+#[test]
+fn test_atanh() {
+    assert_eq!(0.0f32.atanh(), 0.0f32);
+    assert_eq!((-0.0f32).atanh(), -0.0f32);
+
+    let inf32: f32 = f32::INFINITY;
+    let neg_inf32: f32 = f32::NEG_INFINITY;
+    assert_eq!(1.0f32.atanh(), inf32);
+    assert_eq!((-1.0f32).atanh(), neg_inf32);
+
+    assert!(2f64.atanh().atanh().is_nan());
+    assert!((-2f64).atanh().atanh().is_nan());
+
+    let inf64: f32 = f32::INFINITY;
+    let neg_inf64: f32 = f32::NEG_INFINITY;
+    let nan32: f32 = f32::NAN;
+    assert!(inf64.atanh().is_nan());
+    assert!(neg_inf64.atanh().is_nan());
+    assert!(nan32.atanh().is_nan());
+
+    assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32);
+    assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32);
+}
+
+#[test]
+fn test_real_consts() {
+    use super::consts;
+
+    let pi: f32 = consts::PI;
+    let frac_pi_2: f32 = consts::FRAC_PI_2;
+    let frac_pi_3: f32 = consts::FRAC_PI_3;
+    let frac_pi_4: f32 = consts::FRAC_PI_4;
+    let frac_pi_6: f32 = consts::FRAC_PI_6;
+    let frac_pi_8: f32 = consts::FRAC_PI_8;
+    let frac_1_pi: f32 = consts::FRAC_1_PI;
+    let frac_2_pi: f32 = consts::FRAC_2_PI;
+    let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI;
+    let sqrt2: f32 = consts::SQRT_2;
+    let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2;
+    let e: f32 = consts::E;
+    let log2_e: f32 = consts::LOG2_E;
+    let log10_e: f32 = consts::LOG10_E;
+    let ln_2: f32 = consts::LN_2;
+    let ln_10: f32 = consts::LN_10;
+
+    assert_approx_eq!(frac_pi_2, pi / 2f32);
+    assert_approx_eq!(frac_pi_3, pi / 3f32);
+    assert_approx_eq!(frac_pi_4, pi / 4f32);
+    assert_approx_eq!(frac_pi_6, pi / 6f32);
+    assert_approx_eq!(frac_pi_8, pi / 8f32);
+    assert_approx_eq!(frac_1_pi, 1f32 / pi);
+    assert_approx_eq!(frac_2_pi, 2f32 / pi);
+    assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt());
+    assert_approx_eq!(sqrt2, 2f32.sqrt());
+    assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt());
+    assert_approx_eq!(log2_e, e.log2());
+    assert_approx_eq!(log10_e, e.log10());
+    assert_approx_eq!(ln_2, 2f32.ln());
+    assert_approx_eq!(ln_10, 10f32.ln());
+}
+
+#[test]
+fn test_float_bits_conv() {
+    assert_eq!((1f32).to_bits(), 0x3f800000);
+    assert_eq!((12.5f32).to_bits(), 0x41480000);
+    assert_eq!((1337f32).to_bits(), 0x44a72000);
+    assert_eq!((-14.25f32).to_bits(), 0xc1640000);
+    assert_approx_eq!(f32::from_bits(0x3f800000), 1.0);
+    assert_approx_eq!(f32::from_bits(0x41480000), 12.5);
+    assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0);
+    assert_approx_eq!(f32::from_bits(0xc1640000), -14.25);
+
+    // Check that NaNs roundtrip their bits regardless of signaling-ness
+    // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+    let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA;
+    let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555;
+    assert!(f32::from_bits(masked_nan1).is_nan());
+    assert!(f32::from_bits(masked_nan2).is_nan());
+
+    assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1);
+    assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2);
+}
+
+#[test]
+#[should_panic]
+fn test_clamp_min_greater_than_max() {
+    let _ = 1.0f32.clamp(3.0, 1.0);
+}
+
+#[test]
+#[should_panic]
+fn test_clamp_min_is_nan() {
+    let _ = 1.0f32.clamp(f32::NAN, 1.0);
+}
+
+#[test]
+#[should_panic]
+fn test_clamp_max_is_nan() {
+    let _ = 1.0f32.clamp(3.0, f32::NAN);
+}
+
+#[test]
+fn test_total_cmp() {
+    use core::cmp::Ordering;
+
+    fn quiet_bit_mask() -> u32 {
+        1 << (f32::MANTISSA_DIGITS - 2)
+    }
+
+    fn min_subnorm() -> f32 {
+        f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0)
+    }
+
+    fn max_subnorm() -> f32 {
+        f32::MIN_POSITIVE - min_subnorm()
+    }
+
+    fn q_nan() -> f32 {
+        f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask())
+    }
+
+    fn s_nan() -> f32 {
+        f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42)
+    }
+
+    assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan()));
+    assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan()));
+    assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY));
+    assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX));
+    assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5));
+    assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0));
+    assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5));
+    assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5));
+    assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE));
+    assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm()));
+    assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm()));
+    assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0));
+    assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0));
+    assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm()));
+    assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm()));
+    assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE));
+    assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5));
+    assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0));
+    assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5));
+    assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5));
+    assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX));
+    assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY));
+    assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan()));
+    assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan()));
+
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
+    assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX));
+    assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5));
+    assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5));
+    assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0));
+    assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5));
+    assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE));
+    assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm()));
+    assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm()));
+    assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0));
+    assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0));
+    assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm()));
+    assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm()));
+    assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE));
+    assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5));
+    assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0));
+    assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5));
+    assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5));
+    assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX));
+    assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY));
+    assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan()));
+    assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan()));
+
+    assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan()));
+    assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan()));
+    assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY));
+    assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX));
+    assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5));
+    assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5));
+    assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0));
+    assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5));
+    assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE));
+    assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm()));
+    assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm()));
+    assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0));
+    assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0));
+    assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm()));
+    assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm()));
+    assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE));
+    assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5));
+    assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0));
+    assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5));
+    assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5));
+    assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX));
+    assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY));
+    assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan()));
+
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm()));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm()));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm()));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm()));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan()));
+
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm()));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm()));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm()));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm()));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
+}
index f09fc8d790b28faade6c3d0a2193263d32b07a42..bd094bdb55dc343da3c1eb033cd52aed2ff30f7c 100644 (file)
@@ -11,6 +11,9 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 #![allow(missing_docs)]
 
+#[cfg(test)]
+mod tests;
+
 #[cfg(not(test))]
 use crate::intrinsics;
 #[cfg(not(test))]
@@ -936,762 +939,3 @@ fn log_wrapper<F: Fn(f64) -> f64>(self, log_fn: F) -> f64 {
         }
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use crate::f64::consts;
-    use crate::num::FpCategory as Fp;
-    use crate::num::*;
-
-    #[test]
-    fn test_num_f64() {
-        test_num(10f64, 2f64);
-    }
-
-    #[test]
-    fn test_min_nan() {
-        assert_eq!(f64::NAN.min(2.0), 2.0);
-        assert_eq!(2.0f64.min(f64::NAN), 2.0);
-    }
-
-    #[test]
-    fn test_max_nan() {
-        assert_eq!(f64::NAN.max(2.0), 2.0);
-        assert_eq!(2.0f64.max(f64::NAN), 2.0);
-    }
-
-    #[test]
-    fn test_nan() {
-        let nan: f64 = f64::NAN;
-        assert!(nan.is_nan());
-        assert!(!nan.is_infinite());
-        assert!(!nan.is_finite());
-        assert!(!nan.is_normal());
-        assert!(nan.is_sign_positive());
-        assert!(!nan.is_sign_negative());
-        assert_eq!(Fp::Nan, nan.classify());
-    }
-
-    #[test]
-    fn test_infinity() {
-        let inf: f64 = f64::INFINITY;
-        assert!(inf.is_infinite());
-        assert!(!inf.is_finite());
-        assert!(inf.is_sign_positive());
-        assert!(!inf.is_sign_negative());
-        assert!(!inf.is_nan());
-        assert!(!inf.is_normal());
-        assert_eq!(Fp::Infinite, inf.classify());
-    }
-
-    #[test]
-    fn test_neg_infinity() {
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert!(neg_inf.is_infinite());
-        assert!(!neg_inf.is_finite());
-        assert!(!neg_inf.is_sign_positive());
-        assert!(neg_inf.is_sign_negative());
-        assert!(!neg_inf.is_nan());
-        assert!(!neg_inf.is_normal());
-        assert_eq!(Fp::Infinite, neg_inf.classify());
-    }
-
-    #[test]
-    fn test_zero() {
-        let zero: f64 = 0.0f64;
-        assert_eq!(0.0, zero);
-        assert!(!zero.is_infinite());
-        assert!(zero.is_finite());
-        assert!(zero.is_sign_positive());
-        assert!(!zero.is_sign_negative());
-        assert!(!zero.is_nan());
-        assert!(!zero.is_normal());
-        assert_eq!(Fp::Zero, zero.classify());
-    }
-
-    #[test]
-    fn test_neg_zero() {
-        let neg_zero: f64 = -0.0;
-        assert_eq!(0.0, neg_zero);
-        assert!(!neg_zero.is_infinite());
-        assert!(neg_zero.is_finite());
-        assert!(!neg_zero.is_sign_positive());
-        assert!(neg_zero.is_sign_negative());
-        assert!(!neg_zero.is_nan());
-        assert!(!neg_zero.is_normal());
-        assert_eq!(Fp::Zero, neg_zero.classify());
-    }
-
-    #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
-    #[test]
-    fn test_one() {
-        let one: f64 = 1.0f64;
-        assert_eq!(1.0, one);
-        assert!(!one.is_infinite());
-        assert!(one.is_finite());
-        assert!(one.is_sign_positive());
-        assert!(!one.is_sign_negative());
-        assert!(!one.is_nan());
-        assert!(one.is_normal());
-        assert_eq!(Fp::Normal, one.classify());
-    }
-
-    #[test]
-    fn test_is_nan() {
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert!(nan.is_nan());
-        assert!(!0.0f64.is_nan());
-        assert!(!5.3f64.is_nan());
-        assert!(!(-10.732f64).is_nan());
-        assert!(!inf.is_nan());
-        assert!(!neg_inf.is_nan());
-    }
-
-    #[test]
-    fn test_is_infinite() {
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert!(!nan.is_infinite());
-        assert!(inf.is_infinite());
-        assert!(neg_inf.is_infinite());
-        assert!(!0.0f64.is_infinite());
-        assert!(!42.8f64.is_infinite());
-        assert!(!(-109.2f64).is_infinite());
-    }
-
-    #[test]
-    fn test_is_finite() {
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert!(!nan.is_finite());
-        assert!(!inf.is_finite());
-        assert!(!neg_inf.is_finite());
-        assert!(0.0f64.is_finite());
-        assert!(42.8f64.is_finite());
-        assert!((-109.2f64).is_finite());
-    }
-
-    #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
-    #[test]
-    fn test_is_normal() {
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        let zero: f64 = 0.0f64;
-        let neg_zero: f64 = -0.0;
-        assert!(!nan.is_normal());
-        assert!(!inf.is_normal());
-        assert!(!neg_inf.is_normal());
-        assert!(!zero.is_normal());
-        assert!(!neg_zero.is_normal());
-        assert!(1f64.is_normal());
-        assert!(1e-307f64.is_normal());
-        assert!(!1e-308f64.is_normal());
-    }
-
-    #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
-    #[test]
-    fn test_classify() {
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        let zero: f64 = 0.0f64;
-        let neg_zero: f64 = -0.0;
-        assert_eq!(nan.classify(), Fp::Nan);
-        assert_eq!(inf.classify(), Fp::Infinite);
-        assert_eq!(neg_inf.classify(), Fp::Infinite);
-        assert_eq!(zero.classify(), Fp::Zero);
-        assert_eq!(neg_zero.classify(), Fp::Zero);
-        assert_eq!(1e-307f64.classify(), Fp::Normal);
-        assert_eq!(1e-308f64.classify(), Fp::Subnormal);
-    }
-
-    #[test]
-    fn test_floor() {
-        assert_approx_eq!(1.0f64.floor(), 1.0f64);
-        assert_approx_eq!(1.3f64.floor(), 1.0f64);
-        assert_approx_eq!(1.5f64.floor(), 1.0f64);
-        assert_approx_eq!(1.7f64.floor(), 1.0f64);
-        assert_approx_eq!(0.0f64.floor(), 0.0f64);
-        assert_approx_eq!((-0.0f64).floor(), -0.0f64);
-        assert_approx_eq!((-1.0f64).floor(), -1.0f64);
-        assert_approx_eq!((-1.3f64).floor(), -2.0f64);
-        assert_approx_eq!((-1.5f64).floor(), -2.0f64);
-        assert_approx_eq!((-1.7f64).floor(), -2.0f64);
-    }
-
-    #[test]
-    fn test_ceil() {
-        assert_approx_eq!(1.0f64.ceil(), 1.0f64);
-        assert_approx_eq!(1.3f64.ceil(), 2.0f64);
-        assert_approx_eq!(1.5f64.ceil(), 2.0f64);
-        assert_approx_eq!(1.7f64.ceil(), 2.0f64);
-        assert_approx_eq!(0.0f64.ceil(), 0.0f64);
-        assert_approx_eq!((-0.0f64).ceil(), -0.0f64);
-        assert_approx_eq!((-1.0f64).ceil(), -1.0f64);
-        assert_approx_eq!((-1.3f64).ceil(), -1.0f64);
-        assert_approx_eq!((-1.5f64).ceil(), -1.0f64);
-        assert_approx_eq!((-1.7f64).ceil(), -1.0f64);
-    }
-
-    #[test]
-    fn test_round() {
-        assert_approx_eq!(1.0f64.round(), 1.0f64);
-        assert_approx_eq!(1.3f64.round(), 1.0f64);
-        assert_approx_eq!(1.5f64.round(), 2.0f64);
-        assert_approx_eq!(1.7f64.round(), 2.0f64);
-        assert_approx_eq!(0.0f64.round(), 0.0f64);
-        assert_approx_eq!((-0.0f64).round(), -0.0f64);
-        assert_approx_eq!((-1.0f64).round(), -1.0f64);
-        assert_approx_eq!((-1.3f64).round(), -1.0f64);
-        assert_approx_eq!((-1.5f64).round(), -2.0f64);
-        assert_approx_eq!((-1.7f64).round(), -2.0f64);
-    }
-
-    #[test]
-    fn test_trunc() {
-        assert_approx_eq!(1.0f64.trunc(), 1.0f64);
-        assert_approx_eq!(1.3f64.trunc(), 1.0f64);
-        assert_approx_eq!(1.5f64.trunc(), 1.0f64);
-        assert_approx_eq!(1.7f64.trunc(), 1.0f64);
-        assert_approx_eq!(0.0f64.trunc(), 0.0f64);
-        assert_approx_eq!((-0.0f64).trunc(), -0.0f64);
-        assert_approx_eq!((-1.0f64).trunc(), -1.0f64);
-        assert_approx_eq!((-1.3f64).trunc(), -1.0f64);
-        assert_approx_eq!((-1.5f64).trunc(), -1.0f64);
-        assert_approx_eq!((-1.7f64).trunc(), -1.0f64);
-    }
-
-    #[test]
-    fn test_fract() {
-        assert_approx_eq!(1.0f64.fract(), 0.0f64);
-        assert_approx_eq!(1.3f64.fract(), 0.3f64);
-        assert_approx_eq!(1.5f64.fract(), 0.5f64);
-        assert_approx_eq!(1.7f64.fract(), 0.7f64);
-        assert_approx_eq!(0.0f64.fract(), 0.0f64);
-        assert_approx_eq!((-0.0f64).fract(), -0.0f64);
-        assert_approx_eq!((-1.0f64).fract(), -0.0f64);
-        assert_approx_eq!((-1.3f64).fract(), -0.3f64);
-        assert_approx_eq!((-1.5f64).fract(), -0.5f64);
-        assert_approx_eq!((-1.7f64).fract(), -0.7f64);
-    }
-
-    #[test]
-    fn test_abs() {
-        assert_eq!(f64::INFINITY.abs(), f64::INFINITY);
-        assert_eq!(1f64.abs(), 1f64);
-        assert_eq!(0f64.abs(), 0f64);
-        assert_eq!((-0f64).abs(), 0f64);
-        assert_eq!((-1f64).abs(), 1f64);
-        assert_eq!(f64::NEG_INFINITY.abs(), f64::INFINITY);
-        assert_eq!((1f64 / f64::NEG_INFINITY).abs(), 0f64);
-        assert!(f64::NAN.abs().is_nan());
-    }
-
-    #[test]
-    fn test_signum() {
-        assert_eq!(f64::INFINITY.signum(), 1f64);
-        assert_eq!(1f64.signum(), 1f64);
-        assert_eq!(0f64.signum(), 1f64);
-        assert_eq!((-0f64).signum(), -1f64);
-        assert_eq!((-1f64).signum(), -1f64);
-        assert_eq!(f64::NEG_INFINITY.signum(), -1f64);
-        assert_eq!((1f64 / f64::NEG_INFINITY).signum(), -1f64);
-        assert!(f64::NAN.signum().is_nan());
-    }
-
-    #[test]
-    fn test_is_sign_positive() {
-        assert!(f64::INFINITY.is_sign_positive());
-        assert!(1f64.is_sign_positive());
-        assert!(0f64.is_sign_positive());
-        assert!(!(-0f64).is_sign_positive());
-        assert!(!(-1f64).is_sign_positive());
-        assert!(!f64::NEG_INFINITY.is_sign_positive());
-        assert!(!(1f64 / f64::NEG_INFINITY).is_sign_positive());
-        assert!(f64::NAN.is_sign_positive());
-        assert!(!(-f64::NAN).is_sign_positive());
-    }
-
-    #[test]
-    fn test_is_sign_negative() {
-        assert!(!f64::INFINITY.is_sign_negative());
-        assert!(!1f64.is_sign_negative());
-        assert!(!0f64.is_sign_negative());
-        assert!((-0f64).is_sign_negative());
-        assert!((-1f64).is_sign_negative());
-        assert!(f64::NEG_INFINITY.is_sign_negative());
-        assert!((1f64 / f64::NEG_INFINITY).is_sign_negative());
-        assert!(!f64::NAN.is_sign_negative());
-        assert!((-f64::NAN).is_sign_negative());
-    }
-
-    #[test]
-    fn test_mul_add() {
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05);
-        assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65);
-        assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2);
-        assert_approx_eq!(3.4f64.mul_add(-0.0, 5.6), 5.6);
-        assert!(nan.mul_add(7.8, 9.0).is_nan());
-        assert_eq!(inf.mul_add(7.8, 9.0), inf);
-        assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
-        assert_eq!(8.9f64.mul_add(inf, 3.2), inf);
-        assert_eq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf);
-    }
-
-    #[test]
-    fn test_recip() {
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert_eq!(1.0f64.recip(), 1.0);
-        assert_eq!(2.0f64.recip(), 0.5);
-        assert_eq!((-0.4f64).recip(), -2.5);
-        assert_eq!(0.0f64.recip(), inf);
-        assert!(nan.recip().is_nan());
-        assert_eq!(inf.recip(), 0.0);
-        assert_eq!(neg_inf.recip(), 0.0);
-    }
-
-    #[test]
-    fn test_powi() {
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert_eq!(1.0f64.powi(1), 1.0);
-        assert_approx_eq!((-3.1f64).powi(2), 9.61);
-        assert_approx_eq!(5.9f64.powi(-2), 0.028727);
-        assert_eq!(8.3f64.powi(0), 1.0);
-        assert!(nan.powi(2).is_nan());
-        assert_eq!(inf.powi(3), inf);
-        assert_eq!(neg_inf.powi(2), inf);
-    }
-
-    #[test]
-    fn test_powf() {
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert_eq!(1.0f64.powf(1.0), 1.0);
-        assert_approx_eq!(3.4f64.powf(4.5), 246.408183);
-        assert_approx_eq!(2.7f64.powf(-3.2), 0.041652);
-        assert_approx_eq!((-3.1f64).powf(2.0), 9.61);
-        assert_approx_eq!(5.9f64.powf(-2.0), 0.028727);
-        assert_eq!(8.3f64.powf(0.0), 1.0);
-        assert!(nan.powf(2.0).is_nan());
-        assert_eq!(inf.powf(2.0), inf);
-        assert_eq!(neg_inf.powf(3.0), neg_inf);
-    }
-
-    #[test]
-    fn test_sqrt_domain() {
-        assert!(f64::NAN.sqrt().is_nan());
-        assert!(f64::NEG_INFINITY.sqrt().is_nan());
-        assert!((-1.0f64).sqrt().is_nan());
-        assert_eq!((-0.0f64).sqrt(), -0.0);
-        assert_eq!(0.0f64.sqrt(), 0.0);
-        assert_eq!(1.0f64.sqrt(), 1.0);
-        assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY);
-    }
-
-    #[test]
-    fn test_exp() {
-        assert_eq!(1.0, 0.0f64.exp());
-        assert_approx_eq!(2.718282, 1.0f64.exp());
-        assert_approx_eq!(148.413159, 5.0f64.exp());
-
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        let nan: f64 = f64::NAN;
-        assert_eq!(inf, inf.exp());
-        assert_eq!(0.0, neg_inf.exp());
-        assert!(nan.exp().is_nan());
-    }
-
-    #[test]
-    fn test_exp2() {
-        assert_eq!(32.0, 5.0f64.exp2());
-        assert_eq!(1.0, 0.0f64.exp2());
-
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        let nan: f64 = f64::NAN;
-        assert_eq!(inf, inf.exp2());
-        assert_eq!(0.0, neg_inf.exp2());
-        assert!(nan.exp2().is_nan());
-    }
-
-    #[test]
-    fn test_ln() {
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert_approx_eq!(1.0f64.exp().ln(), 1.0);
-        assert!(nan.ln().is_nan());
-        assert_eq!(inf.ln(), inf);
-        assert!(neg_inf.ln().is_nan());
-        assert!((-2.3f64).ln().is_nan());
-        assert_eq!((-0.0f64).ln(), neg_inf);
-        assert_eq!(0.0f64.ln(), neg_inf);
-        assert_approx_eq!(4.0f64.ln(), 1.386294);
-    }
-
-    #[test]
-    fn test_log() {
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert_eq!(10.0f64.log(10.0), 1.0);
-        assert_approx_eq!(2.3f64.log(3.5), 0.664858);
-        assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0);
-        assert!(1.0f64.log(1.0).is_nan());
-        assert!(1.0f64.log(-13.9).is_nan());
-        assert!(nan.log(2.3).is_nan());
-        assert_eq!(inf.log(10.0), inf);
-        assert!(neg_inf.log(8.8).is_nan());
-        assert!((-2.3f64).log(0.1).is_nan());
-        assert_eq!((-0.0f64).log(2.0), neg_inf);
-        assert_eq!(0.0f64.log(7.0), neg_inf);
-    }
-
-    #[test]
-    fn test_log2() {
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert_approx_eq!(10.0f64.log2(), 3.321928);
-        assert_approx_eq!(2.3f64.log2(), 1.201634);
-        assert_approx_eq!(1.0f64.exp().log2(), 1.442695);
-        assert!(nan.log2().is_nan());
-        assert_eq!(inf.log2(), inf);
-        assert!(neg_inf.log2().is_nan());
-        assert!((-2.3f64).log2().is_nan());
-        assert_eq!((-0.0f64).log2(), neg_inf);
-        assert_eq!(0.0f64.log2(), neg_inf);
-    }
-
-    #[test]
-    fn test_log10() {
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert_eq!(10.0f64.log10(), 1.0);
-        assert_approx_eq!(2.3f64.log10(), 0.361728);
-        assert_approx_eq!(1.0f64.exp().log10(), 0.434294);
-        assert_eq!(1.0f64.log10(), 0.0);
-        assert!(nan.log10().is_nan());
-        assert_eq!(inf.log10(), inf);
-        assert!(neg_inf.log10().is_nan());
-        assert!((-2.3f64).log10().is_nan());
-        assert_eq!((-0.0f64).log10(), neg_inf);
-        assert_eq!(0.0f64.log10(), neg_inf);
-    }
-
-    #[test]
-    fn test_to_degrees() {
-        let pi: f64 = consts::PI;
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert_eq!(0.0f64.to_degrees(), 0.0);
-        assert_approx_eq!((-5.8f64).to_degrees(), -332.315521);
-        assert_eq!(pi.to_degrees(), 180.0);
-        assert!(nan.to_degrees().is_nan());
-        assert_eq!(inf.to_degrees(), inf);
-        assert_eq!(neg_inf.to_degrees(), neg_inf);
-    }
-
-    #[test]
-    fn test_to_radians() {
-        let pi: f64 = consts::PI;
-        let nan: f64 = f64::NAN;
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        assert_eq!(0.0f64.to_radians(), 0.0);
-        assert_approx_eq!(154.6f64.to_radians(), 2.698279);
-        assert_approx_eq!((-332.31f64).to_radians(), -5.799903);
-        assert_eq!(180.0f64.to_radians(), pi);
-        assert!(nan.to_radians().is_nan());
-        assert_eq!(inf.to_radians(), inf);
-        assert_eq!(neg_inf.to_radians(), neg_inf);
-    }
-
-    #[test]
-    fn test_asinh() {
-        assert_eq!(0.0f64.asinh(), 0.0f64);
-        assert_eq!((-0.0f64).asinh(), -0.0f64);
-
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        let nan: f64 = f64::NAN;
-        assert_eq!(inf.asinh(), inf);
-        assert_eq!(neg_inf.asinh(), neg_inf);
-        assert!(nan.asinh().is_nan());
-        assert!((-0.0f64).asinh().is_sign_negative());
-        // issue 63271
-        assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
-        assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
-        // regression test for the catastrophic cancellation fixed in 72486
-        assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083);
-    }
-
-    #[test]
-    fn test_acosh() {
-        assert_eq!(1.0f64.acosh(), 0.0f64);
-        assert!(0.999f64.acosh().is_nan());
-
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        let nan: f64 = f64::NAN;
-        assert_eq!(inf.acosh(), inf);
-        assert!(neg_inf.acosh().is_nan());
-        assert!(nan.acosh().is_nan());
-        assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64);
-        assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64);
-    }
-
-    #[test]
-    fn test_atanh() {
-        assert_eq!(0.0f64.atanh(), 0.0f64);
-        assert_eq!((-0.0f64).atanh(), -0.0f64);
-
-        let inf: f64 = f64::INFINITY;
-        let neg_inf: f64 = f64::NEG_INFINITY;
-        let nan: f64 = f64::NAN;
-        assert_eq!(1.0f64.atanh(), inf);
-        assert_eq!((-1.0f64).atanh(), neg_inf);
-        assert!(2f64.atanh().atanh().is_nan());
-        assert!((-2f64).atanh().atanh().is_nan());
-        assert!(inf.atanh().is_nan());
-        assert!(neg_inf.atanh().is_nan());
-        assert!(nan.atanh().is_nan());
-        assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
-        assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64);
-    }
-
-    #[test]
-    fn test_real_consts() {
-        use super::consts;
-        let pi: f64 = consts::PI;
-        let frac_pi_2: f64 = consts::FRAC_PI_2;
-        let frac_pi_3: f64 = consts::FRAC_PI_3;
-        let frac_pi_4: f64 = consts::FRAC_PI_4;
-        let frac_pi_6: f64 = consts::FRAC_PI_6;
-        let frac_pi_8: f64 = consts::FRAC_PI_8;
-        let frac_1_pi: f64 = consts::FRAC_1_PI;
-        let frac_2_pi: f64 = consts::FRAC_2_PI;
-        let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI;
-        let sqrt2: f64 = consts::SQRT_2;
-        let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2;
-        let e: f64 = consts::E;
-        let log2_e: f64 = consts::LOG2_E;
-        let log10_e: f64 = consts::LOG10_E;
-        let ln_2: f64 = consts::LN_2;
-        let ln_10: f64 = consts::LN_10;
-
-        assert_approx_eq!(frac_pi_2, pi / 2f64);
-        assert_approx_eq!(frac_pi_3, pi / 3f64);
-        assert_approx_eq!(frac_pi_4, pi / 4f64);
-        assert_approx_eq!(frac_pi_6, pi / 6f64);
-        assert_approx_eq!(frac_pi_8, pi / 8f64);
-        assert_approx_eq!(frac_1_pi, 1f64 / pi);
-        assert_approx_eq!(frac_2_pi, 2f64 / pi);
-        assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt());
-        assert_approx_eq!(sqrt2, 2f64.sqrt());
-        assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt());
-        assert_approx_eq!(log2_e, e.log2());
-        assert_approx_eq!(log10_e, e.log10());
-        assert_approx_eq!(ln_2, 2f64.ln());
-        assert_approx_eq!(ln_10, 10f64.ln());
-    }
-
-    #[test]
-    fn test_float_bits_conv() {
-        assert_eq!((1f64).to_bits(), 0x3ff0000000000000);
-        assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
-        assert_eq!((1337f64).to_bits(), 0x4094e40000000000);
-        assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000);
-        assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0);
-        assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5);
-        assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0);
-        assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25);
-
-        // Check that NaNs roundtrip their bits regardless of signaling-ness
-        // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
-        let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
-        let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
-        assert!(f64::from_bits(masked_nan1).is_nan());
-        assert!(f64::from_bits(masked_nan2).is_nan());
-
-        assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1);
-        assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2);
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_clamp_min_greater_than_max() {
-        let _ = 1.0f64.clamp(3.0, 1.0);
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_clamp_min_is_nan() {
-        let _ = 1.0f64.clamp(f64::NAN, 1.0);
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_clamp_max_is_nan() {
-        let _ = 1.0f64.clamp(3.0, f64::NAN);
-    }
-
-    #[test]
-    fn test_total_cmp() {
-        use core::cmp::Ordering;
-
-        fn quiet_bit_mask() -> u64 {
-            1 << (f64::MANTISSA_DIGITS - 2)
-        }
-
-        fn min_subnorm() -> f64 {
-            f64::MIN_POSITIVE / f64::powf(2.0, f64::MANTISSA_DIGITS as f64 - 1.0)
-        }
-
-        fn max_subnorm() -> f64 {
-            f64::MIN_POSITIVE - min_subnorm()
-        }
-
-        fn q_nan() -> f64 {
-            f64::from_bits(f64::NAN.to_bits() | quiet_bit_mask())
-        }
-
-        fn s_nan() -> f64 {
-            f64::from_bits((f64::NAN.to_bits() & !quiet_bit_mask()) + 42)
-        }
-
-        assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan()));
-        assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan()));
-        assert_eq!(Ordering::Equal, (-f64::INFINITY).total_cmp(&-f64::INFINITY));
-        assert_eq!(Ordering::Equal, (-f64::MAX).total_cmp(&-f64::MAX));
-        assert_eq!(Ordering::Equal, (-2.5_f64).total_cmp(&-2.5));
-        assert_eq!(Ordering::Equal, (-1.0_f64).total_cmp(&-1.0));
-        assert_eq!(Ordering::Equal, (-1.5_f64).total_cmp(&-1.5));
-        assert_eq!(Ordering::Equal, (-0.5_f64).total_cmp(&-0.5));
-        assert_eq!(Ordering::Equal, (-f64::MIN_POSITIVE).total_cmp(&-f64::MIN_POSITIVE));
-        assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm()));
-        assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm()));
-        assert_eq!(Ordering::Equal, (-0.0_f64).total_cmp(&-0.0));
-        assert_eq!(Ordering::Equal, 0.0_f64.total_cmp(&0.0));
-        assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm()));
-        assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm()));
-        assert_eq!(Ordering::Equal, f64::MIN_POSITIVE.total_cmp(&f64::MIN_POSITIVE));
-        assert_eq!(Ordering::Equal, 0.5_f64.total_cmp(&0.5));
-        assert_eq!(Ordering::Equal, 1.0_f64.total_cmp(&1.0));
-        assert_eq!(Ordering::Equal, 1.5_f64.total_cmp(&1.5));
-        assert_eq!(Ordering::Equal, 2.5_f64.total_cmp(&2.5));
-        assert_eq!(Ordering::Equal, f64::MAX.total_cmp(&f64::MAX));
-        assert_eq!(Ordering::Equal, f64::INFINITY.total_cmp(&f64::INFINITY));
-        assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan()));
-        assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan()));
-
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY));
-        assert_eq!(Ordering::Less, (-f64::INFINITY).total_cmp(&-f64::MAX));
-        assert_eq!(Ordering::Less, (-f64::MAX).total_cmp(&-2.5));
-        assert_eq!(Ordering::Less, (-2.5_f64).total_cmp(&-1.5));
-        assert_eq!(Ordering::Less, (-1.5_f64).total_cmp(&-1.0));
-        assert_eq!(Ordering::Less, (-1.0_f64).total_cmp(&-0.5));
-        assert_eq!(Ordering::Less, (-0.5_f64).total_cmp(&-f64::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, (-f64::MIN_POSITIVE).total_cmp(&-max_subnorm()));
-        assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm()));
-        assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0));
-        assert_eq!(Ordering::Less, (-0.0_f64).total_cmp(&0.0));
-        assert_eq!(Ordering::Less, 0.0_f64.total_cmp(&min_subnorm()));
-        assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm()));
-        assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f64::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, f64::MIN_POSITIVE.total_cmp(&0.5));
-        assert_eq!(Ordering::Less, 0.5_f64.total_cmp(&1.0));
-        assert_eq!(Ordering::Less, 1.0_f64.total_cmp(&1.5));
-        assert_eq!(Ordering::Less, 1.5_f64.total_cmp(&2.5));
-        assert_eq!(Ordering::Less, 2.5_f64.total_cmp(&f64::MAX));
-        assert_eq!(Ordering::Less, f64::MAX.total_cmp(&f64::INFINITY));
-        assert_eq!(Ordering::Less, f64::INFINITY.total_cmp(&s_nan()));
-        assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan()));
-
-        assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan()));
-        assert_eq!(Ordering::Greater, (-f64::INFINITY).total_cmp(&-s_nan()));
-        assert_eq!(Ordering::Greater, (-f64::MAX).total_cmp(&-f64::INFINITY));
-        assert_eq!(Ordering::Greater, (-2.5_f64).total_cmp(&-f64::MAX));
-        assert_eq!(Ordering::Greater, (-1.5_f64).total_cmp(&-2.5));
-        assert_eq!(Ordering::Greater, (-1.0_f64).total_cmp(&-1.5));
-        assert_eq!(Ordering::Greater, (-0.5_f64).total_cmp(&-1.0));
-        assert_eq!(Ordering::Greater, (-f64::MIN_POSITIVE).total_cmp(&-0.5));
-        assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f64::MIN_POSITIVE));
-        assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm()));
-        assert_eq!(Ordering::Greater, (-0.0_f64).total_cmp(&-min_subnorm()));
-        assert_eq!(Ordering::Greater, 0.0_f64.total_cmp(&-0.0));
-        assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0));
-        assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm()));
-        assert_eq!(Ordering::Greater, f64::MIN_POSITIVE.total_cmp(&max_subnorm()));
-        assert_eq!(Ordering::Greater, 0.5_f64.total_cmp(&f64::MIN_POSITIVE));
-        assert_eq!(Ordering::Greater, 1.0_f64.total_cmp(&0.5));
-        assert_eq!(Ordering::Greater, 1.5_f64.total_cmp(&1.0));
-        assert_eq!(Ordering::Greater, 2.5_f64.total_cmp(&1.5));
-        assert_eq!(Ordering::Greater, f64::MAX.total_cmp(&2.5));
-        assert_eq!(Ordering::Greater, f64::INFINITY.total_cmp(&f64::MAX));
-        assert_eq!(Ordering::Greater, s_nan().total_cmp(&f64::INFINITY));
-        assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan()));
-
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::INFINITY));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MAX));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm()));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm()));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm()));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm()));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MAX));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::INFINITY));
-        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan()));
-
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MAX));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm()));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm()));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm()));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm()));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MAX));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY));
-        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
-    }
-}
diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs
new file mode 100644 (file)
index 0000000..5c163cf
--- /dev/null
@@ -0,0 +1,755 @@
+use crate::f64::consts;
+use crate::num::FpCategory as Fp;
+use crate::num::*;
+
+#[test]
+fn test_num_f64() {
+    test_num(10f64, 2f64);
+}
+
+#[test]
+fn test_min_nan() {
+    assert_eq!(f64::NAN.min(2.0), 2.0);
+    assert_eq!(2.0f64.min(f64::NAN), 2.0);
+}
+
+#[test]
+fn test_max_nan() {
+    assert_eq!(f64::NAN.max(2.0), 2.0);
+    assert_eq!(2.0f64.max(f64::NAN), 2.0);
+}
+
+#[test]
+fn test_nan() {
+    let nan: f64 = f64::NAN;
+    assert!(nan.is_nan());
+    assert!(!nan.is_infinite());
+    assert!(!nan.is_finite());
+    assert!(!nan.is_normal());
+    assert!(nan.is_sign_positive());
+    assert!(!nan.is_sign_negative());
+    assert_eq!(Fp::Nan, nan.classify());
+}
+
+#[test]
+fn test_infinity() {
+    let inf: f64 = f64::INFINITY;
+    assert!(inf.is_infinite());
+    assert!(!inf.is_finite());
+    assert!(inf.is_sign_positive());
+    assert!(!inf.is_sign_negative());
+    assert!(!inf.is_nan());
+    assert!(!inf.is_normal());
+    assert_eq!(Fp::Infinite, inf.classify());
+}
+
+#[test]
+fn test_neg_infinity() {
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert!(neg_inf.is_infinite());
+    assert!(!neg_inf.is_finite());
+    assert!(!neg_inf.is_sign_positive());
+    assert!(neg_inf.is_sign_negative());
+    assert!(!neg_inf.is_nan());
+    assert!(!neg_inf.is_normal());
+    assert_eq!(Fp::Infinite, neg_inf.classify());
+}
+
+#[test]
+fn test_zero() {
+    let zero: f64 = 0.0f64;
+    assert_eq!(0.0, zero);
+    assert!(!zero.is_infinite());
+    assert!(zero.is_finite());
+    assert!(zero.is_sign_positive());
+    assert!(!zero.is_sign_negative());
+    assert!(!zero.is_nan());
+    assert!(!zero.is_normal());
+    assert_eq!(Fp::Zero, zero.classify());
+}
+
+#[test]
+fn test_neg_zero() {
+    let neg_zero: f64 = -0.0;
+    assert_eq!(0.0, neg_zero);
+    assert!(!neg_zero.is_infinite());
+    assert!(neg_zero.is_finite());
+    assert!(!neg_zero.is_sign_positive());
+    assert!(neg_zero.is_sign_negative());
+    assert!(!neg_zero.is_nan());
+    assert!(!neg_zero.is_normal());
+    assert_eq!(Fp::Zero, neg_zero.classify());
+}
+
+#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
+#[test]
+fn test_one() {
+    let one: f64 = 1.0f64;
+    assert_eq!(1.0, one);
+    assert!(!one.is_infinite());
+    assert!(one.is_finite());
+    assert!(one.is_sign_positive());
+    assert!(!one.is_sign_negative());
+    assert!(!one.is_nan());
+    assert!(one.is_normal());
+    assert_eq!(Fp::Normal, one.classify());
+}
+
+#[test]
+fn test_is_nan() {
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert!(nan.is_nan());
+    assert!(!0.0f64.is_nan());
+    assert!(!5.3f64.is_nan());
+    assert!(!(-10.732f64).is_nan());
+    assert!(!inf.is_nan());
+    assert!(!neg_inf.is_nan());
+}
+
+#[test]
+fn test_is_infinite() {
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert!(!nan.is_infinite());
+    assert!(inf.is_infinite());
+    assert!(neg_inf.is_infinite());
+    assert!(!0.0f64.is_infinite());
+    assert!(!42.8f64.is_infinite());
+    assert!(!(-109.2f64).is_infinite());
+}
+
+#[test]
+fn test_is_finite() {
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert!(!nan.is_finite());
+    assert!(!inf.is_finite());
+    assert!(!neg_inf.is_finite());
+    assert!(0.0f64.is_finite());
+    assert!(42.8f64.is_finite());
+    assert!((-109.2f64).is_finite());
+}
+
+#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
+#[test]
+fn test_is_normal() {
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    let zero: f64 = 0.0f64;
+    let neg_zero: f64 = -0.0;
+    assert!(!nan.is_normal());
+    assert!(!inf.is_normal());
+    assert!(!neg_inf.is_normal());
+    assert!(!zero.is_normal());
+    assert!(!neg_zero.is_normal());
+    assert!(1f64.is_normal());
+    assert!(1e-307f64.is_normal());
+    assert!(!1e-308f64.is_normal());
+}
+
+#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
+#[test]
+fn test_classify() {
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    let zero: f64 = 0.0f64;
+    let neg_zero: f64 = -0.0;
+    assert_eq!(nan.classify(), Fp::Nan);
+    assert_eq!(inf.classify(), Fp::Infinite);
+    assert_eq!(neg_inf.classify(), Fp::Infinite);
+    assert_eq!(zero.classify(), Fp::Zero);
+    assert_eq!(neg_zero.classify(), Fp::Zero);
+    assert_eq!(1e-307f64.classify(), Fp::Normal);
+    assert_eq!(1e-308f64.classify(), Fp::Subnormal);
+}
+
+#[test]
+fn test_floor() {
+    assert_approx_eq!(1.0f64.floor(), 1.0f64);
+    assert_approx_eq!(1.3f64.floor(), 1.0f64);
+    assert_approx_eq!(1.5f64.floor(), 1.0f64);
+    assert_approx_eq!(1.7f64.floor(), 1.0f64);
+    assert_approx_eq!(0.0f64.floor(), 0.0f64);
+    assert_approx_eq!((-0.0f64).floor(), -0.0f64);
+    assert_approx_eq!((-1.0f64).floor(), -1.0f64);
+    assert_approx_eq!((-1.3f64).floor(), -2.0f64);
+    assert_approx_eq!((-1.5f64).floor(), -2.0f64);
+    assert_approx_eq!((-1.7f64).floor(), -2.0f64);
+}
+
+#[test]
+fn test_ceil() {
+    assert_approx_eq!(1.0f64.ceil(), 1.0f64);
+    assert_approx_eq!(1.3f64.ceil(), 2.0f64);
+    assert_approx_eq!(1.5f64.ceil(), 2.0f64);
+    assert_approx_eq!(1.7f64.ceil(), 2.0f64);
+    assert_approx_eq!(0.0f64.ceil(), 0.0f64);
+    assert_approx_eq!((-0.0f64).ceil(), -0.0f64);
+    assert_approx_eq!((-1.0f64).ceil(), -1.0f64);
+    assert_approx_eq!((-1.3f64).ceil(), -1.0f64);
+    assert_approx_eq!((-1.5f64).ceil(), -1.0f64);
+    assert_approx_eq!((-1.7f64).ceil(), -1.0f64);
+}
+
+#[test]
+fn test_round() {
+    assert_approx_eq!(1.0f64.round(), 1.0f64);
+    assert_approx_eq!(1.3f64.round(), 1.0f64);
+    assert_approx_eq!(1.5f64.round(), 2.0f64);
+    assert_approx_eq!(1.7f64.round(), 2.0f64);
+    assert_approx_eq!(0.0f64.round(), 0.0f64);
+    assert_approx_eq!((-0.0f64).round(), -0.0f64);
+    assert_approx_eq!((-1.0f64).round(), -1.0f64);
+    assert_approx_eq!((-1.3f64).round(), -1.0f64);
+    assert_approx_eq!((-1.5f64).round(), -2.0f64);
+    assert_approx_eq!((-1.7f64).round(), -2.0f64);
+}
+
+#[test]
+fn test_trunc() {
+    assert_approx_eq!(1.0f64.trunc(), 1.0f64);
+    assert_approx_eq!(1.3f64.trunc(), 1.0f64);
+    assert_approx_eq!(1.5f64.trunc(), 1.0f64);
+    assert_approx_eq!(1.7f64.trunc(), 1.0f64);
+    assert_approx_eq!(0.0f64.trunc(), 0.0f64);
+    assert_approx_eq!((-0.0f64).trunc(), -0.0f64);
+    assert_approx_eq!((-1.0f64).trunc(), -1.0f64);
+    assert_approx_eq!((-1.3f64).trunc(), -1.0f64);
+    assert_approx_eq!((-1.5f64).trunc(), -1.0f64);
+    assert_approx_eq!((-1.7f64).trunc(), -1.0f64);
+}
+
+#[test]
+fn test_fract() {
+    assert_approx_eq!(1.0f64.fract(), 0.0f64);
+    assert_approx_eq!(1.3f64.fract(), 0.3f64);
+    assert_approx_eq!(1.5f64.fract(), 0.5f64);
+    assert_approx_eq!(1.7f64.fract(), 0.7f64);
+    assert_approx_eq!(0.0f64.fract(), 0.0f64);
+    assert_approx_eq!((-0.0f64).fract(), -0.0f64);
+    assert_approx_eq!((-1.0f64).fract(), -0.0f64);
+    assert_approx_eq!((-1.3f64).fract(), -0.3f64);
+    assert_approx_eq!((-1.5f64).fract(), -0.5f64);
+    assert_approx_eq!((-1.7f64).fract(), -0.7f64);
+}
+
+#[test]
+fn test_abs() {
+    assert_eq!(f64::INFINITY.abs(), f64::INFINITY);
+    assert_eq!(1f64.abs(), 1f64);
+    assert_eq!(0f64.abs(), 0f64);
+    assert_eq!((-0f64).abs(), 0f64);
+    assert_eq!((-1f64).abs(), 1f64);
+    assert_eq!(f64::NEG_INFINITY.abs(), f64::INFINITY);
+    assert_eq!((1f64 / f64::NEG_INFINITY).abs(), 0f64);
+    assert!(f64::NAN.abs().is_nan());
+}
+
+#[test]
+fn test_signum() {
+    assert_eq!(f64::INFINITY.signum(), 1f64);
+    assert_eq!(1f64.signum(), 1f64);
+    assert_eq!(0f64.signum(), 1f64);
+    assert_eq!((-0f64).signum(), -1f64);
+    assert_eq!((-1f64).signum(), -1f64);
+    assert_eq!(f64::NEG_INFINITY.signum(), -1f64);
+    assert_eq!((1f64 / f64::NEG_INFINITY).signum(), -1f64);
+    assert!(f64::NAN.signum().is_nan());
+}
+
+#[test]
+fn test_is_sign_positive() {
+    assert!(f64::INFINITY.is_sign_positive());
+    assert!(1f64.is_sign_positive());
+    assert!(0f64.is_sign_positive());
+    assert!(!(-0f64).is_sign_positive());
+    assert!(!(-1f64).is_sign_positive());
+    assert!(!f64::NEG_INFINITY.is_sign_positive());
+    assert!(!(1f64 / f64::NEG_INFINITY).is_sign_positive());
+    assert!(f64::NAN.is_sign_positive());
+    assert!(!(-f64::NAN).is_sign_positive());
+}
+
+#[test]
+fn test_is_sign_negative() {
+    assert!(!f64::INFINITY.is_sign_negative());
+    assert!(!1f64.is_sign_negative());
+    assert!(!0f64.is_sign_negative());
+    assert!((-0f64).is_sign_negative());
+    assert!((-1f64).is_sign_negative());
+    assert!(f64::NEG_INFINITY.is_sign_negative());
+    assert!((1f64 / f64::NEG_INFINITY).is_sign_negative());
+    assert!(!f64::NAN.is_sign_negative());
+    assert!((-f64::NAN).is_sign_negative());
+}
+
+#[test]
+fn test_mul_add() {
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05);
+    assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65);
+    assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2);
+    assert_approx_eq!(3.4f64.mul_add(-0.0, 5.6), 5.6);
+    assert!(nan.mul_add(7.8, 9.0).is_nan());
+    assert_eq!(inf.mul_add(7.8, 9.0), inf);
+    assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
+    assert_eq!(8.9f64.mul_add(inf, 3.2), inf);
+    assert_eq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf);
+}
+
+#[test]
+fn test_recip() {
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert_eq!(1.0f64.recip(), 1.0);
+    assert_eq!(2.0f64.recip(), 0.5);
+    assert_eq!((-0.4f64).recip(), -2.5);
+    assert_eq!(0.0f64.recip(), inf);
+    assert!(nan.recip().is_nan());
+    assert_eq!(inf.recip(), 0.0);
+    assert_eq!(neg_inf.recip(), 0.0);
+}
+
+#[test]
+fn test_powi() {
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert_eq!(1.0f64.powi(1), 1.0);
+    assert_approx_eq!((-3.1f64).powi(2), 9.61);
+    assert_approx_eq!(5.9f64.powi(-2), 0.028727);
+    assert_eq!(8.3f64.powi(0), 1.0);
+    assert!(nan.powi(2).is_nan());
+    assert_eq!(inf.powi(3), inf);
+    assert_eq!(neg_inf.powi(2), inf);
+}
+
+#[test]
+fn test_powf() {
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert_eq!(1.0f64.powf(1.0), 1.0);
+    assert_approx_eq!(3.4f64.powf(4.5), 246.408183);
+    assert_approx_eq!(2.7f64.powf(-3.2), 0.041652);
+    assert_approx_eq!((-3.1f64).powf(2.0), 9.61);
+    assert_approx_eq!(5.9f64.powf(-2.0), 0.028727);
+    assert_eq!(8.3f64.powf(0.0), 1.0);
+    assert!(nan.powf(2.0).is_nan());
+    assert_eq!(inf.powf(2.0), inf);
+    assert_eq!(neg_inf.powf(3.0), neg_inf);
+}
+
+#[test]
+fn test_sqrt_domain() {
+    assert!(f64::NAN.sqrt().is_nan());
+    assert!(f64::NEG_INFINITY.sqrt().is_nan());
+    assert!((-1.0f64).sqrt().is_nan());
+    assert_eq!((-0.0f64).sqrt(), -0.0);
+    assert_eq!(0.0f64.sqrt(), 0.0);
+    assert_eq!(1.0f64.sqrt(), 1.0);
+    assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY);
+}
+
+#[test]
+fn test_exp() {
+    assert_eq!(1.0, 0.0f64.exp());
+    assert_approx_eq!(2.718282, 1.0f64.exp());
+    assert_approx_eq!(148.413159, 5.0f64.exp());
+
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    let nan: f64 = f64::NAN;
+    assert_eq!(inf, inf.exp());
+    assert_eq!(0.0, neg_inf.exp());
+    assert!(nan.exp().is_nan());
+}
+
+#[test]
+fn test_exp2() {
+    assert_eq!(32.0, 5.0f64.exp2());
+    assert_eq!(1.0, 0.0f64.exp2());
+
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    let nan: f64 = f64::NAN;
+    assert_eq!(inf, inf.exp2());
+    assert_eq!(0.0, neg_inf.exp2());
+    assert!(nan.exp2().is_nan());
+}
+
+#[test]
+fn test_ln() {
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert_approx_eq!(1.0f64.exp().ln(), 1.0);
+    assert!(nan.ln().is_nan());
+    assert_eq!(inf.ln(), inf);
+    assert!(neg_inf.ln().is_nan());
+    assert!((-2.3f64).ln().is_nan());
+    assert_eq!((-0.0f64).ln(), neg_inf);
+    assert_eq!(0.0f64.ln(), neg_inf);
+    assert_approx_eq!(4.0f64.ln(), 1.386294);
+}
+
+#[test]
+fn test_log() {
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert_eq!(10.0f64.log(10.0), 1.0);
+    assert_approx_eq!(2.3f64.log(3.5), 0.664858);
+    assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0);
+    assert!(1.0f64.log(1.0).is_nan());
+    assert!(1.0f64.log(-13.9).is_nan());
+    assert!(nan.log(2.3).is_nan());
+    assert_eq!(inf.log(10.0), inf);
+    assert!(neg_inf.log(8.8).is_nan());
+    assert!((-2.3f64).log(0.1).is_nan());
+    assert_eq!((-0.0f64).log(2.0), neg_inf);
+    assert_eq!(0.0f64.log(7.0), neg_inf);
+}
+
+#[test]
+fn test_log2() {
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert_approx_eq!(10.0f64.log2(), 3.321928);
+    assert_approx_eq!(2.3f64.log2(), 1.201634);
+    assert_approx_eq!(1.0f64.exp().log2(), 1.442695);
+    assert!(nan.log2().is_nan());
+    assert_eq!(inf.log2(), inf);
+    assert!(neg_inf.log2().is_nan());
+    assert!((-2.3f64).log2().is_nan());
+    assert_eq!((-0.0f64).log2(), neg_inf);
+    assert_eq!(0.0f64.log2(), neg_inf);
+}
+
+#[test]
+fn test_log10() {
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert_eq!(10.0f64.log10(), 1.0);
+    assert_approx_eq!(2.3f64.log10(), 0.361728);
+    assert_approx_eq!(1.0f64.exp().log10(), 0.434294);
+    assert_eq!(1.0f64.log10(), 0.0);
+    assert!(nan.log10().is_nan());
+    assert_eq!(inf.log10(), inf);
+    assert!(neg_inf.log10().is_nan());
+    assert!((-2.3f64).log10().is_nan());
+    assert_eq!((-0.0f64).log10(), neg_inf);
+    assert_eq!(0.0f64.log10(), neg_inf);
+}
+
+#[test]
+fn test_to_degrees() {
+    let pi: f64 = consts::PI;
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert_eq!(0.0f64.to_degrees(), 0.0);
+    assert_approx_eq!((-5.8f64).to_degrees(), -332.315521);
+    assert_eq!(pi.to_degrees(), 180.0);
+    assert!(nan.to_degrees().is_nan());
+    assert_eq!(inf.to_degrees(), inf);
+    assert_eq!(neg_inf.to_degrees(), neg_inf);
+}
+
+#[test]
+fn test_to_radians() {
+    let pi: f64 = consts::PI;
+    let nan: f64 = f64::NAN;
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    assert_eq!(0.0f64.to_radians(), 0.0);
+    assert_approx_eq!(154.6f64.to_radians(), 2.698279);
+    assert_approx_eq!((-332.31f64).to_radians(), -5.799903);
+    assert_eq!(180.0f64.to_radians(), pi);
+    assert!(nan.to_radians().is_nan());
+    assert_eq!(inf.to_radians(), inf);
+    assert_eq!(neg_inf.to_radians(), neg_inf);
+}
+
+#[test]
+fn test_asinh() {
+    assert_eq!(0.0f64.asinh(), 0.0f64);
+    assert_eq!((-0.0f64).asinh(), -0.0f64);
+
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    let nan: f64 = f64::NAN;
+    assert_eq!(inf.asinh(), inf);
+    assert_eq!(neg_inf.asinh(), neg_inf);
+    assert!(nan.asinh().is_nan());
+    assert!((-0.0f64).asinh().is_sign_negative());
+    // issue 63271
+    assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
+    assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
+    // regression test for the catastrophic cancellation fixed in 72486
+    assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083);
+}
+
+#[test]
+fn test_acosh() {
+    assert_eq!(1.0f64.acosh(), 0.0f64);
+    assert!(0.999f64.acosh().is_nan());
+
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    let nan: f64 = f64::NAN;
+    assert_eq!(inf.acosh(), inf);
+    assert!(neg_inf.acosh().is_nan());
+    assert!(nan.acosh().is_nan());
+    assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64);
+    assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64);
+}
+
+#[test]
+fn test_atanh() {
+    assert_eq!(0.0f64.atanh(), 0.0f64);
+    assert_eq!((-0.0f64).atanh(), -0.0f64);
+
+    let inf: f64 = f64::INFINITY;
+    let neg_inf: f64 = f64::NEG_INFINITY;
+    let nan: f64 = f64::NAN;
+    assert_eq!(1.0f64.atanh(), inf);
+    assert_eq!((-1.0f64).atanh(), neg_inf);
+    assert!(2f64.atanh().atanh().is_nan());
+    assert!((-2f64).atanh().atanh().is_nan());
+    assert!(inf.atanh().is_nan());
+    assert!(neg_inf.atanh().is_nan());
+    assert!(nan.atanh().is_nan());
+    assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
+    assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64);
+}
+
+#[test]
+fn test_real_consts() {
+    use super::consts;
+    let pi: f64 = consts::PI;
+    let frac_pi_2: f64 = consts::FRAC_PI_2;
+    let frac_pi_3: f64 = consts::FRAC_PI_3;
+    let frac_pi_4: f64 = consts::FRAC_PI_4;
+    let frac_pi_6: f64 = consts::FRAC_PI_6;
+    let frac_pi_8: f64 = consts::FRAC_PI_8;
+    let frac_1_pi: f64 = consts::FRAC_1_PI;
+    let frac_2_pi: f64 = consts::FRAC_2_PI;
+    let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI;
+    let sqrt2: f64 = consts::SQRT_2;
+    let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2;
+    let e: f64 = consts::E;
+    let log2_e: f64 = consts::LOG2_E;
+    let log10_e: f64 = consts::LOG10_E;
+    let ln_2: f64 = consts::LN_2;
+    let ln_10: f64 = consts::LN_10;
+
+    assert_approx_eq!(frac_pi_2, pi / 2f64);
+    assert_approx_eq!(frac_pi_3, pi / 3f64);
+    assert_approx_eq!(frac_pi_4, pi / 4f64);
+    assert_approx_eq!(frac_pi_6, pi / 6f64);
+    assert_approx_eq!(frac_pi_8, pi / 8f64);
+    assert_approx_eq!(frac_1_pi, 1f64 / pi);
+    assert_approx_eq!(frac_2_pi, 2f64 / pi);
+    assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt());
+    assert_approx_eq!(sqrt2, 2f64.sqrt());
+    assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt());
+    assert_approx_eq!(log2_e, e.log2());
+    assert_approx_eq!(log10_e, e.log10());
+    assert_approx_eq!(ln_2, 2f64.ln());
+    assert_approx_eq!(ln_10, 10f64.ln());
+}
+
+#[test]
+fn test_float_bits_conv() {
+    assert_eq!((1f64).to_bits(), 0x3ff0000000000000);
+    assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
+    assert_eq!((1337f64).to_bits(), 0x4094e40000000000);
+    assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000);
+    assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0);
+    assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5);
+    assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0);
+    assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25);
+
+    // Check that NaNs roundtrip their bits regardless of signaling-ness
+    // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+    let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
+    let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
+    assert!(f64::from_bits(masked_nan1).is_nan());
+    assert!(f64::from_bits(masked_nan2).is_nan());
+
+    assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1);
+    assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2);
+}
+
+#[test]
+#[should_panic]
+fn test_clamp_min_greater_than_max() {
+    let _ = 1.0f64.clamp(3.0, 1.0);
+}
+
+#[test]
+#[should_panic]
+fn test_clamp_min_is_nan() {
+    let _ = 1.0f64.clamp(f64::NAN, 1.0);
+}
+
+#[test]
+#[should_panic]
+fn test_clamp_max_is_nan() {
+    let _ = 1.0f64.clamp(3.0, f64::NAN);
+}
+
+#[test]
+fn test_total_cmp() {
+    use core::cmp::Ordering;
+
+    fn quiet_bit_mask() -> u64 {
+        1 << (f64::MANTISSA_DIGITS - 2)
+    }
+
+    fn min_subnorm() -> f64 {
+        f64::MIN_POSITIVE / f64::powf(2.0, f64::MANTISSA_DIGITS as f64 - 1.0)
+    }
+
+    fn max_subnorm() -> f64 {
+        f64::MIN_POSITIVE - min_subnorm()
+    }
+
+    fn q_nan() -> f64 {
+        f64::from_bits(f64::NAN.to_bits() | quiet_bit_mask())
+    }
+
+    fn s_nan() -> f64 {
+        f64::from_bits((f64::NAN.to_bits() & !quiet_bit_mask()) + 42)
+    }
+
+    assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan()));
+    assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan()));
+    assert_eq!(Ordering::Equal, (-f64::INFINITY).total_cmp(&-f64::INFINITY));
+    assert_eq!(Ordering::Equal, (-f64::MAX).total_cmp(&-f64::MAX));
+    assert_eq!(Ordering::Equal, (-2.5_f64).total_cmp(&-2.5));
+    assert_eq!(Ordering::Equal, (-1.0_f64).total_cmp(&-1.0));
+    assert_eq!(Ordering::Equal, (-1.5_f64).total_cmp(&-1.5));
+    assert_eq!(Ordering::Equal, (-0.5_f64).total_cmp(&-0.5));
+    assert_eq!(Ordering::Equal, (-f64::MIN_POSITIVE).total_cmp(&-f64::MIN_POSITIVE));
+    assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm()));
+    assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm()));
+    assert_eq!(Ordering::Equal, (-0.0_f64).total_cmp(&-0.0));
+    assert_eq!(Ordering::Equal, 0.0_f64.total_cmp(&0.0));
+    assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm()));
+    assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm()));
+    assert_eq!(Ordering::Equal, f64::MIN_POSITIVE.total_cmp(&f64::MIN_POSITIVE));
+    assert_eq!(Ordering::Equal, 0.5_f64.total_cmp(&0.5));
+    assert_eq!(Ordering::Equal, 1.0_f64.total_cmp(&1.0));
+    assert_eq!(Ordering::Equal, 1.5_f64.total_cmp(&1.5));
+    assert_eq!(Ordering::Equal, 2.5_f64.total_cmp(&2.5));
+    assert_eq!(Ordering::Equal, f64::MAX.total_cmp(&f64::MAX));
+    assert_eq!(Ordering::Equal, f64::INFINITY.total_cmp(&f64::INFINITY));
+    assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan()));
+    assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan()));
+
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY));
+    assert_eq!(Ordering::Less, (-f64::INFINITY).total_cmp(&-f64::MAX));
+    assert_eq!(Ordering::Less, (-f64::MAX).total_cmp(&-2.5));
+    assert_eq!(Ordering::Less, (-2.5_f64).total_cmp(&-1.5));
+    assert_eq!(Ordering::Less, (-1.5_f64).total_cmp(&-1.0));
+    assert_eq!(Ordering::Less, (-1.0_f64).total_cmp(&-0.5));
+    assert_eq!(Ordering::Less, (-0.5_f64).total_cmp(&-f64::MIN_POSITIVE));
+    assert_eq!(Ordering::Less, (-f64::MIN_POSITIVE).total_cmp(&-max_subnorm()));
+    assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm()));
+    assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0));
+    assert_eq!(Ordering::Less, (-0.0_f64).total_cmp(&0.0));
+    assert_eq!(Ordering::Less, 0.0_f64.total_cmp(&min_subnorm()));
+    assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm()));
+    assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f64::MIN_POSITIVE));
+    assert_eq!(Ordering::Less, f64::MIN_POSITIVE.total_cmp(&0.5));
+    assert_eq!(Ordering::Less, 0.5_f64.total_cmp(&1.0));
+    assert_eq!(Ordering::Less, 1.0_f64.total_cmp(&1.5));
+    assert_eq!(Ordering::Less, 1.5_f64.total_cmp(&2.5));
+    assert_eq!(Ordering::Less, 2.5_f64.total_cmp(&f64::MAX));
+    assert_eq!(Ordering::Less, f64::MAX.total_cmp(&f64::INFINITY));
+    assert_eq!(Ordering::Less, f64::INFINITY.total_cmp(&s_nan()));
+    assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan()));
+
+    assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan()));
+    assert_eq!(Ordering::Greater, (-f64::INFINITY).total_cmp(&-s_nan()));
+    assert_eq!(Ordering::Greater, (-f64::MAX).total_cmp(&-f64::INFINITY));
+    assert_eq!(Ordering::Greater, (-2.5_f64).total_cmp(&-f64::MAX));
+    assert_eq!(Ordering::Greater, (-1.5_f64).total_cmp(&-2.5));
+    assert_eq!(Ordering::Greater, (-1.0_f64).total_cmp(&-1.5));
+    assert_eq!(Ordering::Greater, (-0.5_f64).total_cmp(&-1.0));
+    assert_eq!(Ordering::Greater, (-f64::MIN_POSITIVE).total_cmp(&-0.5));
+    assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f64::MIN_POSITIVE));
+    assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm()));
+    assert_eq!(Ordering::Greater, (-0.0_f64).total_cmp(&-min_subnorm()));
+    assert_eq!(Ordering::Greater, 0.0_f64.total_cmp(&-0.0));
+    assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0));
+    assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm()));
+    assert_eq!(Ordering::Greater, f64::MIN_POSITIVE.total_cmp(&max_subnorm()));
+    assert_eq!(Ordering::Greater, 0.5_f64.total_cmp(&f64::MIN_POSITIVE));
+    assert_eq!(Ordering::Greater, 1.0_f64.total_cmp(&0.5));
+    assert_eq!(Ordering::Greater, 1.5_f64.total_cmp(&1.0));
+    assert_eq!(Ordering::Greater, 2.5_f64.total_cmp(&1.5));
+    assert_eq!(Ordering::Greater, f64::MAX.total_cmp(&2.5));
+    assert_eq!(Ordering::Greater, f64::INFINITY.total_cmp(&f64::MAX));
+    assert_eq!(Ordering::Greater, s_nan().total_cmp(&f64::INFINITY));
+    assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan()));
+
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::INFINITY));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MAX));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MIN_POSITIVE));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm()));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm()));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm()));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm()));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MIN_POSITIVE));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MAX));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::INFINITY));
+    assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan()));
+
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MAX));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MIN_POSITIVE));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm()));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm()));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm()));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm()));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MIN_POSITIVE));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MAX));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY));
+    assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
+}
index 717967fb7687fa27ede34e9718bb085fabcf0d90..51deb217c7c29a3b8e06fccb1d40e473082927fd 100644 (file)
@@ -1,4 +1,8 @@
 #![deny(unsafe_op_in_unsafe_fn)]
+
+#[cfg(test)]
+mod tests;
+
 use crate::ascii;
 use crate::borrow::{Borrow, Cow};
 use crate::cmp::Ordering;
@@ -1522,202 +1526,3 @@ fn as_ref(&self) -> &CStr {
         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()..];
-    }
-}
diff --git a/library/std/src/ffi/c_str/tests.rs b/library/std/src/ffi/c_str/tests.rs
new file mode 100644 (file)
index 0000000..4dff3df
--- /dev/null
@@ -0,0 +1,195 @@
+use super::*;
+use crate::borrow::Cow::{Borrowed, Owned};
+use crate::collections::hash_map::DefaultHasher;
+use crate::hash::{Hash, Hasher};
+use crate::os::raw::c_char;
+use crate::rc::Rc;
+use crate::sync::Arc;
+
+#[test]
+fn c_to_rust() {
+    let data = b"123\0";
+    let ptr = data.as_ptr() as *const c_char;
+    unsafe {
+        assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123");
+        assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0");
+    }
+}
+
+#[test]
+fn simple() {
+    let s = CString::new("1234").unwrap();
+    assert_eq!(s.as_bytes(), b"1234");
+    assert_eq!(s.as_bytes_with_nul(), b"1234\0");
+}
+
+#[test]
+fn build_with_zero1() {
+    assert!(CString::new(&b"\0"[..]).is_err());
+}
+#[test]
+fn build_with_zero2() {
+    assert!(CString::new(vec![0]).is_err());
+}
+
+#[test]
+fn build_with_zero3() {
+    unsafe {
+        let s = CString::from_vec_unchecked(vec![0]);
+        assert_eq!(s.as_bytes(), b"\0");
+    }
+}
+
+#[test]
+fn formatted() {
+    let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
+    assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
+}
+
+#[test]
+fn borrowed() {
+    unsafe {
+        let s = CStr::from_ptr(b"12\0".as_ptr() as *const _);
+        assert_eq!(s.to_bytes(), b"12");
+        assert_eq!(s.to_bytes_with_nul(), b"12\0");
+    }
+}
+
+#[test]
+fn to_str() {
+    let data = b"123\xE2\x80\xA6\0";
+    let ptr = data.as_ptr() as *const c_char;
+    unsafe {
+        assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
+        assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
+    }
+    let data = b"123\xE2\0";
+    let ptr = data.as_ptr() as *const c_char;
+    unsafe {
+        assert!(CStr::from_ptr(ptr).to_str().is_err());
+        assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::<str>(format!("123\u{FFFD}")));
+    }
+}
+
+#[test]
+fn to_owned() {
+    let data = b"123\0";
+    let ptr = data.as_ptr() as *const c_char;
+
+    let owned = unsafe { CStr::from_ptr(ptr).to_owned() };
+    assert_eq!(owned.as_bytes_with_nul(), data);
+}
+
+#[test]
+fn equal_hash() {
+    let data = b"123\xE2\xFA\xA6\0";
+    let ptr = data.as_ptr() as *const c_char;
+    let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) };
+
+    let mut s = DefaultHasher::new();
+    cstr.hash(&mut s);
+    let cstr_hash = s.finish();
+    let mut s = DefaultHasher::new();
+    CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s);
+    let cstring_hash = s.finish();
+
+    assert_eq!(cstr_hash, cstring_hash);
+}
+
+#[test]
+fn from_bytes_with_nul() {
+    let data = b"123\0";
+    let cstr = CStr::from_bytes_with_nul(data);
+    assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..]));
+    let cstr = CStr::from_bytes_with_nul(data);
+    assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..]));
+
+    unsafe {
+        let cstr = CStr::from_bytes_with_nul(data);
+        let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data);
+        assert_eq!(cstr, Ok(cstr_unchecked));
+    }
+}
+
+#[test]
+fn from_bytes_with_nul_unterminated() {
+    let data = b"123";
+    let cstr = CStr::from_bytes_with_nul(data);
+    assert!(cstr.is_err());
+}
+
+#[test]
+fn from_bytes_with_nul_interior() {
+    let data = b"1\023\0";
+    let cstr = CStr::from_bytes_with_nul(data);
+    assert!(cstr.is_err());
+}
+
+#[test]
+fn into_boxed() {
+    let orig: &[u8] = b"Hello, world!\0";
+    let cstr = CStr::from_bytes_with_nul(orig).unwrap();
+    let boxed: Box<CStr> = Box::from(cstr);
+    let cstring = cstr.to_owned().into_boxed_c_str().into_c_string();
+    assert_eq!(cstr, &*boxed);
+    assert_eq!(&*boxed, &*cstring);
+    assert_eq!(&*cstring, cstr);
+}
+
+#[test]
+fn boxed_default() {
+    let boxed = <Box<CStr>>::default();
+    assert_eq!(boxed.to_bytes_with_nul(), &[0]);
+}
+
+#[test]
+fn test_c_str_clone_into() {
+    let mut c_string = CString::new("lorem").unwrap();
+    let c_ptr = c_string.as_ptr();
+    let c_str = CStr::from_bytes_with_nul(b"ipsum\0").unwrap();
+    c_str.clone_into(&mut c_string);
+    assert_eq!(c_str, c_string.as_c_str());
+    // The exact same size shouldn't have needed to move its allocation
+    assert_eq!(c_ptr, c_string.as_ptr());
+}
+
+#[test]
+fn into_rc() {
+    let orig: &[u8] = b"Hello, world!\0";
+    let cstr = CStr::from_bytes_with_nul(orig).unwrap();
+    let rc: Rc<CStr> = Rc::from(cstr);
+    let arc: Arc<CStr> = Arc::from(cstr);
+
+    assert_eq!(&*rc, cstr);
+    assert_eq!(&*arc, cstr);
+
+    let rc2: Rc<CStr> = Rc::from(cstr.to_owned());
+    let arc2: Arc<CStr> = Arc::from(cstr.to_owned());
+
+    assert_eq!(&*rc2, cstr);
+    assert_eq!(&*arc2, cstr);
+}
+
+#[test]
+fn cstr_const_constructor() {
+    const CSTR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello, world!\0") };
+
+    assert_eq!(CSTR.to_str().unwrap(), "Hello, world!");
+}
+
+#[test]
+fn cstr_index_from() {
+    let original = b"Hello, world!\0";
+    let cstr = CStr::from_bytes_with_nul(original).unwrap();
+    let result = CStr::from_bytes_with_nul(&original[7..]).unwrap();
+
+    assert_eq!(&cstr[7..], result);
+}
+
+#[test]
+#[should_panic]
+fn cstr_index_from_empty() {
+    let original = b"Hello, world!\0";
+    let cstr = CStr::from_bytes_with_nul(original).unwrap();
+    let _ = &cstr[original.len()..];
+}
index 262d39d98ee2ecc66790141c9cb2b11fe3b96162..e0be6d1c836aea9456a45197303778cfdce4c582 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(test)]
+mod tests;
+
 use crate::borrow::{Borrow, Cow};
 use crate::cmp;
 use crate::fmt;
@@ -1145,172 +1148,3 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
         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);
-    }
-}
diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs
new file mode 100644 (file)
index 0000000..283f2b5
--- /dev/null
@@ -0,0 +1,165 @@
+use super::*;
+use crate::sys_common::{AsInner, IntoInner};
+
+use crate::rc::Rc;
+use crate::sync::Arc;
+
+#[test]
+fn test_os_string_with_capacity() {
+    let os_string = OsString::with_capacity(0);
+    assert_eq!(0, os_string.inner.into_inner().capacity());
+
+    let os_string = OsString::with_capacity(10);
+    assert_eq!(10, os_string.inner.into_inner().capacity());
+
+    let mut os_string = OsString::with_capacity(0);
+    os_string.push("abc");
+    assert!(os_string.inner.into_inner().capacity() >= 3);
+}
+
+#[test]
+fn test_os_string_clear() {
+    let mut os_string = OsString::from("abc");
+    assert_eq!(3, os_string.inner.as_inner().len());
+
+    os_string.clear();
+    assert_eq!(&os_string, "");
+    assert_eq!(0, os_string.inner.as_inner().len());
+}
+
+#[test]
+fn test_os_string_capacity() {
+    let os_string = OsString::with_capacity(0);
+    assert_eq!(0, os_string.capacity());
+
+    let os_string = OsString::with_capacity(10);
+    assert_eq!(10, os_string.capacity());
+
+    let mut os_string = OsString::with_capacity(0);
+    os_string.push("abc");
+    assert!(os_string.capacity() >= 3);
+}
+
+#[test]
+fn test_os_string_reserve() {
+    let mut os_string = OsString::new();
+    assert_eq!(os_string.capacity(), 0);
+
+    os_string.reserve(2);
+    assert!(os_string.capacity() >= 2);
+
+    for _ in 0..16 {
+        os_string.push("a");
+    }
+
+    assert!(os_string.capacity() >= 16);
+    os_string.reserve(16);
+    assert!(os_string.capacity() >= 32);
+
+    os_string.push("a");
+
+    os_string.reserve(16);
+    assert!(os_string.capacity() >= 33)
+}
+
+#[test]
+fn test_os_string_reserve_exact() {
+    let mut os_string = OsString::new();
+    assert_eq!(os_string.capacity(), 0);
+
+    os_string.reserve_exact(2);
+    assert!(os_string.capacity() >= 2);
+
+    for _ in 0..16 {
+        os_string.push("a");
+    }
+
+    assert!(os_string.capacity() >= 16);
+    os_string.reserve_exact(16);
+    assert!(os_string.capacity() >= 32);
+
+    os_string.push("a");
+
+    os_string.reserve_exact(16);
+    assert!(os_string.capacity() >= 33)
+}
+
+#[test]
+fn test_os_string_default() {
+    let os_string: OsString = Default::default();
+    assert_eq!("", &os_string);
+}
+
+#[test]
+fn test_os_str_is_empty() {
+    let mut os_string = OsString::new();
+    assert!(os_string.is_empty());
+
+    os_string.push("abc");
+    assert!(!os_string.is_empty());
+
+    os_string.clear();
+    assert!(os_string.is_empty());
+}
+
+#[test]
+fn test_os_str_len() {
+    let mut os_string = OsString::new();
+    assert_eq!(0, os_string.len());
+
+    os_string.push("abc");
+    assert_eq!(3, os_string.len());
+
+    os_string.clear();
+    assert_eq!(0, os_string.len());
+}
+
+#[test]
+fn test_os_str_default() {
+    let os_str: &OsStr = Default::default();
+    assert_eq!("", os_str);
+}
+
+#[test]
+fn into_boxed() {
+    let orig = "Hello, world!";
+    let os_str = OsStr::new(orig);
+    let boxed: Box<OsStr> = Box::from(os_str);
+    let os_string = os_str.to_owned().into_boxed_os_str().into_os_string();
+    assert_eq!(os_str, &*boxed);
+    assert_eq!(&*boxed, &*os_string);
+    assert_eq!(&*os_string, os_str);
+}
+
+#[test]
+fn boxed_default() {
+    let boxed = <Box<OsStr>>::default();
+    assert!(boxed.is_empty());
+}
+
+#[test]
+fn test_os_str_clone_into() {
+    let mut os_string = OsString::with_capacity(123);
+    os_string.push("hello");
+    let os_str = OsStr::new("bonjour");
+    os_str.clone_into(&mut os_string);
+    assert_eq!(os_str, os_string);
+    assert!(os_string.capacity() >= 123);
+}
+
+#[test]
+fn into_rc() {
+    let orig = "Hello, world!";
+    let os_str = OsStr::new(orig);
+    let rc: Rc<OsStr> = Rc::from(os_str);
+    let arc: Arc<OsStr> = Arc::from(os_str);
+
+    assert_eq!(&*rc, os_str);
+    assert_eq!(&*arc, os_str);
+
+    let rc2: Rc<OsStr> = Rc::from(os_str.to_owned());
+    let arc2: Arc<OsStr> = Arc::from(os_str.to_owned());
+
+    assert_eq!(&*rc2, os_str);
+    assert_eq!(&*arc2, os_str);
+}
index b1630f8f5494c7334a0283831ae27668558b2bcc..3cfb6bc9d3d0ba2f4ec2bdd3ef2ec5454c937c40 100644 (file)
@@ -1,5 +1,3 @@
-// ignore-tidy-filelength
-
 //! Filesystem manipulation operations.
 //!
 //! This module contains basic methods to manipulate the contents of the local
@@ -10,6 +8,9 @@
 #![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};
@@ -2194,1349 +2195,3 @@ fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder {
         &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,
-                ),
-            }
-        }
-    }
-}
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
new file mode 100644 (file)
index 0000000..65a2907
--- /dev/null
@@ -0,0 +1,1339 @@
+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,)
+            }
+        }
+    }
+}
index ec3c69dd6160a21c581011b3eb3d743bf1d1a7e5..5ad8f8132e49c8b91ebb897673afad03abab54c5 100644 (file)
@@ -1,5 +1,8 @@
 //! Buffering wrappers for I/O traits
 
+#[cfg(test)]
+mod tests;
+
 use crate::io::prelude::*;
 
 use crate::cmp;
@@ -1388,923 +1391,3 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             .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())]);
-    }
-}
diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs
new file mode 100644 (file)
index 0000000..1cd02ee
--- /dev/null
@@ -0,0 +1,916 @@
+use crate::io::prelude::*;
+use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom};
+use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::thread;
+
+/// A dummy reader intended at testing short-reads propagation.
+pub struct ShortReader {
+    lengths: Vec<usize>,
+}
+
+// FIXME: rustfmt and tidy disagree about the correct formatting of this
+// function. This leads to issues for users with editors configured to
+// rustfmt-on-save.
+impl Read for ShortReader {
+    fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
+        if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) }
+    }
+}
+
+#[test]
+fn test_buffered_reader() {
+    let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+    let mut reader = BufReader::with_capacity(2, inner);
+
+    let mut buf = [0, 0, 0];
+    let nread = reader.read(&mut buf);
+    assert_eq!(nread.unwrap(), 3);
+    assert_eq!(buf, [5, 6, 7]);
+    assert_eq!(reader.buffer(), []);
+
+    let mut buf = [0, 0];
+    let nread = reader.read(&mut buf);
+    assert_eq!(nread.unwrap(), 2);
+    assert_eq!(buf, [0, 1]);
+    assert_eq!(reader.buffer(), []);
+
+    let mut buf = [0];
+    let nread = reader.read(&mut buf);
+    assert_eq!(nread.unwrap(), 1);
+    assert_eq!(buf, [2]);
+    assert_eq!(reader.buffer(), [3]);
+
+    let mut buf = [0, 0, 0];
+    let nread = reader.read(&mut buf);
+    assert_eq!(nread.unwrap(), 1);
+    assert_eq!(buf, [3, 0, 0]);
+    assert_eq!(reader.buffer(), []);
+
+    let nread = reader.read(&mut buf);
+    assert_eq!(nread.unwrap(), 1);
+    assert_eq!(buf, [4, 0, 0]);
+    assert_eq!(reader.buffer(), []);
+
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+}
+
+#[test]
+fn test_buffered_reader_seek() {
+    let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+    let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
+
+    assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3));
+    assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+    assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3));
+    assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+    assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4));
+    assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..]));
+    reader.consume(1);
+    assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3));
+}
+
+#[test]
+fn test_buffered_reader_seek_relative() {
+    let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+    let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
+
+    assert!(reader.seek_relative(3).is_ok());
+    assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+    assert!(reader.seek_relative(0).is_ok());
+    assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+    assert!(reader.seek_relative(1).is_ok());
+    assert_eq!(reader.fill_buf().ok(), Some(&[1][..]));
+    assert!(reader.seek_relative(-1).is_ok());
+    assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+    assert!(reader.seek_relative(2).is_ok());
+    assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..]));
+}
+
+#[test]
+fn test_buffered_reader_invalidated_after_read() {
+    let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+    let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner));
+
+    assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..]));
+    reader.consume(3);
+
+    let mut buffer = [0, 0, 0, 0, 0];
+    assert_eq!(reader.read(&mut buffer).ok(), Some(5));
+    assert_eq!(buffer, [0, 1, 2, 3, 4]);
+
+    assert!(reader.seek_relative(-2).is_ok());
+    let mut buffer = [0, 0];
+    assert_eq!(reader.read(&mut buffer).ok(), Some(2));
+    assert_eq!(buffer, [3, 4]);
+}
+
+#[test]
+fn test_buffered_reader_invalidated_after_seek() {
+    let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+    let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner));
+
+    assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..]));
+    reader.consume(3);
+
+    assert!(reader.seek(SeekFrom::Current(5)).is_ok());
+
+    assert!(reader.seek_relative(-2).is_ok());
+    let mut buffer = [0, 0];
+    assert_eq!(reader.read(&mut buffer).ok(), Some(2));
+    assert_eq!(buffer, [3, 4]);
+}
+
+#[test]
+fn test_buffered_reader_seek_underflow() {
+    // gimmick reader that yields its position modulo 256 for each byte
+    struct PositionReader {
+        pos: u64,
+    }
+    impl Read for PositionReader {
+        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+            let len = buf.len();
+            for x in buf {
+                *x = self.pos as u8;
+                self.pos = self.pos.wrapping_add(1);
+            }
+            Ok(len)
+        }
+    }
+    impl Seek for PositionReader {
+        fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+            match pos {
+                SeekFrom::Start(n) => {
+                    self.pos = n;
+                }
+                SeekFrom::Current(n) => {
+                    self.pos = self.pos.wrapping_add(n as u64);
+                }
+                SeekFrom::End(n) => {
+                    self.pos = u64::MAX.wrapping_add(n as u64);
+                }
+            }
+            Ok(self.pos)
+        }
+    }
+
+    let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 });
+    assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..]));
+    assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::MAX - 5));
+    assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
+    // the following seek will require two underlying seeks
+    let expected = 9223372036854775802;
+    assert_eq!(reader.seek(SeekFrom::Current(i64::MIN)).ok(), Some(expected));
+    assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
+    // seeking to 0 should empty the buffer.
+    assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected));
+    assert_eq!(reader.get_ref().pos, expected);
+}
+
+#[test]
+fn test_buffered_reader_seek_underflow_discard_buffer_between_seeks() {
+    // gimmick reader that returns Err after first seek
+    struct ErrAfterFirstSeekReader {
+        first_seek: bool,
+    }
+    impl Read for ErrAfterFirstSeekReader {
+        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+            for x in &mut *buf {
+                *x = 0;
+            }
+            Ok(buf.len())
+        }
+    }
+    impl Seek for ErrAfterFirstSeekReader {
+        fn seek(&mut self, _: SeekFrom) -> io::Result<u64> {
+            if self.first_seek {
+                self.first_seek = false;
+                Ok(0)
+            } else {
+                Err(io::Error::new(io::ErrorKind::Other, "oh no!"))
+            }
+        }
+    }
+
+    let mut reader = BufReader::with_capacity(5, ErrAfterFirstSeekReader { first_seek: true });
+    assert_eq!(reader.fill_buf().ok(), Some(&[0, 0, 0, 0, 0][..]));
+
+    // The following seek will require two underlying seeks.  The first will
+    // succeed but the second will fail.  This should still invalidate the
+    // buffer.
+    assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err());
+    assert_eq!(reader.buffer().len(), 0);
+}
+
+#[test]
+fn test_buffered_writer() {
+    let inner = Vec::new();
+    let mut writer = BufWriter::with_capacity(2, inner);
+
+    writer.write(&[0, 1]).unwrap();
+    assert_eq!(writer.buffer(), []);
+    assert_eq!(*writer.get_ref(), [0, 1]);
+
+    writer.write(&[2]).unwrap();
+    assert_eq!(writer.buffer(), [2]);
+    assert_eq!(*writer.get_ref(), [0, 1]);
+
+    writer.write(&[3]).unwrap();
+    assert_eq!(writer.buffer(), [2, 3]);
+    assert_eq!(*writer.get_ref(), [0, 1]);
+
+    writer.flush().unwrap();
+    assert_eq!(writer.buffer(), []);
+    assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
+
+    writer.write(&[4]).unwrap();
+    writer.write(&[5]).unwrap();
+    assert_eq!(writer.buffer(), [4, 5]);
+    assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
+
+    writer.write(&[6]).unwrap();
+    assert_eq!(writer.buffer(), [6]);
+    assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]);
+
+    writer.write(&[7, 8]).unwrap();
+    assert_eq!(writer.buffer(), []);
+    assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]);
+
+    writer.write(&[9, 10, 11]).unwrap();
+    assert_eq!(writer.buffer(), []);
+    assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
+
+    writer.flush().unwrap();
+    assert_eq!(writer.buffer(), []);
+    assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
+}
+
+#[test]
+fn test_buffered_writer_inner_flushes() {
+    let mut w = BufWriter::with_capacity(3, Vec::new());
+    w.write(&[0, 1]).unwrap();
+    assert_eq!(*w.get_ref(), []);
+    let w = w.into_inner().unwrap();
+    assert_eq!(w, [0, 1]);
+}
+
+#[test]
+fn test_buffered_writer_seek() {
+    let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new()));
+    w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap();
+    w.write_all(&[6, 7]).unwrap();
+    assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8));
+    assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]);
+    assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2));
+    w.write_all(&[8, 9]).unwrap();
+    assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]);
+}
+
+#[test]
+fn test_read_until() {
+    let inner: &[u8] = &[0, 1, 2, 1, 0];
+    let mut reader = BufReader::with_capacity(2, inner);
+    let mut v = Vec::new();
+    reader.read_until(0, &mut v).unwrap();
+    assert_eq!(v, [0]);
+    v.truncate(0);
+    reader.read_until(2, &mut v).unwrap();
+    assert_eq!(v, [1, 2]);
+    v.truncate(0);
+    reader.read_until(1, &mut v).unwrap();
+    assert_eq!(v, [1]);
+    v.truncate(0);
+    reader.read_until(8, &mut v).unwrap();
+    assert_eq!(v, [0]);
+    v.truncate(0);
+    reader.read_until(9, &mut v).unwrap();
+    assert_eq!(v, []);
+}
+
+#[test]
+fn test_line_buffer() {
+    let mut writer = LineWriter::new(Vec::new());
+    writer.write(&[0]).unwrap();
+    assert_eq!(*writer.get_ref(), []);
+    writer.write(&[1]).unwrap();
+    assert_eq!(*writer.get_ref(), []);
+    writer.flush().unwrap();
+    assert_eq!(*writer.get_ref(), [0, 1]);
+    writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap();
+    assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']);
+    writer.flush().unwrap();
+    assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]);
+    writer.write(&[3, b'\n']).unwrap();
+    assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']);
+}
+
+#[test]
+fn test_read_line() {
+    let in_buf: &[u8] = b"a\nb\nc";
+    let mut reader = BufReader::with_capacity(2, in_buf);
+    let mut s = String::new();
+    reader.read_line(&mut s).unwrap();
+    assert_eq!(s, "a\n");
+    s.truncate(0);
+    reader.read_line(&mut s).unwrap();
+    assert_eq!(s, "b\n");
+    s.truncate(0);
+    reader.read_line(&mut s).unwrap();
+    assert_eq!(s, "c");
+    s.truncate(0);
+    reader.read_line(&mut s).unwrap();
+    assert_eq!(s, "");
+}
+
+#[test]
+fn test_lines() {
+    let in_buf: &[u8] = b"a\nb\nc";
+    let reader = BufReader::with_capacity(2, in_buf);
+    let mut it = reader.lines();
+    assert_eq!(it.next().unwrap().unwrap(), "a".to_string());
+    assert_eq!(it.next().unwrap().unwrap(), "b".to_string());
+    assert_eq!(it.next().unwrap().unwrap(), "c".to_string());
+    assert!(it.next().is_none());
+}
+
+#[test]
+fn test_short_reads() {
+    let inner = ShortReader { lengths: vec![0, 1, 2, 0, 1, 0] };
+    let mut reader = BufReader::new(inner);
+    let mut buf = [0, 0];
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+    assert_eq!(reader.read(&mut buf).unwrap(), 1);
+    assert_eq!(reader.read(&mut buf).unwrap(), 2);
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+    assert_eq!(reader.read(&mut buf).unwrap(), 1);
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+}
+
+#[test]
+#[should_panic]
+fn dont_panic_in_drop_on_panicked_flush() {
+    struct FailFlushWriter;
+
+    impl Write for FailFlushWriter {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            Ok(buf.len())
+        }
+        fn flush(&mut self) -> io::Result<()> {
+            Err(io::Error::last_os_error())
+        }
+    }
+
+    let writer = FailFlushWriter;
+    let _writer = BufWriter::new(writer);
+
+    // If writer panics *again* due to the flush error then the process will
+    // abort.
+    panic!();
+}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn panic_in_write_doesnt_flush_in_drop() {
+    static WRITES: AtomicUsize = AtomicUsize::new(0);
+
+    struct PanicWriter;
+
+    impl Write for PanicWriter {
+        fn write(&mut self, _: &[u8]) -> io::Result<usize> {
+            WRITES.fetch_add(1, Ordering::SeqCst);
+            panic!();
+        }
+        fn flush(&mut self) -> io::Result<()> {
+            Ok(())
+        }
+    }
+
+    thread::spawn(|| {
+        let mut writer = BufWriter::new(PanicWriter);
+        let _ = writer.write(b"hello world");
+        let _ = writer.flush();
+    })
+    .join()
+    .unwrap_err();
+
+    assert_eq!(WRITES.load(Ordering::SeqCst), 1);
+}
+
+#[bench]
+fn bench_buffered_reader(b: &mut test::Bencher) {
+    b.iter(|| BufReader::new(io::empty()));
+}
+
+#[bench]
+fn bench_buffered_writer(b: &mut test::Bencher) {
+    b.iter(|| BufWriter::new(io::sink()));
+}
+
+/// A simple `Write` target, designed to be wrapped by `LineWriter` /
+/// `BufWriter` / etc, that can have its `write` & `flush` behavior
+/// configured
+#[derive(Default, Clone)]
+struct ProgrammableSink {
+    // Writes append to this slice
+    pub buffer: Vec<u8>,
+
+    // Flush sets this flag
+    pub flushed: bool,
+
+    // If true, writes will always be an error
+    pub always_write_error: bool,
+
+    // If true, flushes will always be an error
+    pub always_flush_error: bool,
+
+    // If set, only up to this number of bytes will be written in a single
+    // call to `write`
+    pub accept_prefix: Option<usize>,
+
+    // If set, counts down with each write, and writes return an error
+    // when it hits 0
+    pub max_writes: Option<usize>,
+
+    // If set, attempting to write when max_writes == Some(0) will be an
+    // error; otherwise, it will return Ok(0).
+    pub error_after_max_writes: bool,
+}
+
+impl Write for ProgrammableSink {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        if self.always_write_error {
+            return Err(io::Error::new(io::ErrorKind::Other, "test - always_write_error"));
+        }
+
+        match self.max_writes {
+            Some(0) if self.error_after_max_writes => {
+                return Err(io::Error::new(io::ErrorKind::Other, "test - max_writes"));
+            }
+            Some(0) => return Ok(0),
+            Some(ref mut count) => *count -= 1,
+            None => {}
+        }
+
+        let len = match self.accept_prefix {
+            None => data.len(),
+            Some(prefix) => data.len().min(prefix),
+        };
+
+        let data = &data[..len];
+        self.buffer.extend_from_slice(data);
+
+        Ok(len)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        if self.always_flush_error {
+            Err(io::Error::new(io::ErrorKind::Other, "test - always_flush_error"))
+        } else {
+            self.flushed = true;
+            Ok(())
+        }
+    }
+}
+
+/// Previously the `LineWriter` could successfully write some bytes but
+/// then fail to report that it has done so. Additionally, an erroneous
+/// flush after a successful write was permanently ignored.
+///
+/// Test that a line writer correctly reports the number of written bytes,
+/// and that it attempts to flush buffered lines from previous writes
+/// before processing new data
+///
+/// Regression test for #37807
+#[test]
+fn erroneous_flush_retried() {
+    let writer = ProgrammableSink {
+        // Only write up to 4 bytes at a time
+        accept_prefix: Some(4),
+
+        // Accept the first two writes, then error the others
+        max_writes: Some(2),
+        error_after_max_writes: true,
+
+        ..Default::default()
+    };
+
+    // This should write the first 4 bytes. The rest will be buffered, out
+    // to the last newline.
+    let mut writer = LineWriter::new(writer);
+    assert_eq!(writer.write(b"a\nb\nc\nd\ne").unwrap(), 8);
+
+    // This write should attempt to flush "c\nd\n", then buffer "e". No
+    // errors should happen here because no further writes should be
+    // attempted against `writer`.
+    assert_eq!(writer.write(b"e").unwrap(), 1);
+    assert_eq!(&writer.get_ref().buffer, b"a\nb\nc\nd\n");
+}
+
+#[test]
+fn line_vectored() {
+    let mut a = LineWriter::new(Vec::new());
+    assert_eq!(
+        a.write_vectored(&[
+            IoSlice::new(&[]),
+            IoSlice::new(b"\n"),
+            IoSlice::new(&[]),
+            IoSlice::new(b"a"),
+        ])
+        .unwrap(),
+        2,
+    );
+    assert_eq!(a.get_ref(), b"\n");
+
+    assert_eq!(
+        a.write_vectored(&[
+            IoSlice::new(&[]),
+            IoSlice::new(b"b"),
+            IoSlice::new(&[]),
+            IoSlice::new(b"a"),
+            IoSlice::new(&[]),
+            IoSlice::new(b"c"),
+        ])
+        .unwrap(),
+        3,
+    );
+    assert_eq!(a.get_ref(), b"\n");
+    a.flush().unwrap();
+    assert_eq!(a.get_ref(), b"\nabac");
+    assert_eq!(a.write_vectored(&[]).unwrap(), 0);
+    assert_eq!(
+        a.write_vectored(&[
+            IoSlice::new(&[]),
+            IoSlice::new(&[]),
+            IoSlice::new(&[]),
+            IoSlice::new(&[]),
+        ])
+        .unwrap(),
+        0,
+    );
+    assert_eq!(a.write_vectored(&[IoSlice::new(b"a\nb"),]).unwrap(), 3);
+    assert_eq!(a.get_ref(), b"\nabaca\nb");
+}
+
+#[test]
+fn line_vectored_partial_and_errors() {
+    use crate::collections::VecDeque;
+
+    enum Call {
+        Write { inputs: Vec<&'static [u8]>, output: io::Result<usize> },
+        Flush { output: io::Result<()> },
+    }
+
+    #[derive(Default)]
+    struct Writer {
+        calls: VecDeque<Call>,
+    }
+
+    impl Write for Writer {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            self.write_vectored(&[IoSlice::new(buf)])
+        }
+
+        fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> io::Result<usize> {
+            match self.calls.pop_front().expect("unexpected call to write") {
+                Call::Write { inputs, output } => {
+                    assert_eq!(inputs, buf.iter().map(|b| &**b).collect::<Vec<_>>());
+                    output
+                }
+                Call::Flush { .. } => panic!("unexpected call to write; expected a flush"),
+            }
+        }
+
+        fn is_write_vectored(&self) -> bool {
+            true
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            match self.calls.pop_front().expect("Unexpected call to flush") {
+                Call::Flush { output } => output,
+                Call::Write { .. } => panic!("unexpected call to flush; expected a write"),
+            }
+        }
+    }
+
+    impl Drop for Writer {
+        fn drop(&mut self) {
+            if !thread::panicking() {
+                assert_eq!(self.calls.len(), 0);
+            }
+        }
+    }
+
+    // partial writes keep going
+    let mut a = LineWriter::new(Writer::default());
+    a.write_vectored(&[IoSlice::new(&[]), IoSlice::new(b"abc")]).unwrap();
+
+    a.get_mut().calls.push_back(Call::Write { inputs: vec![b"abc"], output: Ok(1) });
+    a.get_mut().calls.push_back(Call::Write { inputs: vec![b"bc"], output: Ok(2) });
+    a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\n"], output: Ok(2) });
+
+    a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\n")]).unwrap();
+
+    a.get_mut().calls.push_back(Call::Flush { output: Ok(()) });
+    a.flush().unwrap();
+
+    // erroneous writes stop and don't write more
+    a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\na"], output: Err(err()) });
+    a.get_mut().calls.push_back(Call::Flush { output: Ok(()) });
+    assert!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).is_err());
+    a.flush().unwrap();
+
+    fn err() -> io::Error {
+        io::Error::new(io::ErrorKind::Other, "x")
+    }
+}
+
+/// Test that, in cases where vectored writing is not enabled, the
+/// LineWriter uses the normal `write` call, which more-correctly handles
+/// partial lines
+#[test]
+fn line_vectored_ignored() {
+    let writer = ProgrammableSink::default();
+    let mut writer = LineWriter::new(writer);
+
+    let content = [
+        IoSlice::new(&[]),
+        IoSlice::new(b"Line 1\nLine"),
+        IoSlice::new(b" 2\nLine 3\nL"),
+        IoSlice::new(&[]),
+        IoSlice::new(&[]),
+        IoSlice::new(b"ine 4"),
+        IoSlice::new(b"\nLine 5\n"),
+    ];
+
+    let count = writer.write_vectored(&content).unwrap();
+    assert_eq!(count, 11);
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
+
+    let count = writer.write_vectored(&content[2..]).unwrap();
+    assert_eq!(count, 11);
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
+
+    let count = writer.write_vectored(&content[5..]).unwrap();
+    assert_eq!(count, 5);
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
+
+    let count = writer.write_vectored(&content[6..]).unwrap();
+    assert_eq!(count, 8);
+    assert_eq!(
+        writer.get_ref().buffer.as_slice(),
+        b"Line 1\nLine 2\nLine 3\nLine 4\nLine 5\n".as_ref()
+    );
+}
+
+/// Test that, given this input:
+///
+/// Line 1\n
+/// Line 2\n
+/// Line 3\n
+/// Line 4
+///
+/// And given a result that only writes to midway through Line 2
+///
+/// That only up to the end of Line 3 is buffered
+///
+/// This behavior is desirable because it prevents flushing partial lines
+#[test]
+fn partial_write_buffers_line() {
+    let writer = ProgrammableSink { accept_prefix: Some(13), ..Default::default() };
+    let mut writer = LineWriter::new(writer);
+
+    assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3\nLine4").unwrap(), 21);
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2");
+
+    assert_eq!(writer.write(b"Line 4").unwrap(), 6);
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
+}
+
+/// Test that, given this input:
+///
+/// Line 1\n
+/// Line 2\n
+/// Line 3
+///
+/// And given that the full write of lines 1 and 2 was successful
+/// That data up to Line 3 is buffered
+#[test]
+fn partial_line_buffered_after_line_write() {
+    let writer = ProgrammableSink::default();
+    let mut writer = LineWriter::new(writer);
+
+    assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3").unwrap(), 20);
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\n");
+
+    assert!(writer.flush().is_ok());
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3");
+}
+
+/// Test that, given a partial line that exceeds the length of
+/// LineBuffer's buffer (that is, without a trailing newline), that that
+/// line is written to the inner writer
+#[test]
+fn long_line_flushed() {
+    let writer = ProgrammableSink::default();
+    let mut writer = LineWriter::with_capacity(5, writer);
+
+    assert_eq!(writer.write(b"0123456789").unwrap(), 10);
+    assert_eq!(&writer.get_ref().buffer, b"0123456789");
+}
+
+/// Test that, given a very long partial line *after* successfully
+/// flushing a complete line, that that line is buffered unconditionally,
+/// and no additional writes take place. This assures the property that
+/// `write` should make at-most-one attempt to write new data.
+#[test]
+fn line_long_tail_not_flushed() {
+    let writer = ProgrammableSink::default();
+    let mut writer = LineWriter::with_capacity(5, writer);
+
+    // Assert that Line 1\n is flushed, and 01234 is buffered
+    assert_eq!(writer.write(b"Line 1\n0123456789").unwrap(), 12);
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
+
+    // Because the buffer is full, this subsequent write will flush it
+    assert_eq!(writer.write(b"5").unwrap(), 1);
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\n01234");
+}
+
+/// Test that, if an attempt to pre-flush buffered data returns Ok(0),
+/// this is propagated as an error.
+#[test]
+fn line_buffer_write0_error() {
+    let writer = ProgrammableSink {
+        // Accept one write, then return Ok(0) on subsequent ones
+        max_writes: Some(1),
+
+        ..Default::default()
+    };
+    let mut writer = LineWriter::new(writer);
+
+    // This should write "Line 1\n" and buffer "Partial"
+    assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14);
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
+
+    // This will attempt to flush "partial", which will return Ok(0), which
+    // needs to be an error, because we've already informed the client
+    // that we accepted the write.
+    let err = writer.write(b" Line End\n").unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::WriteZero);
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
+}
+
+/// Test that, if a write returns Ok(0) after a successful pre-flush, this
+/// is propagated as Ok(0)
+#[test]
+fn line_buffer_write0_normal() {
+    let writer = ProgrammableSink {
+        // Accept two writes, then return Ok(0) on subsequent ones
+        max_writes: Some(2),
+
+        ..Default::default()
+    };
+    let mut writer = LineWriter::new(writer);
+
+    // This should write "Line 1\n" and buffer "Partial"
+    assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14);
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
+
+    // This will flush partial, which will succeed, but then return Ok(0)
+    // when flushing " Line End\n"
+    assert_eq!(writer.write(b" Line End\n").unwrap(), 0);
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\nPartial");
+}
+
+/// LineWriter has a custom `write_all`; make sure it works correctly
+#[test]
+fn line_write_all() {
+    let writer = ProgrammableSink {
+        // Only write 5 bytes at a time
+        accept_prefix: Some(5),
+        ..Default::default()
+    };
+    let mut writer = LineWriter::new(writer);
+
+    writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial").unwrap();
+    assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\nLine 4\n");
+    writer.write_all(b" Line 5\n").unwrap();
+    assert_eq!(
+        writer.get_ref().buffer.as_slice(),
+        b"Line 1\nLine 2\nLine 3\nLine 4\nPartial Line 5\n".as_ref(),
+    );
+}
+
+#[test]
+fn line_write_all_error() {
+    let writer = ProgrammableSink {
+        // Only accept up to 3 writes of up to 5 bytes each
+        accept_prefix: Some(5),
+        max_writes: Some(3),
+        ..Default::default()
+    };
+
+    let mut writer = LineWriter::new(writer);
+    let res = writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial");
+    assert!(res.is_err());
+    // An error from write_all leaves everything in an indeterminate state,
+    // so there's nothing else to test here
+}
+
+/// Under certain circumstances, the old implementation of LineWriter
+/// would try to buffer "to the last newline" but be forced to buffer
+/// less than that, leading to inappropriate partial line writes.
+/// Regression test for that issue.
+#[test]
+fn partial_multiline_buffering() {
+    let writer = ProgrammableSink {
+        // Write only up to 5 bytes at a time
+        accept_prefix: Some(5),
+        ..Default::default()
+    };
+
+    let mut writer = LineWriter::with_capacity(10, writer);
+
+    let content = b"AAAAABBBBB\nCCCCDDDDDD\nEEE";
+
+    // When content is written, LineWriter will try to write blocks A, B,
+    // C, and D. Only block A will succeed. Under the old behavior, LineWriter
+    // would then try to buffer B, C and D, but because its capacity is 10,
+    // it will only be able to buffer B and C. We don't want to buffer
+    // partial lines concurrent with whole lines, so the correct behavior
+    // is to buffer only block B (out to the newline)
+    assert_eq!(writer.write(content).unwrap(), 11);
+    assert_eq!(writer.get_ref().buffer, *b"AAAAA");
+
+    writer.flush().unwrap();
+    assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB\n");
+}
+
+/// Same as test_partial_multiline_buffering, but in the event NO full lines
+/// fit in the buffer, just buffer as much as possible
+#[test]
+fn partial_multiline_buffering_without_full_line() {
+    let writer = ProgrammableSink {
+        // Write only up to 5 bytes at a time
+        accept_prefix: Some(5),
+        ..Default::default()
+    };
+
+    let mut writer = LineWriter::with_capacity(5, writer);
+
+    let content = b"AAAAABBBBBBBBBB\nCCCCC\nDDDDD";
+
+    // When content is written, LineWriter will try to write blocks A, B,
+    // and C. Only block A will succeed. Under the old behavior, LineWriter
+    // would then try to buffer B and C, but because its capacity is 5,
+    // it will only be able to buffer part of B. Because it's not possible
+    // for it to buffer any complete lines, it should buffer as much of B as
+    // possible
+    assert_eq!(writer.write(content).unwrap(), 10);
+    assert_eq!(writer.get_ref().buffer, *b"AAAAA");
+
+    writer.flush().unwrap();
+    assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB");
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum RecordedEvent {
+    Write(String),
+    Flush,
+}
+
+#[derive(Debug, Clone, Default)]
+struct WriteRecorder {
+    pub events: Vec<RecordedEvent>,
+}
+
+impl Write for WriteRecorder {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        use crate::str::from_utf8;
+
+        self.events.push(RecordedEvent::Write(from_utf8(buf).unwrap().to_string()));
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.events.push(RecordedEvent::Flush);
+        Ok(())
+    }
+}
+
+/// Test that a normal, formatted writeln only results in a single write
+/// call to the underlying writer. A naive implementation of
+/// LineWriter::write_all results in two writes: one of the buffered data,
+/// and another of the final substring in the formatted set
+#[test]
+fn single_formatted_write() {
+    let writer = WriteRecorder::default();
+    let mut writer = LineWriter::new(writer);
+
+    // Under a naive implementation of LineWriter, this will result in two
+    // writes: "hello, world" and "!\n", because write() has to flush the
+    // buffer before attempting to write the last "!\n". write_all shouldn't
+    // have this limitation.
+    writeln!(&mut writer, "{}, {}!", "hello", "world").unwrap();
+    assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]);
+}
index 58343f66f3ffd18a24282e41afd277fb3b256101..5733735dc4ab4be7369f8e03f83d7af07979edf5 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(test)]
+mod tests;
+
 use crate::io::prelude::*;
 
 use crate::cmp;
@@ -447,531 +450,3 @@ fn flush(&mut self) -> io::Result<()> {
         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()));
-    }
-}
diff --git a/library/std/src/io/cursor/tests.rs b/library/std/src/io/cursor/tests.rs
new file mode 100644 (file)
index 0000000..80d88ca
--- /dev/null
@@ -0,0 +1,516 @@
+use crate::io::prelude::*;
+use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom};
+
+#[test]
+fn test_vec_writer() {
+    let mut writer = Vec::new();
+    assert_eq!(writer.write(&[0]).unwrap(), 1);
+    assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+    assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+    assert_eq!(
+        writer
+            .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
+            .unwrap(),
+        3
+    );
+    let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+    assert_eq!(writer, b);
+}
+
+#[test]
+fn test_mem_writer() {
+    let mut writer = Cursor::new(Vec::new());
+    assert_eq!(writer.write(&[0]).unwrap(), 1);
+    assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+    assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+    assert_eq!(
+        writer
+            .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
+            .unwrap(),
+        3
+    );
+    let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+    assert_eq!(&writer.get_ref()[..], b);
+}
+
+#[test]
+fn test_mem_mut_writer() {
+    let mut vec = Vec::new();
+    let mut writer = Cursor::new(&mut vec);
+    assert_eq!(writer.write(&[0]).unwrap(), 1);
+    assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+    assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+    assert_eq!(
+        writer
+            .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
+            .unwrap(),
+        3
+    );
+    let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+    assert_eq!(&writer.get_ref()[..], b);
+}
+
+#[test]
+fn test_box_slice_writer() {
+    let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
+    assert_eq!(writer.position(), 0);
+    assert_eq!(writer.write(&[0]).unwrap(), 1);
+    assert_eq!(writer.position(), 1);
+    assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+    assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+    assert_eq!(writer.position(), 8);
+    assert_eq!(writer.write(&[]).unwrap(), 0);
+    assert_eq!(writer.position(), 8);
+
+    assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
+    assert_eq!(writer.write(&[10]).unwrap(), 0);
+    let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
+    assert_eq!(&**writer.get_ref(), b);
+}
+
+#[test]
+fn test_box_slice_writer_vectored() {
+    let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
+    assert_eq!(writer.position(), 0);
+    assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
+    assert_eq!(writer.position(), 1);
+    assert_eq!(
+        writer.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7]),]).unwrap(),
+        7,
+    );
+    assert_eq!(writer.position(), 8);
+    assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
+    assert_eq!(writer.position(), 8);
+
+    assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
+    assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
+    let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
+    assert_eq!(&**writer.get_ref(), b);
+}
+
+#[test]
+fn test_buf_writer() {
+    let mut buf = [0 as u8; 9];
+    {
+        let mut writer = Cursor::new(&mut buf[..]);
+        assert_eq!(writer.position(), 0);
+        assert_eq!(writer.write(&[0]).unwrap(), 1);
+        assert_eq!(writer.position(), 1);
+        assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+        assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+        assert_eq!(writer.position(), 8);
+        assert_eq!(writer.write(&[]).unwrap(), 0);
+        assert_eq!(writer.position(), 8);
+
+        assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
+        assert_eq!(writer.write(&[10]).unwrap(), 0);
+    }
+    let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
+    assert_eq!(buf, b);
+}
+
+#[test]
+fn test_buf_writer_vectored() {
+    let mut buf = [0 as u8; 9];
+    {
+        let mut writer = Cursor::new(&mut buf[..]);
+        assert_eq!(writer.position(), 0);
+        assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
+        assert_eq!(writer.position(), 1);
+        assert_eq!(
+            writer
+                .write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],)
+                .unwrap(),
+            7,
+        );
+        assert_eq!(writer.position(), 8);
+        assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
+        assert_eq!(writer.position(), 8);
+
+        assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
+        assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
+    }
+    let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
+    assert_eq!(buf, b);
+}
+
+#[test]
+fn test_buf_writer_seek() {
+    let mut buf = [0 as u8; 8];
+    {
+        let mut writer = Cursor::new(&mut buf[..]);
+        assert_eq!(writer.position(), 0);
+        assert_eq!(writer.write(&[1]).unwrap(), 1);
+        assert_eq!(writer.position(), 1);
+
+        assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2);
+        assert_eq!(writer.position(), 2);
+        assert_eq!(writer.write(&[2]).unwrap(), 1);
+        assert_eq!(writer.position(), 3);
+
+        assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1);
+        assert_eq!(writer.position(), 1);
+        assert_eq!(writer.write(&[3]).unwrap(), 1);
+        assert_eq!(writer.position(), 2);
+
+        assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
+        assert_eq!(writer.position(), 7);
+        assert_eq!(writer.write(&[4]).unwrap(), 1);
+        assert_eq!(writer.position(), 8);
+    }
+    let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4];
+    assert_eq!(buf, b);
+}
+
+#[test]
+fn test_buf_writer_error() {
+    let mut buf = [0 as u8; 2];
+    let mut writer = Cursor::new(&mut buf[..]);
+    assert_eq!(writer.write(&[0]).unwrap(), 1);
+    assert_eq!(writer.write(&[0, 0]).unwrap(), 1);
+    assert_eq!(writer.write(&[0, 0]).unwrap(), 0);
+}
+
+#[test]
+fn test_mem_reader() {
+    let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
+    let mut buf = [];
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+    assert_eq!(reader.position(), 0);
+    let mut buf = [0];
+    assert_eq!(reader.read(&mut buf).unwrap(), 1);
+    assert_eq!(reader.position(), 1);
+    let b: &[_] = &[0];
+    assert_eq!(buf, b);
+    let mut buf = [0; 4];
+    assert_eq!(reader.read(&mut buf).unwrap(), 4);
+    assert_eq!(reader.position(), 5);
+    let b: &[_] = &[1, 2, 3, 4];
+    assert_eq!(buf, b);
+    assert_eq!(reader.read(&mut buf).unwrap(), 3);
+    let b: &[_] = &[5, 6, 7];
+    assert_eq!(&buf[..3], b);
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+}
+
+#[test]
+fn test_mem_reader_vectored() {
+    let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
+    let mut buf = [];
+    assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
+    assert_eq!(reader.position(), 0);
+    let mut buf = [0];
+    assert_eq!(
+        reader.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(),
+        1,
+    );
+    assert_eq!(reader.position(), 1);
+    let b: &[_] = &[0];
+    assert_eq!(buf, b);
+    let mut buf1 = [0; 4];
+    let mut buf2 = [0; 4];
+    assert_eq!(
+        reader
+            .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2),])
+            .unwrap(),
+        7,
+    );
+    let b1: &[_] = &[1, 2, 3, 4];
+    let b2: &[_] = &[5, 6, 7];
+    assert_eq!(buf1, b1);
+    assert_eq!(&buf2[..3], b2);
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+}
+
+#[test]
+fn test_boxed_slice_reader() {
+    let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
+    let mut buf = [];
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+    assert_eq!(reader.position(), 0);
+    let mut buf = [0];
+    assert_eq!(reader.read(&mut buf).unwrap(), 1);
+    assert_eq!(reader.position(), 1);
+    let b: &[_] = &[0];
+    assert_eq!(buf, b);
+    let mut buf = [0; 4];
+    assert_eq!(reader.read(&mut buf).unwrap(), 4);
+    assert_eq!(reader.position(), 5);
+    let b: &[_] = &[1, 2, 3, 4];
+    assert_eq!(buf, b);
+    assert_eq!(reader.read(&mut buf).unwrap(), 3);
+    let b: &[_] = &[5, 6, 7];
+    assert_eq!(&buf[..3], b);
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+}
+
+#[test]
+fn test_boxed_slice_reader_vectored() {
+    let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
+    let mut buf = [];
+    assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
+    assert_eq!(reader.position(), 0);
+    let mut buf = [0];
+    assert_eq!(
+        reader.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(),
+        1,
+    );
+    assert_eq!(reader.position(), 1);
+    let b: &[_] = &[0];
+    assert_eq!(buf, b);
+    let mut buf1 = [0; 4];
+    let mut buf2 = [0; 4];
+    assert_eq!(
+        reader
+            .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)
+            .unwrap(),
+        7,
+    );
+    let b1: &[_] = &[1, 2, 3, 4];
+    let b2: &[_] = &[5, 6, 7];
+    assert_eq!(buf1, b1);
+    assert_eq!(&buf2[..3], b2);
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+}
+
+#[test]
+fn read_to_end() {
+    let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
+    let mut v = Vec::new();
+    reader.read_to_end(&mut v).unwrap();
+    assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]);
+}
+
+#[test]
+fn test_slice_reader() {
+    let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+    let reader = &mut &in_buf[..];
+    let mut buf = [];
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+    let mut buf = [0];
+    assert_eq!(reader.read(&mut buf).unwrap(), 1);
+    assert_eq!(reader.len(), 7);
+    let b: &[_] = &[0];
+    assert_eq!(&buf[..], b);
+    let mut buf = [0; 4];
+    assert_eq!(reader.read(&mut buf).unwrap(), 4);
+    assert_eq!(reader.len(), 3);
+    let b: &[_] = &[1, 2, 3, 4];
+    assert_eq!(&buf[..], b);
+    assert_eq!(reader.read(&mut buf).unwrap(), 3);
+    let b: &[_] = &[5, 6, 7];
+    assert_eq!(&buf[..3], b);
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+}
+
+#[test]
+fn test_slice_reader_vectored() {
+    let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+    let reader = &mut &in_buf[..];
+    let mut buf = [];
+    assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
+    let mut buf = [0];
+    assert_eq!(
+        reader.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(),
+        1,
+    );
+    assert_eq!(reader.len(), 7);
+    let b: &[_] = &[0];
+    assert_eq!(buf, b);
+    let mut buf1 = [0; 4];
+    let mut buf2 = [0; 4];
+    assert_eq!(
+        reader
+            .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)
+            .unwrap(),
+        7,
+    );
+    let b1: &[_] = &[1, 2, 3, 4];
+    let b2: &[_] = &[5, 6, 7];
+    assert_eq!(buf1, b1);
+    assert_eq!(&buf2[..3], b2);
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+}
+
+#[test]
+fn test_read_exact() {
+    let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+    let reader = &mut &in_buf[..];
+    let mut buf = [];
+    assert!(reader.read_exact(&mut buf).is_ok());
+    let mut buf = [8];
+    assert!(reader.read_exact(&mut buf).is_ok());
+    assert_eq!(buf[0], 0);
+    assert_eq!(reader.len(), 7);
+    let mut buf = [0, 0, 0, 0, 0, 0, 0];
+    assert!(reader.read_exact(&mut buf).is_ok());
+    assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]);
+    assert_eq!(reader.len(), 0);
+    let mut buf = [0];
+    assert!(reader.read_exact(&mut buf).is_err());
+}
+
+#[test]
+fn test_buf_reader() {
+    let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+    let mut reader = Cursor::new(&in_buf[..]);
+    let mut buf = [];
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+    assert_eq!(reader.position(), 0);
+    let mut buf = [0];
+    assert_eq!(reader.read(&mut buf).unwrap(), 1);
+    assert_eq!(reader.position(), 1);
+    let b: &[_] = &[0];
+    assert_eq!(buf, b);
+    let mut buf = [0; 4];
+    assert_eq!(reader.read(&mut buf).unwrap(), 4);
+    assert_eq!(reader.position(), 5);
+    let b: &[_] = &[1, 2, 3, 4];
+    assert_eq!(buf, b);
+    assert_eq!(reader.read(&mut buf).unwrap(), 3);
+    let b: &[_] = &[5, 6, 7];
+    assert_eq!(&buf[..3], b);
+    assert_eq!(reader.read(&mut buf).unwrap(), 0);
+}
+
+#[test]
+fn seek_past_end() {
+    let buf = [0xff];
+    let mut r = Cursor::new(&buf[..]);
+    assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+    assert_eq!(r.read(&mut [0]).unwrap(), 0);
+
+    let mut r = Cursor::new(vec![10]);
+    assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+    assert_eq!(r.read(&mut [0]).unwrap(), 0);
+
+    let mut buf = [0];
+    let mut r = Cursor::new(&mut buf[..]);
+    assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+    assert_eq!(r.write(&[3]).unwrap(), 0);
+
+    let mut r = Cursor::new(vec![10].into_boxed_slice());
+    assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+    assert_eq!(r.write(&[3]).unwrap(), 0);
+}
+
+#[test]
+fn seek_past_i64() {
+    let buf = [0xff];
+    let mut r = Cursor::new(&buf[..]);
+    assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+    assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+    assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+    assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+    assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+    assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+    let mut r = Cursor::new(vec![10]);
+    assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+    assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+    assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+    assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+    assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+    assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+    let mut buf = [0];
+    let mut r = Cursor::new(&mut buf[..]);
+    assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+    assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+    assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+    assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+    assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+    assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+    let mut r = Cursor::new(vec![10].into_boxed_slice());
+    assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+    assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+    assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+    assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+    assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+    assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+}
+
+#[test]
+fn seek_before_0() {
+    let buf = [0xff];
+    let mut r = Cursor::new(&buf[..]);
+    assert!(r.seek(SeekFrom::End(-2)).is_err());
+
+    let mut r = Cursor::new(vec![10]);
+    assert!(r.seek(SeekFrom::End(-2)).is_err());
+
+    let mut buf = [0];
+    let mut r = Cursor::new(&mut buf[..]);
+    assert!(r.seek(SeekFrom::End(-2)).is_err());
+
+    let mut r = Cursor::new(vec![10].into_boxed_slice());
+    assert!(r.seek(SeekFrom::End(-2)).is_err());
+}
+
+#[test]
+fn test_seekable_mem_writer() {
+    let mut writer = Cursor::new(Vec::<u8>::new());
+    assert_eq!(writer.position(), 0);
+    assert_eq!(writer.write(&[0]).unwrap(), 1);
+    assert_eq!(writer.position(), 1);
+    assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+    assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+    assert_eq!(writer.position(), 8);
+    let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
+    assert_eq!(&writer.get_ref()[..], b);
+
+    assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0);
+    assert_eq!(writer.position(), 0);
+    assert_eq!(writer.write(&[3, 4]).unwrap(), 2);
+    let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
+    assert_eq!(&writer.get_ref()[..], b);
+
+    assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3);
+    assert_eq!(writer.write(&[0, 1]).unwrap(), 2);
+    let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
+    assert_eq!(&writer.get_ref()[..], b);
+
+    assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
+    assert_eq!(writer.write(&[1, 2]).unwrap(), 2);
+    let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
+    assert_eq!(&writer.get_ref()[..], b);
+
+    assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10);
+    assert_eq!(writer.write(&[1]).unwrap(), 1);
+    let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
+    assert_eq!(&writer.get_ref()[..], b);
+}
+
+#[test]
+fn vec_seek_past_end() {
+    let mut r = Cursor::new(Vec::new());
+    assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+    assert_eq!(r.write(&[3]).unwrap(), 1);
+}
+
+#[test]
+fn vec_seek_before_0() {
+    let mut r = Cursor::new(Vec::new());
+    assert!(r.seek(SeekFrom::End(-2)).is_err());
+}
+
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn vec_seek_and_write_past_usize_max() {
+    let mut c = Cursor::new(Vec::new());
+    c.set_position(usize::MAX as u64 + 1);
+    assert!(c.write_all(&[1, 2, 3]).is_err());
+}
+
+#[test]
+fn test_partial_eq() {
+    assert_eq!(Cursor::new(Vec::<u8>::new()), Cursor::new(Vec::<u8>::new()));
+}
+
+#[test]
+fn test_eq() {
+    struct AssertEq<T: Eq>(pub T);
+
+    let _: AssertEq<Cursor<Vec<u8>>> = AssertEq(Cursor::new(Vec::new()));
+}
index e6eda2caf758f88c5296fc44a023d98726f76920..ba0f0a0cd714aadfebb706fcd83909f17186a601 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(test)]
+mod tests;
+
 use crate::convert::From;
 use crate::error;
 use crate::fmt;
@@ -574,60 +577,3 @@ fn _assert_error_is_sync_send() {
     fn _is_sync_send<T: Sync + Send>() {}
     _is_sync_send::<Error>();
 }
-
-#[cfg(test)]
-mod test {
-    use super::{Custom, Error, ErrorKind, Repr};
-    use crate::error;
-    use crate::fmt;
-    use crate::sys::decode_error_kind;
-    use crate::sys::os::error_string;
-
-    #[test]
-    fn test_debug_error() {
-        let code = 6;
-        let msg = error_string(code);
-        let kind = decode_error_kind(code);
-        let err = Error {
-            repr: Repr::Custom(box Custom {
-                kind: ErrorKind::InvalidInput,
-                error: box Error { repr: super::Repr::Os(code) },
-            }),
-        };
-        let expected = format!(
-            "Custom {{ \
-             kind: InvalidInput, \
-             error: Os {{ \
-             code: {:?}, \
-             kind: {:?}, \
-             message: {:?} \
-             }} \
-             }}",
-            code, kind, msg
-        );
-        assert_eq!(format!("{:?}", err), expected);
-    }
-
-    #[test]
-    fn test_downcasting() {
-        #[derive(Debug)]
-        struct TestError;
-
-        impl fmt::Display for TestError {
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                f.write_str("asdf")
-            }
-        }
-
-        impl error::Error for TestError {}
-
-        // we have to call all of these UFCS style right now since method
-        // resolution won't implicitly drop the Send+Sync bounds
-        let mut err = Error::new(ErrorKind::Other, TestError);
-        assert!(err.get_ref().unwrap().is::<TestError>());
-        assert_eq!("asdf", err.get_ref().unwrap().to_string());
-        assert!(err.get_mut().unwrap().is::<TestError>());
-        let extracted = err.into_inner().unwrap();
-        extracted.downcast::<TestError>().unwrap();
-    }
-}
diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs
new file mode 100644 (file)
index 0000000..0cce936
--- /dev/null
@@ -0,0 +1,53 @@
+use super::{Custom, Error, ErrorKind, Repr};
+use crate::error;
+use crate::fmt;
+use crate::sys::decode_error_kind;
+use crate::sys::os::error_string;
+
+#[test]
+fn test_debug_error() {
+    let code = 6;
+    let msg = error_string(code);
+    let kind = decode_error_kind(code);
+    let err = Error {
+        repr: Repr::Custom(box Custom {
+            kind: ErrorKind::InvalidInput,
+            error: box Error { repr: super::Repr::Os(code) },
+        }),
+    };
+    let expected = format!(
+        "Custom {{ \
+         kind: InvalidInput, \
+         error: Os {{ \
+         code: {:?}, \
+         kind: {:?}, \
+         message: {:?} \
+         }} \
+         }}",
+        code, kind, msg
+    );
+    assert_eq!(format!("{:?}", err), expected);
+}
+
+#[test]
+fn test_downcasting() {
+    #[derive(Debug)]
+    struct TestError;
+
+    impl fmt::Display for TestError {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.write_str("asdf")
+        }
+    }
+
+    impl error::Error for TestError {}
+
+    // we have to call all of these UFCS style right now since method
+    // resolution won't implicitly drop the Send+Sync bounds
+    let mut err = Error::new(ErrorKind::Other, TestError);
+    assert!(err.get_ref().unwrap().is::<TestError>());
+    assert_eq!("asdf", err.get_ref().unwrap().to_string());
+    assert!(err.get_mut().unwrap().is::<TestError>());
+    let extracted = err.into_inner().unwrap();
+    extracted.downcast::<TestError>().unwrap();
+}
index 01dff0b3eb3909c25b05057e84089a43ca763699..e09e7ba978e867705b972fa8abc40e9b102535a3 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(test)]
+mod tests;
+
 use crate::cmp;
 use crate::fmt;
 use crate::io::{
@@ -397,64 +400,3 @@ fn flush(&mut self) -> io::Result<()> {
         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);
-            }
-        })
-    }
-}
diff --git a/library/std/src/io/impls/tests.rs b/library/std/src/io/impls/tests.rs
new file mode 100644 (file)
index 0000000..d1cd84a
--- /dev/null
@@ -0,0 +1,57 @@
+use crate::io::prelude::*;
+
+#[bench]
+fn bench_read_slice(b: &mut test::Bencher) {
+    let buf = [5; 1024];
+    let mut dst = [0; 128];
+
+    b.iter(|| {
+        let mut rd = &buf[..];
+        for _ in 0..8 {
+            let _ = rd.read(&mut dst);
+            test::black_box(&dst);
+        }
+    })
+}
+
+#[bench]
+fn bench_write_slice(b: &mut test::Bencher) {
+    let mut buf = [0; 1024];
+    let src = [5; 128];
+
+    b.iter(|| {
+        let mut wr = &mut buf[..];
+        for _ in 0..8 {
+            let _ = wr.write_all(&src);
+            test::black_box(&wr);
+        }
+    })
+}
+
+#[bench]
+fn bench_read_vec(b: &mut test::Bencher) {
+    let buf = vec![5; 1024];
+    let mut dst = [0; 128];
+
+    b.iter(|| {
+        let mut rd = &buf[..];
+        for _ in 0..8 {
+            let _ = rd.read(&mut dst);
+            test::black_box(&dst);
+        }
+    })
+}
+
+#[bench]
+fn bench_write_vec(b: &mut test::Bencher) {
+    let mut buf = Vec::with_capacity(1024);
+    let src = [5; 128];
+
+    b.iter(|| {
+        let mut wr = &mut buf[..];
+        for _ in 0..8 {
+            let _ = wr.write_all(&src);
+            test::black_box(&wr);
+        }
+    })
+}
index 462b696db40cf8ac6dbad7b6e8ae785ed721e7f2..adea8a804e3ca5754047adeba4c93bebed936381 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+#[cfg(test)]
+mod tests;
+
 use crate::cmp;
 use crate::fmt;
 use crate::memchr;
@@ -2481,501 +2484,3 @@ fn next(&mut self) -> Option<Result<String>> {
         }
     }
 }
-
-#[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);
-            }
-        }
-    }
-}
index 3943c66aad53a1ec9ecffd946c6c3401470bc7c7..9974b65f1e1645452c4ad04773f018540480f531 100644 (file)
@@ -1,5 +1,8 @@
 #![cfg_attr(test, allow(unused))]
 
+#[cfg(test)]
+mod tests;
+
 use crate::io::prelude::*;
 
 use crate::cell::RefCell;
@@ -920,54 +923,3 @@ pub fn _eprint(args: fmt::Arguments<'_>) {
 
 #[cfg(test)]
 pub use realstd::io::{_eprint, _print};
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::panic::{RefUnwindSafe, UnwindSafe};
-    use crate::thread;
-
-    #[test]
-    fn stdout_unwind_safe() {
-        assert_unwind_safe::<Stdout>();
-    }
-    #[test]
-    fn stdoutlock_unwind_safe() {
-        assert_unwind_safe::<StdoutLock<'_>>();
-        assert_unwind_safe::<StdoutLock<'static>>();
-    }
-    #[test]
-    fn stderr_unwind_safe() {
-        assert_unwind_safe::<Stderr>();
-    }
-    #[test]
-    fn stderrlock_unwind_safe() {
-        assert_unwind_safe::<StderrLock<'_>>();
-        assert_unwind_safe::<StderrLock<'static>>();
-    }
-
-    fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {}
-
-    #[test]
-    #[cfg_attr(target_os = "emscripten", ignore)]
-    fn panic_doesnt_poison() {
-        thread::spawn(|| {
-            let _a = stdin();
-            let _a = _a.lock();
-            let _a = stdout();
-            let _a = _a.lock();
-            let _a = stderr();
-            let _a = _a.lock();
-            panic!();
-        })
-        .join()
-        .unwrap_err();
-
-        let _a = stdin();
-        let _a = _a.lock();
-        let _a = stdout();
-        let _a = _a.lock();
-        let _a = stderr();
-        let _a = _a.lock();
-    }
-}
diff --git a/library/std/src/io/stdio/tests.rs b/library/std/src/io/stdio/tests.rs
new file mode 100644 (file)
index 0000000..04af500
--- /dev/null
@@ -0,0 +1,47 @@
+use super::*;
+use crate::panic::{RefUnwindSafe, UnwindSafe};
+use crate::thread;
+
+#[test]
+fn stdout_unwind_safe() {
+    assert_unwind_safe::<Stdout>();
+}
+#[test]
+fn stdoutlock_unwind_safe() {
+    assert_unwind_safe::<StdoutLock<'_>>();
+    assert_unwind_safe::<StdoutLock<'static>>();
+}
+#[test]
+fn stderr_unwind_safe() {
+    assert_unwind_safe::<Stderr>();
+}
+#[test]
+fn stderrlock_unwind_safe() {
+    assert_unwind_safe::<StderrLock<'_>>();
+    assert_unwind_safe::<StderrLock<'static>>();
+}
+
+fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn panic_doesnt_poison() {
+    thread::spawn(|| {
+        let _a = stdin();
+        let _a = _a.lock();
+        let _a = stdout();
+        let _a = _a.lock();
+        let _a = stderr();
+        let _a = _a.lock();
+        panic!();
+    })
+    .join()
+    .unwrap_err();
+
+    let _a = stdin();
+    let _a = _a.lock();
+    let _a = stdout();
+    let _a = _a.lock();
+    let _a = stderr();
+    let _a = _a.lock();
+}
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
new file mode 100644 (file)
index 0000000..913b285
--- /dev/null
@@ -0,0 +1,494 @@
+use super::{repeat, Cursor, SeekFrom};
+use crate::cmp::{self, min};
+use crate::io::prelude::*;
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::ops::Deref;
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn read_until() {
+    let mut buf = Cursor::new(&b"12"[..]);
+    let mut v = Vec::new();
+    assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2);
+    assert_eq!(v, b"12");
+
+    let mut buf = Cursor::new(&b"1233"[..]);
+    let mut v = Vec::new();
+    assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3);
+    assert_eq!(v, b"123");
+    v.truncate(0);
+    assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1);
+    assert_eq!(v, b"3");
+    v.truncate(0);
+    assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0);
+    assert_eq!(v, []);
+}
+
+#[test]
+fn split() {
+    let buf = Cursor::new(&b"12"[..]);
+    let mut s = buf.split(b'3');
+    assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
+    assert!(s.next().is_none());
+
+    let buf = Cursor::new(&b"1233"[..]);
+    let mut s = buf.split(b'3');
+    assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
+    assert_eq!(s.next().unwrap().unwrap(), vec![]);
+    assert!(s.next().is_none());
+}
+
+#[test]
+fn read_line() {
+    let mut buf = Cursor::new(&b"12"[..]);
+    let mut v = String::new();
+    assert_eq!(buf.read_line(&mut v).unwrap(), 2);
+    assert_eq!(v, "12");
+
+    let mut buf = Cursor::new(&b"12\n\n"[..]);
+    let mut v = String::new();
+    assert_eq!(buf.read_line(&mut v).unwrap(), 3);
+    assert_eq!(v, "12\n");
+    v.truncate(0);
+    assert_eq!(buf.read_line(&mut v).unwrap(), 1);
+    assert_eq!(v, "\n");
+    v.truncate(0);
+    assert_eq!(buf.read_line(&mut v).unwrap(), 0);
+    assert_eq!(v, "");
+}
+
+#[test]
+fn lines() {
+    let buf = Cursor::new(&b"12\r"[..]);
+    let mut s = buf.lines();
+    assert_eq!(s.next().unwrap().unwrap(), "12\r".to_string());
+    assert!(s.next().is_none());
+
+    let buf = Cursor::new(&b"12\r\n\n"[..]);
+    let mut s = buf.lines();
+    assert_eq!(s.next().unwrap().unwrap(), "12".to_string());
+    assert_eq!(s.next().unwrap().unwrap(), "".to_string());
+    assert!(s.next().is_none());
+}
+
+#[test]
+fn read_to_end() {
+    let mut c = Cursor::new(&b""[..]);
+    let mut v = Vec::new();
+    assert_eq!(c.read_to_end(&mut v).unwrap(), 0);
+    assert_eq!(v, []);
+
+    let mut c = Cursor::new(&b"1"[..]);
+    let mut v = Vec::new();
+    assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
+    assert_eq!(v, b"1");
+
+    let cap = 1024 * 1024;
+    let data = (0..cap).map(|i| (i / 3) as u8).collect::<Vec<_>>();
+    let mut v = Vec::new();
+    let (a, b) = data.split_at(data.len() / 2);
+    assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len());
+    assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len());
+    assert_eq!(v, data);
+}
+
+#[test]
+fn read_to_string() {
+    let mut c = Cursor::new(&b""[..]);
+    let mut v = String::new();
+    assert_eq!(c.read_to_string(&mut v).unwrap(), 0);
+    assert_eq!(v, "");
+
+    let mut c = Cursor::new(&b"1"[..]);
+    let mut v = String::new();
+    assert_eq!(c.read_to_string(&mut v).unwrap(), 1);
+    assert_eq!(v, "1");
+
+    let mut c = Cursor::new(&b"\xff"[..]);
+    let mut v = String::new();
+    assert!(c.read_to_string(&mut v).is_err());
+}
+
+#[test]
+fn read_exact() {
+    let mut buf = [0; 4];
+
+    let mut c = Cursor::new(&b""[..]);
+    assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
+
+    let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..]));
+    c.read_exact(&mut buf).unwrap();
+    assert_eq!(&buf, b"1234");
+    c.read_exact(&mut buf).unwrap();
+    assert_eq!(&buf, b"5678");
+    assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
+}
+
+#[test]
+fn read_exact_slice() {
+    let mut buf = [0; 4];
+
+    let mut c = &b""[..];
+    assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
+
+    let mut c = &b"123"[..];
+    assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
+    // make sure the optimized (early returning) method is being used
+    assert_eq!(&buf, &[0; 4]);
+
+    let mut c = &b"1234"[..];
+    c.read_exact(&mut buf).unwrap();
+    assert_eq!(&buf, b"1234");
+
+    let mut c = &b"56789"[..];
+    c.read_exact(&mut buf).unwrap();
+    assert_eq!(&buf, b"5678");
+    assert_eq!(c, b"9");
+}
+
+#[test]
+fn take_eof() {
+    struct R;
+
+    impl Read for R {
+        fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
+            Err(io::Error::new(io::ErrorKind::Other, ""))
+        }
+    }
+    impl BufRead for R {
+        fn fill_buf(&mut self) -> io::Result<&[u8]> {
+            Err(io::Error::new(io::ErrorKind::Other, ""))
+        }
+        fn consume(&mut self, _amt: usize) {}
+    }
+
+    let mut buf = [0; 1];
+    assert_eq!(0, R.take(0).read(&mut buf).unwrap());
+    assert_eq!(b"", R.take(0).fill_buf().unwrap());
+}
+
+fn cmp_bufread<Br1: BufRead, Br2: BufRead>(mut br1: Br1, mut br2: Br2, exp: &[u8]) {
+    let mut cat = Vec::new();
+    loop {
+        let consume = {
+            let buf1 = br1.fill_buf().unwrap();
+            let buf2 = br2.fill_buf().unwrap();
+            let minlen = if buf1.len() < buf2.len() { buf1.len() } else { buf2.len() };
+            assert_eq!(buf1[..minlen], buf2[..minlen]);
+            cat.extend_from_slice(&buf1[..minlen]);
+            minlen
+        };
+        if consume == 0 {
+            break;
+        }
+        br1.consume(consume);
+        br2.consume(consume);
+    }
+    assert_eq!(br1.fill_buf().unwrap().len(), 0);
+    assert_eq!(br2.fill_buf().unwrap().len(), 0);
+    assert_eq!(&cat[..], &exp[..])
+}
+
+#[test]
+fn chain_bufread() {
+    let testdata = b"ABCDEFGHIJKL";
+    let chain1 =
+        (&testdata[..3]).chain(&testdata[3..6]).chain(&testdata[6..9]).chain(&testdata[9..]);
+    let chain2 = (&testdata[..4]).chain(&testdata[4..8]).chain(&testdata[8..]);
+    cmp_bufread(chain1, chain2, &testdata[..]);
+}
+
+#[test]
+fn chain_zero_length_read_is_not_eof() {
+    let a = b"A";
+    let b = b"B";
+    let mut s = String::new();
+    let mut chain = (&a[..]).chain(&b[..]);
+    chain.read(&mut []).unwrap();
+    chain.read_to_string(&mut s).unwrap();
+    assert_eq!("AB", s);
+}
+
+#[bench]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn bench_read_to_end(b: &mut test::Bencher) {
+    b.iter(|| {
+        let mut lr = repeat(1).take(10000000);
+        let mut vec = Vec::with_capacity(1024);
+        super::read_to_end(&mut lr, &mut vec)
+    });
+}
+
+#[test]
+fn seek_len() -> io::Result<()> {
+    let mut c = Cursor::new(vec![0; 15]);
+    assert_eq!(c.stream_len()?, 15);
+
+    c.seek(SeekFrom::End(0))?;
+    let old_pos = c.stream_position()?;
+    assert_eq!(c.stream_len()?, 15);
+    assert_eq!(c.stream_position()?, old_pos);
+
+    c.seek(SeekFrom::Start(7))?;
+    c.seek(SeekFrom::Current(2))?;
+    let old_pos = c.stream_position()?;
+    assert_eq!(c.stream_len()?, 15);
+    assert_eq!(c.stream_position()?, old_pos);
+
+    Ok(())
+}
+
+#[test]
+fn seek_position() -> io::Result<()> {
+    // All `asserts` are duplicated here to make sure the method does not
+    // change anything about the seek state.
+    let mut c = Cursor::new(vec![0; 15]);
+    assert_eq!(c.stream_position()?, 0);
+    assert_eq!(c.stream_position()?, 0);
+
+    c.seek(SeekFrom::End(0))?;
+    assert_eq!(c.stream_position()?, 15);
+    assert_eq!(c.stream_position()?, 15);
+
+    c.seek(SeekFrom::Start(7))?;
+    c.seek(SeekFrom::Current(2))?;
+    assert_eq!(c.stream_position()?, 9);
+    assert_eq!(c.stream_position()?, 9);
+
+    c.seek(SeekFrom::End(-3))?;
+    c.seek(SeekFrom::Current(1))?;
+    c.seek(SeekFrom::Current(-5))?;
+    assert_eq!(c.stream_position()?, 8);
+    assert_eq!(c.stream_position()?, 8);
+
+    Ok(())
+}
+
+// A simple example reader which uses the default implementation of
+// read_to_end.
+struct ExampleSliceReader<'a> {
+    slice: &'a [u8],
+}
+
+impl<'a> Read for ExampleSliceReader<'a> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let len = cmp::min(self.slice.len(), buf.len());
+        buf[..len].copy_from_slice(&self.slice[..len]);
+        self.slice = &self.slice[len..];
+        Ok(len)
+    }
+}
+
+#[test]
+fn test_read_to_end_capacity() -> io::Result<()> {
+    let input = &b"foo"[..];
+
+    // read_to_end() generally needs to over-allocate, both for efficiency
+    // and so that it can distinguish EOF. Assert that this is the case
+    // with this simple ExampleSliceReader struct, which uses the default
+    // implementation of read_to_end. Even though vec1 is allocated with
+    // exactly enough capacity for the read, read_to_end will allocate more
+    // space here.
+    let mut vec1 = Vec::with_capacity(input.len());
+    ExampleSliceReader { slice: input }.read_to_end(&mut vec1)?;
+    assert_eq!(vec1.len(), input.len());
+    assert!(vec1.capacity() > input.len(), "allocated more");
+
+    // However, std::io::Take includes an implementation of read_to_end
+    // that will not allocate when the limit has already been reached. In
+    // this case, vec2 never grows.
+    let mut vec2 = Vec::with_capacity(input.len());
+    ExampleSliceReader { slice: input }.take(input.len() as u64).read_to_end(&mut vec2)?;
+    assert_eq!(vec2.len(), input.len());
+    assert_eq!(vec2.capacity(), input.len(), "did not allocate more");
+
+    Ok(())
+}
+
+#[test]
+fn io_slice_mut_advance() {
+    let mut buf1 = [1; 8];
+    let mut buf2 = [2; 16];
+    let mut buf3 = [3; 8];
+    let mut bufs = &mut [
+        IoSliceMut::new(&mut buf1),
+        IoSliceMut::new(&mut buf2),
+        IoSliceMut::new(&mut buf3),
+    ][..];
+
+    // Only in a single buffer..
+    bufs = IoSliceMut::advance(bufs, 1);
+    assert_eq!(bufs[0].deref(), [1; 7].as_ref());
+    assert_eq!(bufs[1].deref(), [2; 16].as_ref());
+    assert_eq!(bufs[2].deref(), [3; 8].as_ref());
+
+    // Removing a buffer, leaving others as is.
+    bufs = IoSliceMut::advance(bufs, 7);
+    assert_eq!(bufs[0].deref(), [2; 16].as_ref());
+    assert_eq!(bufs[1].deref(), [3; 8].as_ref());
+
+    // Removing a buffer and removing from the next buffer.
+    bufs = IoSliceMut::advance(bufs, 18);
+    assert_eq!(bufs[0].deref(), [3; 6].as_ref());
+}
+
+#[test]
+fn io_slice_mut_advance_empty_slice() {
+    let empty_bufs = &mut [][..];
+    // Shouldn't panic.
+    IoSliceMut::advance(empty_bufs, 1);
+}
+
+#[test]
+fn io_slice_mut_advance_beyond_total_length() {
+    let mut buf1 = [1; 8];
+    let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..];
+
+    // Going beyond the total length should be ok.
+    bufs = IoSliceMut::advance(bufs, 9);
+    assert!(bufs.is_empty());
+}
+
+#[test]
+fn io_slice_advance() {
+    let buf1 = [1; 8];
+    let buf2 = [2; 16];
+    let buf3 = [3; 8];
+    let mut bufs = &mut [IoSlice::new(&buf1), IoSlice::new(&buf2), IoSlice::new(&buf3)][..];
+
+    // Only in a single buffer..
+    bufs = IoSlice::advance(bufs, 1);
+    assert_eq!(bufs[0].deref(), [1; 7].as_ref());
+    assert_eq!(bufs[1].deref(), [2; 16].as_ref());
+    assert_eq!(bufs[2].deref(), [3; 8].as_ref());
+
+    // Removing a buffer, leaving others as is.
+    bufs = IoSlice::advance(bufs, 7);
+    assert_eq!(bufs[0].deref(), [2; 16].as_ref());
+    assert_eq!(bufs[1].deref(), [3; 8].as_ref());
+
+    // Removing a buffer and removing from the next buffer.
+    bufs = IoSlice::advance(bufs, 18);
+    assert_eq!(bufs[0].deref(), [3; 6].as_ref());
+}
+
+#[test]
+fn io_slice_advance_empty_slice() {
+    let empty_bufs = &mut [][..];
+    // Shouldn't panic.
+    IoSlice::advance(empty_bufs, 1);
+}
+
+#[test]
+fn io_slice_advance_beyond_total_length() {
+    let buf1 = [1; 8];
+    let mut bufs = &mut [IoSlice::new(&buf1)][..];
+
+    // Going beyond the total length should be ok.
+    bufs = IoSlice::advance(bufs, 9);
+    assert!(bufs.is_empty());
+}
+
+/// Create a new writer that reads from at most `n_bufs` and reads
+/// `per_call` bytes (in total) per call to write.
+fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter {
+    TestWriter { n_bufs, per_call, written: Vec::new() }
+}
+
+struct TestWriter {
+    n_bufs: usize,
+    per_call: usize,
+    written: Vec<u8>,
+}
+
+impl Write for TestWriter {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.write_vectored(&[IoSlice::new(buf)])
+    }
+
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        let mut left = self.per_call;
+        let mut written = 0;
+        for buf in bufs.iter().take(self.n_bufs) {
+            let n = min(left, buf.len());
+            self.written.extend_from_slice(&buf[0..n]);
+            left -= n;
+            written += n;
+        }
+        Ok(written)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+#[test]
+fn test_writer_read_from_one_buf() {
+    let mut writer = test_writer(1, 2);
+
+    assert_eq!(writer.write(&[]).unwrap(), 0);
+    assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
+
+    // Read at most 2 bytes.
+    assert_eq!(writer.write(&[1, 1, 1]).unwrap(), 2);
+    let bufs = &[IoSlice::new(&[2, 2, 2])];
+    assert_eq!(writer.write_vectored(bufs).unwrap(), 2);
+
+    // Only read from first buf.
+    let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4, 4])];
+    assert_eq!(writer.write_vectored(bufs).unwrap(), 1);
+
+    assert_eq!(writer.written, &[1, 1, 2, 2, 3]);
+}
+
+#[test]
+fn test_writer_read_from_multiple_bufs() {
+    let mut writer = test_writer(3, 3);
+
+    // Read at most 3 bytes from two buffers.
+    let bufs = &[IoSlice::new(&[1]), IoSlice::new(&[2, 2, 2])];
+    assert_eq!(writer.write_vectored(bufs).unwrap(), 3);
+
+    // Read at most 3 bytes from three buffers.
+    let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4]), IoSlice::new(&[5, 5])];
+    assert_eq!(writer.write_vectored(bufs).unwrap(), 3);
+
+    assert_eq!(writer.written, &[1, 2, 2, 3, 4, 5]);
+}
+
+#[test]
+fn test_write_all_vectored() {
+    #[rustfmt::skip] // Becomes unreadable otherwise.
+    let tests: Vec<(_, &'static [u8])> = vec![
+        (vec![], &[]),
+        (vec![IoSlice::new(&[]), IoSlice::new(&[])], &[]),
+        (vec![IoSlice::new(&[1])], &[1]),
+        (vec![IoSlice::new(&[1, 2])], &[1, 2]),
+        (vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]),
+        (vec![IoSlice::new(&[1, 2, 3, 4])], &[1, 2, 3, 4]),
+        (vec![IoSlice::new(&[1, 2, 3, 4, 5])], &[1, 2, 3, 4, 5]),
+        (vec![IoSlice::new(&[1]), IoSlice::new(&[2])], &[1, 2]),
+        (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2])], &[1, 2, 2]),
+        (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2])], &[1, 1, 2, 2]),
+        (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]),
+        (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]),
+        (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 1, 2, 2, 2]),
+        (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 2, 2, 2, 2]),
+        (vec![IoSlice::new(&[1, 1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 1, 2, 2, 2, 2]),
+        (vec![IoSlice::new(&[1]), IoSlice::new(&[2]), IoSlice::new(&[3])], &[1, 2, 3]),
+        (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3])], &[1, 1, 2, 2, 3, 3]),
+        (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 2, 2, 3, 3, 3]),
+        (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 1, 1, 2, 2, 2, 3, 3, 3]),
+    ];
+
+    let writer_configs = &[(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)];
+
+    for (n_bufs, per_call) in writer_configs.iter().copied() {
+        for (mut input, wanted) in tests.clone().into_iter() {
+            let mut writer = test_writer(n_bufs, per_call);
+            assert!(writer.write_all_vectored(&mut *input).is_ok());
+            assert_eq!(&*writer.written, &*wanted);
+        }
+    }
+}
index a093b745b0c13cd970134465d752a69bdf541a06..bf289fe040edfb5de6970ac20ec9f82ed38948a0 100644 (file)
@@ -1,5 +1,8 @@
 #![allow(missing_copy_implementations)]
 
+#[cfg(test)]
+mod tests;
+
 use crate::fmt;
 use crate::io::{self, BufRead, ErrorKind, Initializer, IoSlice, IoSliceMut, Read, Write};
 use crate::mem::MaybeUninit;
@@ -254,52 +257,3 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         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);
-    }
-}
diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs
new file mode 100644 (file)
index 0000000..e5e32ec
--- /dev/null
@@ -0,0 +1,45 @@
+use crate::io::prelude::*;
+use crate::io::{copy, empty, repeat, sink};
+
+#[test]
+fn copy_copies() {
+    let mut r = repeat(0).take(4);
+    let mut w = sink();
+    assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
+
+    let mut r = repeat(0).take(1 << 17);
+    assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
+}
+
+#[test]
+fn sink_sinks() {
+    let mut s = sink();
+    assert_eq!(s.write(&[]).unwrap(), 0);
+    assert_eq!(s.write(&[0]).unwrap(), 1);
+    assert_eq!(s.write(&[0; 1024]).unwrap(), 1024);
+    assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024);
+}
+
+#[test]
+fn empty_reads() {
+    let mut e = empty();
+    assert_eq!(e.read(&mut []).unwrap(), 0);
+    assert_eq!(e.read(&mut [0]).unwrap(), 0);
+    assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
+    assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
+}
+
+#[test]
+fn repeat_repeats() {
+    let mut r = repeat(4);
+    let mut b = [0; 1024];
+    assert_eq!(r.read(&mut b).unwrap(), 1024);
+    assert!(b.iter().all(|b| *b == 4));
+}
+
+#[test]
+fn take_some_bytes() {
+    assert_eq!(repeat(4).take(100).bytes().count(), 100);
+    assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
+    assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
+}
index d0f27df51850533dd3578b9352e4e01981154cb1..1129f29e949410fca975c6d15b269e17c23d262d 100644 (file)
@@ -1,5 +1,8 @@
 //! Lazy values and one-time initialization of static data.
 
+#[cfg(test)]
+mod tests;
+
 use crate::{
     cell::{Cell, UnsafeCell},
     fmt,
@@ -506,333 +509,3 @@ fn default() -> SyncLazy<T> {
         SyncLazy::new(T::default)
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use crate::{
-        lazy::{Lazy, SyncLazy, SyncOnceCell},
-        panic,
-        sync::{
-            atomic::{AtomicUsize, Ordering::SeqCst},
-            mpsc::channel,
-            Mutex,
-        },
-        thread,
-    };
-
-    #[test]
-    fn lazy_default() {
-        static CALLED: AtomicUsize = AtomicUsize::new(0);
-
-        struct Foo(u8);
-        impl Default for Foo {
-            fn default() -> Self {
-                CALLED.fetch_add(1, SeqCst);
-                Foo(42)
-            }
-        }
-
-        let lazy: Lazy<Mutex<Foo>> = <_>::default();
-
-        assert_eq!(CALLED.load(SeqCst), 0);
-
-        assert_eq!(lazy.lock().unwrap().0, 42);
-        assert_eq!(CALLED.load(SeqCst), 1);
-
-        lazy.lock().unwrap().0 = 21;
-
-        assert_eq!(lazy.lock().unwrap().0, 21);
-        assert_eq!(CALLED.load(SeqCst), 1);
-    }
-
-    #[test]
-    fn lazy_poisoning() {
-        let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
-        for _ in 0..2 {
-            let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len()));
-            assert!(res.is_err());
-        }
-    }
-
-    fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
-        thread::spawn(f).join().unwrap()
-    }
-
-    #[test]
-    fn sync_once_cell() {
-        static ONCE_CELL: SyncOnceCell<i32> = SyncOnceCell::new();
-
-        assert!(ONCE_CELL.get().is_none());
-
-        spawn_and_wait(|| {
-            ONCE_CELL.get_or_init(|| 92);
-            assert_eq!(ONCE_CELL.get(), Some(&92));
-        });
-
-        ONCE_CELL.get_or_init(|| panic!("Kabom!"));
-        assert_eq!(ONCE_CELL.get(), Some(&92));
-    }
-
-    #[test]
-    fn sync_once_cell_get_mut() {
-        let mut c = SyncOnceCell::new();
-        assert!(c.get_mut().is_none());
-        c.set(90).unwrap();
-        *c.get_mut().unwrap() += 2;
-        assert_eq!(c.get_mut(), Some(&mut 92));
-    }
-
-    #[test]
-    fn sync_once_cell_get_unchecked() {
-        let c = SyncOnceCell::new();
-        c.set(92).unwrap();
-        unsafe {
-            assert_eq!(c.get_unchecked(), &92);
-        }
-    }
-
-    #[test]
-    fn sync_once_cell_drop() {
-        static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
-        struct Dropper;
-        impl Drop for Dropper {
-            fn drop(&mut self) {
-                DROP_CNT.fetch_add(1, SeqCst);
-            }
-        }
-
-        let x = SyncOnceCell::new();
-        spawn_and_wait(move || {
-            x.get_or_init(|| Dropper);
-            assert_eq!(DROP_CNT.load(SeqCst), 0);
-            drop(x);
-        });
-
-        assert_eq!(DROP_CNT.load(SeqCst), 1);
-    }
-
-    #[test]
-    fn sync_once_cell_drop_empty() {
-        let x = SyncOnceCell::<String>::new();
-        drop(x);
-    }
-
-    #[test]
-    fn clone() {
-        let s = SyncOnceCell::new();
-        let c = s.clone();
-        assert!(c.get().is_none());
-
-        s.set("hello".to_string()).unwrap();
-        let c = s.clone();
-        assert_eq!(c.get().map(String::as_str), Some("hello"));
-    }
-
-    #[test]
-    fn get_or_try_init() {
-        let cell: SyncOnceCell<String> = SyncOnceCell::new();
-        assert!(cell.get().is_none());
-
-        let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() }));
-        assert!(res.is_err());
-        assert!(!cell.is_initialized());
-        assert!(cell.get().is_none());
-
-        assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
-
-        assert_eq!(
-            cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())),
-            Ok(&"hello".to_string())
-        );
-        assert_eq!(cell.get(), Some(&"hello".to_string()));
-    }
-
-    #[test]
-    fn from_impl() {
-        assert_eq!(SyncOnceCell::from("value").get(), Some(&"value"));
-        assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar"));
-    }
-
-    #[test]
-    fn partialeq_impl() {
-        assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value"));
-        assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar"));
-
-        assert!(SyncOnceCell::<String>::new() == SyncOnceCell::new());
-        assert!(SyncOnceCell::<String>::new() != SyncOnceCell::from("value".to_owned()));
-    }
-
-    #[test]
-    fn into_inner() {
-        let cell: SyncOnceCell<String> = SyncOnceCell::new();
-        assert_eq!(cell.into_inner(), None);
-        let cell = SyncOnceCell::new();
-        cell.set("hello".to_string()).unwrap();
-        assert_eq!(cell.into_inner(), Some("hello".to_string()));
-    }
-
-    #[test]
-    fn sync_lazy_new() {
-        static CALLED: AtomicUsize = AtomicUsize::new(0);
-        static SYNC_LAZY: SyncLazy<i32> = SyncLazy::new(|| {
-            CALLED.fetch_add(1, SeqCst);
-            92
-        });
-
-        assert_eq!(CALLED.load(SeqCst), 0);
-
-        spawn_and_wait(|| {
-            let y = *SYNC_LAZY - 30;
-            assert_eq!(y, 62);
-            assert_eq!(CALLED.load(SeqCst), 1);
-        });
-
-        let y = *SYNC_LAZY - 30;
-        assert_eq!(y, 62);
-        assert_eq!(CALLED.load(SeqCst), 1);
-    }
-
-    #[test]
-    fn sync_lazy_default() {
-        static CALLED: AtomicUsize = AtomicUsize::new(0);
-
-        struct Foo(u8);
-        impl Default for Foo {
-            fn default() -> Self {
-                CALLED.fetch_add(1, SeqCst);
-                Foo(42)
-            }
-        }
-
-        let lazy: SyncLazy<Mutex<Foo>> = <_>::default();
-
-        assert_eq!(CALLED.load(SeqCst), 0);
-
-        assert_eq!(lazy.lock().unwrap().0, 42);
-        assert_eq!(CALLED.load(SeqCst), 1);
-
-        lazy.lock().unwrap().0 = 21;
-
-        assert_eq!(lazy.lock().unwrap().0, 21);
-        assert_eq!(CALLED.load(SeqCst), 1);
-    }
-
-    #[test]
-    fn static_sync_lazy() {
-        static XS: SyncLazy<Vec<i32>> = SyncLazy::new(|| {
-            let mut xs = Vec::new();
-            xs.push(1);
-            xs.push(2);
-            xs.push(3);
-            xs
-        });
-
-        spawn_and_wait(|| {
-            assert_eq!(&*XS, &vec![1, 2, 3]);
-        });
-
-        assert_eq!(&*XS, &vec![1, 2, 3]);
-    }
-
-    #[test]
-    fn static_sync_lazy_via_fn() {
-        fn xs() -> &'static Vec<i32> {
-            static XS: SyncOnceCell<Vec<i32>> = SyncOnceCell::new();
-            XS.get_or_init(|| {
-                let mut xs = Vec::new();
-                xs.push(1);
-                xs.push(2);
-                xs.push(3);
-                xs
-            })
-        }
-        assert_eq!(xs(), &vec![1, 2, 3]);
-    }
-
-    #[test]
-    fn sync_lazy_poisoning() {
-        let x: SyncLazy<String> = SyncLazy::new(|| panic!("kaboom"));
-        for _ in 0..2 {
-            let res = panic::catch_unwind(|| x.len());
-            assert!(res.is_err());
-        }
-    }
-
-    #[test]
-    fn is_sync_send() {
-        fn assert_traits<T: Send + Sync>() {}
-        assert_traits::<SyncOnceCell<String>>();
-        assert_traits::<SyncLazy<String>>();
-    }
-
-    #[test]
-    fn eval_once_macro() {
-        macro_rules! eval_once {
-            (|| -> $ty:ty {
-                $($body:tt)*
-            }) => {{
-                static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new();
-                fn init() -> $ty {
-                    $($body)*
-                }
-                ONCE_CELL.get_or_init(init)
-            }};
-        }
-
-        let fib: &'static Vec<i32> = eval_once! {
-            || -> Vec<i32> {
-                let mut res = vec![1, 1];
-                for i in 0..10 {
-                    let next = res[i] + res[i + 1];
-                    res.push(next);
-                }
-                res
-            }
-        };
-        assert_eq!(fib[5], 8)
-    }
-
-    #[test]
-    fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
-        static ONCE_CELL: SyncOnceCell<String> = SyncOnceCell::new();
-
-        let n_readers = 10;
-        let n_writers = 3;
-        const MSG: &str = "Hello, World";
-
-        let (tx, rx) = channel();
-
-        for _ in 0..n_readers {
-            let tx = tx.clone();
-            thread::spawn(move || {
-                loop {
-                    if let Some(msg) = ONCE_CELL.get() {
-                        tx.send(msg).unwrap();
-                        break;
-                    }
-                    #[cfg(target_env = "sgx")]
-                    crate::thread::yield_now();
-                }
-            });
-        }
-        for _ in 0..n_writers {
-            thread::spawn(move || {
-                let _ = ONCE_CELL.set(MSG.to_owned());
-            });
-        }
-
-        for _ in 0..n_readers {
-            let msg = rx.recv().unwrap();
-            assert_eq!(msg, MSG);
-        }
-    }
-
-    #[test]
-    fn dropck() {
-        let cell = SyncOnceCell::new();
-        {
-            let s = String::new();
-            cell.set(&s).unwrap();
-        }
-    }
-}
diff --git a/library/std/src/lazy/tests.rs b/library/std/src/lazy/tests.rs
new file mode 100644 (file)
index 0000000..a170edb
--- /dev/null
@@ -0,0 +1,323 @@
+use crate::{
+    lazy::{Lazy, SyncLazy, SyncOnceCell},
+    panic,
+    sync::{
+        atomic::{AtomicUsize, Ordering::SeqCst},
+        mpsc::channel,
+        Mutex,
+    },
+    thread,
+};
+
+#[test]
+fn lazy_default() {
+    static CALLED: AtomicUsize = AtomicUsize::new(0);
+
+    struct Foo(u8);
+    impl Default for Foo {
+        fn default() -> Self {
+            CALLED.fetch_add(1, SeqCst);
+            Foo(42)
+        }
+    }
+
+    let lazy: Lazy<Mutex<Foo>> = <_>::default();
+
+    assert_eq!(CALLED.load(SeqCst), 0);
+
+    assert_eq!(lazy.lock().unwrap().0, 42);
+    assert_eq!(CALLED.load(SeqCst), 1);
+
+    lazy.lock().unwrap().0 = 21;
+
+    assert_eq!(lazy.lock().unwrap().0, 21);
+    assert_eq!(CALLED.load(SeqCst), 1);
+}
+
+#[test]
+fn lazy_poisoning() {
+    let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
+    for _ in 0..2 {
+        let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len()));
+        assert!(res.is_err());
+    }
+}
+
+fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
+    thread::spawn(f).join().unwrap()
+}
+
+#[test]
+fn sync_once_cell() {
+    static ONCE_CELL: SyncOnceCell<i32> = SyncOnceCell::new();
+
+    assert!(ONCE_CELL.get().is_none());
+
+    spawn_and_wait(|| {
+        ONCE_CELL.get_or_init(|| 92);
+        assert_eq!(ONCE_CELL.get(), Some(&92));
+    });
+
+    ONCE_CELL.get_or_init(|| panic!("Kabom!"));
+    assert_eq!(ONCE_CELL.get(), Some(&92));
+}
+
+#[test]
+fn sync_once_cell_get_mut() {
+    let mut c = SyncOnceCell::new();
+    assert!(c.get_mut().is_none());
+    c.set(90).unwrap();
+    *c.get_mut().unwrap() += 2;
+    assert_eq!(c.get_mut(), Some(&mut 92));
+}
+
+#[test]
+fn sync_once_cell_get_unchecked() {
+    let c = SyncOnceCell::new();
+    c.set(92).unwrap();
+    unsafe {
+        assert_eq!(c.get_unchecked(), &92);
+    }
+}
+
+#[test]
+fn sync_once_cell_drop() {
+    static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
+    struct Dropper;
+    impl Drop for Dropper {
+        fn drop(&mut self) {
+            DROP_CNT.fetch_add(1, SeqCst);
+        }
+    }
+
+    let x = SyncOnceCell::new();
+    spawn_and_wait(move || {
+        x.get_or_init(|| Dropper);
+        assert_eq!(DROP_CNT.load(SeqCst), 0);
+        drop(x);
+    });
+
+    assert_eq!(DROP_CNT.load(SeqCst), 1);
+}
+
+#[test]
+fn sync_once_cell_drop_empty() {
+    let x = SyncOnceCell::<String>::new();
+    drop(x);
+}
+
+#[test]
+fn clone() {
+    let s = SyncOnceCell::new();
+    let c = s.clone();
+    assert!(c.get().is_none());
+
+    s.set("hello".to_string()).unwrap();
+    let c = s.clone();
+    assert_eq!(c.get().map(String::as_str), Some("hello"));
+}
+
+#[test]
+fn get_or_try_init() {
+    let cell: SyncOnceCell<String> = SyncOnceCell::new();
+    assert!(cell.get().is_none());
+
+    let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() }));
+    assert!(res.is_err());
+    assert!(!cell.is_initialized());
+    assert!(cell.get().is_none());
+
+    assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
+
+    assert_eq!(cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), Ok(&"hello".to_string()));
+    assert_eq!(cell.get(), Some(&"hello".to_string()));
+}
+
+#[test]
+fn from_impl() {
+    assert_eq!(SyncOnceCell::from("value").get(), Some(&"value"));
+    assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar"));
+}
+
+#[test]
+fn partialeq_impl() {
+    assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value"));
+    assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar"));
+
+    assert!(SyncOnceCell::<String>::new() == SyncOnceCell::new());
+    assert!(SyncOnceCell::<String>::new() != SyncOnceCell::from("value".to_owned()));
+}
+
+#[test]
+fn into_inner() {
+    let cell: SyncOnceCell<String> = SyncOnceCell::new();
+    assert_eq!(cell.into_inner(), None);
+    let cell = SyncOnceCell::new();
+    cell.set("hello".to_string()).unwrap();
+    assert_eq!(cell.into_inner(), Some("hello".to_string()));
+}
+
+#[test]
+fn sync_lazy_new() {
+    static CALLED: AtomicUsize = AtomicUsize::new(0);
+    static SYNC_LAZY: SyncLazy<i32> = SyncLazy::new(|| {
+        CALLED.fetch_add(1, SeqCst);
+        92
+    });
+
+    assert_eq!(CALLED.load(SeqCst), 0);
+
+    spawn_and_wait(|| {
+        let y = *SYNC_LAZY - 30;
+        assert_eq!(y, 62);
+        assert_eq!(CALLED.load(SeqCst), 1);
+    });
+
+    let y = *SYNC_LAZY - 30;
+    assert_eq!(y, 62);
+    assert_eq!(CALLED.load(SeqCst), 1);
+}
+
+#[test]
+fn sync_lazy_default() {
+    static CALLED: AtomicUsize = AtomicUsize::new(0);
+
+    struct Foo(u8);
+    impl Default for Foo {
+        fn default() -> Self {
+            CALLED.fetch_add(1, SeqCst);
+            Foo(42)
+        }
+    }
+
+    let lazy: SyncLazy<Mutex<Foo>> = <_>::default();
+
+    assert_eq!(CALLED.load(SeqCst), 0);
+
+    assert_eq!(lazy.lock().unwrap().0, 42);
+    assert_eq!(CALLED.load(SeqCst), 1);
+
+    lazy.lock().unwrap().0 = 21;
+
+    assert_eq!(lazy.lock().unwrap().0, 21);
+    assert_eq!(CALLED.load(SeqCst), 1);
+}
+
+#[test]
+fn static_sync_lazy() {
+    static XS: SyncLazy<Vec<i32>> = SyncLazy::new(|| {
+        let mut xs = Vec::new();
+        xs.push(1);
+        xs.push(2);
+        xs.push(3);
+        xs
+    });
+
+    spawn_and_wait(|| {
+        assert_eq!(&*XS, &vec![1, 2, 3]);
+    });
+
+    assert_eq!(&*XS, &vec![1, 2, 3]);
+}
+
+#[test]
+fn static_sync_lazy_via_fn() {
+    fn xs() -> &'static Vec<i32> {
+        static XS: SyncOnceCell<Vec<i32>> = SyncOnceCell::new();
+        XS.get_or_init(|| {
+            let mut xs = Vec::new();
+            xs.push(1);
+            xs.push(2);
+            xs.push(3);
+            xs
+        })
+    }
+    assert_eq!(xs(), &vec![1, 2, 3]);
+}
+
+#[test]
+fn sync_lazy_poisoning() {
+    let x: SyncLazy<String> = SyncLazy::new(|| panic!("kaboom"));
+    for _ in 0..2 {
+        let res = panic::catch_unwind(|| x.len());
+        assert!(res.is_err());
+    }
+}
+
+#[test]
+fn is_sync_send() {
+    fn assert_traits<T: Send + Sync>() {}
+    assert_traits::<SyncOnceCell<String>>();
+    assert_traits::<SyncLazy<String>>();
+}
+
+#[test]
+fn eval_once_macro() {
+    macro_rules! eval_once {
+        (|| -> $ty:ty {
+            $($body:tt)*
+        }) => {{
+            static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new();
+            fn init() -> $ty {
+                $($body)*
+            }
+            ONCE_CELL.get_or_init(init)
+        }};
+    }
+
+    let fib: &'static Vec<i32> = eval_once! {
+        || -> Vec<i32> {
+            let mut res = vec![1, 1];
+            for i in 0..10 {
+                let next = res[i] + res[i + 1];
+                res.push(next);
+            }
+            res
+        }
+    };
+    assert_eq!(fib[5], 8)
+}
+
+#[test]
+fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
+    static ONCE_CELL: SyncOnceCell<String> = SyncOnceCell::new();
+
+    let n_readers = 10;
+    let n_writers = 3;
+    const MSG: &str = "Hello, World";
+
+    let (tx, rx) = channel();
+
+    for _ in 0..n_readers {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            loop {
+                if let Some(msg) = ONCE_CELL.get() {
+                    tx.send(msg).unwrap();
+                    break;
+                }
+                #[cfg(target_env = "sgx")]
+                crate::thread::yield_now();
+            }
+        });
+    }
+    for _ in 0..n_writers {
+        thread::spawn(move || {
+            let _ = ONCE_CELL.set(MSG.to_owned());
+        });
+    }
+
+    for _ in 0..n_readers {
+        let msg = rx.recv().unwrap();
+        assert_eq!(msg, MSG);
+    }
+}
+
+#[test]
+fn dropck() {
+    let cell = SyncOnceCell::new();
+    {
+        let s = String::new();
+        cell.set(&s).unwrap();
+    }
+}
index d69294b2d200c81ebca63723f7581e2eb291b888..86a08f75a8d4805e65a1edb976fa19c3cf54ffc0 100644 (file)
@@ -1,6 +1,9 @@
 // Original implementation taken from rust-memchr.
 // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
 
+#[cfg(test)]
+mod tests;
+
 /// A safe interface to `memchr`.
 ///
 /// Returns the index corresponding to the first occurrence of `needle` in
@@ -44,90 +47,3 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
 pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
     crate::sys::memchr::memrchr(needle, haystack)
 }
-
-#[cfg(test)]
-mod tests {
-    // test the implementations for the current platform
-    use super::{memchr, memrchr};
-
-    #[test]
-    fn matches_one() {
-        assert_eq!(Some(0), memchr(b'a', b"a"));
-    }
-
-    #[test]
-    fn matches_begin() {
-        assert_eq!(Some(0), memchr(b'a', b"aaaa"));
-    }
-
-    #[test]
-    fn matches_end() {
-        assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
-    }
-
-    #[test]
-    fn matches_nul() {
-        assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
-    }
-
-    #[test]
-    fn matches_past_nul() {
-        assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
-    }
-
-    #[test]
-    fn no_match_empty() {
-        assert_eq!(None, memchr(b'a', b""));
-    }
-
-    #[test]
-    fn no_match() {
-        assert_eq!(None, memchr(b'a', b"xyz"));
-    }
-
-    #[test]
-    fn matches_one_reversed() {
-        assert_eq!(Some(0), memrchr(b'a', b"a"));
-    }
-
-    #[test]
-    fn matches_begin_reversed() {
-        assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
-    }
-
-    #[test]
-    fn matches_end_reversed() {
-        assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
-    }
-
-    #[test]
-    fn matches_nul_reversed() {
-        assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
-    }
-
-    #[test]
-    fn matches_past_nul_reversed() {
-        assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
-    }
-
-    #[test]
-    fn no_match_empty_reversed() {
-        assert_eq!(None, memrchr(b'a', b""));
-    }
-
-    #[test]
-    fn no_match_reversed() {
-        assert_eq!(None, memrchr(b'a', b"xyz"));
-    }
-
-    #[test]
-    fn each_alignment() {
-        let mut data = [1u8; 64];
-        let needle = 2;
-        let pos = 40;
-        data[pos] = needle;
-        for start in 0..16 {
-            assert_eq!(Some(pos - start), memchr(needle, &data[start..]));
-        }
-    }
-}
diff --git a/library/std/src/memchr/tests.rs b/library/std/src/memchr/tests.rs
new file mode 100644 (file)
index 0000000..557d749
--- /dev/null
@@ -0,0 +1,86 @@
+// Original implementation taken from rust-memchr.
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+// test the implementations for the current platform
+use super::{memchr, memrchr};
+
+#[test]
+fn matches_one() {
+    assert_eq!(Some(0), memchr(b'a', b"a"));
+}
+
+#[test]
+fn matches_begin() {
+    assert_eq!(Some(0), memchr(b'a', b"aaaa"));
+}
+
+#[test]
+fn matches_end() {
+    assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
+}
+
+#[test]
+fn matches_nul() {
+    assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
+}
+
+#[test]
+fn matches_past_nul() {
+    assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
+}
+
+#[test]
+fn no_match_empty() {
+    assert_eq!(None, memchr(b'a', b""));
+}
+
+#[test]
+fn no_match() {
+    assert_eq!(None, memchr(b'a', b"xyz"));
+}
+
+#[test]
+fn matches_one_reversed() {
+    assert_eq!(Some(0), memrchr(b'a', b"a"));
+}
+
+#[test]
+fn matches_begin_reversed() {
+    assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
+}
+
+#[test]
+fn matches_end_reversed() {
+    assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
+}
+
+#[test]
+fn matches_nul_reversed() {
+    assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
+}
+
+#[test]
+fn matches_past_nul_reversed() {
+    assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
+}
+
+#[test]
+fn no_match_empty_reversed() {
+    assert_eq!(None, memrchr(b'a', b""));
+}
+
+#[test]
+fn no_match_reversed() {
+    assert_eq!(None, memrchr(b'a', b"xyz"));
+}
+
+#[test]
+fn each_alignment() {
+    let mut data = [1u8; 64];
+    let needle = 2;
+    let pos = 40;
+    data[pos] = needle;
+    for start in 0..16 {
+        assert_eq!(Some(pos - start), memchr(needle, &data[start..]));
+    }
+}
index d7d96862b2116c0d6706d885b8878c4e3ab21d16..1ba243804fec7b3d790c0b08266a9e9c6f64ac0e 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
 use crate::cmp::Ordering;
 use crate::convert::TryInto;
 use crate::fmt;
@@ -991,236 +994,3 @@ fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
         (&**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());
-    }
-}
diff --git a/library/std/src/net/addr/tests.rs b/library/std/src/net/addr/tests.rs
new file mode 100644 (file)
index 0000000..cee9087
--- /dev/null
@@ -0,0 +1,229 @@
+use crate::net::test::{sa4, sa6, tsa};
+use crate::net::*;
+
+#[test]
+fn to_socket_addr_ipaddr_u16() {
+    let a = Ipv4Addr::new(77, 88, 21, 11);
+    let p = 12345;
+    let e = SocketAddr::V4(SocketAddrV4::new(a, p));
+    assert_eq!(Ok(vec![e]), tsa((a, p)));
+}
+
+#[test]
+fn to_socket_addr_str_u16() {
+    let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
+    assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352)));
+
+    let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
+    assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53)));
+
+    let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924);
+    #[cfg(not(target_env = "sgx"))]
+    assert!(tsa(("localhost", 23924)).unwrap().contains(&a));
+    #[cfg(target_env = "sgx")]
+    let _ = a;
+}
+
+#[test]
+fn to_socket_addr_str() {
+    let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
+    assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352"));
+
+    let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
+    assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53"));
+
+    let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924);
+    #[cfg(not(target_env = "sgx"))]
+    assert!(tsa("localhost:23924").unwrap().contains(&a));
+    #[cfg(target_env = "sgx")]
+    let _ = a;
+}
+
+#[test]
+fn to_socket_addr_string() {
+    let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
+    assert_eq!(Ok(vec![a]), tsa(&*format!("{}:{}", "77.88.21.11", "24352")));
+    assert_eq!(Ok(vec![a]), tsa(&format!("{}:{}", "77.88.21.11", "24352")));
+    assert_eq!(Ok(vec![a]), tsa(format!("{}:{}", "77.88.21.11", "24352")));
+
+    let s = format!("{}:{}", "77.88.21.11", "24352");
+    assert_eq!(Ok(vec![a]), tsa(s));
+    // s has been moved into the tsa call
+}
+
+#[test]
+fn bind_udp_socket_bad() {
+    // rust-lang/rust#53957: This is a regression test for a parsing problem
+    // discovered as part of issue rust-lang/rust#23076, where we were
+    // incorrectly parsing invalid input and then that would result in a
+    // successful `UdpSocket` binding when we would expect failure.
+    //
+    // At one time, this test was written as a call to `tsa` with
+    // INPUT_23076. However, that structure yields an unreliable test,
+    // because it ends up passing junk input to the DNS server, and some DNS
+    // servers will respond with `Ok` to such input, with the ip address of
+    // the DNS server itself.
+    //
+    // This form of the test is more robust: even when the DNS server
+    // returns its own address, it is still an error to bind a UDP socket to
+    // a non-local address, and so we still get an error here in that case.
+
+    const INPUT_23076: &'static str = "1200::AB00:1234::2552:7777:1313:34300";
+
+    assert!(crate::net::UdpSocket::bind(INPUT_23076).is_err())
+}
+
+#[test]
+fn set_ip() {
+    fn ip4(low: u8) -> Ipv4Addr {
+        Ipv4Addr::new(77, 88, 21, low)
+    }
+    fn ip6(low: u16) -> Ipv6Addr {
+        Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low)
+    }
+
+    let mut v4 = SocketAddrV4::new(ip4(11), 80);
+    assert_eq!(v4.ip(), &ip4(11));
+    v4.set_ip(ip4(12));
+    assert_eq!(v4.ip(), &ip4(12));
+
+    let mut addr = SocketAddr::V4(v4);
+    assert_eq!(addr.ip(), IpAddr::V4(ip4(12)));
+    addr.set_ip(IpAddr::V4(ip4(13)));
+    assert_eq!(addr.ip(), IpAddr::V4(ip4(13)));
+    addr.set_ip(IpAddr::V6(ip6(14)));
+    assert_eq!(addr.ip(), IpAddr::V6(ip6(14)));
+
+    let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0);
+    assert_eq!(v6.ip(), &ip6(1));
+    v6.set_ip(ip6(2));
+    assert_eq!(v6.ip(), &ip6(2));
+
+    let mut addr = SocketAddr::V6(v6);
+    assert_eq!(addr.ip(), IpAddr::V6(ip6(2)));
+    addr.set_ip(IpAddr::V6(ip6(3)));
+    assert_eq!(addr.ip(), IpAddr::V6(ip6(3)));
+    addr.set_ip(IpAddr::V4(ip4(4)));
+    assert_eq!(addr.ip(), IpAddr::V4(ip4(4)));
+}
+
+#[test]
+fn set_port() {
+    let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80);
+    assert_eq!(v4.port(), 80);
+    v4.set_port(443);
+    assert_eq!(v4.port(), 443);
+
+    let mut addr = SocketAddr::V4(v4);
+    assert_eq!(addr.port(), 443);
+    addr.set_port(8080);
+    assert_eq!(addr.port(), 8080);
+
+    let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0);
+    assert_eq!(v6.port(), 80);
+    v6.set_port(443);
+    assert_eq!(v6.port(), 443);
+
+    let mut addr = SocketAddr::V6(v6);
+    assert_eq!(addr.port(), 443);
+    addr.set_port(8080);
+    assert_eq!(addr.port(), 8080);
+}
+
+#[test]
+fn set_flowinfo() {
+    let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0);
+    assert_eq!(v6.flowinfo(), 10);
+    v6.set_flowinfo(20);
+    assert_eq!(v6.flowinfo(), 20);
+}
+
+#[test]
+fn set_scope_id() {
+    let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10);
+    assert_eq!(v6.scope_id(), 10);
+    v6.set_scope_id(20);
+    assert_eq!(v6.scope_id(), 20);
+}
+
+#[test]
+fn is_v4() {
+    let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80));
+    assert!(v4.is_ipv4());
+    assert!(!v4.is_ipv6());
+}
+
+#[test]
+fn is_v6() {
+    let v6 = SocketAddr::V6(SocketAddrV6::new(
+        Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1),
+        80,
+        10,
+        0,
+    ));
+    assert!(!v6.is_ipv4());
+    assert!(v6.is_ipv6());
+}
+
+#[test]
+fn socket_v4_to_str() {
+    let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080);
+
+    assert_eq!(format!("{}", socket), "192.168.0.1:8080");
+    assert_eq!(format!("{:<20}", socket), "192.168.0.1:8080    ");
+    assert_eq!(format!("{:>20}", socket), "    192.168.0.1:8080");
+    assert_eq!(format!("{:^20}", socket), "  192.168.0.1:8080  ");
+    assert_eq!(format!("{:.10}", socket), "192.168.0.");
+}
+
+#[test]
+fn socket_v6_to_str() {
+    let socket: SocketAddrV6 = "[2a02:6b8:0:1::1]:53".parse().unwrap();
+
+    assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53");
+    assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53    ");
+    assert_eq!(format!("{:>24}", socket), "    [2a02:6b8:0:1::1]:53");
+    assert_eq!(format!("{:^24}", socket), "  [2a02:6b8:0:1::1]:53  ");
+    assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::");
+}
+
+#[test]
+fn compare() {
+    let v4_1 = "224.120.45.1:23456".parse::<SocketAddrV4>().unwrap();
+    let v4_2 = "224.210.103.5:12345".parse::<SocketAddrV4>().unwrap();
+    let v4_3 = "224.210.103.5:23456".parse::<SocketAddrV4>().unwrap();
+    let v6_1 = "[2001:db8:f00::1002]:23456".parse::<SocketAddrV6>().unwrap();
+    let v6_2 = "[2001:db8:f00::2001]:12345".parse::<SocketAddrV6>().unwrap();
+    let v6_3 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap();
+
+    // equality
+    assert_eq!(v4_1, v4_1);
+    assert_eq!(v6_1, v6_1);
+    assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1));
+    assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1));
+    assert!(v4_1 != v4_2);
+    assert!(v6_1 != v6_2);
+
+    // compare different addresses
+    assert!(v4_1 < v4_2);
+    assert!(v6_1 < v6_2);
+    assert!(v4_2 > v4_1);
+    assert!(v6_2 > v6_1);
+
+    // compare the same address with different ports
+    assert!(v4_2 < v4_3);
+    assert!(v6_2 < v6_3);
+    assert!(v4_3 > v4_2);
+    assert!(v6_3 > v6_2);
+
+    // compare different addresses with the same port
+    assert!(v4_1 < v4_3);
+    assert!(v6_1 < v6_3);
+    assert!(v4_3 > v4_1);
+    assert!(v6_3 > v6_1);
+
+    // compare with an inferred right-hand side
+    assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap());
+    assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap());
+    assert_eq!(SocketAddr::V4(v4_1), "224.120.45.1:23456".parse().unwrap());
+}
index 85bb6b60e6829da3d872348c3dc78a0904dba746..10676b49d43753547b443aa6c4d2a1f6c3613d35 100644 (file)
@@ -6,6 +6,10 @@
     issue = "27709"
 )]
 
+// Tests for this module
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
 use crate::cmp::Ordering;
 use crate::fmt::{self, Write as FmtWrite};
 use crate::hash;
@@ -1895,862 +1899,3 @@ fn from(ip: u128) -> Ipv6Addr {
         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());
-    }
-}
diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs
new file mode 100644 (file)
index 0000000..a2fba4b
--- /dev/null
@@ -0,0 +1,811 @@
+use crate::net::test::{sa4, sa6, tsa};
+use crate::net::*;
+use crate::str::FromStr;
+
+#[test]
+fn test_from_str_ipv4() {
+    assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse());
+    assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse());
+    assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse());
+
+    // out of range
+    let none: Option<Ipv4Addr> = "256.0.0.1".parse().ok();
+    assert_eq!(None, none);
+    // too short
+    let none: Option<Ipv4Addr> = "255.0.0".parse().ok();
+    assert_eq!(None, none);
+    // too long
+    let none: Option<Ipv4Addr> = "255.0.0.1.2".parse().ok();
+    assert_eq!(None, none);
+    // no number between dots
+    let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
+    assert_eq!(None, none);
+}
+
+#[test]
+fn test_from_str_ipv6() {
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse());
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse());
+
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse());
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse());
+
+    assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse());
+
+    // too long group
+    let none: Option<Ipv6Addr> = "::00000".parse().ok();
+    assert_eq!(None, none);
+    // too short
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7".parse().ok();
+    assert_eq!(None, none);
+    // too long
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:8:9".parse().ok();
+    assert_eq!(None, none);
+    // triple colon
+    let none: Option<Ipv6Addr> = "1:2:::6:7:8".parse().ok();
+    assert_eq!(None, none);
+    // two double colons
+    let none: Option<Ipv6Addr> = "1:2::6::8".parse().ok();
+    assert_eq!(None, none);
+    // `::` indicating zero groups of zeros
+    let none: Option<Ipv6Addr> = "1:2:3:4::5:6:7:8".parse().ok();
+    assert_eq!(None, none);
+}
+
+#[test]
+fn test_from_str_ipv4_in_ipv6() {
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse());
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse());
+    assert_eq!(
+        Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
+        "64:ff9b::192.0.2.33".parse()
+    );
+    assert_eq!(
+        Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
+        "2001:db8:122:c000:2:2100:192.0.2.33".parse()
+    );
+
+    // colon after v4
+    let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
+    assert_eq!(None, none);
+    // not enough groups
+    let none: Option<Ipv6Addr> = "1.2.3.4.5:127.0.0.1".parse().ok();
+    assert_eq!(None, none);
+    // too many groups
+    let none: Option<Ipv6Addr> = "1.2.3.4.5:6:7:127.0.0.1".parse().ok();
+    assert_eq!(None, none);
+}
+
+#[test]
+fn test_from_str_socket_addr() {
+    assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
+    assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
+    assert_eq!(
+        Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)),
+        "[2a02:6b8:0:1::1]:53".parse()
+    );
+    assert_eq!(
+        Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)),
+        "[2a02:6b8:0:1::1]:53".parse()
+    );
+    assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse());
+    assert_eq!(
+        Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)),
+        "[::127.0.0.1]:22".parse()
+    );
+
+    // without port
+    let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
+    assert_eq!(None, none);
+    // without port
+    let none: Option<SocketAddr> = "127.0.0.1:".parse().ok();
+    assert_eq!(None, none);
+    // wrong brackets around v4
+    let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok();
+    assert_eq!(None, none);
+    // port out of range
+    let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok();
+    assert_eq!(None, none);
+}
+
+#[test]
+fn ipv4_addr_to_string() {
+    assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1");
+    // Short address
+    assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1");
+    // Long address
+    assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127");
+
+    // Test padding
+    assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1         ");
+    assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), "         1.1.1.1");
+}
+
+#[test]
+fn ipv6_addr_to_string() {
+    // ipv4-mapped address
+    let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280);
+    assert_eq!(a1.to_string(), "::ffff:192.0.2.128");
+
+    // ipv4-compatible address
+    let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280);
+    assert_eq!(a1.to_string(), "::192.0.2.128");
+
+    // v6 address with no zero segments
+    assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f");
+
+    // longest possible IPv6 length
+    assert_eq!(
+        Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(),
+        "1111:2222:3333:4444:5555:6666:7777:8888"
+    );
+    // padding
+    assert_eq!(&format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8     ");
+    assert_eq!(&format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "     1:2:3:4:5:6:7:8");
+
+    // reduce a single run of zeros
+    assert_eq!(
+        "ae::ffff:102:304",
+        Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string()
+    );
+
+    // don't reduce just a single zero segment
+    assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string());
+
+    // 'any' address
+    assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string());
+
+    // loopback address
+    assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string());
+
+    // ends in zeros
+    assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string());
+
+    // two runs of zeros, second one is longer
+    assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string());
+
+    // two runs of zeros, equal length
+    assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string());
+}
+
+#[test]
+fn ipv4_to_ipv6() {
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678),
+        Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped()
+    );
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678),
+        Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible()
+    );
+}
+
+#[test]
+fn ipv6_to_ipv4_mapped() {
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(),
+        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
+    );
+    assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None);
+}
+
+#[test]
+fn ipv6_to_ipv4() {
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(),
+        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
+    );
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
+        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
+    );
+    assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None);
+}
+
+#[test]
+fn ip_properties() {
+    macro_rules! ip {
+        ($s:expr) => {
+            IpAddr::from_str($s).unwrap()
+        };
+    }
+
+    macro_rules! check {
+        ($s:expr) => {
+            check!($s, 0);
+        };
+
+        ($s:expr, $mask:expr) => {{
+            let unspec: u8 = 1 << 0;
+            let loopback: u8 = 1 << 1;
+            let global: u8 = 1 << 2;
+            let multicast: u8 = 1 << 3;
+            let doc: u8 = 1 << 4;
+
+            if ($mask & unspec) == unspec {
+                assert!(ip!($s).is_unspecified());
+            } else {
+                assert!(!ip!($s).is_unspecified());
+            }
+
+            if ($mask & loopback) == loopback {
+                assert!(ip!($s).is_loopback());
+            } else {
+                assert!(!ip!($s).is_loopback());
+            }
+
+            if ($mask & global) == global {
+                assert!(ip!($s).is_global());
+            } else {
+                assert!(!ip!($s).is_global());
+            }
+
+            if ($mask & multicast) == multicast {
+                assert!(ip!($s).is_multicast());
+            } else {
+                assert!(!ip!($s).is_multicast());
+            }
+
+            if ($mask & doc) == doc {
+                assert!(ip!($s).is_documentation());
+            } else {
+                assert!(!ip!($s).is_documentation());
+            }
+        }};
+    }
+
+    let unspec: u8 = 1 << 0;
+    let loopback: u8 = 1 << 1;
+    let global: u8 = 1 << 2;
+    let multicast: u8 = 1 << 3;
+    let doc: u8 = 1 << 4;
+
+    check!("0.0.0.0", unspec);
+    check!("0.0.0.1");
+    check!("0.1.0.0");
+    check!("10.9.8.7");
+    check!("127.1.2.3", loopback);
+    check!("172.31.254.253");
+    check!("169.254.253.242");
+    check!("192.0.2.183", doc);
+    check!("192.1.2.183", global);
+    check!("192.168.254.253");
+    check!("198.51.100.0", doc);
+    check!("203.0.113.0", doc);
+    check!("203.2.113.0", global);
+    check!("224.0.0.0", global | multicast);
+    check!("239.255.255.255", global | multicast);
+    check!("255.255.255.255");
+    // make sure benchmarking addresses are not global
+    check!("198.18.0.0");
+    check!("198.18.54.2");
+    check!("198.19.255.255");
+    // make sure addresses reserved for protocol assignment are not global
+    check!("192.0.0.0");
+    check!("192.0.0.255");
+    check!("192.0.0.100");
+    // make sure reserved addresses are not global
+    check!("240.0.0.0");
+    check!("251.54.1.76");
+    check!("254.255.255.255");
+    // make sure shared addresses are not global
+    check!("100.64.0.0");
+    check!("100.127.255.255");
+    check!("100.100.100.0");
+
+    check!("::", unspec);
+    check!("::1", loopback);
+    check!("::0.0.0.2", global);
+    check!("1::", global);
+    check!("fc00::");
+    check!("fdff:ffff::");
+    check!("fe80:ffff::");
+    check!("febf:ffff::");
+    check!("fec0::", global);
+    check!("ff01::", multicast);
+    check!("ff02::", multicast);
+    check!("ff03::", multicast);
+    check!("ff04::", multicast);
+    check!("ff05::", multicast);
+    check!("ff08::", multicast);
+    check!("ff0e::", global | multicast);
+    check!("2001:db8:85a3::8a2e:370:7334", doc);
+    check!("102:304:506:708:90a:b0c:d0e:f10", global);
+}
+
+#[test]
+fn ipv4_properties() {
+    macro_rules! ip {
+        ($s:expr) => {
+            Ipv4Addr::from_str($s).unwrap()
+        };
+    }
+
+    macro_rules! check {
+        ($s:expr) => {
+            check!($s, 0);
+        };
+
+        ($s:expr, $mask:expr) => {{
+            let unspec: u16 = 1 << 0;
+            let loopback: u16 = 1 << 1;
+            let private: u16 = 1 << 2;
+            let link_local: u16 = 1 << 3;
+            let global: u16 = 1 << 4;
+            let multicast: u16 = 1 << 5;
+            let broadcast: u16 = 1 << 6;
+            let documentation: u16 = 1 << 7;
+            let benchmarking: u16 = 1 << 8;
+            let ietf_protocol_assignment: u16 = 1 << 9;
+            let reserved: u16 = 1 << 10;
+            let shared: u16 = 1 << 11;
+
+            if ($mask & unspec) == unspec {
+                assert!(ip!($s).is_unspecified());
+            } else {
+                assert!(!ip!($s).is_unspecified());
+            }
+
+            if ($mask & loopback) == loopback {
+                assert!(ip!($s).is_loopback());
+            } else {
+                assert!(!ip!($s).is_loopback());
+            }
+
+            if ($mask & private) == private {
+                assert!(ip!($s).is_private());
+            } else {
+                assert!(!ip!($s).is_private());
+            }
+
+            if ($mask & link_local) == link_local {
+                assert!(ip!($s).is_link_local());
+            } else {
+                assert!(!ip!($s).is_link_local());
+            }
+
+            if ($mask & global) == global {
+                assert!(ip!($s).is_global());
+            } else {
+                assert!(!ip!($s).is_global());
+            }
+
+            if ($mask & multicast) == multicast {
+                assert!(ip!($s).is_multicast());
+            } else {
+                assert!(!ip!($s).is_multicast());
+            }
+
+            if ($mask & broadcast) == broadcast {
+                assert!(ip!($s).is_broadcast());
+            } else {
+                assert!(!ip!($s).is_broadcast());
+            }
+
+            if ($mask & documentation) == documentation {
+                assert!(ip!($s).is_documentation());
+            } else {
+                assert!(!ip!($s).is_documentation());
+            }
+
+            if ($mask & benchmarking) == benchmarking {
+                assert!(ip!($s).is_benchmarking());
+            } else {
+                assert!(!ip!($s).is_benchmarking());
+            }
+
+            if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment {
+                assert!(ip!($s).is_ietf_protocol_assignment());
+            } else {
+                assert!(!ip!($s).is_ietf_protocol_assignment());
+            }
+
+            if ($mask & reserved) == reserved {
+                assert!(ip!($s).is_reserved());
+            } else {
+                assert!(!ip!($s).is_reserved());
+            }
+
+            if ($mask & shared) == shared {
+                assert!(ip!($s).is_shared());
+            } else {
+                assert!(!ip!($s).is_shared());
+            }
+        }};
+    }
+
+    let unspec: u16 = 1 << 0;
+    let loopback: u16 = 1 << 1;
+    let private: u16 = 1 << 2;
+    let link_local: u16 = 1 << 3;
+    let global: u16 = 1 << 4;
+    let multicast: u16 = 1 << 5;
+    let broadcast: u16 = 1 << 6;
+    let documentation: u16 = 1 << 7;
+    let benchmarking: u16 = 1 << 8;
+    let ietf_protocol_assignment: u16 = 1 << 9;
+    let reserved: u16 = 1 << 10;
+    let shared: u16 = 1 << 11;
+
+    check!("0.0.0.0", unspec);
+    check!("0.0.0.1");
+    check!("0.1.0.0");
+    check!("10.9.8.7", private);
+    check!("127.1.2.3", loopback);
+    check!("172.31.254.253", private);
+    check!("169.254.253.242", link_local);
+    check!("192.0.2.183", documentation);
+    check!("192.1.2.183", global);
+    check!("192.168.254.253", private);
+    check!("198.51.100.0", documentation);
+    check!("203.0.113.0", documentation);
+    check!("203.2.113.0", global);
+    check!("224.0.0.0", global | multicast);
+    check!("239.255.255.255", global | multicast);
+    check!("255.255.255.255", broadcast);
+    check!("198.18.0.0", benchmarking);
+    check!("198.18.54.2", benchmarking);
+    check!("198.19.255.255", benchmarking);
+    check!("192.0.0.0", ietf_protocol_assignment);
+    check!("192.0.0.255", ietf_protocol_assignment);
+    check!("192.0.0.100", ietf_protocol_assignment);
+    check!("240.0.0.0", reserved);
+    check!("251.54.1.76", reserved);
+    check!("254.255.255.255", reserved);
+    check!("100.64.0.0", shared);
+    check!("100.127.255.255", shared);
+    check!("100.100.100.0", shared);
+}
+
+#[test]
+fn ipv6_properties() {
+    macro_rules! ip {
+        ($s:expr) => {
+            Ipv6Addr::from_str($s).unwrap()
+        };
+    }
+
+    macro_rules! check {
+        ($s:expr, &[$($octet:expr),*], $mask:expr) => {
+            assert_eq!($s, ip!($s).to_string());
+            let octets = &[$($octet),*];
+            assert_eq!(&ip!($s).octets(), octets);
+            assert_eq!(Ipv6Addr::from(*octets), ip!($s));
+
+            let unspecified: u16 = 1 << 0;
+            let loopback: u16 = 1 << 1;
+            let unique_local: u16 = 1 << 2;
+            let global: u16 = 1 << 3;
+            let unicast_link_local: u16 = 1 << 4;
+            let unicast_link_local_strict: u16 = 1 << 5;
+            let unicast_site_local: u16 = 1 << 6;
+            let unicast_global: u16 = 1 << 7;
+            let documentation: u16 = 1 << 8;
+            let multicast_interface_local: u16 = 1 << 9;
+            let multicast_link_local: u16 = 1 << 10;
+            let multicast_realm_local: u16 = 1 << 11;
+            let multicast_admin_local: u16 = 1 << 12;
+            let multicast_site_local: u16 = 1 << 13;
+            let multicast_organization_local: u16 = 1 << 14;
+            let multicast_global: u16 = 1 << 15;
+            let multicast: u16 = multicast_interface_local
+                | multicast_admin_local
+                | multicast_global
+                | multicast_link_local
+                | multicast_realm_local
+                | multicast_site_local
+                | multicast_organization_local;
+
+            if ($mask & unspecified) == unspecified {
+                assert!(ip!($s).is_unspecified());
+            } else {
+                assert!(!ip!($s).is_unspecified());
+            }
+            if ($mask & loopback) == loopback {
+                assert!(ip!($s).is_loopback());
+            } else {
+                assert!(!ip!($s).is_loopback());
+            }
+            if ($mask & unique_local) == unique_local {
+                assert!(ip!($s).is_unique_local());
+            } else {
+                assert!(!ip!($s).is_unique_local());
+            }
+            if ($mask & global) == global {
+                assert!(ip!($s).is_global());
+            } else {
+                assert!(!ip!($s).is_global());
+            }
+            if ($mask & unicast_link_local) == unicast_link_local {
+                assert!(ip!($s).is_unicast_link_local());
+            } else {
+                assert!(!ip!($s).is_unicast_link_local());
+            }
+            if ($mask & unicast_link_local_strict) == unicast_link_local_strict {
+                assert!(ip!($s).is_unicast_link_local_strict());
+            } else {
+                assert!(!ip!($s).is_unicast_link_local_strict());
+            }
+            if ($mask & unicast_site_local) == unicast_site_local {
+                assert!(ip!($s).is_unicast_site_local());
+            } else {
+                assert!(!ip!($s).is_unicast_site_local());
+            }
+            if ($mask & unicast_global) == unicast_global {
+                assert!(ip!($s).is_unicast_global());
+            } else {
+                assert!(!ip!($s).is_unicast_global());
+            }
+            if ($mask & documentation) == documentation {
+                assert!(ip!($s).is_documentation());
+            } else {
+                assert!(!ip!($s).is_documentation());
+            }
+            if ($mask & multicast) != 0 {
+                assert!(ip!($s).multicast_scope().is_some());
+                assert!(ip!($s).is_multicast());
+            } else {
+                assert!(ip!($s).multicast_scope().is_none());
+                assert!(!ip!($s).is_multicast());
+            }
+            if ($mask & multicast_interface_local) == multicast_interface_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::InterfaceLocal);
+            }
+            if ($mask & multicast_link_local) == multicast_link_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::LinkLocal);
+            }
+            if ($mask & multicast_realm_local) == multicast_realm_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::RealmLocal);
+            }
+            if ($mask & multicast_admin_local) == multicast_admin_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::AdminLocal);
+            }
+            if ($mask & multicast_site_local) == multicast_site_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::SiteLocal);
+            }
+            if ($mask & multicast_organization_local) == multicast_organization_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::OrganizationLocal);
+            }
+            if ($mask & multicast_global) == multicast_global {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::Global);
+            }
+        }
+    }
+
+    let unspecified: u16 = 1 << 0;
+    let loopback: u16 = 1 << 1;
+    let unique_local: u16 = 1 << 2;
+    let global: u16 = 1 << 3;
+    let unicast_link_local: u16 = 1 << 4;
+    let unicast_link_local_strict: u16 = 1 << 5;
+    let unicast_site_local: u16 = 1 << 6;
+    let unicast_global: u16 = 1 << 7;
+    let documentation: u16 = 1 << 8;
+    let multicast_interface_local: u16 = 1 << 9;
+    let multicast_link_local: u16 = 1 << 10;
+    let multicast_realm_local: u16 = 1 << 11;
+    let multicast_admin_local: u16 = 1 << 12;
+    let multicast_site_local: u16 = 1 << 13;
+    let multicast_organization_local: u16 = 1 << 14;
+    let multicast_global: u16 = 1 << 15;
+
+    check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified);
+
+    check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback);
+
+    check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global);
+
+    check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
+
+    check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
+
+    check!(
+        "fdff:ffff::",
+        &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unique_local
+    );
+
+    check!(
+        "fe80:ffff::",
+        &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_link_local
+    );
+
+    check!(
+        "fe80::",
+        &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_link_local | unicast_link_local_strict
+    );
+
+    check!(
+        "febf:ffff::",
+        &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_link_local
+    );
+
+    check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
+
+    check!(
+        "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+        &[
+            0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff
+        ],
+        unicast_link_local
+    );
+
+    check!(
+        "fe80::ffff:ffff:ffff:ffff",
+        &[
+            0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff
+        ],
+        unicast_link_local | unicast_link_local_strict
+    );
+
+    check!(
+        "fe80:0:0:1::",
+        &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_link_local
+    );
+
+    check!(
+        "fec0::",
+        &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_site_local | unicast_global | global
+    );
+
+    check!(
+        "ff01::",
+        &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_interface_local
+    );
+
+    check!("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_link_local);
+
+    check!("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_realm_local);
+
+    check!("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_admin_local);
+
+    check!("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_site_local);
+
+    check!(
+        "ff08::",
+        &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_organization_local
+    );
+
+    check!(
+        "ff0e::",
+        &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_global | global
+    );
+
+    check!(
+        "2001:db8:85a3::8a2e:370:7334",
+        &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],
+        documentation
+    );
+
+    check!(
+        "102:304:506:708:90a:b0c:d0e:f10",
+        &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
+        global | unicast_global
+    );
+}
+
+#[test]
+fn to_socket_addr_socketaddr() {
+    let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345);
+    assert_eq!(Ok(vec![a]), tsa(a));
+}
+
+#[test]
+fn test_ipv4_to_int() {
+    let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
+    assert_eq!(u32::from(a), 0x11223344);
+}
+
+#[test]
+fn test_int_to_ipv4() {
+    let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
+    assert_eq!(Ipv4Addr::from(0x11223344), a);
+}
+
+#[test]
+fn test_ipv6_to_int() {
+    let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
+    assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128);
+}
+
+#[test]
+fn test_int_to_ipv6() {
+    let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
+    assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a);
+}
+
+#[test]
+fn ipv4_from_constructors() {
+    assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1));
+    assert!(Ipv4Addr::LOCALHOST.is_loopback());
+    assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0));
+    assert!(Ipv4Addr::UNSPECIFIED.is_unspecified());
+    assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255));
+    assert!(Ipv4Addr::BROADCAST.is_broadcast());
+}
+
+#[test]
+fn ipv6_from_contructors() {
+    assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+    assert!(Ipv6Addr::LOCALHOST.is_loopback());
+    assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
+    assert!(Ipv6Addr::UNSPECIFIED.is_unspecified());
+}
+
+#[test]
+fn ipv4_from_octets() {
+    assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1))
+}
+
+#[test]
+fn ipv6_from_segments() {
+    let from_u16s =
+        Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
+    let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff);
+    assert_eq!(new, from_u16s);
+}
+
+#[test]
+fn ipv6_from_octets() {
+    let from_u16s =
+        Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
+    let from_u8s = Ipv6Addr::from([
+        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
+        0xff,
+    ]);
+    assert_eq!(from_u16s, from_u8s);
+}
+
+#[test]
+fn cmp() {
+    let v41 = Ipv4Addr::new(100, 64, 3, 3);
+    let v42 = Ipv4Addr::new(192, 0, 2, 2);
+    let v61 = "2001:db8:f00::1002".parse::<Ipv6Addr>().unwrap();
+    let v62 = "2001:db8:f00::2001".parse::<Ipv6Addr>().unwrap();
+    assert!(v41 < v42);
+    assert!(v61 < v62);
+
+    assert_eq!(v41, IpAddr::V4(v41));
+    assert_eq!(v61, IpAddr::V6(v61));
+    assert!(v41 != IpAddr::V4(v42));
+    assert!(v61 != IpAddr::V6(v62));
+
+    assert!(v41 < IpAddr::V4(v42));
+    assert!(v61 < IpAddr::V6(v62));
+    assert!(IpAddr::V4(v41) < v42);
+    assert!(IpAddr::V6(v61) < v62);
+
+    assert!(v41 < IpAddr::V6(v61));
+    assert!(IpAddr::V4(v41) < v61);
+}
+
+#[test]
+fn is_v4() {
+    let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3));
+    assert!(ip.is_ipv4());
+    assert!(!ip.is_ipv6());
+}
+
+#[test]
+fn is_v6() {
+    let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678));
+    assert!(!ip.is_ipv4());
+    assert!(ip.is_ipv6());
+}
index a425aca5a646debbdeadf98844601dafc3fb70d5..0570a7c41bfe60b62390d4fac0b3124e629779c2 100644 (file)
@@ -3,6 +3,9 @@
 //! This module is "publicly exported" through the `FromStr` implementations
 //! below.
 
+#[cfg(test)]
+mod tests;
+
 use crate::error::Error;
 use crate::fmt;
 use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
@@ -321,146 +324,3 @@ fn description(&self) -> &str {
         "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());
-    }
-}
diff --git a/library/std/src/net/parser/tests.rs b/library/std/src/net/parser/tests.rs
new file mode 100644 (file)
index 0000000..ecf5a78
--- /dev/null
@@ -0,0 +1,139 @@
+// FIXME: These tests are all excellent candidates for AFL fuzz testing
+use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+use crate::str::FromStr;
+
+const PORT: u16 = 8080;
+
+const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1);
+const IPV4_STR: &str = "192.168.0.1";
+const IPV4_STR_PORT: &str = "192.168.0.1:8080";
+
+const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1);
+const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1";
+const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1";
+const IPV6_STR_V4: &str = "2001:db8::192.168.0.1";
+const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080";
+
+#[test]
+fn parse_ipv4() {
+    let result: Ipv4Addr = IPV4_STR.parse().unwrap();
+    assert_eq!(result, IPV4);
+
+    assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err());
+    assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err());
+    assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err());
+    assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err());
+    assert!(Ipv4Addr::from_str(IPV6_STR_PORT).is_err());
+}
+
+#[test]
+fn parse_ipv6() {
+    let result: Ipv6Addr = IPV6_STR_FULL.parse().unwrap();
+    assert_eq!(result, IPV6);
+
+    let result: Ipv6Addr = IPV6_STR_COMPRESS.parse().unwrap();
+    assert_eq!(result, IPV6);
+
+    let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap();
+    assert_eq!(result, IPV6);
+
+    assert!(Ipv6Addr::from_str(IPV4_STR).is_err());
+    assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err());
+    assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err());
+}
+
+#[test]
+fn parse_ip() {
+    let result: IpAddr = IPV4_STR.parse().unwrap();
+    assert_eq!(result, IpAddr::from(IPV4));
+
+    let result: IpAddr = IPV6_STR_FULL.parse().unwrap();
+    assert_eq!(result, IpAddr::from(IPV6));
+
+    let result: IpAddr = IPV6_STR_COMPRESS.parse().unwrap();
+    assert_eq!(result, IpAddr::from(IPV6));
+
+    let result: IpAddr = IPV6_STR_V4.parse().unwrap();
+    assert_eq!(result, IpAddr::from(IPV6));
+
+    assert!(IpAddr::from_str(IPV4_STR_PORT).is_err());
+    assert!(IpAddr::from_str(IPV6_STR_PORT).is_err());
+}
+
+#[test]
+fn parse_socket_v4() {
+    let result: SocketAddrV4 = IPV4_STR_PORT.parse().unwrap();
+    assert_eq!(result, SocketAddrV4::new(IPV4, PORT));
+
+    assert!(SocketAddrV4::from_str(IPV4_STR).is_err());
+    assert!(SocketAddrV4::from_str(IPV6_STR_FULL).is_err());
+    assert!(SocketAddrV4::from_str(IPV6_STR_COMPRESS).is_err());
+    assert!(SocketAddrV4::from_str(IPV6_STR_V4).is_err());
+    assert!(SocketAddrV4::from_str(IPV6_STR_PORT).is_err());
+}
+
+#[test]
+fn parse_socket_v6() {
+    let result: SocketAddrV6 = IPV6_STR_PORT.parse().unwrap();
+    assert_eq!(result, SocketAddrV6::new(IPV6, PORT, 0, 0));
+
+    assert!(SocketAddrV6::from_str(IPV4_STR).is_err());
+    assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err());
+    assert!(SocketAddrV6::from_str(IPV6_STR_FULL).is_err());
+    assert!(SocketAddrV6::from_str(IPV6_STR_COMPRESS).is_err());
+    assert!(SocketAddrV6::from_str(IPV6_STR_V4).is_err());
+}
+
+#[test]
+fn parse_socket() {
+    let result: SocketAddr = IPV4_STR_PORT.parse().unwrap();
+    assert_eq!(result, SocketAddr::from((IPV4, PORT)));
+
+    let result: SocketAddr = IPV6_STR_PORT.parse().unwrap();
+    assert_eq!(result, SocketAddr::from((IPV6, PORT)));
+
+    assert!(SocketAddr::from_str(IPV4_STR).is_err());
+    assert!(SocketAddr::from_str(IPV6_STR_FULL).is_err());
+    assert!(SocketAddr::from_str(IPV6_STR_COMPRESS).is_err());
+    assert!(SocketAddr::from_str(IPV6_STR_V4).is_err());
+}
+
+#[test]
+fn ipv6_corner_cases() {
+    let result: Ipv6Addr = "1::".parse().unwrap();
+    assert_eq!(result, Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0));
+
+    let result: Ipv6Addr = "1:1::".parse().unwrap();
+    assert_eq!(result, Ipv6Addr::new(1, 1, 0, 0, 0, 0, 0, 0));
+
+    let result: Ipv6Addr = "::1".parse().unwrap();
+    assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+
+    let result: Ipv6Addr = "::1:1".parse().unwrap();
+    assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 1, 1));
+
+    let result: Ipv6Addr = "::".parse().unwrap();
+    assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
+
+    let result: Ipv6Addr = "::192.168.0.1".parse().unwrap();
+    assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc0a8, 0x1));
+
+    let result: Ipv6Addr = "::1:192.168.0.1".parse().unwrap();
+    assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 1, 0xc0a8, 0x1));
+
+    let result: Ipv6Addr = "1:1:1:1:1:1:192.168.0.1".parse().unwrap();
+    assert_eq!(result, Ipv6Addr::new(1, 1, 1, 1, 1, 1, 0xc0a8, 0x1));
+}
+
+// Things that might not seem like failures but are
+#[test]
+fn ipv6_corner_failures() {
+    // No IP address before the ::
+    assert!(Ipv6Addr::from_str("1:192.168.0.1::").is_err());
+
+    // :: must have at least 1 set of zeroes
+    assert!(Ipv6Addr::from_str("1:1:1:1::1:1:1:1").is_err());
+
+    // Need brackets for a port
+    assert!(SocketAddrV6::from_str("1:1:1:1:1:1:1:1:8080").is_err());
+}
index a76c9c46c05d2d1068db981c9a7a7c91e1f1a342..58c6343ea34ae9f89ffdaa2b1b15373ee7594d0f 100644 (file)
@@ -1,4 +1,8 @@
 #![deny(unsafe_op_in_unsafe_fn)]
+
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
+mod tests;
+
 use crate::io::prelude::*;
 
 use crate::fmt;
@@ -936,869 +940,3 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         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();
-    }
-}
diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs
new file mode 100644 (file)
index 0000000..abe9bc2
--- /dev/null
@@ -0,0 +1,862 @@
+use crate::fmt;
+use crate::io::prelude::*;
+use crate::io::{ErrorKind, IoSlice, IoSliceMut};
+use crate::net::test::{next_test_ip4, next_test_ip6};
+use crate::net::*;
+use crate::sync::mpsc::channel;
+use crate::thread;
+use crate::time::{Duration, Instant};
+
+fn each_ip(f: &mut dyn FnMut(SocketAddr)) {
+    f(next_test_ip4());
+    f(next_test_ip6());
+}
+
+macro_rules! t {
+    ($e:expr) => {
+        match $e {
+            Ok(t) => t,
+            Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+        }
+    };
+}
+
+#[test]
+fn bind_error() {
+    match TcpListener::bind("1.1.1.1:9999") {
+        Ok(..) => panic!(),
+        Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable),
+    }
+}
+
+#[test]
+fn connect_error() {
+    match TcpStream::connect("0.0.0.0:1") {
+        Ok(..) => panic!(),
+        Err(e) => assert!(
+            e.kind() == ErrorKind::ConnectionRefused
+                || e.kind() == ErrorKind::InvalidInput
+                || e.kind() == ErrorKind::AddrInUse
+                || e.kind() == ErrorKind::AddrNotAvailable,
+            "bad error: {} {:?}",
+            e,
+            e.kind()
+        ),
+    }
+}
+
+#[test]
+fn listen_localhost() {
+    let socket_addr = next_test_ip4();
+    let listener = t!(TcpListener::bind(&socket_addr));
+
+    let _t = thread::spawn(move || {
+        let mut stream = t!(TcpStream::connect(&("localhost", socket_addr.port())));
+        t!(stream.write(&[144]));
+    });
+
+    let mut stream = t!(listener.accept()).0;
+    let mut buf = [0];
+    t!(stream.read(&mut buf));
+    assert!(buf[0] == 144);
+}
+
+#[test]
+fn connect_loopback() {
+    each_ip(&mut |addr| {
+        let acceptor = t!(TcpListener::bind(&addr));
+
+        let _t = thread::spawn(move || {
+            let host = match addr {
+                SocketAddr::V4(..) => "127.0.0.1",
+                SocketAddr::V6(..) => "::1",
+            };
+            let mut stream = t!(TcpStream::connect(&(host, addr.port())));
+            t!(stream.write(&[66]));
+        });
+
+        let mut stream = t!(acceptor.accept()).0;
+        let mut buf = [0];
+        t!(stream.read(&mut buf));
+        assert!(buf[0] == 66);
+    })
+}
+
+#[test]
+fn smoke_test() {
+    each_ip(&mut |addr| {
+        let acceptor = t!(TcpListener::bind(&addr));
+
+        let (tx, rx) = channel();
+        let _t = thread::spawn(move || {
+            let mut stream = t!(TcpStream::connect(&addr));
+            t!(stream.write(&[99]));
+            tx.send(t!(stream.local_addr())).unwrap();
+        });
+
+        let (mut stream, addr) = t!(acceptor.accept());
+        let mut buf = [0];
+        t!(stream.read(&mut buf));
+        assert!(buf[0] == 99);
+        assert_eq!(addr, t!(rx.recv()));
+    })
+}
+
+#[test]
+fn read_eof() {
+    each_ip(&mut |addr| {
+        let acceptor = t!(TcpListener::bind(&addr));
+
+        let _t = thread::spawn(move || {
+            let _stream = t!(TcpStream::connect(&addr));
+            // Close
+        });
+
+        let mut stream = t!(acceptor.accept()).0;
+        let mut buf = [0];
+        let nread = t!(stream.read(&mut buf));
+        assert_eq!(nread, 0);
+        let nread = t!(stream.read(&mut buf));
+        assert_eq!(nread, 0);
+    })
+}
+
+#[test]
+fn write_close() {
+    each_ip(&mut |addr| {
+        let acceptor = t!(TcpListener::bind(&addr));
+
+        let (tx, rx) = channel();
+        let _t = thread::spawn(move || {
+            drop(t!(TcpStream::connect(&addr)));
+            tx.send(()).unwrap();
+        });
+
+        let mut stream = t!(acceptor.accept()).0;
+        rx.recv().unwrap();
+        let buf = [0];
+        match stream.write(&buf) {
+            Ok(..) => {}
+            Err(e) => {
+                assert!(
+                    e.kind() == ErrorKind::ConnectionReset
+                        || e.kind() == ErrorKind::BrokenPipe
+                        || e.kind() == ErrorKind::ConnectionAborted,
+                    "unknown error: {}",
+                    e
+                );
+            }
+        }
+    })
+}
+
+#[test]
+fn multiple_connect_serial() {
+    each_ip(&mut |addr| {
+        let max = 10;
+        let acceptor = t!(TcpListener::bind(&addr));
+
+        let _t = thread::spawn(move || {
+            for _ in 0..max {
+                let mut stream = t!(TcpStream::connect(&addr));
+                t!(stream.write(&[99]));
+            }
+        });
+
+        for stream in acceptor.incoming().take(max) {
+            let mut stream = t!(stream);
+            let mut buf = [0];
+            t!(stream.read(&mut buf));
+            assert_eq!(buf[0], 99);
+        }
+    })
+}
+
+#[test]
+fn multiple_connect_interleaved_greedy_schedule() {
+    const MAX: usize = 10;
+    each_ip(&mut |addr| {
+        let acceptor = t!(TcpListener::bind(&addr));
+
+        let _t = thread::spawn(move || {
+            let acceptor = acceptor;
+            for (i, stream) in acceptor.incoming().enumerate().take(MAX) {
+                // Start another thread to handle the connection
+                let _t = thread::spawn(move || {
+                    let mut stream = t!(stream);
+                    let mut buf = [0];
+                    t!(stream.read(&mut buf));
+                    assert!(buf[0] == i as u8);
+                });
+            }
+        });
+
+        connect(0, addr);
+    });
+
+    fn connect(i: usize, addr: SocketAddr) {
+        if i == MAX {
+            return;
+        }
+
+        let t = thread::spawn(move || {
+            let mut stream = t!(TcpStream::connect(&addr));
+            // Connect again before writing
+            connect(i + 1, addr);
+            t!(stream.write(&[i as u8]));
+        });
+        t.join().ok().expect("thread panicked");
+    }
+}
+
+#[test]
+fn multiple_connect_interleaved_lazy_schedule() {
+    const MAX: usize = 10;
+    each_ip(&mut |addr| {
+        let acceptor = t!(TcpListener::bind(&addr));
+
+        let _t = thread::spawn(move || {
+            for stream in acceptor.incoming().take(MAX) {
+                // Start another thread to handle the connection
+                let _t = thread::spawn(move || {
+                    let mut stream = t!(stream);
+                    let mut buf = [0];
+                    t!(stream.read(&mut buf));
+                    assert!(buf[0] == 99);
+                });
+            }
+        });
+
+        connect(0, addr);
+    });
+
+    fn connect(i: usize, addr: SocketAddr) {
+        if i == MAX {
+            return;
+        }
+
+        let t = thread::spawn(move || {
+            let mut stream = t!(TcpStream::connect(&addr));
+            connect(i + 1, addr);
+            t!(stream.write(&[99]));
+        });
+        t.join().ok().expect("thread panicked");
+    }
+}
+
+#[test]
+fn socket_and_peer_name() {
+    each_ip(&mut |addr| {
+        let listener = t!(TcpListener::bind(&addr));
+        let so_name = t!(listener.local_addr());
+        assert_eq!(addr, so_name);
+        let _t = thread::spawn(move || {
+            t!(listener.accept());
+        });
+
+        let stream = t!(TcpStream::connect(&addr));
+        assert_eq!(addr, t!(stream.peer_addr()));
+    })
+}
+
+#[test]
+fn partial_read() {
+    each_ip(&mut |addr| {
+        let (tx, rx) = channel();
+        let srv = t!(TcpListener::bind(&addr));
+        let _t = thread::spawn(move || {
+            let mut cl = t!(srv.accept()).0;
+            cl.write(&[10]).unwrap();
+            let mut b = [0];
+            t!(cl.read(&mut b));
+            tx.send(()).unwrap();
+        });
+
+        let mut c = t!(TcpStream::connect(&addr));
+        let mut b = [0; 10];
+        assert_eq!(c.read(&mut b).unwrap(), 1);
+        t!(c.write(&[1]));
+        rx.recv().unwrap();
+    })
+}
+
+#[test]
+fn read_vectored() {
+    each_ip(&mut |addr| {
+        let srv = t!(TcpListener::bind(&addr));
+        let mut s1 = t!(TcpStream::connect(&addr));
+        let mut s2 = t!(srv.accept()).0;
+
+        let len = s1.write(&[10, 11, 12]).unwrap();
+        assert_eq!(len, 3);
+
+        let mut a = [];
+        let mut b = [0];
+        let mut c = [0; 3];
+        let len = t!(s2.read_vectored(&mut [
+            IoSliceMut::new(&mut a),
+            IoSliceMut::new(&mut b),
+            IoSliceMut::new(&mut c)
+        ],));
+        assert!(len > 0);
+        assert_eq!(b, [10]);
+        // some implementations don't support readv, so we may only fill the first buffer
+        assert!(len == 1 || c == [11, 12, 0]);
+    })
+}
+
+#[test]
+fn write_vectored() {
+    each_ip(&mut |addr| {
+        let srv = t!(TcpListener::bind(&addr));
+        let mut s1 = t!(TcpStream::connect(&addr));
+        let mut s2 = t!(srv.accept()).0;
+
+        let a = [];
+        let b = [10];
+        let c = [11, 12];
+        t!(s1.write_vectored(&[IoSlice::new(&a), IoSlice::new(&b), IoSlice::new(&c)]));
+
+        let mut buf = [0; 4];
+        let len = t!(s2.read(&mut buf));
+        // some implementations don't support writev, so we may only write the first buffer
+        if len == 1 {
+            assert_eq!(buf, [10, 0, 0, 0]);
+        } else {
+            assert_eq!(len, 3);
+            assert_eq!(buf, [10, 11, 12, 0]);
+        }
+    })
+}
+
+#[test]
+fn double_bind() {
+    each_ip(&mut |addr| {
+        let listener1 = t!(TcpListener::bind(&addr));
+        match TcpListener::bind(&addr) {
+            Ok(listener2) => panic!(
+                "This system (perhaps due to options set by TcpListener::bind) \
+                 permits double binding: {:?} and {:?}",
+                listener1, listener2
+            ),
+            Err(e) => {
+                assert!(
+                    e.kind() == ErrorKind::ConnectionRefused
+                        || e.kind() == ErrorKind::Other
+                        || e.kind() == ErrorKind::AddrInUse,
+                    "unknown error: {} {:?}",
+                    e,
+                    e.kind()
+                );
+            }
+        }
+    })
+}
+
+#[test]
+fn tcp_clone_smoke() {
+    each_ip(&mut |addr| {
+        let acceptor = t!(TcpListener::bind(&addr));
+
+        let _t = thread::spawn(move || {
+            let mut s = t!(TcpStream::connect(&addr));
+            let mut buf = [0, 0];
+            assert_eq!(s.read(&mut buf).unwrap(), 1);
+            assert_eq!(buf[0], 1);
+            t!(s.write(&[2]));
+        });
+
+        let mut s1 = t!(acceptor.accept()).0;
+        let s2 = t!(s1.try_clone());
+
+        let (tx1, rx1) = channel();
+        let (tx2, rx2) = channel();
+        let _t = thread::spawn(move || {
+            let mut s2 = s2;
+            rx1.recv().unwrap();
+            t!(s2.write(&[1]));
+            tx2.send(()).unwrap();
+        });
+        tx1.send(()).unwrap();
+        let mut buf = [0, 0];
+        assert_eq!(s1.read(&mut buf).unwrap(), 1);
+        rx2.recv().unwrap();
+    })
+}
+
+#[test]
+fn tcp_clone_two_read() {
+    each_ip(&mut |addr| {
+        let acceptor = t!(TcpListener::bind(&addr));
+        let (tx1, rx) = channel();
+        let tx2 = tx1.clone();
+
+        let _t = thread::spawn(move || {
+            let mut s = t!(TcpStream::connect(&addr));
+            t!(s.write(&[1]));
+            rx.recv().unwrap();
+            t!(s.write(&[2]));
+            rx.recv().unwrap();
+        });
+
+        let mut s1 = t!(acceptor.accept()).0;
+        let s2 = t!(s1.try_clone());
+
+        let (done, rx) = channel();
+        let _t = thread::spawn(move || {
+            let mut s2 = s2;
+            let mut buf = [0, 0];
+            t!(s2.read(&mut buf));
+            tx2.send(()).unwrap();
+            done.send(()).unwrap();
+        });
+        let mut buf = [0, 0];
+        t!(s1.read(&mut buf));
+        tx1.send(()).unwrap();
+
+        rx.recv().unwrap();
+    })
+}
+
+#[test]
+fn tcp_clone_two_write() {
+    each_ip(&mut |addr| {
+        let acceptor = t!(TcpListener::bind(&addr));
+
+        let _t = thread::spawn(move || {
+            let mut s = t!(TcpStream::connect(&addr));
+            let mut buf = [0, 1];
+            t!(s.read(&mut buf));
+            t!(s.read(&mut buf));
+        });
+
+        let mut s1 = t!(acceptor.accept()).0;
+        let s2 = t!(s1.try_clone());
+
+        let (done, rx) = channel();
+        let _t = thread::spawn(move || {
+            let mut s2 = s2;
+            t!(s2.write(&[1]));
+            done.send(()).unwrap();
+        });
+        t!(s1.write(&[2]));
+
+        rx.recv().unwrap();
+    })
+}
+
+#[test]
+// FIXME: https://github.com/fortanix/rust-sgx/issues/110
+#[cfg_attr(target_env = "sgx", ignore)]
+fn shutdown_smoke() {
+    each_ip(&mut |addr| {
+        let a = t!(TcpListener::bind(&addr));
+        let _t = thread::spawn(move || {
+            let mut c = t!(a.accept()).0;
+            let mut b = [0];
+            assert_eq!(c.read(&mut b).unwrap(), 0);
+            t!(c.write(&[1]));
+        });
+
+        let mut s = t!(TcpStream::connect(&addr));
+        t!(s.shutdown(Shutdown::Write));
+        assert!(s.write(&[1]).is_err());
+        let mut b = [0, 0];
+        assert_eq!(t!(s.read(&mut b)), 1);
+        assert_eq!(b[0], 1);
+    })
+}
+
+#[test]
+// FIXME: https://github.com/fortanix/rust-sgx/issues/110
+#[cfg_attr(target_env = "sgx", ignore)]
+fn close_readwrite_smoke() {
+    each_ip(&mut |addr| {
+        let a = t!(TcpListener::bind(&addr));
+        let (tx, rx) = channel::<()>();
+        let _t = thread::spawn(move || {
+            let _s = t!(a.accept());
+            let _ = rx.recv();
+        });
+
+        let mut b = [0];
+        let mut s = t!(TcpStream::connect(&addr));
+        let mut s2 = t!(s.try_clone());
+
+        // closing should prevent reads/writes
+        t!(s.shutdown(Shutdown::Write));
+        assert!(s.write(&[0]).is_err());
+        t!(s.shutdown(Shutdown::Read));
+        assert_eq!(s.read(&mut b).unwrap(), 0);
+
+        // closing should affect previous handles
+        assert!(s2.write(&[0]).is_err());
+        assert_eq!(s2.read(&mut b).unwrap(), 0);
+
+        // closing should affect new handles
+        let mut s3 = t!(s.try_clone());
+        assert!(s3.write(&[0]).is_err());
+        assert_eq!(s3.read(&mut b).unwrap(), 0);
+
+        // make sure these don't die
+        let _ = s2.shutdown(Shutdown::Read);
+        let _ = s2.shutdown(Shutdown::Write);
+        let _ = s3.shutdown(Shutdown::Read);
+        let _ = s3.shutdown(Shutdown::Write);
+        drop(tx);
+    })
+}
+
+#[test]
+#[cfg(unix)] // test doesn't work on Windows, see #31657
+fn close_read_wakes_up() {
+    each_ip(&mut |addr| {
+        let a = t!(TcpListener::bind(&addr));
+        let (tx1, rx) = channel::<()>();
+        let _t = thread::spawn(move || {
+            let _s = t!(a.accept());
+            let _ = rx.recv();
+        });
+
+        let s = t!(TcpStream::connect(&addr));
+        let s2 = t!(s.try_clone());
+        let (tx, rx) = channel();
+        let _t = thread::spawn(move || {
+            let mut s2 = s2;
+            assert_eq!(t!(s2.read(&mut [0])), 0);
+            tx.send(()).unwrap();
+        });
+        // this should wake up the child thread
+        t!(s.shutdown(Shutdown::Read));
+
+        // this test will never finish if the child doesn't wake up
+        rx.recv().unwrap();
+        drop(tx1);
+    })
+}
+
+#[test]
+fn clone_while_reading() {
+    each_ip(&mut |addr| {
+        let accept = t!(TcpListener::bind(&addr));
+
+        // Enqueue a thread to write to a socket
+        let (tx, rx) = channel();
+        let (txdone, rxdone) = channel();
+        let txdone2 = txdone.clone();
+        let _t = thread::spawn(move || {
+            let mut tcp = t!(TcpStream::connect(&addr));
+            rx.recv().unwrap();
+            t!(tcp.write(&[0]));
+            txdone2.send(()).unwrap();
+        });
+
+        // Spawn off a reading clone
+        let tcp = t!(accept.accept()).0;
+        let tcp2 = t!(tcp.try_clone());
+        let txdone3 = txdone.clone();
+        let _t = thread::spawn(move || {
+            let mut tcp2 = tcp2;
+            t!(tcp2.read(&mut [0]));
+            txdone3.send(()).unwrap();
+        });
+
+        // Try to ensure that the reading clone is indeed reading
+        for _ in 0..50 {
+            thread::yield_now();
+        }
+
+        // clone the handle again while it's reading, then let it finish the
+        // read.
+        let _ = t!(tcp.try_clone());
+        tx.send(()).unwrap();
+        rxdone.recv().unwrap();
+        rxdone.recv().unwrap();
+    })
+}
+
+#[test]
+fn clone_accept_smoke() {
+    each_ip(&mut |addr| {
+        let a = t!(TcpListener::bind(&addr));
+        let a2 = t!(a.try_clone());
+
+        let _t = thread::spawn(move || {
+            let _ = TcpStream::connect(&addr);
+        });
+        let _t = thread::spawn(move || {
+            let _ = TcpStream::connect(&addr);
+        });
+
+        t!(a.accept());
+        t!(a2.accept());
+    })
+}
+
+#[test]
+fn clone_accept_concurrent() {
+    each_ip(&mut |addr| {
+        let a = t!(TcpListener::bind(&addr));
+        let a2 = t!(a.try_clone());
+
+        let (tx, rx) = channel();
+        let tx2 = tx.clone();
+
+        let _t = thread::spawn(move || {
+            tx.send(t!(a.accept())).unwrap();
+        });
+        let _t = thread::spawn(move || {
+            tx2.send(t!(a2.accept())).unwrap();
+        });
+
+        let _t = thread::spawn(move || {
+            let _ = TcpStream::connect(&addr);
+        });
+        let _t = thread::spawn(move || {
+            let _ = TcpStream::connect(&addr);
+        });
+
+        rx.recv().unwrap();
+        rx.recv().unwrap();
+    })
+}
+
+#[test]
+fn debug() {
+    #[cfg(not(target_env = "sgx"))]
+    fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a {
+        addr
+    }
+    #[cfg(target_env = "sgx")]
+    fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a {
+        addr.to_string()
+    }
+
+    #[cfg(target_env = "sgx")]
+    use crate::os::fortanix_sgx::io::AsRawFd;
+    #[cfg(unix)]
+    use crate::os::unix::io::AsRawFd;
+    #[cfg(not(windows))]
+    fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug {
+        addr.as_raw_fd()
+    }
+    #[cfg(windows)]
+    fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Debug {
+        addr.as_raw_socket()
+    }
+
+    let inner_name = if cfg!(windows) { "socket" } else { "fd" };
+    let socket_addr = next_test_ip4();
+
+    let listener = t!(TcpListener::bind(&socket_addr));
+    let compare = format!(
+        "TcpListener {{ addr: {:?}, {}: {:?} }}",
+        render_socket_addr(&socket_addr),
+        inner_name,
+        render_inner(&listener)
+    );
+    assert_eq!(format!("{:?}", listener), compare);
+
+    let stream = t!(TcpStream::connect(&("localhost", socket_addr.port())));
+    let compare = format!(
+        "TcpStream {{ addr: {:?}, peer: {:?}, {}: {:?} }}",
+        render_socket_addr(&stream.local_addr().unwrap()),
+        render_socket_addr(&stream.peer_addr().unwrap()),
+        inner_name,
+        render_inner(&stream)
+    );
+    assert_eq!(format!("{:?}", stream), compare);
+}
+
+// FIXME: re-enabled openbsd tests once their socket timeout code
+//        no longer has rounding errors.
+// VxWorks ignores SO_SNDTIMEO.
+#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)]
+#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+#[test]
+fn timeouts() {
+    let addr = next_test_ip4();
+    let listener = t!(TcpListener::bind(&addr));
+
+    let stream = t!(TcpStream::connect(&("localhost", addr.port())));
+    let dur = Duration::new(15410, 0);
+
+    assert_eq!(None, t!(stream.read_timeout()));
+
+    t!(stream.set_read_timeout(Some(dur)));
+    assert_eq!(Some(dur), t!(stream.read_timeout()));
+
+    assert_eq!(None, t!(stream.write_timeout()));
+
+    t!(stream.set_write_timeout(Some(dur)));
+    assert_eq!(Some(dur), t!(stream.write_timeout()));
+
+    t!(stream.set_read_timeout(None));
+    assert_eq!(None, t!(stream.read_timeout()));
+
+    t!(stream.set_write_timeout(None));
+    assert_eq!(None, t!(stream.write_timeout()));
+    drop(listener);
+}
+
+#[test]
+#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+fn test_read_timeout() {
+    let addr = next_test_ip4();
+    let listener = t!(TcpListener::bind(&addr));
+
+    let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
+    t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+    let mut buf = [0; 10];
+    let start = Instant::now();
+    let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+    assert!(
+        kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+        "unexpected_error: {:?}",
+        kind
+    );
+    assert!(start.elapsed() > Duration::from_millis(400));
+    drop(listener);
+}
+
+#[test]
+#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+fn test_read_with_timeout() {
+    let addr = next_test_ip4();
+    let listener = t!(TcpListener::bind(&addr));
+
+    let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
+    t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+    let mut other_end = t!(listener.accept()).0;
+    t!(other_end.write_all(b"hello world"));
+
+    let mut buf = [0; 11];
+    t!(stream.read(&mut buf));
+    assert_eq!(b"hello world", &buf[..]);
+
+    let start = Instant::now();
+    let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+    assert!(
+        kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+        "unexpected_error: {:?}",
+        kind
+    );
+    assert!(start.elapsed() > Duration::from_millis(400));
+    drop(listener);
+}
+
+// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+// when passed zero Durations
+#[test]
+fn test_timeout_zero_duration() {
+    let addr = next_test_ip4();
+
+    let listener = t!(TcpListener::bind(&addr));
+    let stream = t!(TcpStream::connect(&addr));
+
+    let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
+    let err = result.unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+    let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
+    let err = result.unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+    drop(listener);
+}
+
+#[test]
+#[cfg_attr(target_env = "sgx", ignore)]
+fn nodelay() {
+    let addr = next_test_ip4();
+    let _listener = t!(TcpListener::bind(&addr));
+
+    let stream = t!(TcpStream::connect(&("localhost", addr.port())));
+
+    assert_eq!(false, t!(stream.nodelay()));
+    t!(stream.set_nodelay(true));
+    assert_eq!(true, t!(stream.nodelay()));
+    t!(stream.set_nodelay(false));
+    assert_eq!(false, t!(stream.nodelay()));
+}
+
+#[test]
+#[cfg_attr(target_env = "sgx", ignore)]
+fn ttl() {
+    let ttl = 100;
+
+    let addr = next_test_ip4();
+    let listener = t!(TcpListener::bind(&addr));
+
+    t!(listener.set_ttl(ttl));
+    assert_eq!(ttl, t!(listener.ttl()));
+
+    let stream = t!(TcpStream::connect(&("localhost", addr.port())));
+
+    t!(stream.set_ttl(ttl));
+    assert_eq!(ttl, t!(stream.ttl()));
+}
+
+#[test]
+#[cfg_attr(target_env = "sgx", ignore)]
+fn set_nonblocking() {
+    let addr = next_test_ip4();
+    let listener = t!(TcpListener::bind(&addr));
+
+    t!(listener.set_nonblocking(true));
+    t!(listener.set_nonblocking(false));
+
+    let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
+
+    t!(stream.set_nonblocking(false));
+    t!(stream.set_nonblocking(true));
+
+    let mut buf = [0];
+    match stream.read(&mut buf) {
+        Ok(_) => panic!("expected error"),
+        Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
+        Err(e) => panic!("unexpected error {}", e),
+    }
+}
+
+#[test]
+#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+fn peek() {
+    each_ip(&mut |addr| {
+        let (txdone, rxdone) = channel();
+
+        let srv = t!(TcpListener::bind(&addr));
+        let _t = thread::spawn(move || {
+            let mut cl = t!(srv.accept()).0;
+            cl.write(&[1, 3, 3, 7]).unwrap();
+            t!(rxdone.recv());
+        });
+
+        let mut c = t!(TcpStream::connect(&addr));
+        let mut b = [0; 10];
+        for _ in 1..3 {
+            let len = c.peek(&mut b).unwrap();
+            assert_eq!(len, 4);
+        }
+        let len = c.read(&mut b).unwrap();
+        assert_eq!(len, 4);
+
+        t!(c.set_nonblocking(true));
+        match c.peek(&mut b) {
+            Ok(_) => panic!("expected error"),
+            Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
+            Err(e) => panic!("unexpected error {}", e),
+        }
+        t!(txdone.send(()));
+    })
+}
+
+#[test]
+#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+fn connect_timeout_valid() {
+    let listener = TcpListener::bind("127.0.0.1:0").unwrap();
+    let addr = listener.local_addr().unwrap();
+    TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap();
+}
index d730b2b87ac2595ed52870d3c3bbc114093d80fd..17e3e4497c4a811f59d19de582845ffd4b95c85e 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
+mod tests;
+
 use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
 use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
@@ -798,380 +801,3 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         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),
-            }
-        })
-    }
-}
diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs
new file mode 100644 (file)
index 0000000..658369f
--- /dev/null
@@ -0,0 +1,372 @@
+use crate::io::ErrorKind;
+use crate::net::test::{next_test_ip4, next_test_ip6};
+use crate::net::*;
+use crate::sync::mpsc::channel;
+use crate::sys_common::AsInner;
+use crate::thread;
+use crate::time::{Duration, Instant};
+
+fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) {
+    f(next_test_ip4(), next_test_ip4());
+    f(next_test_ip6(), next_test_ip6());
+}
+
+macro_rules! t {
+    ($e:expr) => {
+        match $e {
+            Ok(t) => t,
+            Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+        }
+    };
+}
+
+#[test]
+fn bind_error() {
+    match UdpSocket::bind("1.1.1.1:9999") {
+        Ok(..) => panic!(),
+        Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable),
+    }
+}
+
+#[test]
+fn socket_smoke_test_ip4() {
+    each_ip(&mut |server_ip, client_ip| {
+        let (tx1, rx1) = channel();
+        let (tx2, rx2) = channel();
+
+        let _t = thread::spawn(move || {
+            let client = t!(UdpSocket::bind(&client_ip));
+            rx1.recv().unwrap();
+            t!(client.send_to(&[99], &server_ip));
+            tx2.send(()).unwrap();
+        });
+
+        let server = t!(UdpSocket::bind(&server_ip));
+        tx1.send(()).unwrap();
+        let mut buf = [0];
+        let (nread, src) = t!(server.recv_from(&mut buf));
+        assert_eq!(nread, 1);
+        assert_eq!(buf[0], 99);
+        assert_eq!(src, client_ip);
+        rx2.recv().unwrap();
+    })
+}
+
+#[test]
+fn socket_name() {
+    each_ip(&mut |addr, _| {
+        let server = t!(UdpSocket::bind(&addr));
+        assert_eq!(addr, t!(server.local_addr()));
+    })
+}
+
+#[test]
+fn socket_peer() {
+    each_ip(&mut |addr1, addr2| {
+        let server = t!(UdpSocket::bind(&addr1));
+        assert_eq!(server.peer_addr().unwrap_err().kind(), ErrorKind::NotConnected);
+        t!(server.connect(&addr2));
+        assert_eq!(addr2, t!(server.peer_addr()));
+    })
+}
+
+#[test]
+fn udp_clone_smoke() {
+    each_ip(&mut |addr1, addr2| {
+        let sock1 = t!(UdpSocket::bind(&addr1));
+        let sock2 = t!(UdpSocket::bind(&addr2));
+
+        let _t = thread::spawn(move || {
+            let mut buf = [0, 0];
+            assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1));
+            assert_eq!(buf[0], 1);
+            t!(sock2.send_to(&[2], &addr1));
+        });
+
+        let sock3 = t!(sock1.try_clone());
+
+        let (tx1, rx1) = channel();
+        let (tx2, rx2) = channel();
+        let _t = thread::spawn(move || {
+            rx1.recv().unwrap();
+            t!(sock3.send_to(&[1], &addr2));
+            tx2.send(()).unwrap();
+        });
+        tx1.send(()).unwrap();
+        let mut buf = [0, 0];
+        assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2));
+        rx2.recv().unwrap();
+    })
+}
+
+#[test]
+fn udp_clone_two_read() {
+    each_ip(&mut |addr1, addr2| {
+        let sock1 = t!(UdpSocket::bind(&addr1));
+        let sock2 = t!(UdpSocket::bind(&addr2));
+        let (tx1, rx) = channel();
+        let tx2 = tx1.clone();
+
+        let _t = thread::spawn(move || {
+            t!(sock2.send_to(&[1], &addr1));
+            rx.recv().unwrap();
+            t!(sock2.send_to(&[2], &addr1));
+            rx.recv().unwrap();
+        });
+
+        let sock3 = t!(sock1.try_clone());
+
+        let (done, rx) = channel();
+        let _t = thread::spawn(move || {
+            let mut buf = [0, 0];
+            t!(sock3.recv_from(&mut buf));
+            tx2.send(()).unwrap();
+            done.send(()).unwrap();
+        });
+        let mut buf = [0, 0];
+        t!(sock1.recv_from(&mut buf));
+        tx1.send(()).unwrap();
+
+        rx.recv().unwrap();
+    })
+}
+
+#[test]
+fn udp_clone_two_write() {
+    each_ip(&mut |addr1, addr2| {
+        let sock1 = t!(UdpSocket::bind(&addr1));
+        let sock2 = t!(UdpSocket::bind(&addr2));
+
+        let (tx, rx) = channel();
+        let (serv_tx, serv_rx) = channel();
+
+        let _t = thread::spawn(move || {
+            let mut buf = [0, 1];
+            rx.recv().unwrap();
+            t!(sock2.recv_from(&mut buf));
+            serv_tx.send(()).unwrap();
+        });
+
+        let sock3 = t!(sock1.try_clone());
+
+        let (done, rx) = channel();
+        let tx2 = tx.clone();
+        let _t = thread::spawn(move || {
+            match sock3.send_to(&[1], &addr2) {
+                Ok(..) => {
+                    let _ = tx2.send(());
+                }
+                Err(..) => {}
+            }
+            done.send(()).unwrap();
+        });
+        match sock1.send_to(&[2], &addr2) {
+            Ok(..) => {
+                let _ = tx.send(());
+            }
+            Err(..) => {}
+        }
+        drop(tx);
+
+        rx.recv().unwrap();
+        serv_rx.recv().unwrap();
+    })
+}
+
+#[test]
+fn debug() {
+    let name = if cfg!(windows) { "socket" } else { "fd" };
+    let socket_addr = next_test_ip4();
+
+    let udpsock = t!(UdpSocket::bind(&socket_addr));
+    let udpsock_inner = udpsock.0.socket().as_inner();
+    let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner);
+    assert_eq!(format!("{:?}", udpsock), compare);
+}
+
+// FIXME: re-enabled openbsd/netbsd tests once their socket timeout code
+//        no longer has rounding errors.
+// VxWorks ignores SO_SNDTIMEO.
+#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)]
+#[test]
+fn timeouts() {
+    let addr = next_test_ip4();
+
+    let stream = t!(UdpSocket::bind(&addr));
+    let dur = Duration::new(15410, 0);
+
+    assert_eq!(None, t!(stream.read_timeout()));
+
+    t!(stream.set_read_timeout(Some(dur)));
+    assert_eq!(Some(dur), t!(stream.read_timeout()));
+
+    assert_eq!(None, t!(stream.write_timeout()));
+
+    t!(stream.set_write_timeout(Some(dur)));
+    assert_eq!(Some(dur), t!(stream.write_timeout()));
+
+    t!(stream.set_read_timeout(None));
+    assert_eq!(None, t!(stream.read_timeout()));
+
+    t!(stream.set_write_timeout(None));
+    assert_eq!(None, t!(stream.write_timeout()));
+}
+
+#[test]
+fn test_read_timeout() {
+    let addr = next_test_ip4();
+
+    let stream = t!(UdpSocket::bind(&addr));
+    t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+    let mut buf = [0; 10];
+
+    let start = Instant::now();
+    loop {
+        let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
+        if kind != ErrorKind::Interrupted {
+            assert!(
+                kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+                "unexpected_error: {:?}",
+                kind
+            );
+            break;
+        }
+    }
+    assert!(start.elapsed() > Duration::from_millis(400));
+}
+
+#[test]
+fn test_read_with_timeout() {
+    let addr = next_test_ip4();
+
+    let stream = t!(UdpSocket::bind(&addr));
+    t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+    t!(stream.send_to(b"hello world", &addr));
+
+    let mut buf = [0; 11];
+    t!(stream.recv_from(&mut buf));
+    assert_eq!(b"hello world", &buf[..]);
+
+    let start = Instant::now();
+    loop {
+        let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
+        if kind != ErrorKind::Interrupted {
+            assert!(
+                kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+                "unexpected_error: {:?}",
+                kind
+            );
+            break;
+        }
+    }
+    assert!(start.elapsed() > Duration::from_millis(400));
+}
+
+// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+// when passed zero Durations
+#[test]
+fn test_timeout_zero_duration() {
+    let addr = next_test_ip4();
+
+    let socket = t!(UdpSocket::bind(&addr));
+
+    let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+    let err = result.unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+    let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+    let err = result.unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::InvalidInput);
+}
+
+#[test]
+fn connect_send_recv() {
+    let addr = next_test_ip4();
+
+    let socket = t!(UdpSocket::bind(&addr));
+    t!(socket.connect(addr));
+
+    t!(socket.send(b"hello world"));
+
+    let mut buf = [0; 11];
+    t!(socket.recv(&mut buf));
+    assert_eq!(b"hello world", &buf[..]);
+}
+
+#[test]
+fn connect_send_peek_recv() {
+    each_ip(&mut |addr, _| {
+        let socket = t!(UdpSocket::bind(&addr));
+        t!(socket.connect(addr));
+
+        t!(socket.send(b"hello world"));
+
+        for _ in 1..3 {
+            let mut buf = [0; 11];
+            let size = t!(socket.peek(&mut buf));
+            assert_eq!(b"hello world", &buf[..]);
+            assert_eq!(size, 11);
+        }
+
+        let mut buf = [0; 11];
+        let size = t!(socket.recv(&mut buf));
+        assert_eq!(b"hello world", &buf[..]);
+        assert_eq!(size, 11);
+    })
+}
+
+#[test]
+fn peek_from() {
+    each_ip(&mut |addr, _| {
+        let socket = t!(UdpSocket::bind(&addr));
+        t!(socket.send_to(b"hello world", &addr));
+
+        for _ in 1..3 {
+            let mut buf = [0; 11];
+            let (size, _) = t!(socket.peek_from(&mut buf));
+            assert_eq!(b"hello world", &buf[..]);
+            assert_eq!(size, 11);
+        }
+
+        let mut buf = [0; 11];
+        let (size, _) = t!(socket.recv_from(&mut buf));
+        assert_eq!(b"hello world", &buf[..]);
+        assert_eq!(size, 11);
+    })
+}
+
+#[test]
+fn ttl() {
+    let ttl = 100;
+
+    let addr = next_test_ip4();
+
+    let stream = t!(UdpSocket::bind(&addr));
+
+    t!(stream.set_ttl(ttl));
+    assert_eq!(ttl, t!(stream.ttl()));
+}
+
+#[test]
+fn set_nonblocking() {
+    each_ip(&mut |addr, _| {
+        let socket = t!(UdpSocket::bind(&addr));
+
+        t!(socket.set_nonblocking(true));
+        t!(socket.set_nonblocking(false));
+
+        t!(socket.connect(addr));
+
+        t!(socket.set_nonblocking(false));
+        t!(socket.set_nonblocking(true));
+
+        let mut buf = [0];
+        match socket.recv(&mut buf) {
+            Ok(_) => panic!("expected error"),
+            Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
+            Err(e) => panic!("unexpected error {}", e),
+        }
+    })
+}
index b496c16a749cf8b3027706bf5ffdcb672411be2e..0f1c59626859411ee501d47abe7715d19c63ff02 100644 (file)
@@ -6,6 +6,12 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 #![allow(missing_docs)]
 
+#[cfg(test)]
+mod tests;
+
+#[cfg(test)]
+mod benches;
+
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::num::Wrapping;
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -48,250 +54,3 @@ pub fn test_num<T>(ten: T, two: T)
     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));
-        });
-    }
-}
diff --git a/library/std/src/num/benches.rs b/library/std/src/num/benches.rs
new file mode 100644 (file)
index 0000000..233ea05
--- /dev/null
@@ -0,0 +1,9 @@
+use test::Bencher;
+
+#[bench]
+fn bench_pow_function(b: &mut Bencher) {
+    let v = (0..1024).collect::<Vec<u32>>();
+    b.iter(|| {
+        v.iter().fold(0u32, |old, new| old.pow(*new as u32));
+    });
+}
diff --git a/library/std/src/num/tests.rs b/library/std/src/num/tests.rs
new file mode 100644 (file)
index 0000000..2f50b73
--- /dev/null
@@ -0,0 +1,230 @@
+use crate::ops::Mul;
+
+#[test]
+fn test_saturating_add_uint() {
+    assert_eq!(3_usize.saturating_add(5_usize), 8_usize);
+    assert_eq!(3_usize.saturating_add(usize::MAX - 1), usize::MAX);
+    assert_eq!(usize::MAX.saturating_add(usize::MAX), usize::MAX);
+    assert_eq!((usize::MAX - 2).saturating_add(1), usize::MAX - 1);
+}
+
+#[test]
+fn test_saturating_sub_uint() {
+    assert_eq!(5_usize.saturating_sub(3_usize), 2_usize);
+    assert_eq!(3_usize.saturating_sub(5_usize), 0_usize);
+    assert_eq!(0_usize.saturating_sub(1_usize), 0_usize);
+    assert_eq!((usize::MAX - 1).saturating_sub(usize::MAX), 0);
+}
+
+#[test]
+fn test_saturating_add_int() {
+    assert_eq!(3i32.saturating_add(5), 8);
+    assert_eq!(3isize.saturating_add(isize::MAX - 1), isize::MAX);
+    assert_eq!(isize::MAX.saturating_add(isize::MAX), isize::MAX);
+    assert_eq!((isize::MAX - 2).saturating_add(1), isize::MAX - 1);
+    assert_eq!(3i32.saturating_add(-5), -2);
+    assert_eq!(isize::MIN.saturating_add(-1), isize::MIN);
+    assert_eq!((-2isize).saturating_add(-isize::MAX), isize::MIN);
+}
+
+#[test]
+fn test_saturating_sub_int() {
+    assert_eq!(3i32.saturating_sub(5), -2);
+    assert_eq!(isize::MIN.saturating_sub(1), isize::MIN);
+    assert_eq!((-2isize).saturating_sub(isize::MAX), isize::MIN);
+    assert_eq!(3i32.saturating_sub(-5), 8);
+    assert_eq!(3isize.saturating_sub(-(isize::MAX - 1)), isize::MAX);
+    assert_eq!(isize::MAX.saturating_sub(-isize::MAX), isize::MAX);
+    assert_eq!((isize::MAX - 2).saturating_sub(-1), isize::MAX - 1);
+}
+
+#[test]
+fn test_checked_add() {
+    let five_less = usize::MAX - 5;
+    assert_eq!(five_less.checked_add(0), Some(usize::MAX - 5));
+    assert_eq!(five_less.checked_add(1), Some(usize::MAX - 4));
+    assert_eq!(five_less.checked_add(2), Some(usize::MAX - 3));
+    assert_eq!(five_less.checked_add(3), Some(usize::MAX - 2));
+    assert_eq!(five_less.checked_add(4), Some(usize::MAX - 1));
+    assert_eq!(five_less.checked_add(5), Some(usize::MAX));
+    assert_eq!(five_less.checked_add(6), None);
+    assert_eq!(five_less.checked_add(7), None);
+}
+
+#[test]
+fn test_checked_sub() {
+    assert_eq!(5_usize.checked_sub(0), Some(5));
+    assert_eq!(5_usize.checked_sub(1), Some(4));
+    assert_eq!(5_usize.checked_sub(2), Some(3));
+    assert_eq!(5_usize.checked_sub(3), Some(2));
+    assert_eq!(5_usize.checked_sub(4), Some(1));
+    assert_eq!(5_usize.checked_sub(5), Some(0));
+    assert_eq!(5_usize.checked_sub(6), None);
+    assert_eq!(5_usize.checked_sub(7), None);
+}
+
+#[test]
+fn test_checked_mul() {
+    let third = usize::MAX / 3;
+    assert_eq!(third.checked_mul(0), Some(0));
+    assert_eq!(third.checked_mul(1), Some(third));
+    assert_eq!(third.checked_mul(2), Some(third * 2));
+    assert_eq!(third.checked_mul(3), Some(third * 3));
+    assert_eq!(third.checked_mul(4), None);
+}
+
+macro_rules! test_is_power_of_two {
+    ($test_name:ident, $T:ident) => {
+        fn $test_name() {
+            #![test]
+            assert_eq!((0 as $T).is_power_of_two(), false);
+            assert_eq!((1 as $T).is_power_of_two(), true);
+            assert_eq!((2 as $T).is_power_of_two(), true);
+            assert_eq!((3 as $T).is_power_of_two(), false);
+            assert_eq!((4 as $T).is_power_of_two(), true);
+            assert_eq!((5 as $T).is_power_of_two(), false);
+            assert_eq!(($T::MAX / 2 + 1).is_power_of_two(), true);
+        }
+    };
+}
+
+test_is_power_of_two! { test_is_power_of_two_u8, u8 }
+test_is_power_of_two! { test_is_power_of_two_u16, u16 }
+test_is_power_of_two! { test_is_power_of_two_u32, u32 }
+test_is_power_of_two! { test_is_power_of_two_u64, u64 }
+test_is_power_of_two! { test_is_power_of_two_uint, usize }
+
+macro_rules! test_next_power_of_two {
+    ($test_name:ident, $T:ident) => {
+        fn $test_name() {
+            #![test]
+            assert_eq!((0 as $T).next_power_of_two(), 1);
+            let mut next_power = 1;
+            for i in 1 as $T..40 {
+                assert_eq!(i.next_power_of_two(), next_power);
+                if i == next_power {
+                    next_power *= 2
+                }
+            }
+        }
+    };
+}
+
+test_next_power_of_two! { test_next_power_of_two_u8, u8 }
+test_next_power_of_two! { test_next_power_of_two_u16, u16 }
+test_next_power_of_two! { test_next_power_of_two_u32, u32 }
+test_next_power_of_two! { test_next_power_of_two_u64, u64 }
+test_next_power_of_two! { test_next_power_of_two_uint, usize }
+
+macro_rules! test_checked_next_power_of_two {
+    ($test_name:ident, $T:ident) => {
+        fn $test_name() {
+            #![test]
+            assert_eq!((0 as $T).checked_next_power_of_two(), Some(1));
+            let smax = $T::MAX >> 1;
+            assert_eq!(smax.checked_next_power_of_two(), Some(smax + 1));
+            assert_eq!((smax + 1).checked_next_power_of_two(), Some(smax + 1));
+            assert_eq!((smax + 2).checked_next_power_of_two(), None);
+            assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None);
+            assert_eq!($T::MAX.checked_next_power_of_two(), None);
+            let mut next_power = 1;
+            for i in 1 as $T..40 {
+                assert_eq!(i.checked_next_power_of_two(), Some(next_power));
+                if i == next_power {
+                    next_power *= 2
+                }
+            }
+        }
+    };
+}
+
+test_checked_next_power_of_two! { test_checked_next_power_of_two_u8, u8 }
+test_checked_next_power_of_two! { test_checked_next_power_of_two_u16, u16 }
+test_checked_next_power_of_two! { test_checked_next_power_of_two_u32, u32 }
+test_checked_next_power_of_two! { test_checked_next_power_of_two_u64, u64 }
+test_checked_next_power_of_two! { test_checked_next_power_of_two_uint, usize }
+
+#[test]
+fn test_pow() {
+    fn naive_pow<T: Mul<Output = T> + Copy>(one: T, base: T, exp: usize) -> T {
+        (0..exp).fold(one, |acc, _| acc * base)
+    }
+    macro_rules! assert_pow {
+        (($num:expr, $exp:expr) => $expected:expr) => {{
+            let result = $num.pow($exp);
+            assert_eq!(result, $expected);
+            assert_eq!(result, naive_pow(1, $num, $exp));
+        }};
+    }
+    assert_pow!((3u32,     0 ) => 1);
+    assert_pow!((5u32,     1 ) => 5);
+    assert_pow!((-4i32,    2 ) => 16);
+    assert_pow!((8u32,     3 ) => 512);
+    assert_pow!((2u64,     50) => 1125899906842624);
+}
+
+#[test]
+fn test_uint_to_str_overflow() {
+    let mut u8_val: u8 = 255;
+    assert_eq!(u8_val.to_string(), "255");
+
+    u8_val = u8_val.wrapping_add(1);
+    assert_eq!(u8_val.to_string(), "0");
+
+    let mut u16_val: u16 = 65_535;
+    assert_eq!(u16_val.to_string(), "65535");
+
+    u16_val = u16_val.wrapping_add(1);
+    assert_eq!(u16_val.to_string(), "0");
+
+    let mut u32_val: u32 = 4_294_967_295;
+    assert_eq!(u32_val.to_string(), "4294967295");
+
+    u32_val = u32_val.wrapping_add(1);
+    assert_eq!(u32_val.to_string(), "0");
+
+    let mut u64_val: u64 = 18_446_744_073_709_551_615;
+    assert_eq!(u64_val.to_string(), "18446744073709551615");
+
+    u64_val = u64_val.wrapping_add(1);
+    assert_eq!(u64_val.to_string(), "0");
+}
+
+fn from_str<T: crate::str::FromStr>(t: &str) -> Option<T> {
+    crate::str::FromStr::from_str(t).ok()
+}
+
+#[test]
+fn test_uint_from_str_overflow() {
+    let mut u8_val: u8 = 255;
+    assert_eq!(from_str::<u8>("255"), Some(u8_val));
+    assert_eq!(from_str::<u8>("256"), None);
+
+    u8_val = u8_val.wrapping_add(1);
+    assert_eq!(from_str::<u8>("0"), Some(u8_val));
+    assert_eq!(from_str::<u8>("-1"), None);
+
+    let mut u16_val: u16 = 65_535;
+    assert_eq!(from_str::<u16>("65535"), Some(u16_val));
+    assert_eq!(from_str::<u16>("65536"), None);
+
+    u16_val = u16_val.wrapping_add(1);
+    assert_eq!(from_str::<u16>("0"), Some(u16_val));
+    assert_eq!(from_str::<u16>("-1"), None);
+
+    let mut u32_val: u32 = 4_294_967_295;
+    assert_eq!(from_str::<u32>("4294967295"), Some(u32_val));
+    assert_eq!(from_str::<u32>("4294967296"), None);
+
+    u32_val = u32_val.wrapping_add(1);
+    assert_eq!(from_str::<u32>("0"), Some(u32_val));
+    assert_eq!(from_str::<u32>("-1"), None);
+
+    let mut u64_val: u64 = 18_446_744_073_709_551_615;
+    assert_eq!(from_str::<u64>("18446744073709551615"), Some(u64_val));
+    assert_eq!(from_str::<u64>("18446744073709551616"), None);
+
+    u64_val = u64_val.wrapping_add(1);
+    assert_eq!(from_str::<u64>("0"), Some(u64_val));
+    assert_eq!(from_str::<u64>("-1"), None);
+}
index 47daf0cce1b379c4b21e89cc5d5b5a8d92f78e50..1fe27a34600003730ef69419aec1c74b70a7eec9 100644 (file)
@@ -8,6 +8,10 @@
 
 #![stable(feature = "raw_os", since = "1.1.0")]
 
+#[cfg(test)]
+#[allow(unused_imports)]
+mod tests;
+
 #[doc(include = "char.md")]
 #[cfg(any(
     all(
 #[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);
-    }
-}
diff --git a/library/std/src/os/raw/tests.rs b/library/std/src/os/raw/tests.rs
new file mode 100644 (file)
index 0000000..e808faf
--- /dev/null
@@ -0,0 +1,16 @@
+use crate::any::TypeId;
+use crate::mem;
+
+macro_rules! ok {
+    ($($t:ident)*) => {$(
+        assert!(TypeId::of::<libc::$t>() == TypeId::of::<raw::$t>(),
+                "{} is wrong", stringify!($t));
+    )*}
+}
+
+#[test]
+fn same() {
+    use crate::os::raw;
+    ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong
+        c_longlong c_ulonglong c_float c_double);
+}
index afdbdbeac3e54a12e2c5ef85c36c67c258cd31b1..d71e89d0eee682f7d7ab15d61eef35840d80fa34 100644 (file)
@@ -1,5 +1,3 @@
-// ignore-tidy-filelength
-
 //! Cross-platform path manipulation.
 //!
 //! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`]
@@ -61,6 +59,9 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+#[cfg(test)]
+mod tests;
+
 use crate::borrow::{Borrow, Cow};
 use crate::cmp;
 use crate::error::Error;
@@ -2741,1401 +2742,3 @@ fn description(&self) -> &str {
         "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);
-    }
-}
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
new file mode 100644 (file)
index 0000000..ff94fda
--- /dev/null
@@ -0,0 +1,1394 @@
+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);
+}
index c42bc1096528b7266507ce755737bd5535e16234..d1960a049d9062cb01e32b642b2a88e66cfda7fb 100644 (file)
@@ -96,6 +96,9 @@
 
 #![stable(feature = "process", since = "1.0.0")]
 
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
+mod tests;
+
 use crate::io::prelude::*;
 
 use crate::ffi::OsStr;
@@ -1702,411 +1705,3 @@ fn report(self) -> i32 {
         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(""))
-    }
-}
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
new file mode 100644 (file)
index 0000000..05e0934
--- /dev/null
@@ -0,0 +1,401 @@
+use crate::io::prelude::*;
+
+use super::{Command, Output, Stdio};
+use crate::io::ErrorKind;
+use crate::str;
+
+// FIXME(#10380) these tests should not all be ignored on android.
+
+#[test]
+#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+fn smoke() {
+    let p = if cfg!(target_os = "windows") {
+        Command::new("cmd").args(&["/C", "exit 0"]).spawn()
+    } else {
+        Command::new("true").spawn()
+    };
+    assert!(p.is_ok());
+    let mut p = p.unwrap();
+    assert!(p.wait().unwrap().success());
+}
+
+#[test]
+#[cfg_attr(target_os = "android", ignore)]
+fn smoke_failure() {
+    match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
+        Ok(..) => panic!(),
+        Err(..) => {}
+    }
+}
+
+#[test]
+#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+fn exit_reported_right() {
+    let p = if cfg!(target_os = "windows") {
+        Command::new("cmd").args(&["/C", "exit 1"]).spawn()
+    } else {
+        Command::new("false").spawn()
+    };
+    assert!(p.is_ok());
+    let mut p = p.unwrap();
+    assert!(p.wait().unwrap().code() == Some(1));
+    drop(p.wait());
+}
+
+#[test]
+#[cfg(unix)]
+#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+fn signal_reported_right() {
+    use crate::os::unix::process::ExitStatusExt;
+
+    let mut p =
+        Command::new("/bin/sh").arg("-c").arg("read a").stdin(Stdio::piped()).spawn().unwrap();
+    p.kill().unwrap();
+    match p.wait().unwrap().signal() {
+        Some(9) => {}
+        result => panic!("not terminated by signal 9 (instead, {:?})", result),
+    }
+}
+
+pub fn run_output(mut cmd: Command) -> String {
+    let p = cmd.spawn();
+    assert!(p.is_ok());
+    let mut p = p.unwrap();
+    assert!(p.stdout.is_some());
+    let mut ret = String::new();
+    p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap();
+    assert!(p.wait().unwrap().success());
+    return ret;
+}
+
+#[test]
+#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+fn stdout_works() {
+    if cfg!(target_os = "windows") {
+        let mut cmd = Command::new("cmd");
+        cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped());
+        assert_eq!(run_output(cmd), "foobar\r\n");
+    } else {
+        let mut cmd = Command::new("echo");
+        cmd.arg("foobar").stdout(Stdio::piped());
+        assert_eq!(run_output(cmd), "foobar\n");
+    }
+}
+
+#[test]
+#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)]
+fn set_current_dir_works() {
+    let mut cmd = Command::new("/bin/sh");
+    cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped());
+    assert_eq!(run_output(cmd), "/\n");
+}
+
+#[test]
+#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)]
+fn stdin_works() {
+    let mut p = Command::new("/bin/sh")
+        .arg("-c")
+        .arg("read line; echo $line")
+        .stdin(Stdio::piped())
+        .stdout(Stdio::piped())
+        .spawn()
+        .unwrap();
+    p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap();
+    drop(p.stdin.take());
+    let mut out = String::new();
+    p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap();
+    assert!(p.wait().unwrap().success());
+    assert_eq!(out, "foobar\n");
+}
+
+#[test]
+#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+fn test_process_status() {
+    let mut status = if cfg!(target_os = "windows") {
+        Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap()
+    } else {
+        Command::new("false").status().unwrap()
+    };
+    assert!(status.code() == Some(1));
+
+    status = if cfg!(target_os = "windows") {
+        Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap()
+    } else {
+        Command::new("true").status().unwrap()
+    };
+    assert!(status.success());
+}
+
+#[test]
+fn test_process_output_fail_to_start() {
+    match Command::new("/no-binary-by-this-name-should-exist").output() {
+        Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound),
+        Ok(..) => panic!(),
+    }
+}
+
+#[test]
+#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+fn test_process_output_output() {
+    let Output { status, stdout, stderr } = if cfg!(target_os = "windows") {
+        Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap()
+    } else {
+        Command::new("echo").arg("hello").output().unwrap()
+    };
+    let output_str = str::from_utf8(&stdout).unwrap();
+
+    assert!(status.success());
+    assert_eq!(output_str.trim().to_string(), "hello");
+    assert_eq!(stderr, Vec::new());
+}
+
+#[test]
+#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+fn test_process_output_error() {
+    let Output { status, stdout, stderr } = if cfg!(target_os = "windows") {
+        Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap()
+    } else {
+        Command::new("mkdir").arg("./").output().unwrap()
+    };
+
+    assert!(status.code() == Some(1));
+    assert_eq!(stdout, Vec::new());
+    assert!(!stderr.is_empty());
+}
+
+#[test]
+#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+fn test_finish_once() {
+    let mut prog = if cfg!(target_os = "windows") {
+        Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
+    } else {
+        Command::new("false").spawn().unwrap()
+    };
+    assert!(prog.wait().unwrap().code() == Some(1));
+}
+
+#[test]
+#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+fn test_finish_twice() {
+    let mut prog = if cfg!(target_os = "windows") {
+        Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
+    } else {
+        Command::new("false").spawn().unwrap()
+    };
+    assert!(prog.wait().unwrap().code() == Some(1));
+    assert!(prog.wait().unwrap().code() == Some(1));
+}
+
+#[test]
+#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+fn test_wait_with_output_once() {
+    let prog = if cfg!(target_os = "windows") {
+        Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap()
+    } else {
+        Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap()
+    };
+
+    let Output { status, stdout, stderr } = prog.wait_with_output().unwrap();
+    let output_str = str::from_utf8(&stdout).unwrap();
+
+    assert!(status.success());
+    assert_eq!(output_str.trim().to_string(), "hello");
+    assert_eq!(stderr, Vec::new());
+}
+
+#[cfg(all(unix, not(target_os = "android")))]
+pub fn env_cmd() -> Command {
+    Command::new("env")
+}
+#[cfg(target_os = "android")]
+pub fn env_cmd() -> Command {
+    let mut cmd = Command::new("/system/bin/sh");
+    cmd.arg("-c").arg("set");
+    cmd
+}
+
+#[cfg(windows)]
+pub fn env_cmd() -> Command {
+    let mut cmd = Command::new("cmd");
+    cmd.arg("/c").arg("set");
+    cmd
+}
+
+#[test]
+#[cfg_attr(target_os = "vxworks", ignore)]
+fn test_override_env() {
+    use crate::env;
+
+    // In some build environments (such as chrooted Nix builds), `env` can
+    // only be found in the explicitly-provided PATH env variable, not in
+    // default places such as /bin or /usr/bin. So we need to pass through
+    // PATH to our sub-process.
+    let mut cmd = env_cmd();
+    cmd.env_clear().env("RUN_TEST_NEW_ENV", "123");
+    if let Some(p) = env::var_os("PATH") {
+        cmd.env("PATH", &p);
+    }
+    let result = cmd.output().unwrap();
+    let output = String::from_utf8_lossy(&result.stdout).to_string();
+
+    assert!(
+        output.contains("RUN_TEST_NEW_ENV=123"),
+        "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
+        output
+    );
+}
+
+#[test]
+#[cfg_attr(target_os = "vxworks", ignore)]
+fn test_add_to_env() {
+    let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap();
+    let output = String::from_utf8_lossy(&result.stdout).to_string();
+
+    assert!(
+        output.contains("RUN_TEST_NEW_ENV=123"),
+        "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
+        output
+    );
+}
+
+#[test]
+#[cfg_attr(target_os = "vxworks", ignore)]
+fn test_capture_env_at_spawn() {
+    use crate::env;
+
+    let mut cmd = env_cmd();
+    cmd.env("RUN_TEST_NEW_ENV1", "123");
+
+    // This variable will not be present if the environment has already
+    // been captured above.
+    env::set_var("RUN_TEST_NEW_ENV2", "456");
+    let result = cmd.output().unwrap();
+    env::remove_var("RUN_TEST_NEW_ENV2");
+
+    let output = String::from_utf8_lossy(&result.stdout).to_string();
+
+    assert!(
+        output.contains("RUN_TEST_NEW_ENV1=123"),
+        "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}",
+        output
+    );
+    assert!(
+        output.contains("RUN_TEST_NEW_ENV2=456"),
+        "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}",
+        output
+    );
+}
+
+// Regression tests for #30858.
+#[test]
+fn test_interior_nul_in_progname_is_error() {
+    match Command::new("has-some-\0\0s-inside").spawn() {
+        Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+        Ok(_) => panic!(),
+    }
+}
+
+#[test]
+fn test_interior_nul_in_arg_is_error() {
+    match Command::new("echo").arg("has-some-\0\0s-inside").spawn() {
+        Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+        Ok(_) => panic!(),
+    }
+}
+
+#[test]
+fn test_interior_nul_in_args_is_error() {
+    match Command::new("echo").args(&["has-some-\0\0s-inside"]).spawn() {
+        Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+        Ok(_) => panic!(),
+    }
+}
+
+#[test]
+fn test_interior_nul_in_current_dir_is_error() {
+    match Command::new("echo").current_dir("has-some-\0\0s-inside").spawn() {
+        Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+        Ok(_) => panic!(),
+    }
+}
+
+// Regression tests for #30862.
+#[test]
+#[cfg_attr(target_os = "vxworks", ignore)]
+fn test_interior_nul_in_env_key_is_error() {
+    match env_cmd().env("has-some-\0\0s-inside", "value").spawn() {
+        Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+        Ok(_) => panic!(),
+    }
+}
+
+#[test]
+#[cfg_attr(target_os = "vxworks", ignore)]
+fn test_interior_nul_in_env_value_is_error() {
+    match env_cmd().env("key", "has-some-\0\0s-inside").spawn() {
+        Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+        Ok(_) => panic!(),
+    }
+}
+
+/// Tests that process creation flags work by debugging a process.
+/// Other creation flags make it hard or impossible to detect
+/// behavioral changes in the process.
+#[test]
+#[cfg(windows)]
+fn test_creation_flags() {
+    use crate::os::windows::process::CommandExt;
+    use crate::sys::c::{BOOL, DWORD, INFINITE};
+    #[repr(C, packed)]
+    struct DEBUG_EVENT {
+        pub event_code: DWORD,
+        pub process_id: DWORD,
+        pub thread_id: DWORD,
+        // This is a union in the real struct, but we don't
+        // need this data for the purposes of this test.
+        pub _junk: [u8; 164],
+    }
+
+    extern "system" {
+        fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL;
+        fn ContinueDebugEvent(
+            dwProcessId: DWORD,
+            dwThreadId: DWORD,
+            dwContinueStatus: DWORD,
+        ) -> BOOL;
+    }
+
+    const DEBUG_PROCESS: DWORD = 1;
+    const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5;
+    const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001;
+
+    let mut child =
+        Command::new("cmd").creation_flags(DEBUG_PROCESS).stdin(Stdio::piped()).spawn().unwrap();
+    child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap();
+    let mut events = 0;
+    let mut event = DEBUG_EVENT { event_code: 0, process_id: 0, thread_id: 0, _junk: [0; 164] };
+    loop {
+        if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 {
+            panic!("WaitForDebugEvent failed!");
+        }
+        events += 1;
+
+        if event.event_code == EXIT_PROCESS_DEBUG_EVENT {
+            break;
+        }
+
+        if unsafe {
+            ContinueDebugEvent(event.process_id, event.thread_id, DBG_EXCEPTION_NOT_HANDLED)
+        } == 0
+        {
+            panic!("ContinueDebugEvent failed!");
+        }
+    }
+    assert!(events > 0);
+}
+
+#[test]
+fn test_command_implements_send_sync() {
+    fn take_send_sync_type<T: Send + Sync>(_: T) {}
+    take_send_sync_type(Command::new(""))
+}
index 23c989fd2fdfb78cee8678a22addb8b61886788d..5d434791e9afb342c40ba9e90e97d38c639482cc 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(test)]
+mod tests;
+
 use crate::fmt;
 use crate::sync::{Condvar, Mutex};
 
@@ -174,42 +177,3 @@ pub fn is_leader(&self) -> bool {
         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);
-    }
-}
diff --git a/library/std/src/sync/barrier/tests.rs b/library/std/src/sync/barrier/tests.rs
new file mode 100644 (file)
index 0000000..834a3e7
--- /dev/null
@@ -0,0 +1,35 @@
+use crate::sync::mpsc::{channel, TryRecvError};
+use crate::sync::{Arc, Barrier};
+use crate::thread;
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn test_barrier() {
+    const N: usize = 10;
+
+    let barrier = Arc::new(Barrier::new(N));
+    let (tx, rx) = channel();
+
+    for _ in 0..N - 1 {
+        let c = barrier.clone();
+        let tx = tx.clone();
+        thread::spawn(move || {
+            tx.send(c.wait().is_leader()).unwrap();
+        });
+    }
+
+    // At this point, all spawned threads should be blocked,
+    // so we shouldn't get anything from the port
+    assert!(matches!(rx.try_recv(), Err(TryRecvError::Empty)));
+
+    let mut leader_found = barrier.wait().is_leader();
+
+    // Now, the barrier is cleared and we should get data.
+    for _ in 0..N - 1 {
+        if rx.recv().unwrap() {
+            assert!(!leader_found);
+            leader_found = true;
+        }
+    }
+    assert!(leader_found);
+}
index 4efd86aa3ede8c3e7c99c2f845f3c164a3cd57b4..651f813b3e2271e71e91399cd34f2aae17a3915e 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(test)]
+mod tests;
+
 use crate::fmt;
 use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sync::{mutex, MutexGuard, PoisonError};
@@ -598,218 +601,3 @@ fn drop(&mut self) {
         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();
-    }
-}
diff --git a/library/std/src/sync/condvar/tests.rs b/library/std/src/sync/condvar/tests.rs
new file mode 100644 (file)
index 0000000..86d099e
--- /dev/null
@@ -0,0 +1,211 @@
+use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::mpsc::channel;
+use crate::sync::{Arc, Condvar, Mutex};
+use crate::thread;
+use crate::time::Duration;
+
+#[test]
+fn smoke() {
+    let c = Condvar::new();
+    c.notify_one();
+    c.notify_all();
+}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn notify_one() {
+    let m = Arc::new(Mutex::new(()));
+    let m2 = m.clone();
+    let c = Arc::new(Condvar::new());
+    let c2 = c.clone();
+
+    let g = m.lock().unwrap();
+    let _t = thread::spawn(move || {
+        let _g = m2.lock().unwrap();
+        c2.notify_one();
+    });
+    let g = c.wait(g).unwrap();
+    drop(g);
+}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn notify_all() {
+    const N: usize = 10;
+
+    let data = Arc::new((Mutex::new(0), Condvar::new()));
+    let (tx, rx) = channel();
+    for _ in 0..N {
+        let data = data.clone();
+        let tx = tx.clone();
+        thread::spawn(move || {
+            let &(ref lock, ref cond) = &*data;
+            let mut cnt = lock.lock().unwrap();
+            *cnt += 1;
+            if *cnt == N {
+                tx.send(()).unwrap();
+            }
+            while *cnt != 0 {
+                cnt = cond.wait(cnt).unwrap();
+            }
+            tx.send(()).unwrap();
+        });
+    }
+    drop(tx);
+
+    let &(ref lock, ref cond) = &*data;
+    rx.recv().unwrap();
+    let mut cnt = lock.lock().unwrap();
+    *cnt = 0;
+    cond.notify_all();
+    drop(cnt);
+
+    for _ in 0..N {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn wait_while() {
+    let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    let pair2 = pair.clone();
+
+    // Inside of our lock, spawn a new thread, and then wait for it to start.
+    thread::spawn(move || {
+        let &(ref lock, ref cvar) = &*pair2;
+        let mut started = lock.lock().unwrap();
+        *started = true;
+        // We notify the condvar that the value has changed.
+        cvar.notify_one();
+    });
+
+    // Wait for the thread to start up.
+    let &(ref lock, ref cvar) = &*pair;
+    let guard = cvar.wait_while(lock.lock().unwrap(), |started| !*started);
+    assert!(*guard.unwrap());
+}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn wait_timeout_wait() {
+    let m = Arc::new(Mutex::new(()));
+    let c = Arc::new(Condvar::new());
+
+    loop {
+        let g = m.lock().unwrap();
+        let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap();
+        // spurious wakeups mean this isn't necessarily true
+        // so execute test again, if not timeout
+        if !no_timeout.timed_out() {
+            continue;
+        }
+
+        break;
+    }
+}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn wait_timeout_while_wait() {
+    let m = Arc::new(Mutex::new(()));
+    let c = Arc::new(Condvar::new());
+
+    let g = m.lock().unwrap();
+    let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(1), |_| true).unwrap();
+    // no spurious wakeups. ensure it timed-out
+    assert!(wait.timed_out());
+}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn wait_timeout_while_instant_satisfy() {
+    let m = Arc::new(Mutex::new(()));
+    let c = Arc::new(Condvar::new());
+
+    let g = m.lock().unwrap();
+    let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(0), |_| false).unwrap();
+    // ensure it didn't time-out even if we were not given any time.
+    assert!(!wait.timed_out());
+}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn wait_timeout_while_wake() {
+    let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    let pair_copy = pair.clone();
+
+    let &(ref m, ref c) = &*pair;
+    let g = m.lock().unwrap();
+    let _t = thread::spawn(move || {
+        let &(ref lock, ref cvar) = &*pair_copy;
+        let mut started = lock.lock().unwrap();
+        thread::sleep(Duration::from_millis(1));
+        *started = true;
+        cvar.notify_one();
+    });
+    let (g2, wait) = c
+        .wait_timeout_while(g, Duration::from_millis(u64::MAX), |&mut notified| !notified)
+        .unwrap();
+    // ensure it didn't time-out even if we were not given any time.
+    assert!(!wait.timed_out());
+    assert!(*g2);
+}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn wait_timeout_wake() {
+    let m = Arc::new(Mutex::new(()));
+    let c = Arc::new(Condvar::new());
+
+    loop {
+        let g = m.lock().unwrap();
+
+        let c2 = c.clone();
+        let m2 = m.clone();
+
+        let notified = Arc::new(AtomicBool::new(false));
+        let notified_copy = notified.clone();
+
+        let t = thread::spawn(move || {
+            let _g = m2.lock().unwrap();
+            thread::sleep(Duration::from_millis(1));
+            notified_copy.store(true, Ordering::SeqCst);
+            c2.notify_one();
+        });
+        let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap();
+        assert!(!timeout_res.timed_out());
+        // spurious wakeups mean this isn't necessarily true
+        // so execute test again, if not notified
+        if !notified.load(Ordering::SeqCst) {
+            t.join().unwrap();
+            continue;
+        }
+        drop(g);
+
+        t.join().unwrap();
+
+        break;
+    }
+}
+
+#[test]
+#[should_panic]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn two_mutexes() {
+    let m = Arc::new(Mutex::new(()));
+    let m2 = m.clone();
+    let c = Arc::new(Condvar::new());
+    let c2 = c.clone();
+
+    let mut g = m.lock().unwrap();
+    let _t = thread::spawn(move || {
+        let _g = m2.lock().unwrap();
+        c2.notify_one();
+    });
+    g = c.wait(g).unwrap();
+    drop(g);
+
+    let m = Mutex::new(());
+    let _ = c.wait(m.lock().unwrap()).unwrap();
+}
index ac83017d9e1246d35bd28a34618fae72823976c1..073f969bbe25b5cb8df7d29721e9ab33c157fd4d 100644 (file)
 
 #![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
@@ -1606,1364 +1612,3 @@ fn from(err: RecvError) -> RecvTimeoutError {
         }
     }
 }
-
-#[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()
-        }
-    }
-}
index 6e7a7be4430edae471def217e6c63b5ae451ce9b..42bc639dc252784fc8f864bafa91696c2cb82af8 100644 (file)
@@ -11,6 +11,9 @@
 // http://www.1024cores.net/home/lock-free-algorithms
 //                         /queues/non-intrusive-mpsc-node-based-queue
 
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
 pub use self::PopResult::*;
 
 use core::cell::UnsafeCell;
@@ -112,54 +115,3 @@ fn drop(&mut self) {
         }
     }
 }
-
-#[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();
-        }
-    }
-}
diff --git a/library/std/src/sync/mpsc/mpsc_queue/tests.rs b/library/std/src/sync/mpsc/mpsc_queue/tests.rs
new file mode 100644 (file)
index 0000000..348b834
--- /dev/null
@@ -0,0 +1,47 @@
+use super::{Data, Empty, Inconsistent, Queue};
+use crate::sync::mpsc::channel;
+use crate::sync::Arc;
+use crate::thread;
+
+#[test]
+fn test_full() {
+    let q: Queue<Box<_>> = Queue::new();
+    q.push(box 1);
+    q.push(box 2);
+}
+
+#[test]
+fn test() {
+    let nthreads = 8;
+    let nmsgs = 1000;
+    let q = Queue::new();
+    match q.pop() {
+        Empty => {}
+        Inconsistent | Data(..) => panic!(),
+    }
+    let (tx, rx) = channel();
+    let q = Arc::new(q);
+
+    for _ in 0..nthreads {
+        let tx = tx.clone();
+        let q = q.clone();
+        thread::spawn(move || {
+            for i in 0..nmsgs {
+                q.push(i);
+            }
+            tx.send(()).unwrap();
+        });
+    }
+
+    let mut i = 0;
+    while i < nthreads * nmsgs {
+        match q.pop() {
+            Empty | Inconsistent => {}
+            Data(_) => i += 1,
+        }
+    }
+    drop(tx);
+    for _ in 0..nthreads {
+        rx.recv().unwrap();
+    }
+}
index 0274268f69f25b34f43084bf1b82bc2b4cd34489..9bf99f193ca3ae0707212defb1d0a241de1c04bd 100644 (file)
@@ -6,6 +6,9 @@
 
 // http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue
 
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
 use core::cell::UnsafeCell;
 use core::ptr;
 
@@ -231,108 +234,3 @@ fn drop(&mut self) {
         }
     }
 }
-
-#[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();
-        }
-    }
-}
diff --git a/library/std/src/sync/mpsc/spsc_queue/tests.rs b/library/std/src/sync/mpsc/spsc_queue/tests.rs
new file mode 100644 (file)
index 0000000..e4fd15c
--- /dev/null
@@ -0,0 +1,101 @@
+use super::Queue;
+use crate::sync::mpsc::channel;
+use crate::sync::Arc;
+use crate::thread;
+
+#[test]
+fn smoke() {
+    unsafe {
+        let queue = Queue::with_additions(0, (), ());
+        queue.push(1);
+        queue.push(2);
+        assert_eq!(queue.pop(), Some(1));
+        assert_eq!(queue.pop(), Some(2));
+        assert_eq!(queue.pop(), None);
+        queue.push(3);
+        queue.push(4);
+        assert_eq!(queue.pop(), Some(3));
+        assert_eq!(queue.pop(), Some(4));
+        assert_eq!(queue.pop(), None);
+    }
+}
+
+#[test]
+fn peek() {
+    unsafe {
+        let queue = Queue::with_additions(0, (), ());
+        queue.push(vec![1]);
+
+        // Ensure the borrowchecker works
+        match queue.peek() {
+            Some(vec) => {
+                assert_eq!(&*vec, &[1]);
+            }
+            None => unreachable!(),
+        }
+
+        match queue.pop() {
+            Some(vec) => {
+                assert_eq!(&*vec, &[1]);
+            }
+            None => unreachable!(),
+        }
+    }
+}
+
+#[test]
+fn drop_full() {
+    unsafe {
+        let q: Queue<Box<_>> = Queue::with_additions(0, (), ());
+        q.push(box 1);
+        q.push(box 2);
+    }
+}
+
+#[test]
+fn smoke_bound() {
+    unsafe {
+        let q = Queue::with_additions(0, (), ());
+        q.push(1);
+        q.push(2);
+        assert_eq!(q.pop(), Some(1));
+        assert_eq!(q.pop(), Some(2));
+        assert_eq!(q.pop(), None);
+        q.push(3);
+        q.push(4);
+        assert_eq!(q.pop(), Some(3));
+        assert_eq!(q.pop(), Some(4));
+        assert_eq!(q.pop(), None);
+    }
+}
+
+#[test]
+fn stress() {
+    unsafe {
+        stress_bound(0);
+        stress_bound(1);
+    }
+
+    unsafe fn stress_bound(bound: usize) {
+        let q = Arc::new(Queue::with_additions(bound, (), ()));
+
+        let (tx, rx) = channel();
+        let q2 = q.clone();
+        let _t = thread::spawn(move || {
+            for _ in 0..100000 {
+                loop {
+                    match q2.pop() {
+                        Some(1) => break,
+                        Some(_) => panic!(),
+                        None => {}
+                    }
+                }
+            }
+            tx.send(()).unwrap();
+        });
+        for _ in 0..100000 {
+            q.push(1);
+        }
+        rx.recv().unwrap();
+    }
+}
diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs
new file mode 100644 (file)
index 0000000..0052a38
--- /dev/null
@@ -0,0 +1,647 @@
+use super::*;
+use crate::env;
+use crate::thread;
+use crate::time::Duration;
+
+pub fn stress_factor() -> usize {
+    match env::var("RUST_TEST_STRESS") {
+        Ok(val) => val.parse().unwrap(),
+        Err(..) => 1,
+    }
+}
+
+#[test]
+fn smoke() {
+    let (tx, rx) = sync_channel::<i32>(1);
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+}
+
+#[test]
+fn drop_full() {
+    let (tx, _rx) = sync_channel::<Box<isize>>(1);
+    tx.send(box 1).unwrap();
+}
+
+#[test]
+fn smoke_shared() {
+    let (tx, rx) = sync_channel::<i32>(1);
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+    let tx = tx.clone();
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+}
+
+#[test]
+fn recv_timeout() {
+    let (tx, rx) = sync_channel::<i32>(1);
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1));
+}
+
+#[test]
+fn smoke_threads() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    let _t = thread::spawn(move || {
+        tx.send(1).unwrap();
+    });
+    assert_eq!(rx.recv().unwrap(), 1);
+}
+
+#[test]
+fn smoke_port_gone() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    drop(rx);
+    assert!(tx.send(1).is_err());
+}
+
+#[test]
+fn smoke_shared_port_gone2() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    drop(rx);
+    let tx2 = tx.clone();
+    drop(tx);
+    assert!(tx2.send(1).is_err());
+}
+
+#[test]
+fn port_gone_concurrent() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap();
+    });
+    while tx.send(1).is_ok() {}
+}
+
+#[test]
+fn port_gone_concurrent_shared() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    let tx2 = tx.clone();
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap();
+    });
+    while tx.send(1).is_ok() && tx2.send(1).is_ok() {}
+}
+
+#[test]
+fn smoke_chan_gone() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    drop(tx);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn smoke_chan_gone_shared() {
+    let (tx, rx) = sync_channel::<()>(0);
+    let tx2 = tx.clone();
+    drop(tx);
+    drop(tx2);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn chan_gone_concurrent() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    thread::spawn(move || {
+        tx.send(1).unwrap();
+        tx.send(1).unwrap();
+    });
+    while rx.recv().is_ok() {}
+}
+
+#[test]
+fn stress() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    thread::spawn(move || {
+        for _ in 0..10000 {
+            tx.send(1).unwrap();
+        }
+    });
+    for _ in 0..10000 {
+        assert_eq!(rx.recv().unwrap(), 1);
+    }
+}
+
+#[test]
+fn stress_recv_timeout_two_threads() {
+    let (tx, rx) = sync_channel::<i32>(0);
+
+    thread::spawn(move || {
+        for _ in 0..10000 {
+            tx.send(1).unwrap();
+        }
+    });
+
+    let mut recv_count = 0;
+    loop {
+        match rx.recv_timeout(Duration::from_millis(1)) {
+            Ok(v) => {
+                assert_eq!(v, 1);
+                recv_count += 1;
+            }
+            Err(RecvTimeoutError::Timeout) => continue,
+            Err(RecvTimeoutError::Disconnected) => break,
+        }
+    }
+
+    assert_eq!(recv_count, 10000);
+}
+
+#[test]
+fn stress_recv_timeout_shared() {
+    const AMT: u32 = 1000;
+    const NTHREADS: u32 = 8;
+    let (tx, rx) = sync_channel::<i32>(0);
+    let (dtx, drx) = sync_channel::<()>(0);
+
+    thread::spawn(move || {
+        let mut recv_count = 0;
+        loop {
+            match rx.recv_timeout(Duration::from_millis(10)) {
+                Ok(v) => {
+                    assert_eq!(v, 1);
+                    recv_count += 1;
+                }
+                Err(RecvTimeoutError::Timeout) => continue,
+                Err(RecvTimeoutError::Disconnected) => break,
+            }
+        }
+
+        assert_eq!(recv_count, AMT * NTHREADS);
+        assert!(rx.try_recv().is_err());
+
+        dtx.send(()).unwrap();
+    });
+
+    for _ in 0..NTHREADS {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            for _ in 0..AMT {
+                tx.send(1).unwrap();
+            }
+        });
+    }
+
+    drop(tx);
+
+    drx.recv().unwrap();
+}
+
+#[test]
+fn stress_shared() {
+    const AMT: u32 = 1000;
+    const NTHREADS: u32 = 8;
+    let (tx, rx) = sync_channel::<i32>(0);
+    let (dtx, drx) = sync_channel::<()>(0);
+
+    thread::spawn(move || {
+        for _ in 0..AMT * NTHREADS {
+            assert_eq!(rx.recv().unwrap(), 1);
+        }
+        match rx.try_recv() {
+            Ok(..) => panic!(),
+            _ => {}
+        }
+        dtx.send(()).unwrap();
+    });
+
+    for _ in 0..NTHREADS {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            for _ in 0..AMT {
+                tx.send(1).unwrap();
+            }
+        });
+    }
+    drop(tx);
+    drx.recv().unwrap();
+}
+
+#[test]
+fn oneshot_single_thread_close_port_first() {
+    // Simple test of closing without sending
+    let (_tx, rx) = sync_channel::<i32>(0);
+    drop(rx);
+}
+
+#[test]
+fn oneshot_single_thread_close_chan_first() {
+    // Simple test of closing without sending
+    let (tx, _rx) = sync_channel::<i32>(0);
+    drop(tx);
+}
+
+#[test]
+fn oneshot_single_thread_send_port_close() {
+    // Testing that the sender cleans up the payload if receiver is closed
+    let (tx, rx) = sync_channel::<Box<i32>>(0);
+    drop(rx);
+    assert!(tx.send(box 0).is_err());
+}
+
+#[test]
+fn oneshot_single_thread_recv_chan_close() {
+    // Receiving on a closed chan will panic
+    let res = thread::spawn(move || {
+        let (tx, rx) = sync_channel::<i32>(0);
+        drop(tx);
+        rx.recv().unwrap();
+    })
+    .join();
+    // What is our res?
+    assert!(res.is_err());
+}
+
+#[test]
+fn oneshot_single_thread_send_then_recv() {
+    let (tx, rx) = sync_channel::<Box<i32>>(1);
+    tx.send(box 10).unwrap();
+    assert!(*rx.recv().unwrap() == 10);
+}
+
+#[test]
+fn oneshot_single_thread_try_send_open() {
+    let (tx, rx) = sync_channel::<i32>(1);
+    assert_eq!(tx.try_send(10), Ok(()));
+    assert!(rx.recv().unwrap() == 10);
+}
+
+#[test]
+fn oneshot_single_thread_try_send_closed() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    drop(rx);
+    assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10)));
+}
+
+#[test]
+fn oneshot_single_thread_try_send_closed2() {
+    let (tx, _rx) = sync_channel::<i32>(0);
+    assert_eq!(tx.try_send(10), Err(TrySendError::Full(10)));
+}
+
+#[test]
+fn oneshot_single_thread_try_recv_open() {
+    let (tx, rx) = sync_channel::<i32>(1);
+    tx.send(10).unwrap();
+    assert!(rx.recv() == Ok(10));
+}
+
+#[test]
+fn oneshot_single_thread_try_recv_closed() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    drop(tx);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn oneshot_single_thread_try_recv_closed_with_data() {
+    let (tx, rx) = sync_channel::<i32>(1);
+    tx.send(10).unwrap();
+    drop(tx);
+    assert_eq!(rx.try_recv(), Ok(10));
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+}
+
+#[test]
+fn oneshot_single_thread_peek_data() {
+    let (tx, rx) = sync_channel::<i32>(1);
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+    tx.send(10).unwrap();
+    assert_eq!(rx.try_recv(), Ok(10));
+}
+
+#[test]
+fn oneshot_single_thread_peek_close() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    drop(tx);
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+}
+
+#[test]
+fn oneshot_single_thread_peek_open() {
+    let (_tx, rx) = sync_channel::<i32>(0);
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+}
+
+#[test]
+fn oneshot_multi_task_recv_then_send() {
+    let (tx, rx) = sync_channel::<Box<i32>>(0);
+    let _t = thread::spawn(move || {
+        assert!(*rx.recv().unwrap() == 10);
+    });
+
+    tx.send(box 10).unwrap();
+}
+
+#[test]
+fn oneshot_multi_task_recv_then_close() {
+    let (tx, rx) = sync_channel::<Box<i32>>(0);
+    let _t = thread::spawn(move || {
+        drop(tx);
+    });
+    let res = thread::spawn(move || {
+        assert!(*rx.recv().unwrap() == 10);
+    })
+    .join();
+    assert!(res.is_err());
+}
+
+#[test]
+fn oneshot_multi_thread_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = sync_channel::<i32>(0);
+        let _t = thread::spawn(move || {
+            drop(rx);
+        });
+        drop(tx);
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_send_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = sync_channel::<i32>(0);
+        let _t = thread::spawn(move || {
+            drop(rx);
+        });
+        let _ = thread::spawn(move || {
+            tx.send(1).unwrap();
+        })
+        .join();
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_recv_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = sync_channel::<i32>(0);
+        let _t = thread::spawn(move || {
+            let res = thread::spawn(move || {
+                rx.recv().unwrap();
+            })
+            .join();
+            assert!(res.is_err());
+        });
+        let _t = thread::spawn(move || {
+            thread::spawn(move || {
+                drop(tx);
+            });
+        });
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_send_recv_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = sync_channel::<Box<i32>>(0);
+        let _t = thread::spawn(move || {
+            tx.send(box 10).unwrap();
+        });
+        assert!(*rx.recv().unwrap() == 10);
+    }
+}
+
+#[test]
+fn stream_send_recv_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = sync_channel::<Box<i32>>(0);
+
+        send(tx, 0);
+        recv(rx, 0);
+
+        fn send(tx: SyncSender<Box<i32>>, i: i32) {
+            if i == 10 {
+                return;
+            }
+
+            thread::spawn(move || {
+                tx.send(box i).unwrap();
+                send(tx, i + 1);
+            });
+        }
+
+        fn recv(rx: Receiver<Box<i32>>, i: i32) {
+            if i == 10 {
+                return;
+            }
+
+            thread::spawn(move || {
+                assert!(*rx.recv().unwrap() == i);
+                recv(rx, i + 1);
+            });
+        }
+    }
+}
+
+#[test]
+fn recv_a_lot() {
+    // Regression test that we don't run out of stack in scheduler context
+    let (tx, rx) = sync_channel(10000);
+    for _ in 0..10000 {
+        tx.send(()).unwrap();
+    }
+    for _ in 0..10000 {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+fn shared_chan_stress() {
+    let (tx, rx) = sync_channel(0);
+    let total = stress_factor() + 100;
+    for _ in 0..total {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            tx.send(()).unwrap();
+        });
+    }
+
+    for _ in 0..total {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+fn test_nested_recv_iter() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    let (total_tx, total_rx) = sync_channel::<i32>(0);
+
+    let _t = thread::spawn(move || {
+        let mut acc = 0;
+        for x in rx.iter() {
+            acc += x;
+        }
+        total_tx.send(acc).unwrap();
+    });
+
+    tx.send(3).unwrap();
+    tx.send(1).unwrap();
+    tx.send(2).unwrap();
+    drop(tx);
+    assert_eq!(total_rx.recv().unwrap(), 6);
+}
+
+#[test]
+fn test_recv_iter_break() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    let (count_tx, count_rx) = sync_channel(0);
+
+    let _t = thread::spawn(move || {
+        let mut count = 0;
+        for x in rx.iter() {
+            if count >= 3 {
+                break;
+            } else {
+                count += x;
+            }
+        }
+        count_tx.send(count).unwrap();
+    });
+
+    tx.send(2).unwrap();
+    tx.send(2).unwrap();
+    tx.send(2).unwrap();
+    let _ = tx.try_send(2);
+    drop(tx);
+    assert_eq!(count_rx.recv().unwrap(), 4);
+}
+
+#[test]
+fn try_recv_states() {
+    let (tx1, rx1) = sync_channel::<i32>(1);
+    let (tx2, rx2) = sync_channel::<()>(1);
+    let (tx3, rx3) = sync_channel::<()>(1);
+    let _t = thread::spawn(move || {
+        rx2.recv().unwrap();
+        tx1.send(1).unwrap();
+        tx3.send(()).unwrap();
+        rx2.recv().unwrap();
+        drop(tx1);
+        tx3.send(()).unwrap();
+    });
+
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+    tx2.send(()).unwrap();
+    rx3.recv().unwrap();
+    assert_eq!(rx1.try_recv(), Ok(1));
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+    tx2.send(()).unwrap();
+    rx3.recv().unwrap();
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected));
+}
+
+// This bug used to end up in a livelock inside of the Receiver destructor
+// because the internal state of the Shared packet was corrupted
+#[test]
+fn destroy_upgraded_shared_port_when_sender_still_active() {
+    let (tx, rx) = sync_channel::<()>(0);
+    let (tx2, rx2) = sync_channel::<()>(0);
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap(); // wait on a oneshot
+        drop(rx); // destroy a shared
+        tx2.send(()).unwrap();
+    });
+    // make sure the other thread has gone to sleep
+    for _ in 0..5000 {
+        thread::yield_now();
+    }
+
+    // upgrade to a shared chan and send a message
+    let t = tx.clone();
+    drop(tx);
+    t.send(()).unwrap();
+
+    // wait for the child thread to exit before we exit
+    rx2.recv().unwrap();
+}
+
+#[test]
+fn send1() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap();
+    });
+    assert_eq!(tx.send(1), Ok(()));
+}
+
+#[test]
+fn send2() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    let _t = thread::spawn(move || {
+        drop(rx);
+    });
+    assert!(tx.send(1).is_err());
+}
+
+#[test]
+fn send3() {
+    let (tx, rx) = sync_channel::<i32>(1);
+    assert_eq!(tx.send(1), Ok(()));
+    let _t = thread::spawn(move || {
+        drop(rx);
+    });
+    assert!(tx.send(1).is_err());
+}
+
+#[test]
+fn send4() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    let tx2 = tx.clone();
+    let (done, donerx) = channel();
+    let done2 = done.clone();
+    let _t = thread::spawn(move || {
+        assert!(tx.send(1).is_err());
+        done.send(()).unwrap();
+    });
+    let _t = thread::spawn(move || {
+        assert!(tx2.send(2).is_err());
+        done2.send(()).unwrap();
+    });
+    drop(rx);
+    donerx.recv().unwrap();
+    donerx.recv().unwrap();
+}
+
+#[test]
+fn try_send1() {
+    let (tx, _rx) = sync_channel::<i32>(0);
+    assert_eq!(tx.try_send(1), Err(TrySendError::Full(1)));
+}
+
+#[test]
+fn try_send2() {
+    let (tx, _rx) = sync_channel::<i32>(1);
+    assert_eq!(tx.try_send(1), Ok(()));
+    assert_eq!(tx.try_send(1), Err(TrySendError::Full(1)));
+}
+
+#[test]
+fn try_send3() {
+    let (tx, rx) = sync_channel::<i32>(1);
+    assert_eq!(tx.try_send(1), Ok(()));
+    drop(rx);
+    assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1)));
+}
+
+#[test]
+fn issue_15761() {
+    fn repro() {
+        let (tx1, rx1) = sync_channel::<()>(3);
+        let (tx2, rx2) = sync_channel::<()>(3);
+
+        let _t = thread::spawn(move || {
+            rx1.recv().unwrap();
+            tx2.try_send(()).unwrap();
+        });
+
+        tx1.try_send(()).unwrap();
+        rx2.recv().unwrap();
+    }
+
+    for _ in 0..100 {
+        repro()
+    }
+}
diff --git a/library/std/src/sync/mpsc/tests.rs b/library/std/src/sync/mpsc/tests.rs
new file mode 100644 (file)
index 0000000..184ce19
--- /dev/null
@@ -0,0 +1,706 @@
+use super::*;
+use crate::env;
+use crate::thread;
+use crate::time::{Duration, Instant};
+
+pub fn stress_factor() -> usize {
+    match env::var("RUST_TEST_STRESS") {
+        Ok(val) => val.parse().unwrap(),
+        Err(..) => 1,
+    }
+}
+
+#[test]
+fn smoke() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+}
+
+#[test]
+fn drop_full() {
+    let (tx, _rx) = channel::<Box<isize>>();
+    tx.send(box 1).unwrap();
+}
+
+#[test]
+fn drop_full_shared() {
+    let (tx, _rx) = channel::<Box<isize>>();
+    drop(tx.clone());
+    drop(tx.clone());
+    tx.send(box 1).unwrap();
+}
+
+#[test]
+fn smoke_shared() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+    let tx = tx.clone();
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+}
+
+#[test]
+fn smoke_threads() {
+    let (tx, rx) = channel::<i32>();
+    let _t = thread::spawn(move || {
+        tx.send(1).unwrap();
+    });
+    assert_eq!(rx.recv().unwrap(), 1);
+}
+
+#[test]
+fn smoke_port_gone() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    assert!(tx.send(1).is_err());
+}
+
+#[test]
+fn smoke_shared_port_gone() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    assert!(tx.send(1).is_err())
+}
+
+#[test]
+fn smoke_shared_port_gone2() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    let tx2 = tx.clone();
+    drop(tx);
+    assert!(tx2.send(1).is_err());
+}
+
+#[test]
+fn port_gone_concurrent() {
+    let (tx, rx) = channel::<i32>();
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap();
+    });
+    while tx.send(1).is_ok() {}
+}
+
+#[test]
+fn port_gone_concurrent_shared() {
+    let (tx, rx) = channel::<i32>();
+    let tx2 = tx.clone();
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap();
+    });
+    while tx.send(1).is_ok() && tx2.send(1).is_ok() {}
+}
+
+#[test]
+fn smoke_chan_gone() {
+    let (tx, rx) = channel::<i32>();
+    drop(tx);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn smoke_chan_gone_shared() {
+    let (tx, rx) = channel::<()>();
+    let tx2 = tx.clone();
+    drop(tx);
+    drop(tx2);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn chan_gone_concurrent() {
+    let (tx, rx) = channel::<i32>();
+    let _t = thread::spawn(move || {
+        tx.send(1).unwrap();
+        tx.send(1).unwrap();
+    });
+    while rx.recv().is_ok() {}
+}
+
+#[test]
+fn stress() {
+    let (tx, rx) = channel::<i32>();
+    let t = thread::spawn(move || {
+        for _ in 0..10000 {
+            tx.send(1).unwrap();
+        }
+    });
+    for _ in 0..10000 {
+        assert_eq!(rx.recv().unwrap(), 1);
+    }
+    t.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn stress_shared() {
+    const AMT: u32 = 10000;
+    const NTHREADS: u32 = 8;
+    let (tx, rx) = channel::<i32>();
+
+    let t = thread::spawn(move || {
+        for _ in 0..AMT * NTHREADS {
+            assert_eq!(rx.recv().unwrap(), 1);
+        }
+        match rx.try_recv() {
+            Ok(..) => panic!(),
+            _ => {}
+        }
+    });
+
+    for _ in 0..NTHREADS {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            for _ in 0..AMT {
+                tx.send(1).unwrap();
+            }
+        });
+    }
+    drop(tx);
+    t.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn send_from_outside_runtime() {
+    let (tx1, rx1) = channel::<()>();
+    let (tx2, rx2) = channel::<i32>();
+    let t1 = thread::spawn(move || {
+        tx1.send(()).unwrap();
+        for _ in 0..40 {
+            assert_eq!(rx2.recv().unwrap(), 1);
+        }
+    });
+    rx1.recv().unwrap();
+    let t2 = thread::spawn(move || {
+        for _ in 0..40 {
+            tx2.send(1).unwrap();
+        }
+    });
+    t1.join().ok().expect("thread panicked");
+    t2.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn recv_from_outside_runtime() {
+    let (tx, rx) = channel::<i32>();
+    let t = thread::spawn(move || {
+        for _ in 0..40 {
+            assert_eq!(rx.recv().unwrap(), 1);
+        }
+    });
+    for _ in 0..40 {
+        tx.send(1).unwrap();
+    }
+    t.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn no_runtime() {
+    let (tx1, rx1) = channel::<i32>();
+    let (tx2, rx2) = channel::<i32>();
+    let t1 = thread::spawn(move || {
+        assert_eq!(rx1.recv().unwrap(), 1);
+        tx2.send(2).unwrap();
+    });
+    let t2 = thread::spawn(move || {
+        tx1.send(1).unwrap();
+        assert_eq!(rx2.recv().unwrap(), 2);
+    });
+    t1.join().ok().expect("thread panicked");
+    t2.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn oneshot_single_thread_close_port_first() {
+    // Simple test of closing without sending
+    let (_tx, rx) = channel::<i32>();
+    drop(rx);
+}
+
+#[test]
+fn oneshot_single_thread_close_chan_first() {
+    // Simple test of closing without sending
+    let (tx, _rx) = channel::<i32>();
+    drop(tx);
+}
+
+#[test]
+fn oneshot_single_thread_send_port_close() {
+    // Testing that the sender cleans up the payload if receiver is closed
+    let (tx, rx) = channel::<Box<i32>>();
+    drop(rx);
+    assert!(tx.send(box 0).is_err());
+}
+
+#[test]
+fn oneshot_single_thread_recv_chan_close() {
+    // Receiving on a closed chan will panic
+    let res = thread::spawn(move || {
+        let (tx, rx) = channel::<i32>();
+        drop(tx);
+        rx.recv().unwrap();
+    })
+    .join();
+    // What is our res?
+    assert!(res.is_err());
+}
+
+#[test]
+fn oneshot_single_thread_send_then_recv() {
+    let (tx, rx) = channel::<Box<i32>>();
+    tx.send(box 10).unwrap();
+    assert!(*rx.recv().unwrap() == 10);
+}
+
+#[test]
+fn oneshot_single_thread_try_send_open() {
+    let (tx, rx) = channel::<i32>();
+    assert!(tx.send(10).is_ok());
+    assert!(rx.recv().unwrap() == 10);
+}
+
+#[test]
+fn oneshot_single_thread_try_send_closed() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    assert!(tx.send(10).is_err());
+}
+
+#[test]
+fn oneshot_single_thread_try_recv_open() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(10).unwrap();
+    assert!(rx.recv() == Ok(10));
+}
+
+#[test]
+fn oneshot_single_thread_try_recv_closed() {
+    let (tx, rx) = channel::<i32>();
+    drop(tx);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn oneshot_single_thread_peek_data() {
+    let (tx, rx) = channel::<i32>();
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+    tx.send(10).unwrap();
+    assert_eq!(rx.try_recv(), Ok(10));
+}
+
+#[test]
+fn oneshot_single_thread_peek_close() {
+    let (tx, rx) = channel::<i32>();
+    drop(tx);
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+}
+
+#[test]
+fn oneshot_single_thread_peek_open() {
+    let (_tx, rx) = channel::<i32>();
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+}
+
+#[test]
+fn oneshot_multi_task_recv_then_send() {
+    let (tx, rx) = channel::<Box<i32>>();
+    let _t = thread::spawn(move || {
+        assert!(*rx.recv().unwrap() == 10);
+    });
+
+    tx.send(box 10).unwrap();
+}
+
+#[test]
+fn oneshot_multi_task_recv_then_close() {
+    let (tx, rx) = channel::<Box<i32>>();
+    let _t = thread::spawn(move || {
+        drop(tx);
+    });
+    let res = thread::spawn(move || {
+        assert!(*rx.recv().unwrap() == 10);
+    })
+    .join();
+    assert!(res.is_err());
+}
+
+#[test]
+fn oneshot_multi_thread_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<i32>();
+        let _t = thread::spawn(move || {
+            drop(rx);
+        });
+        drop(tx);
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_send_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<i32>();
+        let _t = thread::spawn(move || {
+            drop(rx);
+        });
+        let _ = thread::spawn(move || {
+            tx.send(1).unwrap();
+        })
+        .join();
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_recv_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<i32>();
+        thread::spawn(move || {
+            let res = thread::spawn(move || {
+                rx.recv().unwrap();
+            })
+            .join();
+            assert!(res.is_err());
+        });
+        let _t = thread::spawn(move || {
+            thread::spawn(move || {
+                drop(tx);
+            });
+        });
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_send_recv_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<Box<isize>>();
+        let _t = thread::spawn(move || {
+            tx.send(box 10).unwrap();
+        });
+        assert!(*rx.recv().unwrap() == 10);
+    }
+}
+
+#[test]
+fn stream_send_recv_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel();
+
+        send(tx, 0);
+        recv(rx, 0);
+
+        fn send(tx: Sender<Box<i32>>, i: i32) {
+            if i == 10 {
+                return;
+            }
+
+            thread::spawn(move || {
+                tx.send(box i).unwrap();
+                send(tx, i + 1);
+            });
+        }
+
+        fn recv(rx: Receiver<Box<i32>>, i: i32) {
+            if i == 10 {
+                return;
+            }
+
+            thread::spawn(move || {
+                assert!(*rx.recv().unwrap() == i);
+                recv(rx, i + 1);
+            });
+        }
+    }
+}
+
+#[test]
+fn oneshot_single_thread_recv_timeout() {
+    let (tx, rx) = channel();
+    tx.send(()).unwrap();
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+    tx.send(()).unwrap();
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+}
+
+#[test]
+fn stress_recv_timeout_two_threads() {
+    let (tx, rx) = channel();
+    let stress = stress_factor() + 100;
+    let timeout = Duration::from_millis(100);
+
+    thread::spawn(move || {
+        for i in 0..stress {
+            if i % 2 == 0 {
+                thread::sleep(timeout * 2);
+            }
+            tx.send(1usize).unwrap();
+        }
+    });
+
+    let mut recv_count = 0;
+    loop {
+        match rx.recv_timeout(timeout) {
+            Ok(n) => {
+                assert_eq!(n, 1usize);
+                recv_count += 1;
+            }
+            Err(RecvTimeoutError::Timeout) => continue,
+            Err(RecvTimeoutError::Disconnected) => break,
+        }
+    }
+
+    assert_eq!(recv_count, stress);
+}
+
+#[test]
+fn recv_timeout_upgrade() {
+    let (tx, rx) = channel::<()>();
+    let timeout = Duration::from_millis(1);
+    let _tx_clone = tx.clone();
+
+    let start = Instant::now();
+    assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout));
+    assert!(Instant::now() >= start + timeout);
+}
+
+#[test]
+fn stress_recv_timeout_shared() {
+    let (tx, rx) = channel();
+    let stress = stress_factor() + 100;
+
+    for i in 0..stress {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            thread::sleep(Duration::from_millis(i as u64 * 10));
+            tx.send(1usize).unwrap();
+        });
+    }
+
+    drop(tx);
+
+    let mut recv_count = 0;
+    loop {
+        match rx.recv_timeout(Duration::from_millis(10)) {
+            Ok(n) => {
+                assert_eq!(n, 1usize);
+                recv_count += 1;
+            }
+            Err(RecvTimeoutError::Timeout) => continue,
+            Err(RecvTimeoutError::Disconnected) => break,
+        }
+    }
+
+    assert_eq!(recv_count, stress);
+}
+
+#[test]
+fn very_long_recv_timeout_wont_panic() {
+    let (tx, rx) = channel::<()>();
+    let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX)));
+    thread::sleep(Duration::from_secs(1));
+    assert!(tx.send(()).is_ok());
+    assert_eq!(join_handle.join().unwrap(), Ok(()));
+}
+
+#[test]
+fn recv_a_lot() {
+    // Regression test that we don't run out of stack in scheduler context
+    let (tx, rx) = channel();
+    for _ in 0..10000 {
+        tx.send(()).unwrap();
+    }
+    for _ in 0..10000 {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+fn shared_recv_timeout() {
+    let (tx, rx) = channel();
+    let total = 5;
+    for _ in 0..total {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            tx.send(()).unwrap();
+        });
+    }
+
+    for _ in 0..total {
+        rx.recv().unwrap();
+    }
+
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+    tx.send(()).unwrap();
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+}
+
+#[test]
+fn shared_chan_stress() {
+    let (tx, rx) = channel();
+    let total = stress_factor() + 100;
+    for _ in 0..total {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            tx.send(()).unwrap();
+        });
+    }
+
+    for _ in 0..total {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+fn test_nested_recv_iter() {
+    let (tx, rx) = channel::<i32>();
+    let (total_tx, total_rx) = channel::<i32>();
+
+    let _t = thread::spawn(move || {
+        let mut acc = 0;
+        for x in rx.iter() {
+            acc += x;
+        }
+        total_tx.send(acc).unwrap();
+    });
+
+    tx.send(3).unwrap();
+    tx.send(1).unwrap();
+    tx.send(2).unwrap();
+    drop(tx);
+    assert_eq!(total_rx.recv().unwrap(), 6);
+}
+
+#[test]
+fn test_recv_iter_break() {
+    let (tx, rx) = channel::<i32>();
+    let (count_tx, count_rx) = channel();
+
+    let _t = thread::spawn(move || {
+        let mut count = 0;
+        for x in rx.iter() {
+            if count >= 3 {
+                break;
+            } else {
+                count += x;
+            }
+        }
+        count_tx.send(count).unwrap();
+    });
+
+    tx.send(2).unwrap();
+    tx.send(2).unwrap();
+    tx.send(2).unwrap();
+    let _ = tx.send(2);
+    drop(tx);
+    assert_eq!(count_rx.recv().unwrap(), 4);
+}
+
+#[test]
+fn test_recv_try_iter() {
+    let (request_tx, request_rx) = channel();
+    let (response_tx, response_rx) = channel();
+
+    // Request `x`s until we have `6`.
+    let t = thread::spawn(move || {
+        let mut count = 0;
+        loop {
+            for x in response_rx.try_iter() {
+                count += x;
+                if count == 6 {
+                    return count;
+                }
+            }
+            request_tx.send(()).unwrap();
+        }
+    });
+
+    for _ in request_rx.iter() {
+        if response_tx.send(2).is_err() {
+            break;
+        }
+    }
+
+    assert_eq!(t.join().unwrap(), 6);
+}
+
+#[test]
+fn test_recv_into_iter_owned() {
+    let mut iter = {
+        let (tx, rx) = channel::<i32>();
+        tx.send(1).unwrap();
+        tx.send(2).unwrap();
+
+        rx.into_iter()
+    };
+    assert_eq!(iter.next().unwrap(), 1);
+    assert_eq!(iter.next().unwrap(), 2);
+    assert_eq!(iter.next().is_none(), true);
+}
+
+#[test]
+fn test_recv_into_iter_borrowed() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(1).unwrap();
+    tx.send(2).unwrap();
+    drop(tx);
+    let mut iter = (&rx).into_iter();
+    assert_eq!(iter.next().unwrap(), 1);
+    assert_eq!(iter.next().unwrap(), 2);
+    assert_eq!(iter.next().is_none(), true);
+}
+
+#[test]
+fn try_recv_states() {
+    let (tx1, rx1) = channel::<i32>();
+    let (tx2, rx2) = channel::<()>();
+    let (tx3, rx3) = channel::<()>();
+    let _t = thread::spawn(move || {
+        rx2.recv().unwrap();
+        tx1.send(1).unwrap();
+        tx3.send(()).unwrap();
+        rx2.recv().unwrap();
+        drop(tx1);
+        tx3.send(()).unwrap();
+    });
+
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+    tx2.send(()).unwrap();
+    rx3.recv().unwrap();
+    assert_eq!(rx1.try_recv(), Ok(1));
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+    tx2.send(()).unwrap();
+    rx3.recv().unwrap();
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected));
+}
+
+// This bug used to end up in a livelock inside of the Receiver destructor
+// because the internal state of the Shared packet was corrupted
+#[test]
+fn destroy_upgraded_shared_port_when_sender_still_active() {
+    let (tx, rx) = channel();
+    let (tx2, rx2) = channel();
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap(); // wait on a oneshot
+        drop(rx); // destroy a shared
+        tx2.send(()).unwrap();
+    });
+    // make sure the other thread has gone to sleep
+    for _ in 0..5000 {
+        thread::yield_now();
+    }
+
+    // upgrade to a shared chan and send a message
+    let t = tx.clone();
+    drop(tx);
+    t.send(()).unwrap();
+
+    // wait for the child thread to exit before we exit
+    rx2.recv().unwrap();
+}
+
+#[test]
+fn issue_32114() {
+    let (tx, _) = channel();
+    let _ = tx.send(123);
+    assert_eq!(tx.send(123), Err(SendError(123)));
+}
index d7a4f00305c71a458501a599b3a529652a53bfda..0de717938348d3bdc2599675d95cfb311158db9c 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
 use crate::cell::UnsafeCell;
 use crate::fmt;
 use crate::mem;
@@ -515,245 +518,3 @@ pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
 pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
     &guard.lock.poison
 }
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests {
-    use crate::sync::atomic::{AtomicUsize, Ordering};
-    use crate::sync::mpsc::channel;
-    use crate::sync::{Arc, Condvar, Mutex};
-    use crate::thread;
-
-    struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
-
-    #[derive(Eq, PartialEq, Debug)]
-    struct NonCopy(i32);
-
-    #[test]
-    fn smoke() {
-        let m = Mutex::new(());
-        drop(m.lock().unwrap());
-        drop(m.lock().unwrap());
-    }
-
-    #[test]
-    fn lots_and_lots() {
-        const J: u32 = 1000;
-        const K: u32 = 3;
-
-        let m = Arc::new(Mutex::new(0));
-
-        fn inc(m: &Mutex<u32>) {
-            for _ in 0..J {
-                *m.lock().unwrap() += 1;
-            }
-        }
-
-        let (tx, rx) = channel();
-        for _ in 0..K {
-            let tx2 = tx.clone();
-            let m2 = m.clone();
-            thread::spawn(move || {
-                inc(&m2);
-                tx2.send(()).unwrap();
-            });
-            let tx2 = tx.clone();
-            let m2 = m.clone();
-            thread::spawn(move || {
-                inc(&m2);
-                tx2.send(()).unwrap();
-            });
-        }
-
-        drop(tx);
-        for _ in 0..2 * K {
-            rx.recv().unwrap();
-        }
-        assert_eq!(*m.lock().unwrap(), J * K * 2);
-    }
-
-    #[test]
-    fn try_lock() {
-        let m = Mutex::new(());
-        *m.try_lock().unwrap() = ();
-    }
-
-    #[test]
-    fn test_into_inner() {
-        let m = Mutex::new(NonCopy(10));
-        assert_eq!(m.into_inner().unwrap(), NonCopy(10));
-    }
-
-    #[test]
-    fn test_into_inner_drop() {
-        struct Foo(Arc<AtomicUsize>);
-        impl Drop for Foo {
-            fn drop(&mut self) {
-                self.0.fetch_add(1, Ordering::SeqCst);
-            }
-        }
-        let num_drops = Arc::new(AtomicUsize::new(0));
-        let m = Mutex::new(Foo(num_drops.clone()));
-        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
-        {
-            let _inner = m.into_inner().unwrap();
-            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
-        }
-        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
-    }
-
-    #[test]
-    fn test_into_inner_poison() {
-        let m = Arc::new(Mutex::new(NonCopy(10)));
-        let m2 = m.clone();
-        let _ = thread::spawn(move || {
-            let _lock = m2.lock().unwrap();
-            panic!("test panic in inner thread to poison mutex");
-        })
-        .join();
-
-        assert!(m.is_poisoned());
-        match Arc::try_unwrap(m).unwrap().into_inner() {
-            Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
-            Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x),
-        }
-    }
-
-    #[test]
-    fn test_get_mut() {
-        let mut m = Mutex::new(NonCopy(10));
-        *m.get_mut().unwrap() = NonCopy(20);
-        assert_eq!(m.into_inner().unwrap(), NonCopy(20));
-    }
-
-    #[test]
-    fn test_get_mut_poison() {
-        let m = Arc::new(Mutex::new(NonCopy(10)));
-        let m2 = m.clone();
-        let _ = thread::spawn(move || {
-            let _lock = m2.lock().unwrap();
-            panic!("test panic in inner thread to poison mutex");
-        })
-        .join();
-
-        assert!(m.is_poisoned());
-        match Arc::try_unwrap(m).unwrap().get_mut() {
-            Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
-            Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x),
-        }
-    }
-
-    #[test]
-    fn test_mutex_arc_condvar() {
-        let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
-        let packet2 = Packet(packet.0.clone());
-        let (tx, rx) = channel();
-        let _t = thread::spawn(move || {
-            // wait until parent gets in
-            rx.recv().unwrap();
-            let &(ref lock, ref cvar) = &*packet2.0;
-            let mut lock = lock.lock().unwrap();
-            *lock = true;
-            cvar.notify_one();
-        });
-
-        let &(ref lock, ref cvar) = &*packet.0;
-        let mut lock = lock.lock().unwrap();
-        tx.send(()).unwrap();
-        assert!(!*lock);
-        while !*lock {
-            lock = cvar.wait(lock).unwrap();
-        }
-    }
-
-    #[test]
-    fn test_arc_condvar_poison() {
-        let packet = Packet(Arc::new((Mutex::new(1), Condvar::new())));
-        let packet2 = Packet(packet.0.clone());
-        let (tx, rx) = channel();
-
-        let _t = thread::spawn(move || -> () {
-            rx.recv().unwrap();
-            let &(ref lock, ref cvar) = &*packet2.0;
-            let _g = lock.lock().unwrap();
-            cvar.notify_one();
-            // Parent should fail when it wakes up.
-            panic!();
-        });
-
-        let &(ref lock, ref cvar) = &*packet.0;
-        let mut lock = lock.lock().unwrap();
-        tx.send(()).unwrap();
-        while *lock == 1 {
-            match cvar.wait(lock) {
-                Ok(l) => {
-                    lock = l;
-                    assert_eq!(*lock, 1);
-                }
-                Err(..) => break,
-            }
-        }
-    }
-
-    #[test]
-    fn test_mutex_arc_poison() {
-        let arc = Arc::new(Mutex::new(1));
-        assert!(!arc.is_poisoned());
-        let arc2 = arc.clone();
-        let _ = thread::spawn(move || {
-            let lock = arc2.lock().unwrap();
-            assert_eq!(*lock, 2);
-        })
-        .join();
-        assert!(arc.lock().is_err());
-        assert!(arc.is_poisoned());
-    }
-
-    #[test]
-    fn test_mutex_arc_nested() {
-        // Tests nested mutexes and access
-        // to underlying data.
-        let arc = Arc::new(Mutex::new(1));
-        let arc2 = Arc::new(Mutex::new(arc));
-        let (tx, rx) = channel();
-        let _t = thread::spawn(move || {
-            let lock = arc2.lock().unwrap();
-            let lock2 = lock.lock().unwrap();
-            assert_eq!(*lock2, 1);
-            tx.send(()).unwrap();
-        });
-        rx.recv().unwrap();
-    }
-
-    #[test]
-    fn test_mutex_arc_access_in_unwind() {
-        let arc = Arc::new(Mutex::new(1));
-        let arc2 = arc.clone();
-        let _ = thread::spawn(move || -> () {
-            struct Unwinder {
-                i: Arc<Mutex<i32>>,
-            }
-            impl Drop for Unwinder {
-                fn drop(&mut self) {
-                    *self.i.lock().unwrap() += 1;
-                }
-            }
-            let _u = Unwinder { i: arc2 };
-            panic!();
-        })
-        .join();
-        let lock = arc.lock().unwrap();
-        assert_eq!(*lock, 2);
-    }
-
-    #[test]
-    fn test_mutex_unsized() {
-        let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
-        {
-            let b = &mut *mutex.lock().unwrap();
-            b[0] = 4;
-            b[2] = 5;
-        }
-        let comp: &[i32] = &[4, 2, 5];
-        assert_eq!(&*mutex.lock().unwrap(), comp);
-    }
-}
diff --git a/library/std/src/sync/mutex/tests.rs b/library/std/src/sync/mutex/tests.rs
new file mode 100644 (file)
index 0000000..a1b5aed
--- /dev/null
@@ -0,0 +1,238 @@
+use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::mpsc::channel;
+use crate::sync::{Arc, Condvar, Mutex};
+use crate::thread;
+
+struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
+
+#[derive(Eq, PartialEq, Debug)]
+struct NonCopy(i32);
+
+#[test]
+fn smoke() {
+    let m = Mutex::new(());
+    drop(m.lock().unwrap());
+    drop(m.lock().unwrap());
+}
+
+#[test]
+fn lots_and_lots() {
+    const J: u32 = 1000;
+    const K: u32 = 3;
+
+    let m = Arc::new(Mutex::new(0));
+
+    fn inc(m: &Mutex<u32>) {
+        for _ in 0..J {
+            *m.lock().unwrap() += 1;
+        }
+    }
+
+    let (tx, rx) = channel();
+    for _ in 0..K {
+        let tx2 = tx.clone();
+        let m2 = m.clone();
+        thread::spawn(move || {
+            inc(&m2);
+            tx2.send(()).unwrap();
+        });
+        let tx2 = tx.clone();
+        let m2 = m.clone();
+        thread::spawn(move || {
+            inc(&m2);
+            tx2.send(()).unwrap();
+        });
+    }
+
+    drop(tx);
+    for _ in 0..2 * K {
+        rx.recv().unwrap();
+    }
+    assert_eq!(*m.lock().unwrap(), J * K * 2);
+}
+
+#[test]
+fn try_lock() {
+    let m = Mutex::new(());
+    *m.try_lock().unwrap() = ();
+}
+
+#[test]
+fn test_into_inner() {
+    let m = Mutex::new(NonCopy(10));
+    assert_eq!(m.into_inner().unwrap(), NonCopy(10));
+}
+
+#[test]
+fn test_into_inner_drop() {
+    struct Foo(Arc<AtomicUsize>);
+    impl Drop for Foo {
+        fn drop(&mut self) {
+            self.0.fetch_add(1, Ordering::SeqCst);
+        }
+    }
+    let num_drops = Arc::new(AtomicUsize::new(0));
+    let m = Mutex::new(Foo(num_drops.clone()));
+    assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+    {
+        let _inner = m.into_inner().unwrap();
+        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+    }
+    assert_eq!(num_drops.load(Ordering::SeqCst), 1);
+}
+
+#[test]
+fn test_into_inner_poison() {
+    let m = Arc::new(Mutex::new(NonCopy(10)));
+    let m2 = m.clone();
+    let _ = thread::spawn(move || {
+        let _lock = m2.lock().unwrap();
+        panic!("test panic in inner thread to poison mutex");
+    })
+    .join();
+
+    assert!(m.is_poisoned());
+    match Arc::try_unwrap(m).unwrap().into_inner() {
+        Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
+        Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x),
+    }
+}
+
+#[test]
+fn test_get_mut() {
+    let mut m = Mutex::new(NonCopy(10));
+    *m.get_mut().unwrap() = NonCopy(20);
+    assert_eq!(m.into_inner().unwrap(), NonCopy(20));
+}
+
+#[test]
+fn test_get_mut_poison() {
+    let m = Arc::new(Mutex::new(NonCopy(10)));
+    let m2 = m.clone();
+    let _ = thread::spawn(move || {
+        let _lock = m2.lock().unwrap();
+        panic!("test panic in inner thread to poison mutex");
+    })
+    .join();
+
+    assert!(m.is_poisoned());
+    match Arc::try_unwrap(m).unwrap().get_mut() {
+        Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
+        Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x),
+    }
+}
+
+#[test]
+fn test_mutex_arc_condvar() {
+    let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
+    let packet2 = Packet(packet.0.clone());
+    let (tx, rx) = channel();
+    let _t = thread::spawn(move || {
+        // wait until parent gets in
+        rx.recv().unwrap();
+        let &(ref lock, ref cvar) = &*packet2.0;
+        let mut lock = lock.lock().unwrap();
+        *lock = true;
+        cvar.notify_one();
+    });
+
+    let &(ref lock, ref cvar) = &*packet.0;
+    let mut lock = lock.lock().unwrap();
+    tx.send(()).unwrap();
+    assert!(!*lock);
+    while !*lock {
+        lock = cvar.wait(lock).unwrap();
+    }
+}
+
+#[test]
+fn test_arc_condvar_poison() {
+    let packet = Packet(Arc::new((Mutex::new(1), Condvar::new())));
+    let packet2 = Packet(packet.0.clone());
+    let (tx, rx) = channel();
+
+    let _t = thread::spawn(move || -> () {
+        rx.recv().unwrap();
+        let &(ref lock, ref cvar) = &*packet2.0;
+        let _g = lock.lock().unwrap();
+        cvar.notify_one();
+        // Parent should fail when it wakes up.
+        panic!();
+    });
+
+    let &(ref lock, ref cvar) = &*packet.0;
+    let mut lock = lock.lock().unwrap();
+    tx.send(()).unwrap();
+    while *lock == 1 {
+        match cvar.wait(lock) {
+            Ok(l) => {
+                lock = l;
+                assert_eq!(*lock, 1);
+            }
+            Err(..) => break,
+        }
+    }
+}
+
+#[test]
+fn test_mutex_arc_poison() {
+    let arc = Arc::new(Mutex::new(1));
+    assert!(!arc.is_poisoned());
+    let arc2 = arc.clone();
+    let _ = thread::spawn(move || {
+        let lock = arc2.lock().unwrap();
+        assert_eq!(*lock, 2);
+    })
+    .join();
+    assert!(arc.lock().is_err());
+    assert!(arc.is_poisoned());
+}
+
+#[test]
+fn test_mutex_arc_nested() {
+    // Tests nested mutexes and access
+    // to underlying data.
+    let arc = Arc::new(Mutex::new(1));
+    let arc2 = Arc::new(Mutex::new(arc));
+    let (tx, rx) = channel();
+    let _t = thread::spawn(move || {
+        let lock = arc2.lock().unwrap();
+        let lock2 = lock.lock().unwrap();
+        assert_eq!(*lock2, 1);
+        tx.send(()).unwrap();
+    });
+    rx.recv().unwrap();
+}
+
+#[test]
+fn test_mutex_arc_access_in_unwind() {
+    let arc = Arc::new(Mutex::new(1));
+    let arc2 = arc.clone();
+    let _ = thread::spawn(move || -> () {
+        struct Unwinder {
+            i: Arc<Mutex<i32>>,
+        }
+        impl Drop for Unwinder {
+            fn drop(&mut self) {
+                *self.i.lock().unwrap() += 1;
+            }
+        }
+        let _u = Unwinder { i: arc2 };
+        panic!();
+    })
+    .join();
+    let lock = arc.lock().unwrap();
+    assert_eq!(*lock, 2);
+}
+
+#[test]
+fn test_mutex_unsized() {
+    let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
+    {
+        let b = &mut *mutex.lock().unwrap();
+        b[0] = 4;
+        b[2] = 5;
+    }
+    let comp: &[i32] = &[4, 2, 5];
+    assert_eq!(&*mutex.lock().unwrap(), comp);
+}
index 714ec3e878617adfad8c2308741d9f599d8e2c84..8fed369bffc27dd6ee5003c8e0c408e3c1a20225 100644 (file)
@@ -84,6 +84,9 @@
 //   processor. Because both use Acquire ordering such a reordering is not
 //   allowed, so no need for SeqCst.
 
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
 use crate::cell::Cell;
 use crate::fmt;
 use crate::marker;
@@ -568,123 +571,3 @@ pub(crate) fn poison(&self) {
         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());
-    }
-}
diff --git a/library/std/src/sync/once/tests.rs b/library/std/src/sync/once/tests.rs
new file mode 100644 (file)
index 0000000..fae2752
--- /dev/null
@@ -0,0 +1,116 @@
+use super::Once;
+use crate::panic;
+use crate::sync::mpsc::channel;
+use crate::thread;
+
+#[test]
+fn smoke_once() {
+    static O: Once = Once::new();
+    let mut a = 0;
+    O.call_once(|| a += 1);
+    assert_eq!(a, 1);
+    O.call_once(|| a += 1);
+    assert_eq!(a, 1);
+}
+
+#[test]
+fn stampede_once() {
+    static O: Once = Once::new();
+    static mut RUN: bool = false;
+
+    let (tx, rx) = channel();
+    for _ in 0..10 {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            for _ in 0..4 {
+                thread::yield_now()
+            }
+            unsafe {
+                O.call_once(|| {
+                    assert!(!RUN);
+                    RUN = true;
+                });
+                assert!(RUN);
+            }
+            tx.send(()).unwrap();
+        });
+    }
+
+    unsafe {
+        O.call_once(|| {
+            assert!(!RUN);
+            RUN = true;
+        });
+        assert!(RUN);
+    }
+
+    for _ in 0..10 {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+fn poison_bad() {
+    static O: Once = Once::new();
+
+    // poison the once
+    let t = panic::catch_unwind(|| {
+        O.call_once(|| panic!());
+    });
+    assert!(t.is_err());
+
+    // poisoning propagates
+    let t = panic::catch_unwind(|| {
+        O.call_once(|| {});
+    });
+    assert!(t.is_err());
+
+    // we can subvert poisoning, however
+    let mut called = false;
+    O.call_once_force(|p| {
+        called = true;
+        assert!(p.poisoned())
+    });
+    assert!(called);
+
+    // once any success happens, we stop propagating the poison
+    O.call_once(|| {});
+}
+
+#[test]
+fn wait_for_force_to_finish() {
+    static O: Once = Once::new();
+
+    // poison the once
+    let t = panic::catch_unwind(|| {
+        O.call_once(|| panic!());
+    });
+    assert!(t.is_err());
+
+    // make sure someone's waiting inside the once via a force
+    let (tx1, rx1) = channel();
+    let (tx2, rx2) = channel();
+    let t1 = thread::spawn(move || {
+        O.call_once_force(|p| {
+            assert!(p.poisoned());
+            tx1.send(()).unwrap();
+            rx2.recv().unwrap();
+        });
+    });
+
+    rx1.recv().unwrap();
+
+    // put another waiter on the once
+    let t2 = thread::spawn(|| {
+        let mut called = false;
+        O.call_once(|| {
+            called = true;
+        });
+        assert!(!called);
+    });
+
+    tx2.send(()).unwrap();
+
+    assert!(t1.join().is_ok());
+    assert!(t2.join().is_ok());
+}
index 586093c916deabb7f5dfed6626d7a895a7e6d57e..2d219c2c7dd2aebdaec788a226c231c654e0d707 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
 use crate::cell::UnsafeCell;
 use crate::fmt;
 use crate::mem;
@@ -538,254 +541,3 @@ fn drop(&mut self) {
         }
     }
 }
-
-#[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),
-        }
-    }
-}
diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs
new file mode 100644 (file)
index 0000000..e9b74fb
--- /dev/null
@@ -0,0 +1,247 @@
+use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::mpsc::channel;
+use crate::sync::{Arc, RwLock, TryLockError};
+use crate::thread;
+use rand::{self, Rng};
+
+#[derive(Eq, PartialEq, Debug)]
+struct NonCopy(i32);
+
+#[test]
+fn smoke() {
+    let l = RwLock::new(());
+    drop(l.read().unwrap());
+    drop(l.write().unwrap());
+    drop((l.read().unwrap(), l.read().unwrap()));
+    drop(l.write().unwrap());
+}
+
+#[test]
+fn frob() {
+    const N: u32 = 10;
+    const M: usize = 1000;
+
+    let r = Arc::new(RwLock::new(()));
+
+    let (tx, rx) = channel::<()>();
+    for _ in 0..N {
+        let tx = tx.clone();
+        let r = r.clone();
+        thread::spawn(move || {
+            let mut rng = rand::thread_rng();
+            for _ in 0..M {
+                if rng.gen_bool(1.0 / (N as f64)) {
+                    drop(r.write().unwrap());
+                } else {
+                    drop(r.read().unwrap());
+                }
+            }
+            drop(tx);
+        });
+    }
+    drop(tx);
+    let _ = rx.recv();
+}
+
+#[test]
+fn test_rw_arc_poison_wr() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let _lock = arc2.write().unwrap();
+        panic!();
+    })
+    .join();
+    assert!(arc.read().is_err());
+}
+
+#[test]
+fn test_rw_arc_poison_ww() {
+    let arc = Arc::new(RwLock::new(1));
+    assert!(!arc.is_poisoned());
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let _lock = arc2.write().unwrap();
+        panic!();
+    })
+    .join();
+    assert!(arc.write().is_err());
+    assert!(arc.is_poisoned());
+}
+
+#[test]
+fn test_rw_arc_no_poison_rr() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let _lock = arc2.read().unwrap();
+        panic!();
+    })
+    .join();
+    let lock = arc.read().unwrap();
+    assert_eq!(*lock, 1);
+}
+#[test]
+fn test_rw_arc_no_poison_rw() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let _lock = arc2.read().unwrap();
+        panic!()
+    })
+    .join();
+    let lock = arc.write().unwrap();
+    assert_eq!(*lock, 1);
+}
+
+#[test]
+fn test_rw_arc() {
+    let arc = Arc::new(RwLock::new(0));
+    let arc2 = arc.clone();
+    let (tx, rx) = channel();
+
+    thread::spawn(move || {
+        let mut lock = arc2.write().unwrap();
+        for _ in 0..10 {
+            let tmp = *lock;
+            *lock = -1;
+            thread::yield_now();
+            *lock = tmp + 1;
+        }
+        tx.send(()).unwrap();
+    });
+
+    // Readers try to catch the writer in the act
+    let mut children = Vec::new();
+    for _ in 0..5 {
+        let arc3 = arc.clone();
+        children.push(thread::spawn(move || {
+            let lock = arc3.read().unwrap();
+            assert!(*lock >= 0);
+        }));
+    }
+
+    // Wait for children to pass their asserts
+    for r in children {
+        assert!(r.join().is_ok());
+    }
+
+    // Wait for writer to finish
+    rx.recv().unwrap();
+    let lock = arc.read().unwrap();
+    assert_eq!(*lock, 10);
+}
+
+#[test]
+fn test_rw_arc_access_in_unwind() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _ = thread::spawn(move || -> () {
+        struct Unwinder {
+            i: Arc<RwLock<isize>>,
+        }
+        impl Drop for Unwinder {
+            fn drop(&mut self) {
+                let mut lock = self.i.write().unwrap();
+                *lock += 1;
+            }
+        }
+        let _u = Unwinder { i: arc2 };
+        panic!();
+    })
+    .join();
+    let lock = arc.read().unwrap();
+    assert_eq!(*lock, 2);
+}
+
+#[test]
+fn test_rwlock_unsized() {
+    let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
+    {
+        let b = &mut *rw.write().unwrap();
+        b[0] = 4;
+        b[2] = 5;
+    }
+    let comp: &[i32] = &[4, 2, 5];
+    assert_eq!(&*rw.read().unwrap(), comp);
+}
+
+#[test]
+fn test_rwlock_try_write() {
+    let lock = RwLock::new(0isize);
+    let read_guard = lock.read().unwrap();
+
+    let write_result = lock.try_write();
+    match write_result {
+        Err(TryLockError::WouldBlock) => (),
+        Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"),
+        Err(_) => assert!(false, "unexpected error"),
+    }
+
+    drop(read_guard);
+}
+
+#[test]
+fn test_into_inner() {
+    let m = RwLock::new(NonCopy(10));
+    assert_eq!(m.into_inner().unwrap(), NonCopy(10));
+}
+
+#[test]
+fn test_into_inner_drop() {
+    struct Foo(Arc<AtomicUsize>);
+    impl Drop for Foo {
+        fn drop(&mut self) {
+            self.0.fetch_add(1, Ordering::SeqCst);
+        }
+    }
+    let num_drops = Arc::new(AtomicUsize::new(0));
+    let m = RwLock::new(Foo(num_drops.clone()));
+    assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+    {
+        let _inner = m.into_inner().unwrap();
+        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+    }
+    assert_eq!(num_drops.load(Ordering::SeqCst), 1);
+}
+
+#[test]
+fn test_into_inner_poison() {
+    let m = Arc::new(RwLock::new(NonCopy(10)));
+    let m2 = m.clone();
+    let _ = thread::spawn(move || {
+        let _lock = m2.write().unwrap();
+        panic!("test panic in inner thread to poison RwLock");
+    })
+    .join();
+
+    assert!(m.is_poisoned());
+    match Arc::try_unwrap(m).unwrap().into_inner() {
+        Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
+        Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x),
+    }
+}
+
+#[test]
+fn test_get_mut() {
+    let mut m = RwLock::new(NonCopy(10));
+    *m.get_mut().unwrap() = NonCopy(20);
+    assert_eq!(m.into_inner().unwrap(), NonCopy(20));
+}
+
+#[test]
+fn test_get_mut_poison() {
+    let m = Arc::new(RwLock::new(NonCopy(10)));
+    let m2 = m.clone();
+    let _ = thread::spawn(move || {
+        let _lock = m2.write().unwrap();
+        panic!("test panic in inner thread to poison RwLock");
+    })
+    .join();
+
+    assert!(m.is_poisoned());
+    match Arc::try_unwrap(m).unwrap().get_mut() {
+        Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
+        Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x),
+    }
+}
index 2b0485c4f03635041b91de0f320d5681496a046a..0d8952b2f273b2ddea95453fc09e56a3bc35194a 100644 (file)
@@ -1,3 +1,5 @@
+mod sync_bitset;
+
 use self::sync_bitset::*;
 use crate::cell::Cell;
 use crate::mem;
@@ -125,117 +127,3 @@ pub fn destroy(key: Key) {
         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));
-        }
-    }
-}
diff --git a/library/std/src/sys/sgx/abi/tls/sync_bitset.rs b/library/std/src/sys/sgx/abi/tls/sync_bitset.rs
new file mode 100644 (file)
index 0000000..4eeff8f
--- /dev/null
@@ -0,0 +1,85 @@
+#[cfg(test)]
+mod tests;
+
+use super::{TLS_KEYS_BITSET_SIZE, USIZE_BITS};
+use crate::iter::{Enumerate, Peekable};
+use crate::slice::Iter;
+use crate::sync::atomic::{AtomicUsize, Ordering};
+
+/// A bitset that can be used synchronously.
+pub(super) struct SyncBitset([AtomicUsize; TLS_KEYS_BITSET_SIZE]);
+
+pub(super) const SYNC_BITSET_INIT: SyncBitset =
+    SyncBitset([AtomicUsize::new(0), AtomicUsize::new(0)]);
+
+impl SyncBitset {
+    pub fn get(&self, index: usize) -> bool {
+        let (hi, lo) = Self::split(index);
+        (self.0[hi].load(Ordering::Relaxed) & lo) != 0
+    }
+
+    /// Not atomic.
+    pub fn iter(&self) -> SyncBitsetIter<'_> {
+        SyncBitsetIter { iter: self.0.iter().enumerate().peekable(), elem_idx: 0 }
+    }
+
+    pub fn clear(&self, index: usize) {
+        let (hi, lo) = Self::split(index);
+        self.0[hi].fetch_and(!lo, Ordering::Relaxed);
+    }
+
+    /// Sets any unset bit. Not atomic. Returns `None` if all bits were
+    /// observed to be set.
+    pub fn set(&self) -> Option<usize> {
+        'elems: for (idx, elem) in self.0.iter().enumerate() {
+            let mut current = elem.load(Ordering::Relaxed);
+            loop {
+                if 0 == !current {
+                    continue 'elems;
+                }
+                let trailing_ones = (!current).trailing_zeros() as usize;
+                match elem.compare_exchange(
+                    current,
+                    current | (1 << trailing_ones),
+                    Ordering::AcqRel,
+                    Ordering::Relaxed,
+                ) {
+                    Ok(_) => return Some(idx * USIZE_BITS + trailing_ones),
+                    Err(previous) => current = previous,
+                }
+            }
+        }
+        None
+    }
+
+    fn split(index: usize) -> (usize, usize) {
+        (index / USIZE_BITS, 1 << (index % USIZE_BITS))
+    }
+}
+
+pub(super) struct SyncBitsetIter<'a> {
+    iter: Peekable<Enumerate<Iter<'a, AtomicUsize>>>,
+    elem_idx: usize,
+}
+
+impl<'a> Iterator for SyncBitsetIter<'a> {
+    type Item = usize;
+
+    fn next(&mut self) -> Option<usize> {
+        self.iter.peek().cloned().and_then(|(idx, elem)| {
+            let elem = elem.load(Ordering::Relaxed);
+            let low_mask = (1 << self.elem_idx) - 1;
+            let next = elem & !low_mask;
+            let next_idx = next.trailing_zeros() as usize;
+            self.elem_idx = next_idx + 1;
+            if self.elem_idx >= 64 {
+                self.elem_idx = 0;
+                self.iter.next();
+            }
+            match next_idx {
+                64 => self.next(),
+                _ => Some(idx * USIZE_BITS + next_idx),
+            }
+        })
+    }
+}
diff --git a/library/std/src/sys/sgx/abi/tls/sync_bitset/tests.rs b/library/std/src/sys/sgx/abi/tls/sync_bitset/tests.rs
new file mode 100644 (file)
index 0000000..d7eb2e1
--- /dev/null
@@ -0,0 +1,25 @@
+use super::*;
+
+fn test_data(bitset: [usize; 2], bit_indices: &[usize]) {
+    let set = SyncBitset([AtomicUsize::new(bitset[0]), AtomicUsize::new(bitset[1])]);
+    assert_eq!(set.iter().collect::<Vec<_>>(), bit_indices);
+    for &i in bit_indices {
+        assert!(set.get(i));
+    }
+}
+
+#[test]
+fn iter() {
+    test_data([0b0110_1001, 0], &[0, 3, 5, 6]);
+    test_data([0x8000_0000_0000_0000, 0x8000_0000_0000_0001], &[63, 64, 127]);
+    test_data([0, 0], &[]);
+}
+
+#[test]
+fn set_get_clear() {
+    let set = SYNC_BITSET_INIT;
+    let key = set.set().unwrap();
+    assert!(set.get(key));
+    set.clear(key);
+    assert!(!set.get(key));
+}
index 722b4f5e0ba387fcc98b584025d8ee59aa6629bf..3bf2a7d8fb46c3df0f81230768f1289f01b8762d 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(test)]
+mod tests;
+
 use crate::num::NonZeroUsize;
 
 use super::waitqueue::{
@@ -198,50 +201,3 @@ pub unsafe fn destroy(&self) {}
     (*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)
-        };
-    }
-}
diff --git a/library/std/src/sys/sgx/rwlock/tests.rs b/library/std/src/sys/sgx/rwlock/tests.rs
new file mode 100644 (file)
index 0000000..05b36c6
--- /dev/null
@@ -0,0 +1,43 @@
+use super::*;
+use crate::mem::{self, MaybeUninit};
+use core::array::FixedSizeArray;
+
+// Verify that the bytes of initialized RWLock are the same as in
+// libunwind. If they change, `src/UnwindRustSgx.h` in libunwind needs to
+// be changed too.
+#[test]
+fn test_c_rwlock_initializer() {
+    #[rustfmt::skip]
+    const RWLOCK_INIT: &[u8] = &[
+        /* 0x00 */ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        /* 0x10 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        /* 0x20 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        /* 0x30 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        /* 0x40 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        /* 0x50 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        /* 0x60 */ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        /* 0x70 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        /* 0x80 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    ];
+
+    #[inline(never)]
+    fn zero_stack() {
+        test::black_box(MaybeUninit::<[RWLock; 16]>::zeroed());
+    }
+
+    #[inline(never)]
+    unsafe fn rwlock_new(init: &mut MaybeUninit<RWLock>) {
+        init.write(RWLock::new());
+    }
+
+    unsafe {
+        // try hard to make sure that the padding/unused bytes in RWLock
+        // get initialized as 0. If the assertion below fails, that might
+        // just be an issue with the test code and not with the value of
+        // RWLOCK_INIT.
+        zero_stack();
+        let mut init = MaybeUninit::<RWLock>::zeroed();
+        rwlock_new(&mut init);
+        assert_eq!(mem::transmute::<_, [u8; 144]>(init.assume_init()).as_slice(), RWLOCK_INIT)
+    };
+}
index 070afa55f301927e3d5f7ac429a5fb930e3c595c..e464dc3ee9d40139a348c7847112e956de07cb54 100644 (file)
@@ -9,6 +9,18 @@
 //! Since userspace may send spurious wake-ups, the wakeup event state is
 //! recorded in the enclave. The wakeup event state is protected by a spinlock.
 //! The queue and associated wait state are stored in a `WaitVariable`.
+
+#[cfg(test)]
+mod tests;
+
+/// A doubly-linked list where callers are in charge of memory allocation
+/// of the nodes in the list.
+mod unsafe_list;
+
+/// Trivial spinlock-based implementation of `sync::Mutex`.
+// FIXME: Perhaps use Intel TSX to avoid locking?
+mod spin_mutex;
+
 use crate::num::NonZeroUsize;
 use crate::ops::{Deref, DerefMut};
 use crate::time::Duration;
@@ -231,389 +243,3 @@ pub fn notify_all<T>(
         }
     }
 }
-
-/// 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();
-    }
-}
diff --git a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs
new file mode 100644 (file)
index 0000000..d99ce89
--- /dev/null
@@ -0,0 +1,76 @@
+#[cfg(test)]
+mod tests;
+
+use crate::cell::UnsafeCell;
+use crate::ops::{Deref, DerefMut};
+use crate::sync::atomic::{spin_loop_hint, AtomicBool, Ordering};
+
+#[derive(Default)]
+pub struct SpinMutex<T> {
+    value: UnsafeCell<T>,
+    lock: AtomicBool,
+}
+
+unsafe impl<T: Send> Send for SpinMutex<T> {}
+unsafe impl<T: Send> Sync for SpinMutex<T> {}
+
+pub struct SpinMutexGuard<'a, T: 'a> {
+    mutex: &'a SpinMutex<T>,
+}
+
+impl<'a, T> !Send for SpinMutexGuard<'a, T> {}
+unsafe impl<'a, T: Sync> Sync for SpinMutexGuard<'a, T> {}
+
+impl<T> SpinMutex<T> {
+    pub const fn new(value: T) -> Self {
+        SpinMutex { value: UnsafeCell::new(value), lock: AtomicBool::new(false) }
+    }
+
+    #[inline(always)]
+    pub fn lock(&self) -> SpinMutexGuard<'_, T> {
+        loop {
+            match self.try_lock() {
+                None => {
+                    while self.lock.load(Ordering::Relaxed) {
+                        spin_loop_hint()
+                    }
+                }
+                Some(guard) => return guard,
+            }
+        }
+    }
+
+    #[inline(always)]
+    pub fn try_lock(&self) -> Option<SpinMutexGuard<'_, T>> {
+        if !self.lock.compare_and_swap(false, true, Ordering::Acquire) {
+            Some(SpinMutexGuard { mutex: self })
+        } else {
+            None
+        }
+    }
+}
+
+/// Lock the Mutex or return false.
+pub macro try_lock_or_false($e:expr) {
+    if let Some(v) = $e.try_lock() { v } else { return false }
+}
+
+impl<'a, T> Deref for SpinMutexGuard<'a, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        unsafe { &*self.mutex.value.get() }
+    }
+}
+
+impl<'a, T> DerefMut for SpinMutexGuard<'a, T> {
+    fn deref_mut(&mut self) -> &mut T {
+        unsafe { &mut *self.mutex.value.get() }
+    }
+}
+
+impl<'a, T> Drop for SpinMutexGuard<'a, T> {
+    fn drop(&mut self) {
+        self.mutex.lock.store(false, Ordering::Release)
+    }
+}
diff --git a/library/std/src/sys/sgx/waitqueue/spin_mutex/tests.rs b/library/std/src/sys/sgx/waitqueue/spin_mutex/tests.rs
new file mode 100644 (file)
index 0000000..4c5994b
--- /dev/null
@@ -0,0 +1,23 @@
+#![allow(deprecated)]
+
+use super::*;
+use crate::sync::Arc;
+use crate::thread;
+use crate::time::Duration;
+
+#[test]
+fn sleep() {
+    let mutex = Arc::new(SpinMutex::<i32>::default());
+    let mutex2 = mutex.clone();
+    let guard = mutex.lock();
+    let t1 = thread::spawn(move || {
+        *mutex2.lock() = 1;
+    });
+
+    thread::sleep(Duration::from_millis(50));
+
+    assert_eq!(*guard, 0);
+    drop(guard);
+    t1.join().unwrap();
+    assert_eq!(*mutex.lock(), 1);
+}
diff --git a/library/std/src/sys/sgx/waitqueue/tests.rs b/library/std/src/sys/sgx/waitqueue/tests.rs
new file mode 100644 (file)
index 0000000..bf91fdd
--- /dev/null
@@ -0,0 +1,20 @@
+use super::*;
+use crate::sync::Arc;
+use crate::thread;
+
+#[test]
+fn queue() {
+    let wq = Arc::new(SpinMutex::<WaitVariable<()>>::default());
+    let wq2 = wq.clone();
+
+    let locked = wq.lock();
+
+    let t1 = thread::spawn(move || {
+        // if we obtain the lock, the main thread should be waiting
+        assert!(WaitQueue::notify_one(wq2.lock()).is_ok());
+    });
+
+    WaitQueue::wait(locked, || {});
+
+    t1.join().unwrap();
+}
diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs
new file mode 100644 (file)
index 0000000..7a24654
--- /dev/null
@@ -0,0 +1,146 @@
+#[cfg(test)]
+mod tests;
+
+use crate::mem;
+use crate::ptr::NonNull;
+
+pub struct UnsafeListEntry<T> {
+    next: NonNull<UnsafeListEntry<T>>,
+    prev: NonNull<UnsafeListEntry<T>>,
+    value: Option<T>,
+}
+
+impl<T> UnsafeListEntry<T> {
+    fn dummy() -> Self {
+        UnsafeListEntry { next: NonNull::dangling(), prev: NonNull::dangling(), value: None }
+    }
+
+    pub fn new(value: T) -> Self {
+        UnsafeListEntry { value: Some(value), ..Self::dummy() }
+    }
+}
+
+pub struct UnsafeList<T> {
+    head_tail: NonNull<UnsafeListEntry<T>>,
+    head_tail_entry: Option<UnsafeListEntry<T>>,
+}
+
+impl<T> UnsafeList<T> {
+    pub const fn new() -> Self {
+        unsafe { UnsafeList { head_tail: NonNull::new_unchecked(1 as _), head_tail_entry: None } }
+    }
+
+    unsafe fn init(&mut self) {
+        if self.head_tail_entry.is_none() {
+            self.head_tail_entry = Some(UnsafeListEntry::dummy());
+            self.head_tail = NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap());
+            self.head_tail.as_mut().next = self.head_tail;
+            self.head_tail.as_mut().prev = self.head_tail;
+        }
+    }
+
+    pub fn is_empty(&self) -> bool {
+        unsafe {
+            if self.head_tail_entry.is_some() {
+                let first = self.head_tail.as_ref().next;
+                if first == self.head_tail {
+                    // ,-------> /---------\ next ---,
+                    // |         |head_tail|         |
+                    // `--- prev \---------/ <-------`
+                    rtassert!(self.head_tail.as_ref().prev == first);
+                    true
+                } else {
+                    false
+                }
+            } else {
+                true
+            }
+        }
+    }
+
+    /// Pushes an entry onto the back of the list.
+    ///
+    /// # Safety
+    ///
+    /// The entry must remain allocated until the entry is removed from the
+    /// list AND the caller who popped is done using the entry. Special
+    /// care must be taken in the caller of `push` to ensure unwinding does
+    /// not destroy the stack frame containing the entry.
+    pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T {
+        self.init();
+
+        // BEFORE:
+        //     /---------\ next ---> /---------\
+        // ... |prev_tail|           |head_tail| ...
+        //     \---------/ <--- prev \---------/
+        //
+        // AFTER:
+        //     /---------\ next ---> /-----\ next ---> /---------\
+        // ... |prev_tail|           |entry|           |head_tail| ...
+        //     \---------/ <--- prev \-----/ <--- prev \---------/
+        let mut entry = NonNull::new_unchecked(entry);
+        let mut prev_tail = mem::replace(&mut self.head_tail.as_mut().prev, entry);
+        entry.as_mut().prev = prev_tail;
+        entry.as_mut().next = self.head_tail;
+        prev_tail.as_mut().next = entry;
+        // unwrap ok: always `Some` on non-dummy entries
+        (*entry.as_ptr()).value.as_ref().unwrap()
+    }
+
+    /// Pops an entry from the front of the list.
+    ///
+    /// # Safety
+    ///
+    /// The caller must make sure to synchronize ending the borrow of the
+    /// return value and deallocation of the containing entry.
+    pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> {
+        self.init();
+
+        if self.is_empty() {
+            None
+        } else {
+            // BEFORE:
+            //     /---------\ next ---> /-----\ next ---> /------\
+            // ... |head_tail|           |first|           |second| ...
+            //     \---------/ <--- prev \-----/ <--- prev \------/
+            //
+            // AFTER:
+            //     /---------\ next ---> /------\
+            // ... |head_tail|           |second| ...
+            //     \---------/ <--- prev \------/
+            let mut first = self.head_tail.as_mut().next;
+            let mut second = first.as_mut().next;
+            self.head_tail.as_mut().next = second;
+            second.as_mut().prev = self.head_tail;
+            first.as_mut().next = NonNull::dangling();
+            first.as_mut().prev = NonNull::dangling();
+            // unwrap ok: always `Some` on non-dummy entries
+            Some((*first.as_ptr()).value.as_ref().unwrap())
+        }
+    }
+
+    /// Removes an entry from the list.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `entry` has been pushed onto `self`
+    /// prior to this call and has not moved since then.
+    pub unsafe fn remove(&mut self, entry: &mut UnsafeListEntry<T>) {
+        rtassert!(!self.is_empty());
+        // BEFORE:
+        //     /----\ next ---> /-----\ next ---> /----\
+        // ... |prev|           |entry|           |next| ...
+        //     \----/ <--- prev \-----/ <--- prev \----/
+        //
+        // AFTER:
+        //     /----\ next ---> /----\
+        // ... |prev|           |next| ...
+        //     \----/ <--- prev \----/
+        let mut prev = entry.prev;
+        let mut next = entry.next;
+        prev.as_mut().next = next;
+        next.as_mut().prev = prev;
+        entry.next = NonNull::dangling();
+        entry.prev = NonNull::dangling();
+    }
+}
diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs
new file mode 100644 (file)
index 0000000..1f031ed
--- /dev/null
@@ -0,0 +1,103 @@
+use super::*;
+use crate::cell::Cell;
+
+unsafe fn assert_empty<T>(list: &mut UnsafeList<T>) {
+    assert!(list.pop().is_none(), "assertion failed: list is not empty");
+}
+
+#[test]
+fn init_empty() {
+    unsafe {
+        assert_empty(&mut UnsafeList::<i32>::new());
+    }
+}
+
+#[test]
+fn push_pop() {
+    unsafe {
+        let mut node = UnsafeListEntry::new(1234);
+        let mut list = UnsafeList::new();
+        assert_eq!(list.push(&mut node), &1234);
+        assert_eq!(list.pop().unwrap(), &1234);
+        assert_empty(&mut list);
+    }
+}
+
+#[test]
+fn push_remove() {
+    unsafe {
+        let mut node = UnsafeListEntry::new(1234);
+        let mut list = UnsafeList::new();
+        assert_eq!(list.push(&mut node), &1234);
+        list.remove(&mut node);
+        assert_empty(&mut list);
+    }
+}
+
+#[test]
+fn push_remove_pop() {
+    unsafe {
+        let mut node1 = UnsafeListEntry::new(11);
+        let mut node2 = UnsafeListEntry::new(12);
+        let mut node3 = UnsafeListEntry::new(13);
+        let mut node4 = UnsafeListEntry::new(14);
+        let mut node5 = UnsafeListEntry::new(15);
+        let mut list = UnsafeList::new();
+        assert_eq!(list.push(&mut node1), &11);
+        assert_eq!(list.push(&mut node2), &12);
+        assert_eq!(list.push(&mut node3), &13);
+        assert_eq!(list.push(&mut node4), &14);
+        assert_eq!(list.push(&mut node5), &15);
+
+        list.remove(&mut node1);
+        assert_eq!(list.pop().unwrap(), &12);
+        list.remove(&mut node3);
+        assert_eq!(list.pop().unwrap(), &14);
+        list.remove(&mut node5);
+        assert_empty(&mut list);
+
+        assert_eq!(list.push(&mut node1), &11);
+        assert_eq!(list.pop().unwrap(), &11);
+        assert_empty(&mut list);
+
+        assert_eq!(list.push(&mut node3), &13);
+        assert_eq!(list.push(&mut node4), &14);
+        list.remove(&mut node3);
+        list.remove(&mut node4);
+        assert_empty(&mut list);
+    }
+}
+
+#[test]
+fn complex_pushes_pops() {
+    unsafe {
+        let mut node1 = UnsafeListEntry::new(1234);
+        let mut node2 = UnsafeListEntry::new(4567);
+        let mut node3 = UnsafeListEntry::new(9999);
+        let mut node4 = UnsafeListEntry::new(8642);
+        let mut list = UnsafeList::new();
+        list.push(&mut node1);
+        list.push(&mut node2);
+        assert_eq!(list.pop().unwrap(), &1234);
+        list.push(&mut node3);
+        assert_eq!(list.pop().unwrap(), &4567);
+        assert_eq!(list.pop().unwrap(), &9999);
+        assert_empty(&mut list);
+        list.push(&mut node4);
+        assert_eq!(list.pop().unwrap(), &8642);
+        assert_empty(&mut list);
+    }
+}
+
+#[test]
+fn cell() {
+    unsafe {
+        let mut node = UnsafeListEntry::new(Cell::new(0));
+        let mut list = UnsafeList::new();
+        let noderef = list.push(&mut node);
+        assert_eq!(noderef.get(), 0);
+        list.pop().unwrap().set(1);
+        assert_empty(&mut list);
+        assert_eq!(noderef.get(), 1);
+    }
+}
index 55803ddfc43232209238a246ac65cafd5eb5313f..0e07106f5ce5cdbdd7d80e3c82acecdea8706d71 100644 (file)
@@ -2,6 +2,9 @@
 
 //! Unix-specific networking functionality
 
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
 #[cfg(not(unix))]
 #[allow(non_camel_case_types)]
@@ -1620,382 +1623,3 @@ fn into_raw_fd(self) -> RawFd {
         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());
-    }
-}
diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs
new file mode 100644 (file)
index 0000000..be98766
--- /dev/null
@@ -0,0 +1,374 @@
+use crate::io::prelude::*;
+use crate::io::{self, ErrorKind};
+use crate::sys_common::io::test::tmpdir;
+use crate::thread;
+use crate::time::Duration;
+
+use super::*;
+
+macro_rules! or_panic {
+    ($e:expr) => {
+        match $e {
+            Ok(e) => e,
+            Err(e) => panic!("{}", e),
+        }
+    };
+}
+
+#[test]
+fn basic() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+    let msg1 = b"hello";
+    let msg2 = b"world!";
+
+    let listener = or_panic!(UnixListener::bind(&socket_path));
+    let thread = thread::spawn(move || {
+        let mut stream = or_panic!(listener.accept()).0;
+        let mut buf = [0; 5];
+        or_panic!(stream.read(&mut buf));
+        assert_eq!(&msg1[..], &buf[..]);
+        or_panic!(stream.write_all(msg2));
+    });
+
+    let mut stream = or_panic!(UnixStream::connect(&socket_path));
+    assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname());
+    or_panic!(stream.write_all(msg1));
+    let mut buf = vec![];
+    or_panic!(stream.read_to_end(&mut buf));
+    assert_eq!(&msg2[..], &buf[..]);
+    drop(stream);
+
+    thread.join().unwrap();
+}
+
+#[test]
+fn vectored() {
+    let (mut s1, mut s2) = or_panic!(UnixStream::pair());
+
+    let len = or_panic!(s1.write_vectored(&[
+        IoSlice::new(b"hello"),
+        IoSlice::new(b" "),
+        IoSlice::new(b"world!")
+    ],));
+    assert_eq!(len, 12);
+
+    let mut buf1 = [0; 6];
+    let mut buf2 = [0; 7];
+    let len =
+        or_panic!(s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],));
+    assert_eq!(len, 12);
+    assert_eq!(&buf1, b"hello ");
+    assert_eq!(&buf2, b"world!\0");
+}
+
+#[test]
+fn pair() {
+    let msg1 = b"hello";
+    let msg2 = b"world!";
+
+    let (mut s1, mut s2) = or_panic!(UnixStream::pair());
+    let thread = thread::spawn(move || {
+        // s1 must be moved in or the test will hang!
+        let mut buf = [0; 5];
+        or_panic!(s1.read(&mut buf));
+        assert_eq!(&msg1[..], &buf[..]);
+        or_panic!(s1.write_all(msg2));
+    });
+
+    or_panic!(s2.write_all(msg1));
+    let mut buf = vec![];
+    or_panic!(s2.read_to_end(&mut buf));
+    assert_eq!(&msg2[..], &buf[..]);
+    drop(s2);
+
+    thread.join().unwrap();
+}
+
+#[test]
+fn try_clone() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+    let msg1 = b"hello";
+    let msg2 = b"world";
+
+    let listener = or_panic!(UnixListener::bind(&socket_path));
+    let thread = thread::spawn(move || {
+        let mut stream = or_panic!(listener.accept()).0;
+        or_panic!(stream.write_all(msg1));
+        or_panic!(stream.write_all(msg2));
+    });
+
+    let mut stream = or_panic!(UnixStream::connect(&socket_path));
+    let mut stream2 = or_panic!(stream.try_clone());
+
+    let mut buf = [0; 5];
+    or_panic!(stream.read(&mut buf));
+    assert_eq!(&msg1[..], &buf[..]);
+    or_panic!(stream2.read(&mut buf));
+    assert_eq!(&msg2[..], &buf[..]);
+
+    thread.join().unwrap();
+}
+
+#[test]
+fn iter() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+
+    let listener = or_panic!(UnixListener::bind(&socket_path));
+    let thread = thread::spawn(move || {
+        for stream in listener.incoming().take(2) {
+            let mut stream = or_panic!(stream);
+            let mut buf = [0];
+            or_panic!(stream.read(&mut buf));
+        }
+    });
+
+    for _ in 0..2 {
+        let mut stream = or_panic!(UnixStream::connect(&socket_path));
+        or_panic!(stream.write_all(&[0]));
+    }
+
+    thread.join().unwrap();
+}
+
+#[test]
+fn long_path() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join(
+        "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\
+                                sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf",
+    );
+    match UnixStream::connect(&socket_path) {
+        Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+        Err(e) => panic!("unexpected error {}", e),
+        Ok(_) => panic!("unexpected success"),
+    }
+
+    match UnixListener::bind(&socket_path) {
+        Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+        Err(e) => panic!("unexpected error {}", e),
+        Ok(_) => panic!("unexpected success"),
+    }
+
+    match UnixDatagram::bind(&socket_path) {
+        Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+        Err(e) => panic!("unexpected error {}", e),
+        Ok(_) => panic!("unexpected success"),
+    }
+}
+
+#[test]
+fn timeouts() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+
+    let _listener = or_panic!(UnixListener::bind(&socket_path));
+
+    let stream = or_panic!(UnixStream::connect(&socket_path));
+    let dur = Duration::new(15410, 0);
+
+    assert_eq!(None, or_panic!(stream.read_timeout()));
+
+    or_panic!(stream.set_read_timeout(Some(dur)));
+    assert_eq!(Some(dur), or_panic!(stream.read_timeout()));
+
+    assert_eq!(None, or_panic!(stream.write_timeout()));
+
+    or_panic!(stream.set_write_timeout(Some(dur)));
+    assert_eq!(Some(dur), or_panic!(stream.write_timeout()));
+
+    or_panic!(stream.set_read_timeout(None));
+    assert_eq!(None, or_panic!(stream.read_timeout()));
+
+    or_panic!(stream.set_write_timeout(None));
+    assert_eq!(None, or_panic!(stream.write_timeout()));
+}
+
+#[test]
+fn test_read_timeout() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+
+    let _listener = or_panic!(UnixListener::bind(&socket_path));
+
+    let mut stream = or_panic!(UnixStream::connect(&socket_path));
+    or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+    let mut buf = [0; 10];
+    let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+    assert!(
+        kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+        "unexpected_error: {:?}",
+        kind
+    );
+}
+
+#[test]
+fn test_read_with_timeout() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+
+    let listener = or_panic!(UnixListener::bind(&socket_path));
+
+    let mut stream = or_panic!(UnixStream::connect(&socket_path));
+    or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+    let mut other_end = or_panic!(listener.accept()).0;
+    or_panic!(other_end.write_all(b"hello world"));
+
+    let mut buf = [0; 11];
+    or_panic!(stream.read(&mut buf));
+    assert_eq!(b"hello world", &buf[..]);
+
+    let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+    assert!(
+        kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+        "unexpected_error: {:?}",
+        kind
+    );
+}
+
+// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+// when passed zero Durations
+#[test]
+fn test_unix_stream_timeout_zero_duration() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+
+    let listener = or_panic!(UnixListener::bind(&socket_path));
+    let stream = or_panic!(UnixStream::connect(&socket_path));
+
+    let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
+    let err = result.unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+    let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
+    let err = result.unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+    drop(listener);
+}
+
+#[test]
+fn test_unix_datagram() {
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock1");
+    let path2 = dir.path().join("sock2");
+
+    let sock1 = or_panic!(UnixDatagram::bind(&path1));
+    let sock2 = or_panic!(UnixDatagram::bind(&path2));
+
+    let msg = b"hello world";
+    or_panic!(sock1.send_to(msg, &path2));
+    let mut buf = [0; 11];
+    or_panic!(sock2.recv_from(&mut buf));
+    assert_eq!(msg, &buf[..]);
+}
+
+#[test]
+fn test_unnamed_unix_datagram() {
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock1");
+
+    let sock1 = or_panic!(UnixDatagram::bind(&path1));
+    let sock2 = or_panic!(UnixDatagram::unbound());
+
+    let msg = b"hello world";
+    or_panic!(sock2.send_to(msg, &path1));
+    let mut buf = [0; 11];
+    let (usize, addr) = or_panic!(sock1.recv_from(&mut buf));
+    assert_eq!(usize, 11);
+    assert!(addr.is_unnamed());
+    assert_eq!(msg, &buf[..]);
+}
+
+#[test]
+fn test_connect_unix_datagram() {
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock1");
+    let path2 = dir.path().join("sock2");
+
+    let bsock1 = or_panic!(UnixDatagram::bind(&path1));
+    let bsock2 = or_panic!(UnixDatagram::bind(&path2));
+    let sock = or_panic!(UnixDatagram::unbound());
+    or_panic!(sock.connect(&path1));
+
+    // Check send()
+    let msg = b"hello there";
+    or_panic!(sock.send(msg));
+    let mut buf = [0; 11];
+    let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf));
+    assert_eq!(usize, 11);
+    assert!(addr.is_unnamed());
+    assert_eq!(msg, &buf[..]);
+
+    // Changing default socket works too
+    or_panic!(sock.connect(&path2));
+    or_panic!(sock.send(msg));
+    or_panic!(bsock2.recv_from(&mut buf));
+}
+
+#[test]
+fn test_unix_datagram_recv() {
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock1");
+
+    let sock1 = or_panic!(UnixDatagram::bind(&path1));
+    let sock2 = or_panic!(UnixDatagram::unbound());
+    or_panic!(sock2.connect(&path1));
+
+    let msg = b"hello world";
+    or_panic!(sock2.send(msg));
+    let mut buf = [0; 11];
+    let size = or_panic!(sock1.recv(&mut buf));
+    assert_eq!(size, 11);
+    assert_eq!(msg, &buf[..]);
+}
+
+#[test]
+fn datagram_pair() {
+    let msg1 = b"hello";
+    let msg2 = b"world!";
+
+    let (s1, s2) = or_panic!(UnixDatagram::pair());
+    let thread = thread::spawn(move || {
+        // s1 must be moved in or the test will hang!
+        let mut buf = [0; 5];
+        or_panic!(s1.recv(&mut buf));
+        assert_eq!(&msg1[..], &buf[..]);
+        or_panic!(s1.send(msg2));
+    });
+
+    or_panic!(s2.send(msg1));
+    let mut buf = [0; 6];
+    or_panic!(s2.recv(&mut buf));
+    assert_eq!(&msg2[..], &buf[..]);
+    drop(s2);
+
+    thread.join().unwrap();
+}
+
+// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+// when passed zero Durations
+#[test]
+fn test_unix_datagram_timeout_zero_duration() {
+    let dir = tmpdir();
+    let path = dir.path().join("sock");
+
+    let datagram = or_panic!(UnixDatagram::bind(&path));
+
+    let result = datagram.set_write_timeout(Some(Duration::new(0, 0)));
+    let err = result.unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+    let result = datagram.set_read_timeout(Some(Duration::new(0, 0)));
+    let err = result.unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::InvalidInput);
+}
+
+#[test]
+fn abstract_namespace_not_allowed() {
+    assert!(UnixStream::connect("\0asdf").is_err());
+}
index ba169b251b0bc7ad768593f8fef355ce8e800d39..b2f15eda9d7b093ccc69c5028ecb51ccd2d893c1 100644 (file)
@@ -1,5 +1,8 @@
 #![unstable(reason = "not public", issue = "none", feature = "fd")]
 
+#[cfg(test)]
+mod tests;
+
 use crate::cmp;
 use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
 use crate::mem;
@@ -279,16 +282,3 @@ fn drop(&mut self) {
         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());
-    }
-}
diff --git a/library/std/src/sys/unix/fd/tests.rs b/library/std/src/sys/unix/fd/tests.rs
new file mode 100644 (file)
index 0000000..a932043
--- /dev/null
@@ -0,0 +1,9 @@
+use super::{FileDesc, IoSlice};
+use core::mem::ManuallyDrop;
+
+#[test]
+fn limit_vector_count() {
+    let stdout = ManuallyDrop::new(FileDesc { fd: 1 });
+    let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>();
+    assert!(stdout.write_vectored(&bufs).is_ok());
+}
index 2fcb5b9c4e66e722098efde38810b1ab60389582..4aa61fc5bf68768c33e289d8999182eef6d1ca52 100644 (file)
@@ -2,6 +2,9 @@
 
 #![allow(unused_imports)] // lots of cfg code here
 
+#[cfg(all(test, target_env = "gnu"))]
+mod tests;
+
 use crate::os::unix::prelude::*;
 
 use crate::error::Error as StdError;
@@ -645,30 +648,3 @@ fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
         _ => None,
     }
 }
-
-#[cfg(all(test, target_env = "gnu"))]
-mod test {
-    use super::*;
-
-    #[test]
-    fn test_glibc_version() {
-        // This mostly just tests that the weak linkage doesn't panic wildly...
-        glibc_version();
-    }
-
-    #[test]
-    fn test_parse_glibc_version() {
-        let cases = [
-            ("0.0", Some((0, 0))),
-            ("01.+2", Some((1, 2))),
-            ("3.4.5.six", Some((3, 4))),
-            ("1", None),
-            ("1.-2", None),
-            ("1.foo", None),
-            ("foo.1", None),
-        ];
-        for &(version_str, parsed) in cases.iter() {
-            assert_eq!(parsed, parse_glibc_version(version_str));
-        }
-    }
-}
diff --git a/library/std/src/sys/unix/os/tests.rs b/library/std/src/sys/unix/os/tests.rs
new file mode 100644 (file)
index 0000000..0e1dcb3
--- /dev/null
@@ -0,0 +1,23 @@
+use super::*;
+
+#[test]
+fn test_glibc_version() {
+    // This mostly just tests that the weak linkage doesn't panic wildly...
+    glibc_version();
+}
+
+#[test]
+fn test_parse_glibc_version() {
+    let cases = [
+        ("0.0", Some((0, 0))),
+        ("01.+2", Some((1, 2))),
+        ("3.4.5.six", Some((3, 4))),
+        ("1", None),
+        ("1.-2", None),
+        ("1.foo", None),
+        ("foo.1", None),
+    ];
+    for &(version_str, parsed) in cases.iter() {
+        assert_eq!(parsed, parse_glibc_version(version_str));
+    }
+}
index 6e33cdd3c48269432bbcebab6fa723865157710a..f8666485eeccb71fab09c44bae17fd1de9d79370 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
 use crate::os::unix::prelude::*;
 
 use crate::collections::BTreeMap;
@@ -399,71 +402,3 @@ pub fn as_i32(&self) -> i32 {
         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());
-        }
-    }
-}
diff --git a/library/std/src/sys/unix/process/process_common/tests.rs b/library/std/src/sys/unix/process/process_common/tests.rs
new file mode 100644 (file)
index 0000000..e72fbf0
--- /dev/null
@@ -0,0 +1,64 @@
+use super::*;
+
+use crate::ffi::OsStr;
+use crate::mem;
+use crate::ptr;
+use crate::sys::cvt;
+
+macro_rules! t {
+    ($e:expr) => {
+        match $e {
+            Ok(t) => t,
+            Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+        }
+    };
+}
+
+// See #14232 for more information, but it appears that signal delivery to a
+// newly spawned process may just be raced in the macOS, so to prevent this
+// test from being flaky we ignore it on macOS.
+#[test]
+#[cfg_attr(target_os = "macos", ignore)]
+// When run under our current QEMU emulation test suite this test fails,
+// although the reason isn't very clear as to why. For now this test is
+// ignored there.
+#[cfg_attr(target_arch = "arm", ignore)]
+#[cfg_attr(target_arch = "aarch64", ignore)]
+#[cfg_attr(target_arch = "riscv64", ignore)]
+fn test_process_mask() {
+    unsafe {
+        // Test to make sure that a signal mask does not get inherited.
+        let mut cmd = Command::new(OsStr::new("cat"));
+
+        let mut set = mem::MaybeUninit::<libc::sigset_t>::uninit();
+        let mut old_set = mem::MaybeUninit::<libc::sigset_t>::uninit();
+        t!(cvt(sigemptyset(set.as_mut_ptr())));
+        t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT)));
+        t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), old_set.as_mut_ptr())));
+
+        cmd.stdin(Stdio::MakePipe);
+        cmd.stdout(Stdio::MakePipe);
+
+        let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
+        let stdin_write = pipes.stdin.take().unwrap();
+        let stdout_read = pipes.stdout.take().unwrap();
+
+        t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut())));
+
+        t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
+        // We need to wait until SIGINT is definitely delivered. The
+        // easiest way is to write something to cat, and try to read it
+        // back: if SIGINT is unmasked, it'll get delivered when cat is
+        // next scheduled.
+        let _ = stdin_write.write(b"Hello");
+        drop(stdin_write);
+
+        // Either EOF or failure (EPIPE) is okay.
+        let mut buf = [0; 5];
+        if let Ok(ret) = stdout_read.read(&mut buf) {
+            assert_eq!(ret, 0);
+        }
+
+        t!(cat.wait());
+    }
+}
index 32c27ab6e9e8d4cb2247befc969929dcc4d44d95..7613fbec46f397c454bab142949fdc58159486c8 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(all(test, taget_env = "gnu"))]
+mod tests;
+
 use crate::cmp;
 use crate::ffi::CStr;
 use crate::io;
@@ -330,30 +333,3 @@ fn on_resolver_failure() {
 
 #[cfg(not(target_env = "gnu"))]
 fn on_resolver_failure() {}
-
-#[cfg(all(test, taget_env = "gnu"))]
-mod test {
-    use super::*;
-
-    #[test]
-    fn test_res_init() {
-        // This mostly just tests that the weak linkage doesn't panic wildly...
-        res_init_if_glibc_before_2_26().unwrap();
-    }
-
-    #[test]
-    fn test_parse_glibc_version() {
-        let cases = [
-            ("0.0", Some((0, 0))),
-            ("01.+2", Some((1, 2))),
-            ("3.4.5.six", Some((3, 4))),
-            ("1", None),
-            ("1.-2", None),
-            ("1.foo", None),
-            ("foo.1", None),
-        ];
-        for &(version_str, parsed) in cases.iter() {
-            assert_eq!(parsed, parse_glibc_version(version_str));
-        }
-    }
-}
diff --git a/library/std/src/sys/vxworks/net/tests.rs b/library/std/src/sys/vxworks/net/tests.rs
new file mode 100644 (file)
index 0000000..e7c6e34
--- /dev/null
@@ -0,0 +1,23 @@
+use super::*;
+
+#[test]
+fn test_res_init() {
+    // This mostly just tests that the weak linkage doesn't panic wildly...
+    res_init_if_glibc_before_2_26().unwrap();
+}
+
+#[test]
+fn test_parse_glibc_version() {
+    let cases = [
+        ("0.0", Some((0, 0))),
+        ("01.+2", Some((1, 2))),
+        ("3.4.5.six", Some((3, 4))),
+        ("1", None),
+        ("1.-2", None),
+        ("1.foo", None),
+        ("foo.1", None),
+    ];
+    for &(version_str, parsed) in cases.iter() {
+        assert_eq!(parsed, parse_glibc_version(version_str));
+    }
+}
index 5fbea2a2910174c32c8ab9aacb71a00abb8b4712..bcc2ea9ae00f02f5cffb7515f07133a4a902d192 100644 (file)
@@ -1,5 +1,8 @@
 #![allow(dead_code)] // runtime init functions not used during testing
 
+#[cfg(test)]
+mod tests;
+
 use crate::ffi::OsString;
 use crate::fmt;
 use crate::os::windows::prelude::*;
@@ -198,69 +201,3 @@ fn len(&self) -> usize {
         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"]);
-    }
-}
diff --git a/library/std/src/sys/windows/args/tests.rs b/library/std/src/sys/windows/args/tests.rs
new file mode 100644 (file)
index 0000000..756a436
--- /dev/null
@@ -0,0 +1,61 @@
+use crate::ffi::OsString;
+use crate::sys::windows::args::*;
+
+fn chk(string: &str, parts: &[&str]) {
+    let mut wide: Vec<u16> = OsString::from(string).encode_wide().collect();
+    wide.push(0);
+    let parsed =
+        unsafe { parse_lp_cmd_line(wide.as_ptr() as *const u16, || OsString::from("TEST.EXE")) };
+    let expected: Vec<OsString> = parts.iter().map(|k| OsString::from(k)).collect();
+    assert_eq!(parsed.as_slice(), expected.as_slice());
+}
+
+#[test]
+fn empty() {
+    chk("", &["TEST.EXE"]);
+    chk("\0", &["TEST.EXE"]);
+}
+
+#[test]
+fn single_words() {
+    chk("EXE one_word", &["EXE", "one_word"]);
+    chk("EXE a", &["EXE", "a"]);
+    chk("EXE 😅", &["EXE", "😅"]);
+    chk("EXE 😅🤦", &["EXE", "😅🤦"]);
+}
+
+#[test]
+fn official_examples() {
+    chk(r#"EXE "abc" d e"#, &["EXE", "abc", "d", "e"]);
+    chk(r#"EXE a\\\b d"e f"g h"#, &["EXE", r#"a\\\b"#, "de fg", "h"]);
+    chk(r#"EXE a\\\"b c d"#, &["EXE", r#"a\"b"#, "c", "d"]);
+    chk(r#"EXE a\\\\"b c" d e"#, &["EXE", r#"a\\b c"#, "d", "e"]);
+}
+
+#[test]
+fn whitespace_behavior() {
+    chk(r#" test"#, &["", "test"]);
+    chk(r#"  test"#, &["", "test"]);
+    chk(r#" test test2"#, &["", "test", "test2"]);
+    chk(r#" test  test2"#, &["", "test", "test2"]);
+    chk(r#"test test2 "#, &["test", "test2"]);
+    chk(r#"test  test2 "#, &["test", "test2"]);
+    chk(r#"test "#, &["test"]);
+}
+
+#[test]
+fn genius_quotes() {
+    chk(r#"EXE "" """#, &["EXE", "", ""]);
+    chk(r#"EXE "" """"#, &["EXE", "", "\""]);
+    chk(
+        r#"EXE "this is """all""" in the same argument""#,
+        &["EXE", "this is \"all\" in the same argument"],
+    );
+    chk(r#"EXE "a"""#, &["EXE", "a\""]);
+    chk(r#"EXE "a"" a"#, &["EXE", "a\"", "a"]);
+    // quotes cannot be escaped in command names
+    chk(r#""EXE" check"#, &["EXE", "check"]);
+    chk(r#""EXE check""#, &["EXE check"]);
+    chk(r#""EXE """for""" check"#, &["EXE ", r#"for""#, "check"]);
+    chk(r#""EXE \"for\" check"#, &[r#"EXE \"#, r#"for""#, "check"]);
+}
index a0da2498bb7e0fec156dd7cb11251f4ed98ffb1c..77c378a66afd78724215dace7d45702a845fbf65 100644 (file)
@@ -2,6 +2,9 @@
 
 #![allow(nonstandard_style)]
 
+#[cfg(test)]
+mod tests;
+
 use crate::os::windows::prelude::*;
 
 use crate::error::Error as StdError;
@@ -328,20 +331,3 @@ pub fn exit(code: i32) -> ! {
 pub fn getpid() -> u32 {
     unsafe { c::GetCurrentProcessId() as u32 }
 }
-
-#[cfg(test)]
-mod tests {
-    use crate::io::Error;
-    use crate::sys::c;
-
-    // tests `error_string` above
-    #[test]
-    fn ntstatus_error() {
-        const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001;
-        assert!(
-            !Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _)
-                .to_string()
-                .contains("FormatMessageW() returned error")
-        );
-    }
-}
diff --git a/library/std/src/sys/windows/os/tests.rs b/library/std/src/sys/windows/os/tests.rs
new file mode 100644 (file)
index 0000000..458d6e1
--- /dev/null
@@ -0,0 +1,13 @@
+use crate::io::Error;
+use crate::sys::c;
+
+// tests `error_string` above
+#[test]
+fn ntstatus_error() {
+    const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001;
+    assert!(
+        !Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _)
+            .to_string()
+            .contains("FormatMessageW() returned error")
+    );
+}
index 7d6d4775eec8a87b588d94c2603f90ab4bb87915..e18521bb30d91fd29cc7809082457a069805fd4c 100644 (file)
@@ -1,5 +1,8 @@
 #![unstable(feature = "process_internals", issue = "none")]
 
+#[cfg(test)]
+mod tests;
+
 use crate::borrow::Borrow;
 use crate::collections::BTreeMap;
 use crate::env;
@@ -526,41 +529,3 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
         None => Ok((ptr::null(), Vec::new())),
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::make_command_line;
-    use crate::ffi::{OsStr, OsString};
-
-    #[test]
-    fn test_make_command_line() {
-        fn test_wrapper(prog: &str, args: &[&str]) -> String {
-            let command_line = &make_command_line(
-                OsStr::new(prog),
-                &args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(),
-            )
-            .unwrap();
-            String::from_utf16(command_line).unwrap()
-        }
-
-        assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"]), "\"prog\" aaa bbb ccc");
-
-        assert_eq!(
-            test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]),
-            "\"C:\\Program Files\\blah\\blah.exe\" aaa"
-        );
-        assert_eq!(
-            test_wrapper("C:\\Program Files\\test", &["aa\"bb"]),
-            "\"C:\\Program Files\\test\" aa\\\"bb"
-        );
-        assert_eq!(test_wrapper("echo", &["a b c"]), "\"echo\" \"a b c\"");
-        assert_eq!(
-            test_wrapper("echo", &["\" \\\" \\", "\\"]),
-            "\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
-        );
-        assert_eq!(
-            test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
-            "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
-        );
-    }
-}
diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs
new file mode 100644 (file)
index 0000000..81627ad
--- /dev/null
@@ -0,0 +1,31 @@
+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}\""
+    );
+}
index dccc3bc4a19a85f61112a759a45faabc9e83037e..97fba60c27109e3773cccf77c7ef9708be5cc084 100644 (file)
@@ -1,5 +1,8 @@
 #![allow(dead_code)]
 
+#[cfg(test)]
+mod tests;
+
 use crate::fmt::{Formatter, Result, Write};
 use core::str::lossy::{Utf8Lossy, Utf8LossyChunk};
 
@@ -21,26 +24,3 @@ fn write_str_escaped(f: &mut Formatter<'_>, s: &str) -> Result {
     }
     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);
-    }
-}
diff --git a/library/std/src/sys_common/bytestring/tests.rs b/library/std/src/sys_common/bytestring/tests.rs
new file mode 100644 (file)
index 0000000..1685f08
--- /dev/null
@@ -0,0 +1,19 @@
+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);
+}
index 840f9093e00f15dd2ece0c6f81526db752e82ec1..28cdfefb12a08b76742746c3582e89efe56edd2d 100644 (file)
@@ -15,6 +15,9 @@
 #![allow(missing_docs)]
 #![allow(missing_debug_implementations)]
 
+#[cfg(test)]
+mod tests;
+
 use crate::sync::Once;
 use crate::sys;
 
@@ -141,8 +144,3 @@ pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 {
     // 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);
-}
index 0bb136078bc95c6539c449adb9bf6ae5be233691..48ba4ddfc0b2c8e64ec731af7ec0aafe5ab38792 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(test)]
+mod tests;
+
 use crate::cmp;
 use crate::convert::{TryFrom, TryInto};
 use crate::ffi::CString;
@@ -672,26 +675,3 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         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"
-        );
-    }
-}
diff --git a/library/std/src/sys_common/net/tests.rs b/library/std/src/sys_common/net/tests.rs
new file mode 100644 (file)
index 0000000..7d45621
--- /dev/null
@@ -0,0 +1,19 @@
+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"
+    );
+}
index 4f19bbc467f33d19b47d70a7fc320562d58506f5..360337c030be487728a6386aaa04773cd57feb1b 100644 (file)
@@ -1,3 +1,6 @@
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
 use crate::fmt;
 use crate::marker;
 use crate::ops::Deref;
@@ -146,79 +149,3 @@ fn drop(&mut self) {
         }
     }
 }
-
-#[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;
-        }
-    }
-}
diff --git a/library/std/src/sys_common/remutex/tests.rs b/library/std/src/sys_common/remutex/tests.rs
new file mode 100644 (file)
index 0000000..9c686e5
--- /dev/null
@@ -0,0 +1,72 @@
+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;
+    }
+}
diff --git a/library/std/src/sys_common/tests.rs b/library/std/src/sys_common/tests.rs
new file mode 100644 (file)
index 0000000..1b6446d
--- /dev/null
@@ -0,0 +1,6 @@
+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);
+}
index ac5b128298d7856419aed0eb3cb3d626e62863a3..3a2218854a7300c71e802a1db195170f2da81524 100644 (file)
@@ -48,6 +48,9 @@
 #![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;
@@ -231,41 +234,3 @@ fn drop(&mut self) {
         // 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);
-        }
-    }
-}
diff --git a/library/std/src/sys_common/thread_local_key/tests.rs b/library/std/src/sys_common/thread_local_key/tests.rs
new file mode 100644 (file)
index 0000000..968738a
--- /dev/null
@@ -0,0 +1,34 @@
+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);
+    }
+}
index bdb6a05464ed472b20b5b637963030271fe1bac1..7d4b0d5283199012a23425cd3afd50d7591e0ba7 100644 (file)
@@ -15,6 +15,9 @@
 // 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;
@@ -879,407 +882,3 @@ fn hash<H: Hasher>(&self, state: &mut H) {
         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]
-        );
-    }
-}
diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs
new file mode 100644 (file)
index 0000000..385e01f
--- /dev/null
@@ -0,0 +1,397 @@
+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]
+    );
+}
index a4562967f0bcb904ed738f8e8855bfe55acccabd..9d8c6f1815eeb38963decadd4bbb98d13a23a821 100644 (file)
@@ -2,6 +2,12 @@
 
 #![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;
 
@@ -547,203 +553,3 @@ unsafe fn try_initialize(&'static self, init: fn() -> T) -> Option<&'static T> {
         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);
-        });
-    }
-}
diff --git a/library/std/src/thread/local/dynamic_tests.rs b/library/std/src/thread/local/dynamic_tests.rs
new file mode 100644 (file)
index 0000000..dd18004
--- /dev/null
@@ -0,0 +1,40 @@
+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);
+    });
+}
diff --git a/library/std/src/thread/local/tests.rs b/library/std/src/thread/local/tests.rs
new file mode 100644 (file)
index 0000000..4fb0a08
--- /dev/null
@@ -0,0 +1,154 @@
+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();
+}
index 0b9849517c2526bbfb1a9a4fd5881eac7682cf6a..6d6be8560aa3647589d032fb8825cf1eaee2824d 100644 (file)
 
 #![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};
@@ -1470,273 +1473,3 @@ fn _assert_both<T: Send + Sync>() {}
     _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.
-}
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
new file mode 100644 (file)
index 0000000..16ad366
--- /dev/null
@@ -0,0 +1,262 @@
+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.
index c8aee1da39b394dffa7d6ba7e233ea93f4cac5b5..73c0a7b403a7bed8382bbd9d693efa1bb259b297 100644 (file)
@@ -12,6 +12,9 @@
 
 #![stable(feature = "time", since = "1.3.0")]
 
+#[cfg(test)]
+mod tests;
+
 use crate::cmp;
 use crate::error::Error;
 use crate::fmt;
@@ -630,172 +633,3 @@ fn from_inner(time: time::SystemTime) -> SystemTime {
         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);
-    }
-}
diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs
new file mode 100644 (file)
index 0000000..783bf49
--- /dev/null
@@ -0,0 +1,165 @@
+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);
+}