diff options
| author | Jacob Pratt <jacob@jhpratt.dev> | 2025-02-04 05:36:50 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-04 05:36:50 -0500 |
| commit | d2aa3dec8ab901a684ab2347a030f346fec52fb2 (patch) | |
| tree | c79e159465fa77caeca338bd3a103a7fc898603b /library/std/src | |
| parent | 2a8a1911da03907542c317a85a8bdbbc3692640e (diff) | |
| parent | cc7e3a6228e3016c069b7f62ed40004ede6fafb8 (diff) | |
| download | rust-d2aa3dec8ab901a684ab2347a030f346fec52fb2.tar.gz rust-d2aa3dec8ab901a684ab2347a030f346fec52fb2.zip | |
Rollup merge of #135621 - bjorn3:move_tests_to_stdtests, r=Noratrieb
Move some std tests to integration tests Unit tests directly inside of standard library crates require a very fragile way of building that is hard to reproduce outside of bootstrap. Follow up to https://github.com/rust-lang/rust/pull/133859
Diffstat (limited to 'library/std/src')
44 files changed, 8 insertions, 11586 deletions
diff --git a/library/std/src/env.rs b/library/std/src/env.rs index bbd506127fb..c665dfd3624 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -10,9 +10,6 @@ #![stable(feature = "env", since = "1.0.0")] -#[cfg(test)] -mod tests; - use crate::error::Error; use crate::ffi::{OsStr, OsString}; use crate::path::{Path, PathBuf}; diff --git a/library/std/src/env/tests.rs b/library/std/src/env/tests.rs deleted file mode 100644 index d0217261068..00000000000 --- a/library/std/src/env/tests.rs +++ /dev/null @@ -1,120 +0,0 @@ -use super::*; - -#[test] -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi", 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()) - ); -} - -#[test] -fn args_os_debug() { - assert_eq!( - format!("ArgsOs {{ inner: {:?} }}", args_os().collect::<Vec<_>>()), - format!("{:?}", args_os()) - ); -} - -#[test] -fn vars_debug() { - assert_eq!( - format!("Vars {{ inner: {:?} }}", vars().collect::<Vec<_>>()), - format!("{:?}", vars()) - ); -} - -#[test] -fn vars_os_debug() { - assert_eq!( - format!("VarsOs {{ inner: {:?} }}", vars_os().collect::<Vec<_>>()), - format!("{:?}", vars_os()) - ); -} diff --git a/library/std/src/error.rs b/library/std/src/error.rs index b3e63aaf1c5..def5f984c88 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -1,9 +1,6 @@ #![doc = include_str!("../../core/src/error.md")] #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(test)] -mod tests; - #[stable(feature = "rust1", since = "1.0.0")] pub use core::error::Error; #[unstable(feature = "error_generic_member_access", issue = "99301")] diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs deleted file mode 100644 index 88a9f33c079..00000000000 --- a/library/std/src/error/tests.rs +++ /dev/null @@ -1,444 +0,0 @@ -use core::error::Request; - -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), - } -} - -use crate::backtrace::Backtrace; -use crate::error::Report; - -#[derive(Debug)] -struct SuperError { - source: SuperErrorSideKick, -} - -impl fmt::Display for SuperError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "SuperError is here!") - } -} - -impl Error for SuperError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - Some(&self.source) - } -} - -#[derive(Debug)] -struct SuperErrorSideKick; - -impl fmt::Display for SuperErrorSideKick { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "SuperErrorSideKick is here!") - } -} - -impl Error for SuperErrorSideKick {} - -#[test] -fn single_line_formatting() { - let error = SuperError { source: SuperErrorSideKick }; - let report = Report::new(&error); - let actual = report.to_string(); - let expected = String::from("SuperError is here!: SuperErrorSideKick is here!"); - - assert_eq!(expected, actual); -} - -#[test] -fn multi_line_formatting() { - let error = SuperError { source: SuperErrorSideKick }; - let report = Report::new(&error).pretty(true); - let actual = report.to_string(); - let expected = String::from( - "\ -SuperError is here! - -Caused by: - SuperErrorSideKick is here!", - ); - - assert_eq!(expected, actual); -} - -#[test] -fn error_with_no_sources_formats_single_line_correctly() { - let report = Report::new(SuperErrorSideKick); - let actual = report.to_string(); - let expected = String::from("SuperErrorSideKick is here!"); - - assert_eq!(expected, actual); -} - -#[test] -fn error_with_no_sources_formats_multi_line_correctly() { - let report = Report::new(SuperErrorSideKick).pretty(true); - let actual = report.to_string(); - let expected = String::from("SuperErrorSideKick is here!"); - - assert_eq!(expected, actual); -} - -#[test] -fn error_with_backtrace_outputs_correctly_with_one_source() { - let trace = Backtrace::force_capture(); - let expected = format!( - "\ -The source of the error - -Caused by: - Error with backtrace - -Stack backtrace: -{}", - trace - ); - let error = GenericError::new("Error with backtrace"); - let mut error = GenericError::new_with_source("The source of the error", error); - error.backtrace = Some(trace); - let report = Report::new(error).pretty(true).show_backtrace(true); - - println!("Error: {report}"); - assert_eq!(expected.trim_end(), report.to_string()); -} - -#[test] -fn error_with_backtrace_outputs_correctly_with_two_sources() { - let trace = Backtrace::force_capture(); - let expected = format!( - "\ -Error with two sources - -Caused by: - 0: The source of the error - 1: Error with backtrace - -Stack backtrace: -{}", - trace - ); - let mut error = GenericError::new("Error with backtrace"); - error.backtrace = Some(trace); - let error = GenericError::new_with_source("The source of the error", error); - let error = GenericError::new_with_source("Error with two sources", error); - let report = Report::new(error).pretty(true).show_backtrace(true); - - println!("Error: {report}"); - assert_eq!(expected.trim_end(), report.to_string()); -} - -#[derive(Debug)] -struct GenericError<D> { - message: D, - backtrace: Option<Backtrace>, - source: Option<Box<dyn Error + 'static>>, -} - -impl<D> GenericError<D> { - fn new(message: D) -> GenericError<D> { - Self { message, backtrace: None, source: None } - } - - fn new_with_source<E>(message: D, source: E) -> GenericError<D> - where - E: Error + 'static, - { - let source: Box<dyn Error + 'static> = Box::new(source); - let source = Some(source); - GenericError { message, backtrace: None, source } - } -} - -impl<D> fmt::Display for GenericError<D> -where - D: fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.message, f) - } -} - -impl<D> Error for GenericError<D> -where - D: fmt::Debug + fmt::Display, -{ - fn source(&self) -> Option<&(dyn Error + 'static)> { - self.source.as_deref() - } - - fn provide<'a>(&'a self, req: &mut Request<'a>) { - self.backtrace.as_ref().map(|bt| req.provide_ref::<Backtrace>(bt)); - } -} - -#[test] -fn error_formats_single_line_with_rude_display_impl() { - #[derive(Debug)] - struct MyMessage; - - impl fmt::Display for MyMessage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("line 1\nline 2")?; - f.write_str("\nline 3\nline 4\n")?; - f.write_str("line 5\nline 6")?; - Ok(()) - } - } - - let error = GenericError::new(MyMessage); - let error = GenericError::new_with_source(MyMessage, error); - let error = GenericError::new_with_source(MyMessage, error); - let error = GenericError::new_with_source(MyMessage, error); - let report = Report::new(error); - let expected = "\ -line 1 -line 2 -line 3 -line 4 -line 5 -line 6: line 1 -line 2 -line 3 -line 4 -line 5 -line 6: line 1 -line 2 -line 3 -line 4 -line 5 -line 6: line 1 -line 2 -line 3 -line 4 -line 5 -line 6"; - - let actual = report.to_string(); - assert_eq!(expected, actual); -} - -#[test] -fn error_formats_multi_line_with_rude_display_impl() { - #[derive(Debug)] - struct MyMessage; - - impl fmt::Display for MyMessage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("line 1\nline 2")?; - f.write_str("\nline 3\nline 4\n")?; - f.write_str("line 5\nline 6")?; - Ok(()) - } - } - - let error = GenericError::new(MyMessage); - let error = GenericError::new_with_source(MyMessage, error); - let error = GenericError::new_with_source(MyMessage, error); - let error = GenericError::new_with_source(MyMessage, error); - let report = Report::new(error).pretty(true); - let expected = "line 1 -line 2 -line 3 -line 4 -line 5 -line 6 - -Caused by: - 0: line 1 - line 2 - line 3 - line 4 - line 5 - line 6 - 1: line 1 - line 2 - line 3 - line 4 - line 5 - line 6 - 2: line 1 - line 2 - line 3 - line 4 - line 5 - line 6"; - - let actual = report.to_string(); - assert_eq!(expected, actual); -} - -#[test] -fn errors_that_start_with_newline_formats_correctly() { - #[derive(Debug)] - struct MyMessage; - - impl fmt::Display for MyMessage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("\nThe message\n") - } - } - - let error = GenericError::new(MyMessage); - let error = GenericError::new_with_source(MyMessage, error); - let error = GenericError::new_with_source(MyMessage, error); - let report = Report::new(error).pretty(true); - let expected = " -The message - - -Caused by: - 0: \ -\n The message - \ -\n 1: \ -\n The message - "; - - let actual = report.to_string(); - assert_eq!(expected, actual); -} - -#[test] -fn errors_with_multiple_writes_on_same_line_dont_insert_erroneous_newlines() { - #[derive(Debug)] - struct MyMessage; - - impl fmt::Display for MyMessage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("The message")?; - f.write_str(" goes on")?; - f.write_str(" and on.") - } - } - - let error = GenericError::new(MyMessage); - let error = GenericError::new_with_source(MyMessage, error); - let error = GenericError::new_with_source(MyMessage, error); - let report = Report::new(error).pretty(true); - let expected = "\ -The message goes on and on. - -Caused by: - 0: The message goes on and on. - 1: The message goes on and on."; - - let actual = report.to_string(); - println!("{actual}"); - assert_eq!(expected, actual); -} - -#[test] -fn errors_with_string_interpolation_formats_correctly() { - #[derive(Debug)] - struct MyMessage(usize); - - impl fmt::Display for MyMessage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Got an error code: ({}). ", self.0)?; - write!(f, "What would you like to do in response?") - } - } - - let error = GenericError::new(MyMessage(10)); - let error = GenericError::new_with_source(MyMessage(20), error); - let report = Report::new(error).pretty(true); - let expected = "\ -Got an error code: (20). What would you like to do in response? - -Caused by: - Got an error code: (10). What would you like to do in response?"; - let actual = report.to_string(); - assert_eq!(expected, actual); -} - -#[test] -fn empty_lines_mid_message() { - #[derive(Debug)] - struct MyMessage; - - impl fmt::Display for MyMessage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("line 1\n\nline 2") - } - } - - let error = GenericError::new(MyMessage); - let error = GenericError::new_with_source(MyMessage, error); - let error = GenericError::new_with_source(MyMessage, error); - let report = Report::new(error).pretty(true); - let expected = "\ -line 1 - -line 2 - -Caused by: - 0: line 1 - \ -\n line 2 - 1: line 1 - \ -\n line 2"; - - let actual = report.to_string(); - assert_eq!(expected, actual); -} - -#[test] -fn only_one_source() { - #[derive(Debug)] - struct MyMessage; - - impl fmt::Display for MyMessage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("line 1\nline 2") - } - } - - let error = GenericError::new(MyMessage); - let error = GenericError::new_with_source(MyMessage, error); - let report = Report::new(error).pretty(true); - let expected = "\ -line 1 -line 2 - -Caused by: - line 1 - line 2"; - - let actual = report.to_string(); - assert_eq!(expected, actual); -} diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs index d65f5ed61cf..89612fa7475 100644 --- a/library/std/src/f128.rs +++ b/library/std/src/f128.rs @@ -4,9 +4,6 @@ //! //! Mathematically significant numbers are provided in the `consts` sub-module. -#[cfg(test)] -mod tests; - #[unstable(feature = "f128", issue = "116909")] pub use core::f128::consts; diff --git a/library/std/src/f128/tests.rs b/library/std/src/f128/tests.rs deleted file mode 100644 index cbcf9f96239..00000000000 --- a/library/std/src/f128/tests.rs +++ /dev/null @@ -1,987 +0,0 @@ -// FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy -#![cfg(reliable_f128)] - -use crate::f128::consts; -use crate::num::FpCategory as Fp; -#[cfg(reliable_f128_math)] -use crate::ops::Rem; -use crate::ops::{Add, Div, Mul, Sub}; - -// Note these tolerances make sense around zero, but not for more extreme exponents. - -/// For operations that are near exact, usually not involving math of different -/// signs. -const TOL_PRECISE: f128 = 1e-28; - -/// Default tolerances. Works for values that should be near precise but not exact. Roughly -/// the precision carried by `100 * 100`. -const TOL: f128 = 1e-12; - -/// Tolerances for math that is allowed to be imprecise, usually due to multiple chained -/// operations. -#[cfg(reliable_f128_math)] -const TOL_IMPR: f128 = 1e-10; - -/// Smallest number -const TINY_BITS: u128 = 0x1; - -/// Next smallest number -const TINY_UP_BITS: u128 = 0x2; - -/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 -const MAX_DOWN_BITS: u128 = 0x7ffefffffffffffffffffffffffffffe; - -/// Zeroed exponent, full significant -const LARGEST_SUBNORMAL_BITS: u128 = 0x0000ffffffffffffffffffffffffffff; - -/// Exponent = 0b1, zeroed significand -const SMALLEST_NORMAL_BITS: u128 = 0x00010000000000000000000000000000; - -/// First pattern over the mantissa -const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa; - -/// Second pattern over the mantissa -const NAN_MASK2: u128 = 0x00005555555555555555555555555555; - -/// Compare by representation -#[allow(unused_macros)] -macro_rules! assert_f128_biteq { - ($a:expr, $b:expr) => { - let (l, r): (&f128, &f128) = (&$a, &$b); - let lb = l.to_bits(); - let rb = r.to_bits(); - assert_eq!(lb, rb, "float {l:?} is not bitequal to {r:?}.\na: {lb:#034x}\nb: {rb:#034x}"); - }; -} - -#[test] -fn test_num_f128() { - // FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128` - // function is available on all platforms. - let ten = 10f128; - let two = 2f128; - assert_eq!(ten.add(two), ten + two); - assert_eq!(ten.sub(two), ten - two); - assert_eq!(ten.mul(two), ten * two); - assert_eq!(ten.div(two), ten / two); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_num_f128_rem() { - let ten = 10f128; - let two = 2f128; - assert_eq!(ten.rem(two), ten % two); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_min_nan() { - assert_eq!(f128::NAN.min(2.0), 2.0); - assert_eq!(2.0f128.min(f128::NAN), 2.0); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_max_nan() { - assert_eq!(f128::NAN.max(2.0), 2.0); - assert_eq!(2.0f128.max(f128::NAN), 2.0); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_minimum() { - assert!(f128::NAN.minimum(2.0).is_nan()); - assert!(2.0f128.minimum(f128::NAN).is_nan()); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_maximum() { - assert!(f128::NAN.maximum(2.0).is_nan()); - assert!(2.0f128.maximum(f128::NAN).is_nan()); -} - -#[test] -fn test_nan() { - let nan: f128 = f128::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert!(!nan.is_normal()); - assert_eq!(Fp::Nan, nan.classify()); -} - -#[test] -fn test_infinity() { - let inf: f128 = f128::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: f128 = f128::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: f128 = 0.0f128; - 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: f128 = -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: f128 = 1.0f128; - 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: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f128.is_nan()); - assert!(!5.3f128.is_nan()); - assert!(!(-10.732f128).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f128.is_infinite()); - assert!(!42.8f128.is_infinite()); - assert!(!(-109.2f128).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f128.is_finite()); - assert!(42.8f128.is_finite()); - assert!((-109.2f128).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -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!(1f128.is_normal()); - assert!(1e-4931f128.is_normal()); - assert!(!1e-4932f128.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -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!(1f128.classify(), Fp::Normal); - assert_eq!(1e-4931f128.classify(), Fp::Normal); - assert_eq!(1e-4932f128.classify(), Fp::Subnormal); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_floor() { - assert_approx_eq!(1.0f128.floor(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.3f128.floor(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.5f128.floor(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.7f128.floor(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(0.0f128.floor(), 0.0f128, TOL_PRECISE); - assert_approx_eq!((-0.0f128).floor(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.0f128).floor(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.3f128).floor(), -2.0f128, TOL_PRECISE); - assert_approx_eq!((-1.5f128).floor(), -2.0f128, TOL_PRECISE); - assert_approx_eq!((-1.7f128).floor(), -2.0f128, TOL_PRECISE); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_ceil() { - assert_approx_eq!(1.0f128.ceil(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.3f128.ceil(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(1.5f128.ceil(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(1.7f128.ceil(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(0.0f128.ceil(), 0.0f128, TOL_PRECISE); - assert_approx_eq!((-0.0f128).ceil(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.0f128).ceil(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.3f128).ceil(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.5f128).ceil(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.7f128).ceil(), -1.0f128, TOL_PRECISE); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_round() { - assert_approx_eq!(2.5f128.round(), 3.0f128, TOL_PRECISE); - assert_approx_eq!(1.0f128.round(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.3f128.round(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.5f128.round(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(1.7f128.round(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(0.0f128.round(), 0.0f128, TOL_PRECISE); - assert_approx_eq!((-0.0f128).round(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.0f128).round(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.3f128).round(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.5f128).round(), -2.0f128, TOL_PRECISE); - assert_approx_eq!((-1.7f128).round(), -2.0f128, TOL_PRECISE); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_round_ties_even() { - assert_approx_eq!(2.5f128.round_ties_even(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(1.0f128.round_ties_even(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.3f128.round_ties_even(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.5f128.round_ties_even(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(1.7f128.round_ties_even(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(0.0f128.round_ties_even(), 0.0f128, TOL_PRECISE); - assert_approx_eq!((-0.0f128).round_ties_even(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.0f128).round_ties_even(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.3f128).round_ties_even(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.5f128).round_ties_even(), -2.0f128, TOL_PRECISE); - assert_approx_eq!((-1.7f128).round_ties_even(), -2.0f128, TOL_PRECISE); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_trunc() { - assert_approx_eq!(1.0f128.trunc(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.3f128.trunc(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.5f128.trunc(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.7f128.trunc(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(0.0f128.trunc(), 0.0f128, TOL_PRECISE); - assert_approx_eq!((-0.0f128).trunc(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.0f128).trunc(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.3f128).trunc(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.5f128).trunc(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.7f128).trunc(), -1.0f128, TOL_PRECISE); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_fract() { - assert_approx_eq!(1.0f128.fract(), 0.0f128, TOL_PRECISE); - assert_approx_eq!(1.3f128.fract(), 0.3f128, TOL_PRECISE); - assert_approx_eq!(1.5f128.fract(), 0.5f128, TOL_PRECISE); - assert_approx_eq!(1.7f128.fract(), 0.7f128, TOL_PRECISE); - assert_approx_eq!(0.0f128.fract(), 0.0f128, TOL_PRECISE); - assert_approx_eq!((-0.0f128).fract(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.0f128).fract(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.3f128).fract(), -0.3f128, TOL_PRECISE); - assert_approx_eq!((-1.5f128).fract(), -0.5f128, TOL_PRECISE); - assert_approx_eq!((-1.7f128).fract(), -0.7f128, TOL_PRECISE); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_abs() { - assert_eq!(f128::INFINITY.abs(), f128::INFINITY); - assert_eq!(1f128.abs(), 1f128); - assert_eq!(0f128.abs(), 0f128); - assert_eq!((-0f128).abs(), 0f128); - assert_eq!((-1f128).abs(), 1f128); - assert_eq!(f128::NEG_INFINITY.abs(), f128::INFINITY); - assert_eq!((1f128 / f128::NEG_INFINITY).abs(), 0f128); - assert!(f128::NAN.abs().is_nan()); -} - -#[test] -fn test_is_sign_positive() { - assert!(f128::INFINITY.is_sign_positive()); - assert!(1f128.is_sign_positive()); - assert!(0f128.is_sign_positive()); - assert!(!(-0f128).is_sign_positive()); - assert!(!(-1f128).is_sign_positive()); - assert!(!f128::NEG_INFINITY.is_sign_positive()); - assert!(!(1f128 / f128::NEG_INFINITY).is_sign_positive()); - assert!(f128::NAN.is_sign_positive()); - assert!(!(-f128::NAN).is_sign_positive()); -} - -#[test] -fn test_is_sign_negative() { - assert!(!f128::INFINITY.is_sign_negative()); - assert!(!1f128.is_sign_negative()); - assert!(!0f128.is_sign_negative()); - assert!((-0f128).is_sign_negative()); - assert!((-1f128).is_sign_negative()); - assert!(f128::NEG_INFINITY.is_sign_negative()); - assert!((1f128 / f128::NEG_INFINITY).is_sign_negative()); - assert!(!f128::NAN.is_sign_negative()); - assert!((-f128::NAN).is_sign_negative()); -} - -#[test] -fn test_next_up() { - let tiny = f128::from_bits(TINY_BITS); - let tiny_up = f128::from_bits(TINY_UP_BITS); - let max_down = f128::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f128::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f128::from_bits(SMALLEST_NORMAL_BITS); - assert_f128_biteq!(f128::NEG_INFINITY.next_up(), f128::MIN); - assert_f128_biteq!(f128::MIN.next_up(), -max_down); - assert_f128_biteq!((-1.0 - f128::EPSILON).next_up(), -1.0); - assert_f128_biteq!((-smallest_normal).next_up(), -largest_subnormal); - assert_f128_biteq!((-tiny_up).next_up(), -tiny); - assert_f128_biteq!((-tiny).next_up(), -0.0f128); - assert_f128_biteq!((-0.0f128).next_up(), tiny); - assert_f128_biteq!(0.0f128.next_up(), tiny); - assert_f128_biteq!(tiny.next_up(), tiny_up); - assert_f128_biteq!(largest_subnormal.next_up(), smallest_normal); - assert_f128_biteq!(1.0f128.next_up(), 1.0 + f128::EPSILON); - assert_f128_biteq!(f128::MAX.next_up(), f128::INFINITY); - assert_f128_biteq!(f128::INFINITY.next_up(), f128::INFINITY); - - // Check that NaNs roundtrip. - let nan0 = f128::NAN; - let nan1 = f128::from_bits(f128::NAN.to_bits() ^ 0x002a_aaaa); - let nan2 = f128::from_bits(f128::NAN.to_bits() ^ 0x0055_5555); - assert_f128_biteq!(nan0.next_up(), nan0); - assert_f128_biteq!(nan1.next_up(), nan1); - assert_f128_biteq!(nan2.next_up(), nan2); -} - -#[test] -fn test_next_down() { - let tiny = f128::from_bits(TINY_BITS); - let tiny_up = f128::from_bits(TINY_UP_BITS); - let max_down = f128::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f128::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f128::from_bits(SMALLEST_NORMAL_BITS); - assert_f128_biteq!(f128::NEG_INFINITY.next_down(), f128::NEG_INFINITY); - assert_f128_biteq!(f128::MIN.next_down(), f128::NEG_INFINITY); - assert_f128_biteq!((-max_down).next_down(), f128::MIN); - assert_f128_biteq!((-1.0f128).next_down(), -1.0 - f128::EPSILON); - assert_f128_biteq!((-largest_subnormal).next_down(), -smallest_normal); - assert_f128_biteq!((-tiny).next_down(), -tiny_up); - assert_f128_biteq!((-0.0f128).next_down(), -tiny); - assert_f128_biteq!((0.0f128).next_down(), -tiny); - assert_f128_biteq!(tiny.next_down(), 0.0f128); - assert_f128_biteq!(tiny_up.next_down(), tiny); - assert_f128_biteq!(smallest_normal.next_down(), largest_subnormal); - assert_f128_biteq!((1.0 + f128::EPSILON).next_down(), 1.0f128); - assert_f128_biteq!(f128::MAX.next_down(), max_down); - assert_f128_biteq!(f128::INFINITY.next_down(), f128::MAX); - - // Check that NaNs roundtrip. - let nan0 = f128::NAN; - let nan1 = f128::from_bits(f128::NAN.to_bits() ^ 0x002a_aaaa); - let nan2 = f128::from_bits(f128::NAN.to_bits() ^ 0x0055_5555); - assert_f128_biteq!(nan0.next_down(), nan0); - assert_f128_biteq!(nan1.next_down(), nan1); - assert_f128_biteq!(nan2.next_down(), nan2); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_mul_add() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_approx_eq!(12.3f128.mul_add(4.5, 6.7), 62.05, TOL_PRECISE); - assert_approx_eq!((-12.3f128).mul_add(-4.5, -6.7), 48.65, TOL_PRECISE); - assert_approx_eq!(0.0f128.mul_add(8.9, 1.2), 1.2, TOL_PRECISE); - assert_approx_eq!(3.4f128.mul_add(-0.0, 5.6), 5.6, TOL_PRECISE); - 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.9f128.mul_add(inf, 3.2), inf); - assert_eq!((-3.2f128).mul_add(2.4, neg_inf), neg_inf); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_recip() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(1.0f128.recip(), 1.0); - assert_eq!(2.0f128.recip(), 0.5); - assert_eq!((-0.4f128).recip(), -2.5); - assert_eq!(0.0f128.recip(), inf); - assert_approx_eq!( - f128::MAX.recip(), - 8.40525785778023376565669454330438228902076605e-4933, - 1e-4900 - ); - assert!(nan.recip().is_nan()); - assert_eq!(inf.recip(), 0.0); - assert_eq!(neg_inf.recip(), 0.0); -} - -// Many math functions allow for less accurate results, so the next tolerance up is used - -#[test] -#[cfg(reliable_f128_math)] -fn test_powi() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(1.0f128.powi(1), 1.0); - assert_approx_eq!((-3.1f128).powi(2), 9.6100000000000005506706202140776519387, TOL); - assert_approx_eq!(5.9f128.powi(-2), 0.028727377190462507313100483690639638451, TOL); - assert_eq!(8.3f128.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_eq!(inf.powi(3), inf); - assert_eq!(neg_inf.powi(2), inf); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_powf() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(1.0f128.powf(1.0), 1.0); - assert_approx_eq!(3.4f128.powf(4.5), 246.40818323761892815995637964326426756, TOL_IMPR); - assert_approx_eq!(2.7f128.powf(-3.2), 0.041652009108526178281070304373500889273, TOL_IMPR); - assert_approx_eq!((-3.1f128).powf(2.0), 9.6100000000000005506706202140776519387, TOL_IMPR); - assert_approx_eq!(5.9f128.powf(-2.0), 0.028727377190462507313100483690639638451, TOL_IMPR); - assert_eq!(8.3f128.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] -#[cfg(reliable_f128_math)] -fn test_sqrt_domain() { - assert!(f128::NAN.sqrt().is_nan()); - assert!(f128::NEG_INFINITY.sqrt().is_nan()); - assert!((-1.0f128).sqrt().is_nan()); - assert_eq!((-0.0f128).sqrt(), -0.0); - assert_eq!(0.0f128.sqrt(), 0.0); - assert_eq!(1.0f128.sqrt(), 1.0); - assert_eq!(f128::INFINITY.sqrt(), f128::INFINITY); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_exp() { - assert_eq!(1.0, 0.0f128.exp()); - assert_approx_eq!(consts::E, 1.0f128.exp(), TOL); - assert_approx_eq!(148.41315910257660342111558004055227962348775, 5.0f128.exp(), TOL); - - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let nan: f128 = f128::NAN; - assert_eq!(inf, inf.exp()); - assert_eq!(0.0, neg_inf.exp()); - assert!(nan.exp().is_nan()); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_exp2() { - assert_eq!(32.0, 5.0f128.exp2()); - assert_eq!(1.0, 0.0f128.exp2()); - - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let nan: f128 = f128::NAN; - assert_eq!(inf, inf.exp2()); - assert_eq!(0.0, neg_inf.exp2()); - assert!(nan.exp2().is_nan()); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_ln() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_approx_eq!(1.0f128.exp().ln(), 1.0, TOL); - assert!(nan.ln().is_nan()); - assert_eq!(inf.ln(), inf); - assert!(neg_inf.ln().is_nan()); - assert!((-2.3f128).ln().is_nan()); - assert_eq!((-0.0f128).ln(), neg_inf); - assert_eq!(0.0f128.ln(), neg_inf); - assert_approx_eq!(4.0f128.ln(), 1.3862943611198906188344642429163531366, TOL); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_log() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(10.0f128.log(10.0), 1.0); - assert_approx_eq!(2.3f128.log(3.5), 0.66485771361478710036766645911922010272, TOL); - assert_eq!(1.0f128.exp().log(1.0f128.exp()), 1.0); - assert!(1.0f128.log(1.0).is_nan()); - assert!(1.0f128.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.3f128).log(0.1).is_nan()); - assert_eq!((-0.0f128).log(2.0), neg_inf); - assert_eq!(0.0f128.log(7.0), neg_inf); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_log2() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_approx_eq!(10.0f128.log2(), 3.32192809488736234787031942948939017, TOL); - assert_approx_eq!(2.3f128.log2(), 1.2016338611696504130002982471978765921, TOL); - assert_approx_eq!(1.0f128.exp().log2(), 1.4426950408889634073599246810018921381, TOL); - assert!(nan.log2().is_nan()); - assert_eq!(inf.log2(), inf); - assert!(neg_inf.log2().is_nan()); - assert!((-2.3f128).log2().is_nan()); - assert_eq!((-0.0f128).log2(), neg_inf); - assert_eq!(0.0f128.log2(), neg_inf); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_log10() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(10.0f128.log10(), 1.0); - assert_approx_eq!(2.3f128.log10(), 0.36172783601759284532595218865859309898, TOL); - assert_approx_eq!(1.0f128.exp().log10(), 0.43429448190325182765112891891660508222, TOL); - assert_eq!(1.0f128.log10(), 0.0); - assert!(nan.log10().is_nan()); - assert_eq!(inf.log10(), inf); - assert!(neg_inf.log10().is_nan()); - assert!((-2.3f128).log10().is_nan()); - assert_eq!((-0.0f128).log10(), neg_inf); - assert_eq!(0.0f128.log10(), neg_inf); -} - -#[test] -fn test_to_degrees() { - let pi: f128 = consts::PI; - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(0.0f128.to_degrees(), 0.0); - assert_approx_eq!((-5.8f128).to_degrees(), -332.31552117587745090765431723855668471, TOL); - assert_approx_eq!(pi.to_degrees(), 180.0, TOL); - assert!(nan.to_degrees().is_nan()); - assert_eq!(inf.to_degrees(), inf); - assert_eq!(neg_inf.to_degrees(), neg_inf); - assert_eq!(1_f128.to_degrees(), 57.2957795130823208767981548141051703); -} - -#[test] -fn test_to_radians() { - let pi: f128 = consts::PI; - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(0.0f128.to_radians(), 0.0); - assert_approx_eq!(154.6f128.to_radians(), 2.6982790235832334267135442069489767804, TOL); - assert_approx_eq!((-332.31f128).to_radians(), -5.7999036373023566567593094812182763013, TOL); - // check approx rather than exact because round trip for pi doesn't fall on an exactly - // representable value (unlike `f32` and `f64`). - assert_approx_eq!(180.0f128.to_radians(), pi, TOL_PRECISE); - assert!(nan.to_radians().is_nan()); - assert_eq!(inf.to_radians(), inf); - assert_eq!(neg_inf.to_radians(), neg_inf); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_asinh() { - // Lower accuracy results are allowed, use increased tolerances - assert_eq!(0.0f128.asinh(), 0.0f128); - assert_eq!((-0.0f128).asinh(), -0.0f128); - - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let nan: f128 = f128::NAN; - assert_eq!(inf.asinh(), inf); - assert_eq!(neg_inf.asinh(), neg_inf); - assert!(nan.asinh().is_nan()); - assert!((-0.0f128).asinh().is_sign_negative()); - - // issue 63271 - assert_approx_eq!(2.0f128.asinh(), 1.443635475178810342493276740273105f128, TOL_IMPR); - assert_approx_eq!((-2.0f128).asinh(), -1.443635475178810342493276740273105f128, TOL_IMPR); - // regression test for the catastrophic cancellation fixed in 72486 - assert_approx_eq!( - (-67452098.07139316f128).asinh(), - -18.720075426274544393985484294000831757220, - TOL_IMPR - ); - - // test for low accuracy from issue 104548 - assert_approx_eq!(60.0f128, 60.0f128.sinh().asinh(), TOL_IMPR); - // mul needed for approximate comparison to be meaningful - assert_approx_eq!(1.0f128, 1e-15f128.sinh().asinh() * 1e15f128, TOL_IMPR); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_acosh() { - assert_eq!(1.0f128.acosh(), 0.0f128); - assert!(0.999f128.acosh().is_nan()); - - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let nan: f128 = f128::NAN; - assert_eq!(inf.acosh(), inf); - assert!(neg_inf.acosh().is_nan()); - assert!(nan.acosh().is_nan()); - assert_approx_eq!(2.0f128.acosh(), 1.31695789692481670862504634730796844f128, TOL_IMPR); - assert_approx_eq!(3.0f128.acosh(), 1.76274717403908605046521864995958461f128, TOL_IMPR); - - // test for low accuracy from issue 104548 - assert_approx_eq!(60.0f128, 60.0f128.cosh().acosh(), TOL_IMPR); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_atanh() { - assert_eq!(0.0f128.atanh(), 0.0f128); - assert_eq!((-0.0f128).atanh(), -0.0f128); - - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let nan: f128 = f128::NAN; - assert_eq!(1.0f128.atanh(), inf); - assert_eq!((-1.0f128).atanh(), neg_inf); - assert!(2f128.atanh().atanh().is_nan()); - assert!((-2f128).atanh().atanh().is_nan()); - assert!(inf.atanh().is_nan()); - assert!(neg_inf.atanh().is_nan()); - assert!(nan.atanh().is_nan()); - assert_approx_eq!(0.5f128.atanh(), 0.54930614433405484569762261846126285f128, TOL_IMPR); - assert_approx_eq!((-0.5f128).atanh(), -0.54930614433405484569762261846126285f128, TOL_IMPR); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_gamma() { - // precision can differ among platforms - assert_approx_eq!(1.0f128.gamma(), 1.0f128, TOL_IMPR); - assert_approx_eq!(2.0f128.gamma(), 1.0f128, TOL_IMPR); - assert_approx_eq!(3.0f128.gamma(), 2.0f128, TOL_IMPR); - assert_approx_eq!(4.0f128.gamma(), 6.0f128, TOL_IMPR); - assert_approx_eq!(5.0f128.gamma(), 24.0f128, TOL_IMPR); - assert_approx_eq!(0.5f128.gamma(), consts::PI.sqrt(), TOL_IMPR); - assert_approx_eq!((-0.5f128).gamma(), -2.0 * consts::PI.sqrt(), TOL_IMPR); - assert_eq!(0.0f128.gamma(), f128::INFINITY); - assert_eq!((-0.0f128).gamma(), f128::NEG_INFINITY); - assert!((-1.0f128).gamma().is_nan()); - assert!((-2.0f128).gamma().is_nan()); - assert!(f128::NAN.gamma().is_nan()); - assert!(f128::NEG_INFINITY.gamma().is_nan()); - assert_eq!(f128::INFINITY.gamma(), f128::INFINITY); - assert_eq!(1760.9f128.gamma(), f128::INFINITY); -} - -#[test] -#[cfg(reliable_f128_math)] -fn test_ln_gamma() { - assert_approx_eq!(1.0f128.ln_gamma().0, 0.0f128, TOL_IMPR); - assert_eq!(1.0f128.ln_gamma().1, 1); - assert_approx_eq!(2.0f128.ln_gamma().0, 0.0f128, TOL_IMPR); - assert_eq!(2.0f128.ln_gamma().1, 1); - assert_approx_eq!(3.0f128.ln_gamma().0, 2.0f128.ln(), TOL_IMPR); - assert_eq!(3.0f128.ln_gamma().1, 1); - assert_approx_eq!((-0.5f128).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_IMPR); - assert_eq!((-0.5f128).ln_gamma().1, -1); -} - -#[test] -fn test_real_consts() { - use super::consts; - - let pi: f128 = consts::PI; - let frac_pi_2: f128 = consts::FRAC_PI_2; - let frac_pi_3: f128 = consts::FRAC_PI_3; - let frac_pi_4: f128 = consts::FRAC_PI_4; - let frac_pi_6: f128 = consts::FRAC_PI_6; - let frac_pi_8: f128 = consts::FRAC_PI_8; - let frac_1_pi: f128 = consts::FRAC_1_PI; - let frac_2_pi: f128 = consts::FRAC_2_PI; - - assert_approx_eq!(frac_pi_2, pi / 2f128, TOL_PRECISE); - assert_approx_eq!(frac_pi_3, pi / 3f128, TOL_PRECISE); - assert_approx_eq!(frac_pi_4, pi / 4f128, TOL_PRECISE); - assert_approx_eq!(frac_pi_6, pi / 6f128, TOL_PRECISE); - assert_approx_eq!(frac_pi_8, pi / 8f128, TOL_PRECISE); - assert_approx_eq!(frac_1_pi, 1f128 / pi, TOL_PRECISE); - assert_approx_eq!(frac_2_pi, 2f128 / pi, TOL_PRECISE); - - #[cfg(reliable_f128_math)] - { - let frac_2_sqrtpi: f128 = consts::FRAC_2_SQRT_PI; - let sqrt2: f128 = consts::SQRT_2; - let frac_1_sqrt2: f128 = consts::FRAC_1_SQRT_2; - let e: f128 = consts::E; - let log2_e: f128 = consts::LOG2_E; - let log10_e: f128 = consts::LOG10_E; - let ln_2: f128 = consts::LN_2; - let ln_10: f128 = consts::LN_10; - - assert_approx_eq!(frac_2_sqrtpi, 2f128 / pi.sqrt(), TOL_PRECISE); - assert_approx_eq!(sqrt2, 2f128.sqrt(), TOL_PRECISE); - assert_approx_eq!(frac_1_sqrt2, 1f128 / 2f128.sqrt(), TOL_PRECISE); - assert_approx_eq!(log2_e, e.log2(), TOL_PRECISE); - assert_approx_eq!(log10_e, e.log10(), TOL_PRECISE); - assert_approx_eq!(ln_2, 2f128.ln(), TOL_PRECISE); - assert_approx_eq!(ln_10, 10f128.ln(), TOL_PRECISE); - } -} - -#[test] -fn test_float_bits_conv() { - assert_eq!((1f128).to_bits(), 0x3fff0000000000000000000000000000); - assert_eq!((12.5f128).to_bits(), 0x40029000000000000000000000000000); - assert_eq!((1337f128).to_bits(), 0x40094e40000000000000000000000000); - assert_eq!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000); - assert_approx_eq!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0, TOL_PRECISE); - assert_approx_eq!(f128::from_bits(0x40029000000000000000000000000000), 12.5, TOL_PRECISE); - assert_approx_eq!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0, TOL_PRECISE); - assert_approx_eq!(f128::from_bits(0xc002c800000000000000000000000000), -14.25, TOL_PRECISE); - - // 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 = f128::NAN.to_bits() ^ NAN_MASK1; - let masked_nan2 = f128::NAN.to_bits() ^ NAN_MASK2; - assert!(f128::from_bits(masked_nan1).is_nan()); - assert!(f128::from_bits(masked_nan2).is_nan()); - - assert_eq!(f128::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f128::from_bits(masked_nan2).to_bits(), masked_nan2); -} - -#[test] -#[should_panic] -fn test_clamp_min_greater_than_max() { - let _ = 1.0f128.clamp(3.0, 1.0); -} - -#[test] -#[should_panic] -fn test_clamp_min_is_nan() { - let _ = 1.0f128.clamp(f128::NAN, 1.0); -} - -#[test] -#[should_panic] -fn test_clamp_max_is_nan() { - let _ = 1.0f128.clamp(3.0, f128::NAN); -} - -#[test] -fn test_total_cmp() { - use core::cmp::Ordering; - - fn quiet_bit_mask() -> u128 { - 1 << (f128::MANTISSA_DIGITS - 2) - } - - // FIXME(f16_f128): test subnormals when powf is available - // fn min_subnorm() -> f128 { - // f128::MIN_POSITIVE / f128::powf(2.0, f128::MANTISSA_DIGITS as f128 - 1.0) - // } - - // fn max_subnorm() -> f128 { - // f128::MIN_POSITIVE - min_subnorm() - // } - - fn q_nan() -> f128 { - f128::from_bits(f128::NAN.to_bits() | quiet_bit_mask()) - } - - fn s_nan() -> f128 { - f128::from_bits((f128::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, (-f128::INFINITY).total_cmp(&-f128::INFINITY)); - assert_eq!(Ordering::Equal, (-f128::MAX).total_cmp(&-f128::MAX)); - assert_eq!(Ordering::Equal, (-2.5_f128).total_cmp(&-2.5)); - assert_eq!(Ordering::Equal, (-1.0_f128).total_cmp(&-1.0)); - assert_eq!(Ordering::Equal, (-1.5_f128).total_cmp(&-1.5)); - assert_eq!(Ordering::Equal, (-0.5_f128).total_cmp(&-0.5)); - assert_eq!(Ordering::Equal, (-f128::MIN_POSITIVE).total_cmp(&-f128::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_f128).total_cmp(&-0.0)); - assert_eq!(Ordering::Equal, 0.0_f128.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, f128::MIN_POSITIVE.total_cmp(&f128::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, 0.5_f128.total_cmp(&0.5)); - assert_eq!(Ordering::Equal, 1.0_f128.total_cmp(&1.0)); - assert_eq!(Ordering::Equal, 1.5_f128.total_cmp(&1.5)); - assert_eq!(Ordering::Equal, 2.5_f128.total_cmp(&2.5)); - assert_eq!(Ordering::Equal, f128::MAX.total_cmp(&f128::MAX)); - assert_eq!(Ordering::Equal, f128::INFINITY.total_cmp(&f128::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(&-f128::INFINITY)); - assert_eq!(Ordering::Less, (-f128::INFINITY).total_cmp(&-f128::MAX)); - assert_eq!(Ordering::Less, (-f128::MAX).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-2.5_f128).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-1.5_f128).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-1.0_f128).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-0.5_f128).total_cmp(&-f128::MIN_POSITIVE)); - // assert_eq!(Ordering::Less, (-f128::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_f128).total_cmp(&0.0)); - // assert_eq!(Ordering::Less, 0.0_f128.total_cmp(&min_subnorm())); - // assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); - // assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f128::MIN_POSITIVE)); - assert_eq!(Ordering::Less, f128::MIN_POSITIVE.total_cmp(&0.5)); - assert_eq!(Ordering::Less, 0.5_f128.total_cmp(&1.0)); - assert_eq!(Ordering::Less, 1.0_f128.total_cmp(&1.5)); - assert_eq!(Ordering::Less, 1.5_f128.total_cmp(&2.5)); - assert_eq!(Ordering::Less, 2.5_f128.total_cmp(&f128::MAX)); - assert_eq!(Ordering::Less, f128::MAX.total_cmp(&f128::INFINITY)); - assert_eq!(Ordering::Less, f128::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, (-f128::INFINITY).total_cmp(&-s_nan())); - assert_eq!(Ordering::Greater, (-f128::MAX).total_cmp(&-f128::INFINITY)); - assert_eq!(Ordering::Greater, (-2.5_f128).total_cmp(&-f128::MAX)); - assert_eq!(Ordering::Greater, (-1.5_f128).total_cmp(&-2.5)); - assert_eq!(Ordering::Greater, (-1.0_f128).total_cmp(&-1.5)); - assert_eq!(Ordering::Greater, (-0.5_f128).total_cmp(&-1.0)); - assert_eq!(Ordering::Greater, (-f128::MIN_POSITIVE).total_cmp(&-0.5)); - // assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f128::MIN_POSITIVE)); - // assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); - // assert_eq!(Ordering::Greater, (-0.0_f128).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Greater, 0.0_f128.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, f128::MIN_POSITIVE.total_cmp(&max_subnorm())); - assert_eq!(Ordering::Greater, 0.5_f128.total_cmp(&f128::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, 1.0_f128.total_cmp(&0.5)); - assert_eq!(Ordering::Greater, 1.5_f128.total_cmp(&1.0)); - assert_eq!(Ordering::Greater, 2.5_f128.total_cmp(&1.5)); - assert_eq!(Ordering::Greater, f128::MAX.total_cmp(&2.5)); - assert_eq!(Ordering::Greater, f128::INFINITY.total_cmp(&f128::MAX)); - assert_eq!(Ordering::Greater, s_nan().total_cmp(&f128::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(&-f128::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f128::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(&-f128::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(&f128::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(&f128::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f128::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f128::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f128::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(&-f128::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(&f128::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(&f128::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f128::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); -} diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index 5b0903bceab..cc523c93b4d 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -4,9 +4,6 @@ //! //! Mathematically significant numbers are provided in the `consts` sub-module. -#[cfg(test)] -mod tests; - #[unstable(feature = "f16", issue = "116909")] pub use core::f16::consts; diff --git a/library/std/src/f16/tests.rs b/library/std/src/f16/tests.rs deleted file mode 100644 index 684ee3f3855..00000000000 --- a/library/std/src/f16/tests.rs +++ /dev/null @@ -1,958 +0,0 @@ -// FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy -#![cfg(reliable_f16)] - -use crate::f16::consts; -use crate::num::{FpCategory as Fp, *}; - -/// Tolerance for results on the order of 10.0e-2 -#[allow(unused)] -const TOL_N2: f16 = 0.0001; - -/// Tolerance for results on the order of 10.0e+0 -#[allow(unused)] -const TOL_0: f16 = 0.01; - -/// Tolerance for results on the order of 10.0e+2 -#[allow(unused)] -const TOL_P2: f16 = 0.5; - -/// Tolerance for results on the order of 10.0e+4 -#[allow(unused)] -const TOL_P4: f16 = 10.0; - -/// Smallest number -const TINY_BITS: u16 = 0x1; - -/// Next smallest number -const TINY_UP_BITS: u16 = 0x2; - -/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 -const MAX_DOWN_BITS: u16 = 0x7bfe; - -/// Zeroed exponent, full significant -const LARGEST_SUBNORMAL_BITS: u16 = 0x03ff; - -/// Exponent = 0b1, zeroed significand -const SMALLEST_NORMAL_BITS: u16 = 0x0400; - -/// First pattern over the mantissa -const NAN_MASK1: u16 = 0x02aa; - -/// Second pattern over the mantissa -const NAN_MASK2: u16 = 0x0155; - -/// Compare by representation -#[allow(unused_macros)] -macro_rules! assert_f16_biteq { - ($a:expr, $b:expr) => { - let (l, r): (&f16, &f16) = (&$a, &$b); - let lb = l.to_bits(); - let rb = r.to_bits(); - assert_eq!(lb, rb, "float {l:?} ({lb:#04x}) is not bitequal to {r:?} ({rb:#04x})"); - }; -} - -#[test] -fn test_num_f16() { - test_num(10f16, 2f16); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_min_nan() { - assert_eq!(f16::NAN.min(2.0), 2.0); - assert_eq!(2.0f16.min(f16::NAN), 2.0); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_max_nan() { - assert_eq!(f16::NAN.max(2.0), 2.0); - assert_eq!(2.0f16.max(f16::NAN), 2.0); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_minimum() { - assert!(f16::NAN.minimum(2.0).is_nan()); - assert!(2.0f16.minimum(f16::NAN).is_nan()); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_maximum() { - assert!(f16::NAN.maximum(2.0).is_nan()); - assert!(2.0f16.maximum(f16::NAN).is_nan()); -} - -#[test] -fn test_nan() { - let nan: f16 = f16::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert!(!nan.is_normal()); - assert_eq!(Fp::Nan, nan.classify()); -} - -#[test] -fn test_infinity() { - let inf: f16 = f16::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: f16 = f16::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: f16 = 0.0f16; - 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: f16 = -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: f16 = 1.0f16; - 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: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f16.is_nan()); - assert!(!5.3f16.is_nan()); - assert!(!(-10.732f16).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f16.is_infinite()); - assert!(!42.8f16.is_infinite()); - assert!(!(-109.2f16).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f16.is_finite()); - assert!(42.8f16.is_finite()); - assert!((-109.2f16).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -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!(1f16.is_normal()); - assert!(1e-4f16.is_normal()); - assert!(!1e-5f16.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -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!(1f16.classify(), Fp::Normal); - assert_eq!(1e-4f16.classify(), Fp::Normal); - assert_eq!(1e-5f16.classify(), Fp::Subnormal); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_floor() { - assert_approx_eq!(1.0f16.floor(), 1.0f16, TOL_0); - assert_approx_eq!(1.3f16.floor(), 1.0f16, TOL_0); - assert_approx_eq!(1.5f16.floor(), 1.0f16, TOL_0); - assert_approx_eq!(1.7f16.floor(), 1.0f16, TOL_0); - assert_approx_eq!(0.0f16.floor(), 0.0f16, TOL_0); - assert_approx_eq!((-0.0f16).floor(), -0.0f16, TOL_0); - assert_approx_eq!((-1.0f16).floor(), -1.0f16, TOL_0); - assert_approx_eq!((-1.3f16).floor(), -2.0f16, TOL_0); - assert_approx_eq!((-1.5f16).floor(), -2.0f16, TOL_0); - assert_approx_eq!((-1.7f16).floor(), -2.0f16, TOL_0); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_ceil() { - assert_approx_eq!(1.0f16.ceil(), 1.0f16, TOL_0); - assert_approx_eq!(1.3f16.ceil(), 2.0f16, TOL_0); - assert_approx_eq!(1.5f16.ceil(), 2.0f16, TOL_0); - assert_approx_eq!(1.7f16.ceil(), 2.0f16, TOL_0); - assert_approx_eq!(0.0f16.ceil(), 0.0f16, TOL_0); - assert_approx_eq!((-0.0f16).ceil(), -0.0f16, TOL_0); - assert_approx_eq!((-1.0f16).ceil(), -1.0f16, TOL_0); - assert_approx_eq!((-1.3f16).ceil(), -1.0f16, TOL_0); - assert_approx_eq!((-1.5f16).ceil(), -1.0f16, TOL_0); - assert_approx_eq!((-1.7f16).ceil(), -1.0f16, TOL_0); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_round() { - assert_approx_eq!(2.5f16.round(), 3.0f16, TOL_0); - assert_approx_eq!(1.0f16.round(), 1.0f16, TOL_0); - assert_approx_eq!(1.3f16.round(), 1.0f16, TOL_0); - assert_approx_eq!(1.5f16.round(), 2.0f16, TOL_0); - assert_approx_eq!(1.7f16.round(), 2.0f16, TOL_0); - assert_approx_eq!(0.0f16.round(), 0.0f16, TOL_0); - assert_approx_eq!((-0.0f16).round(), -0.0f16, TOL_0); - assert_approx_eq!((-1.0f16).round(), -1.0f16, TOL_0); - assert_approx_eq!((-1.3f16).round(), -1.0f16, TOL_0); - assert_approx_eq!((-1.5f16).round(), -2.0f16, TOL_0); - assert_approx_eq!((-1.7f16).round(), -2.0f16, TOL_0); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_round_ties_even() { - assert_approx_eq!(2.5f16.round_ties_even(), 2.0f16, TOL_0); - assert_approx_eq!(1.0f16.round_ties_even(), 1.0f16, TOL_0); - assert_approx_eq!(1.3f16.round_ties_even(), 1.0f16, TOL_0); - assert_approx_eq!(1.5f16.round_ties_even(), 2.0f16, TOL_0); - assert_approx_eq!(1.7f16.round_ties_even(), 2.0f16, TOL_0); - assert_approx_eq!(0.0f16.round_ties_even(), 0.0f16, TOL_0); - assert_approx_eq!((-0.0f16).round_ties_even(), -0.0f16, TOL_0); - assert_approx_eq!((-1.0f16).round_ties_even(), -1.0f16, TOL_0); - assert_approx_eq!((-1.3f16).round_ties_even(), -1.0f16, TOL_0); - assert_approx_eq!((-1.5f16).round_ties_even(), -2.0f16, TOL_0); - assert_approx_eq!((-1.7f16).round_ties_even(), -2.0f16, TOL_0); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_trunc() { - assert_approx_eq!(1.0f16.trunc(), 1.0f16, TOL_0); - assert_approx_eq!(1.3f16.trunc(), 1.0f16, TOL_0); - assert_approx_eq!(1.5f16.trunc(), 1.0f16, TOL_0); - assert_approx_eq!(1.7f16.trunc(), 1.0f16, TOL_0); - assert_approx_eq!(0.0f16.trunc(), 0.0f16, TOL_0); - assert_approx_eq!((-0.0f16).trunc(), -0.0f16, TOL_0); - assert_approx_eq!((-1.0f16).trunc(), -1.0f16, TOL_0); - assert_approx_eq!((-1.3f16).trunc(), -1.0f16, TOL_0); - assert_approx_eq!((-1.5f16).trunc(), -1.0f16, TOL_0); - assert_approx_eq!((-1.7f16).trunc(), -1.0f16, TOL_0); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_fract() { - assert_approx_eq!(1.0f16.fract(), 0.0f16, TOL_0); - assert_approx_eq!(1.3f16.fract(), 0.3f16, TOL_0); - assert_approx_eq!(1.5f16.fract(), 0.5f16, TOL_0); - assert_approx_eq!(1.7f16.fract(), 0.7f16, TOL_0); - assert_approx_eq!(0.0f16.fract(), 0.0f16, TOL_0); - assert_approx_eq!((-0.0f16).fract(), -0.0f16, TOL_0); - assert_approx_eq!((-1.0f16).fract(), -0.0f16, TOL_0); - assert_approx_eq!((-1.3f16).fract(), -0.3f16, TOL_0); - assert_approx_eq!((-1.5f16).fract(), -0.5f16, TOL_0); - assert_approx_eq!((-1.7f16).fract(), -0.7f16, TOL_0); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_abs() { - assert_eq!(f16::INFINITY.abs(), f16::INFINITY); - assert_eq!(1f16.abs(), 1f16); - assert_eq!(0f16.abs(), 0f16); - assert_eq!((-0f16).abs(), 0f16); - assert_eq!((-1f16).abs(), 1f16); - assert_eq!(f16::NEG_INFINITY.abs(), f16::INFINITY); - assert_eq!((1f16 / f16::NEG_INFINITY).abs(), 0f16); - assert!(f16::NAN.abs().is_nan()); -} - -#[test] -fn test_is_sign_positive() { - assert!(f16::INFINITY.is_sign_positive()); - assert!(1f16.is_sign_positive()); - assert!(0f16.is_sign_positive()); - assert!(!(-0f16).is_sign_positive()); - assert!(!(-1f16).is_sign_positive()); - assert!(!f16::NEG_INFINITY.is_sign_positive()); - assert!(!(1f16 / f16::NEG_INFINITY).is_sign_positive()); - assert!(f16::NAN.is_sign_positive()); - assert!(!(-f16::NAN).is_sign_positive()); -} - -#[test] -fn test_is_sign_negative() { - assert!(!f16::INFINITY.is_sign_negative()); - assert!(!1f16.is_sign_negative()); - assert!(!0f16.is_sign_negative()); - assert!((-0f16).is_sign_negative()); - assert!((-1f16).is_sign_negative()); - assert!(f16::NEG_INFINITY.is_sign_negative()); - assert!((1f16 / f16::NEG_INFINITY).is_sign_negative()); - assert!(!f16::NAN.is_sign_negative()); - assert!((-f16::NAN).is_sign_negative()); -} - -#[test] -fn test_next_up() { - let tiny = f16::from_bits(TINY_BITS); - let tiny_up = f16::from_bits(TINY_UP_BITS); - let max_down = f16::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f16::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f16::from_bits(SMALLEST_NORMAL_BITS); - assert_f16_biteq!(f16::NEG_INFINITY.next_up(), f16::MIN); - assert_f16_biteq!(f16::MIN.next_up(), -max_down); - assert_f16_biteq!((-1.0 - f16::EPSILON).next_up(), -1.0); - assert_f16_biteq!((-smallest_normal).next_up(), -largest_subnormal); - assert_f16_biteq!((-tiny_up).next_up(), -tiny); - assert_f16_biteq!((-tiny).next_up(), -0.0f16); - assert_f16_biteq!((-0.0f16).next_up(), tiny); - assert_f16_biteq!(0.0f16.next_up(), tiny); - assert_f16_biteq!(tiny.next_up(), tiny_up); - assert_f16_biteq!(largest_subnormal.next_up(), smallest_normal); - assert_f16_biteq!(1.0f16.next_up(), 1.0 + f16::EPSILON); - assert_f16_biteq!(f16::MAX.next_up(), f16::INFINITY); - assert_f16_biteq!(f16::INFINITY.next_up(), f16::INFINITY); - - // Check that NaNs roundtrip. - let nan0 = f16::NAN; - let nan1 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK1); - let nan2 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK2); - assert_f16_biteq!(nan0.next_up(), nan0); - assert_f16_biteq!(nan1.next_up(), nan1); - assert_f16_biteq!(nan2.next_up(), nan2); -} - -#[test] -fn test_next_down() { - let tiny = f16::from_bits(TINY_BITS); - let tiny_up = f16::from_bits(TINY_UP_BITS); - let max_down = f16::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f16::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f16::from_bits(SMALLEST_NORMAL_BITS); - assert_f16_biteq!(f16::NEG_INFINITY.next_down(), f16::NEG_INFINITY); - assert_f16_biteq!(f16::MIN.next_down(), f16::NEG_INFINITY); - assert_f16_biteq!((-max_down).next_down(), f16::MIN); - assert_f16_biteq!((-1.0f16).next_down(), -1.0 - f16::EPSILON); - assert_f16_biteq!((-largest_subnormal).next_down(), -smallest_normal); - assert_f16_biteq!((-tiny).next_down(), -tiny_up); - assert_f16_biteq!((-0.0f16).next_down(), -tiny); - assert_f16_biteq!((0.0f16).next_down(), -tiny); - assert_f16_biteq!(tiny.next_down(), 0.0f16); - assert_f16_biteq!(tiny_up.next_down(), tiny); - assert_f16_biteq!(smallest_normal.next_down(), largest_subnormal); - assert_f16_biteq!((1.0 + f16::EPSILON).next_down(), 1.0f16); - assert_f16_biteq!(f16::MAX.next_down(), max_down); - assert_f16_biteq!(f16::INFINITY.next_down(), f16::MAX); - - // Check that NaNs roundtrip. - let nan0 = f16::NAN; - let nan1 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK1); - let nan2 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK2); - assert_f16_biteq!(nan0.next_down(), nan0); - assert_f16_biteq!(nan1.next_down(), nan1); - assert_f16_biteq!(nan2.next_down(), nan2); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_mul_add() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_approx_eq!(12.3f16.mul_add(4.5, 6.7), 62.05, TOL_P2); - assert_approx_eq!((-12.3f16).mul_add(-4.5, -6.7), 48.65, TOL_P2); - assert_approx_eq!(0.0f16.mul_add(8.9, 1.2), 1.2, TOL_0); - assert_approx_eq!(3.4f16.mul_add(-0.0, 5.6), 5.6, TOL_0); - 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.9f16.mul_add(inf, 3.2), inf); - assert_eq!((-3.2f16).mul_add(2.4, neg_inf), neg_inf); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_recip() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_eq!(1.0f16.recip(), 1.0); - assert_eq!(2.0f16.recip(), 0.5); - assert_eq!((-0.4f16).recip(), -2.5); - assert_eq!(0.0f16.recip(), inf); - assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4); - assert!(nan.recip().is_nan()); - assert_eq!(inf.recip(), 0.0); - assert_eq!(neg_inf.recip(), 0.0); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_powi() { - // FIXME(llvm19): LLVM misoptimizes `powi.f16` - // <https://github.com/llvm/llvm-project/issues/98665> - // let nan: f16 = f16::NAN; - // let inf: f16 = f16::INFINITY; - // let neg_inf: f16 = f16::NEG_INFINITY; - // assert_eq!(1.0f16.powi(1), 1.0); - // assert_approx_eq!((-3.1f16).powi(2), 9.61, TOL_0); - // assert_approx_eq!(5.9f16.powi(-2), 0.028727, TOL_N2); - // assert_eq!(8.3f16.powi(0), 1.0); - // assert!(nan.powi(2).is_nan()); - // assert_eq!(inf.powi(3), inf); - // assert_eq!(neg_inf.powi(2), inf); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_powf() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_eq!(1.0f16.powf(1.0), 1.0); - assert_approx_eq!(3.4f16.powf(4.5), 246.408183, TOL_P2); - assert_approx_eq!(2.7f16.powf(-3.2), 0.041652, TOL_N2); - assert_approx_eq!((-3.1f16).powf(2.0), 9.61, TOL_P2); - assert_approx_eq!(5.9f16.powf(-2.0), 0.028727, TOL_N2); - assert_eq!(8.3f16.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] -#[cfg(reliable_f16_math)] -fn test_sqrt_domain() { - assert!(f16::NAN.sqrt().is_nan()); - assert!(f16::NEG_INFINITY.sqrt().is_nan()); - assert!((-1.0f16).sqrt().is_nan()); - assert_eq!((-0.0f16).sqrt(), -0.0); - assert_eq!(0.0f16.sqrt(), 0.0); - assert_eq!(1.0f16.sqrt(), 1.0); - assert_eq!(f16::INFINITY.sqrt(), f16::INFINITY); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_exp() { - assert_eq!(1.0, 0.0f16.exp()); - assert_approx_eq!(2.718282, 1.0f16.exp(), TOL_0); - assert_approx_eq!(148.413159, 5.0f16.exp(), TOL_0); - - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let nan: f16 = f16::NAN; - assert_eq!(inf, inf.exp()); - assert_eq!(0.0, neg_inf.exp()); - assert!(nan.exp().is_nan()); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_exp2() { - assert_eq!(32.0, 5.0f16.exp2()); - assert_eq!(1.0, 0.0f16.exp2()); - - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let nan: f16 = f16::NAN; - assert_eq!(inf, inf.exp2()); - assert_eq!(0.0, neg_inf.exp2()); - assert!(nan.exp2().is_nan()); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_ln() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_approx_eq!(1.0f16.exp().ln(), 1.0, TOL_0); - assert!(nan.ln().is_nan()); - assert_eq!(inf.ln(), inf); - assert!(neg_inf.ln().is_nan()); - assert!((-2.3f16).ln().is_nan()); - assert_eq!((-0.0f16).ln(), neg_inf); - assert_eq!(0.0f16.ln(), neg_inf); - assert_approx_eq!(4.0f16.ln(), 1.386294, TOL_0); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_log() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_eq!(10.0f16.log(10.0), 1.0); - assert_approx_eq!(2.3f16.log(3.5), 0.664858, TOL_0); - assert_eq!(1.0f16.exp().log(1.0f16.exp()), 1.0); - assert!(1.0f16.log(1.0).is_nan()); - assert!(1.0f16.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.3f16).log(0.1).is_nan()); - assert_eq!((-0.0f16).log(2.0), neg_inf); - assert_eq!(0.0f16.log(7.0), neg_inf); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_log2() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_approx_eq!(10.0f16.log2(), 3.321928, TOL_0); - assert_approx_eq!(2.3f16.log2(), 1.201634, TOL_0); - assert_approx_eq!(1.0f16.exp().log2(), 1.442695, TOL_0); - assert!(nan.log2().is_nan()); - assert_eq!(inf.log2(), inf); - assert!(neg_inf.log2().is_nan()); - assert!((-2.3f16).log2().is_nan()); - assert_eq!((-0.0f16).log2(), neg_inf); - assert_eq!(0.0f16.log2(), neg_inf); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_log10() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_eq!(10.0f16.log10(), 1.0); - assert_approx_eq!(2.3f16.log10(), 0.361728, TOL_0); - assert_approx_eq!(1.0f16.exp().log10(), 0.434294, TOL_0); - assert_eq!(1.0f16.log10(), 0.0); - assert!(nan.log10().is_nan()); - assert_eq!(inf.log10(), inf); - assert!(neg_inf.log10().is_nan()); - assert!((-2.3f16).log10().is_nan()); - assert_eq!((-0.0f16).log10(), neg_inf); - assert_eq!(0.0f16.log10(), neg_inf); -} - -#[test] -fn test_to_degrees() { - let pi: f16 = consts::PI; - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_eq!(0.0f16.to_degrees(), 0.0); - assert_approx_eq!((-5.8f16).to_degrees(), -332.315521, TOL_P2); - assert_approx_eq!(pi.to_degrees(), 180.0, TOL_P2); - assert!(nan.to_degrees().is_nan()); - assert_eq!(inf.to_degrees(), inf); - assert_eq!(neg_inf.to_degrees(), neg_inf); - assert_eq!(1_f16.to_degrees(), 57.2957795130823208767981548141051703); -} - -#[test] -fn test_to_radians() { - let pi: f16 = consts::PI; - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_eq!(0.0f16.to_radians(), 0.0); - assert_approx_eq!(154.6f16.to_radians(), 2.698279, TOL_0); - assert_approx_eq!((-332.31f16).to_radians(), -5.799903, TOL_0); - assert_approx_eq!(180.0f16.to_radians(), pi, TOL_0); - assert!(nan.to_radians().is_nan()); - assert_eq!(inf.to_radians(), inf); - assert_eq!(neg_inf.to_radians(), neg_inf); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_asinh() { - assert_eq!(0.0f16.asinh(), 0.0f16); - assert_eq!((-0.0f16).asinh(), -0.0f16); - - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let nan: f16 = f16::NAN; - assert_eq!(inf.asinh(), inf); - assert_eq!(neg_inf.asinh(), neg_inf); - assert!(nan.asinh().is_nan()); - assert!((-0.0f16).asinh().is_sign_negative()); - // issue 63271 - assert_approx_eq!(2.0f16.asinh(), 1.443635475178810342493276740273105f16, TOL_0); - assert_approx_eq!((-2.0f16).asinh(), -1.443635475178810342493276740273105f16, TOL_0); - // regression test for the catastrophic cancellation fixed in 72486 - assert_approx_eq!((-200.0f16).asinh(), -5.991470797049389, TOL_0); - - // test for low accuracy from issue 104548 - assert_approx_eq!(10.0f16, 10.0f16.sinh().asinh(), TOL_0); - // mul needed for approximate comparison to be meaningful - assert_approx_eq!(1.0f16, 1e-3f16.sinh().asinh() * 1e3f16, TOL_0); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_acosh() { - assert_eq!(1.0f16.acosh(), 0.0f16); - assert!(0.999f16.acosh().is_nan()); - - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let nan: f16 = f16::NAN; - assert_eq!(inf.acosh(), inf); - assert!(neg_inf.acosh().is_nan()); - assert!(nan.acosh().is_nan()); - assert_approx_eq!(2.0f16.acosh(), 1.31695789692481670862504634730796844f16, TOL_0); - assert_approx_eq!(3.0f16.acosh(), 1.76274717403908605046521864995958461f16, TOL_0); - - // test for low accuracy from issue 104548 - assert_approx_eq!(10.0f16, 10.0f16.cosh().acosh(), TOL_P2); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_atanh() { - assert_eq!(0.0f16.atanh(), 0.0f16); - assert_eq!((-0.0f16).atanh(), -0.0f16); - - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let nan: f16 = f16::NAN; - assert_eq!(1.0f16.atanh(), inf); - assert_eq!((-1.0f16).atanh(), neg_inf); - assert!(2f16.atanh().atanh().is_nan()); - assert!((-2f16).atanh().atanh().is_nan()); - assert!(inf.atanh().is_nan()); - assert!(neg_inf.atanh().is_nan()); - assert!(nan.atanh().is_nan()); - assert_approx_eq!(0.5f16.atanh(), 0.54930614433405484569762261846126285f16, TOL_0); - assert_approx_eq!((-0.5f16).atanh(), -0.54930614433405484569762261846126285f16, TOL_0); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_gamma() { - // precision can differ among platforms - assert_approx_eq!(1.0f16.gamma(), 1.0f16, TOL_0); - assert_approx_eq!(2.0f16.gamma(), 1.0f16, TOL_0); - assert_approx_eq!(3.0f16.gamma(), 2.0f16, TOL_0); - assert_approx_eq!(4.0f16.gamma(), 6.0f16, TOL_0); - assert_approx_eq!(5.0f16.gamma(), 24.0f16, TOL_0); - assert_approx_eq!(0.5f16.gamma(), consts::PI.sqrt(), TOL_0); - assert_approx_eq!((-0.5f16).gamma(), -2.0 * consts::PI.sqrt(), TOL_0); - assert_eq!(0.0f16.gamma(), f16::INFINITY); - assert_eq!((-0.0f16).gamma(), f16::NEG_INFINITY); - assert!((-1.0f16).gamma().is_nan()); - assert!((-2.0f16).gamma().is_nan()); - assert!(f16::NAN.gamma().is_nan()); - assert!(f16::NEG_INFINITY.gamma().is_nan()); - assert_eq!(f16::INFINITY.gamma(), f16::INFINITY); - assert_eq!(171.71f16.gamma(), f16::INFINITY); -} - -#[test] -#[cfg(reliable_f16_math)] -fn test_ln_gamma() { - assert_approx_eq!(1.0f16.ln_gamma().0, 0.0f16, TOL_0); - assert_eq!(1.0f16.ln_gamma().1, 1); - assert_approx_eq!(2.0f16.ln_gamma().0, 0.0f16, TOL_0); - assert_eq!(2.0f16.ln_gamma().1, 1); - assert_approx_eq!(3.0f16.ln_gamma().0, 2.0f16.ln(), TOL_0); - assert_eq!(3.0f16.ln_gamma().1, 1); - assert_approx_eq!((-0.5f16).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_0); - assert_eq!((-0.5f16).ln_gamma().1, -1); -} - -#[test] -fn test_real_consts() { - // FIXME(f16_f128): add math tests when available - use super::consts; - - let pi: f16 = consts::PI; - let frac_pi_2: f16 = consts::FRAC_PI_2; - let frac_pi_3: f16 = consts::FRAC_PI_3; - let frac_pi_4: f16 = consts::FRAC_PI_4; - let frac_pi_6: f16 = consts::FRAC_PI_6; - let frac_pi_8: f16 = consts::FRAC_PI_8; - let frac_1_pi: f16 = consts::FRAC_1_PI; - let frac_2_pi: f16 = consts::FRAC_2_PI; - - assert_approx_eq!(frac_pi_2, pi / 2f16, TOL_0); - assert_approx_eq!(frac_pi_3, pi / 3f16, TOL_0); - assert_approx_eq!(frac_pi_4, pi / 4f16, TOL_0); - assert_approx_eq!(frac_pi_6, pi / 6f16, TOL_0); - assert_approx_eq!(frac_pi_8, pi / 8f16, TOL_0); - assert_approx_eq!(frac_1_pi, 1f16 / pi, TOL_0); - assert_approx_eq!(frac_2_pi, 2f16 / pi, TOL_0); - - #[cfg(reliable_f16_math)] - { - let frac_2_sqrtpi: f16 = consts::FRAC_2_SQRT_PI; - let sqrt2: f16 = consts::SQRT_2; - let frac_1_sqrt2: f16 = consts::FRAC_1_SQRT_2; - let e: f16 = consts::E; - let log2_e: f16 = consts::LOG2_E; - let log10_e: f16 = consts::LOG10_E; - let ln_2: f16 = consts::LN_2; - let ln_10: f16 = consts::LN_10; - - assert_approx_eq!(frac_2_sqrtpi, 2f16 / pi.sqrt(), TOL_0); - assert_approx_eq!(sqrt2, 2f16.sqrt(), TOL_0); - assert_approx_eq!(frac_1_sqrt2, 1f16 / 2f16.sqrt(), TOL_0); - assert_approx_eq!(log2_e, e.log2(), TOL_0); - assert_approx_eq!(log10_e, e.log10(), TOL_0); - assert_approx_eq!(ln_2, 2f16.ln(), TOL_0); - assert_approx_eq!(ln_10, 10f16.ln(), TOL_0); - } -} - -#[test] -fn test_float_bits_conv() { - assert_eq!((1f16).to_bits(), 0x3c00); - assert_eq!((12.5f16).to_bits(), 0x4a40); - assert_eq!((1337f16).to_bits(), 0x6539); - assert_eq!((-14.25f16).to_bits(), 0xcb20); - assert_approx_eq!(f16::from_bits(0x3c00), 1.0, TOL_0); - assert_approx_eq!(f16::from_bits(0x4a40), 12.5, TOL_0); - assert_approx_eq!(f16::from_bits(0x6539), 1337.0, TOL_P4); - assert_approx_eq!(f16::from_bits(0xcb20), -14.25, TOL_0); - - // Check that NaNs roundtrip their bits regardless of signaling-ness - let masked_nan1 = f16::NAN.to_bits() ^ NAN_MASK1; - let masked_nan2 = f16::NAN.to_bits() ^ NAN_MASK2; - assert!(f16::from_bits(masked_nan1).is_nan()); - assert!(f16::from_bits(masked_nan2).is_nan()); - - assert_eq!(f16::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f16::from_bits(masked_nan2).to_bits(), masked_nan2); -} - -#[test] -#[should_panic] -fn test_clamp_min_greater_than_max() { - let _ = 1.0f16.clamp(3.0, 1.0); -} - -#[test] -#[should_panic] -fn test_clamp_min_is_nan() { - let _ = 1.0f16.clamp(f16::NAN, 1.0); -} - -#[test] -#[should_panic] -fn test_clamp_max_is_nan() { - let _ = 1.0f16.clamp(3.0, f16::NAN); -} - -#[test] -fn test_total_cmp() { - use core::cmp::Ordering; - - fn quiet_bit_mask() -> u16 { - 1 << (f16::MANTISSA_DIGITS - 2) - } - - // FIXME(f16_f128): test subnormals when powf is available - // fn min_subnorm() -> f16 { - // f16::MIN_POSITIVE / f16::powf(2.0, f16::MANTISSA_DIGITS as f16 - 1.0) - // } - - // fn max_subnorm() -> f16 { - // f16::MIN_POSITIVE - min_subnorm() - // } - - fn q_nan() -> f16 { - f16::from_bits(f16::NAN.to_bits() | quiet_bit_mask()) - } - - fn s_nan() -> f16 { - f16::from_bits((f16::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, (-f16::INFINITY).total_cmp(&-f16::INFINITY)); - assert_eq!(Ordering::Equal, (-f16::MAX).total_cmp(&-f16::MAX)); - assert_eq!(Ordering::Equal, (-2.5_f16).total_cmp(&-2.5)); - assert_eq!(Ordering::Equal, (-1.0_f16).total_cmp(&-1.0)); - assert_eq!(Ordering::Equal, (-1.5_f16).total_cmp(&-1.5)); - assert_eq!(Ordering::Equal, (-0.5_f16).total_cmp(&-0.5)); - assert_eq!(Ordering::Equal, (-f16::MIN_POSITIVE).total_cmp(&-f16::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_f16).total_cmp(&-0.0)); - assert_eq!(Ordering::Equal, 0.0_f16.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, f16::MIN_POSITIVE.total_cmp(&f16::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, 0.5_f16.total_cmp(&0.5)); - assert_eq!(Ordering::Equal, 1.0_f16.total_cmp(&1.0)); - assert_eq!(Ordering::Equal, 1.5_f16.total_cmp(&1.5)); - assert_eq!(Ordering::Equal, 2.5_f16.total_cmp(&2.5)); - assert_eq!(Ordering::Equal, f16::MAX.total_cmp(&f16::MAX)); - assert_eq!(Ordering::Equal, f16::INFINITY.total_cmp(&f16::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(&-f16::INFINITY)); - assert_eq!(Ordering::Less, (-f16::INFINITY).total_cmp(&-f16::MAX)); - assert_eq!(Ordering::Less, (-f16::MAX).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-2.5_f16).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-1.5_f16).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-1.0_f16).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-0.5_f16).total_cmp(&-f16::MIN_POSITIVE)); - // assert_eq!(Ordering::Less, (-f16::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_f16).total_cmp(&0.0)); - // assert_eq!(Ordering::Less, 0.0_f16.total_cmp(&min_subnorm())); - // assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); - // assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f16::MIN_POSITIVE)); - assert_eq!(Ordering::Less, f16::MIN_POSITIVE.total_cmp(&0.5)); - assert_eq!(Ordering::Less, 0.5_f16.total_cmp(&1.0)); - assert_eq!(Ordering::Less, 1.0_f16.total_cmp(&1.5)); - assert_eq!(Ordering::Less, 1.5_f16.total_cmp(&2.5)); - assert_eq!(Ordering::Less, 2.5_f16.total_cmp(&f16::MAX)); - assert_eq!(Ordering::Less, f16::MAX.total_cmp(&f16::INFINITY)); - assert_eq!(Ordering::Less, f16::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, (-f16::INFINITY).total_cmp(&-s_nan())); - assert_eq!(Ordering::Greater, (-f16::MAX).total_cmp(&-f16::INFINITY)); - assert_eq!(Ordering::Greater, (-2.5_f16).total_cmp(&-f16::MAX)); - assert_eq!(Ordering::Greater, (-1.5_f16).total_cmp(&-2.5)); - assert_eq!(Ordering::Greater, (-1.0_f16).total_cmp(&-1.5)); - assert_eq!(Ordering::Greater, (-0.5_f16).total_cmp(&-1.0)); - assert_eq!(Ordering::Greater, (-f16::MIN_POSITIVE).total_cmp(&-0.5)); - // assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f16::MIN_POSITIVE)); - // assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); - // assert_eq!(Ordering::Greater, (-0.0_f16).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Greater, 0.0_f16.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, f16::MIN_POSITIVE.total_cmp(&max_subnorm())); - assert_eq!(Ordering::Greater, 0.5_f16.total_cmp(&f16::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, 1.0_f16.total_cmp(&0.5)); - assert_eq!(Ordering::Greater, 1.5_f16.total_cmp(&1.0)); - assert_eq!(Ordering::Greater, 2.5_f16.total_cmp(&1.5)); - assert_eq!(Ordering::Greater, f16::MAX.total_cmp(&2.5)); - assert_eq!(Ordering::Greater, f16::INFINITY.total_cmp(&f16::MAX)); - assert_eq!(Ordering::Greater, s_nan().total_cmp(&f16::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(&-f16::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f16::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(&-f16::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(&f16::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(&f16::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f16::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f16::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f16::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(&-f16::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(&f16::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(&f16::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f16::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); -} diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index f9b6723788a..260c499b7f4 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -12,9 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#[cfg(test)] -mod tests; - #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::f32::{ diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs deleted file mode 100644 index 99cfcfb231d..00000000000 --- a/library/std/src/f32/tests.rs +++ /dev/null @@ -1,919 +0,0 @@ -use crate::f32::consts; -use crate::num::{FpCategory as Fp, *}; - -/// Smallest number -const TINY_BITS: u32 = 0x1; - -/// Next smallest number -const TINY_UP_BITS: u32 = 0x2; - -/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 -const MAX_DOWN_BITS: u32 = 0x7f7f_fffe; - -/// Zeroed exponent, full significant -const LARGEST_SUBNORMAL_BITS: u32 = 0x007f_ffff; - -/// Exponent = 0b1, zeroed significand -const SMALLEST_NORMAL_BITS: u32 = 0x0080_0000; - -/// First pattern over the mantissa -const NAN_MASK1: u32 = 0x002a_aaaa; - -/// Second pattern over the mantissa -const NAN_MASK2: u32 = 0x0055_5555; - -#[allow(unused_macros)] -macro_rules! assert_f32_biteq { - ($left : expr, $right : expr) => { - let l: &f32 = &$left; - let r: &f32 = &$right; - let lb = l.to_bits(); - let rb = r.to_bits(); - assert_eq!(lb, rb, "float {l} ({lb:#010x}) is not bitequal to {r} ({rb:#010x})"); - }; -} - -#[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_minimum() { - assert!(f32::NAN.minimum(2.0).is_nan()); - assert!(2.0f32.minimum(f32::NAN).is_nan()); -} - -#[test] -fn test_maximum() { - assert!(f32::NAN.maximum(2.0).is_nan()); - assert!(2.0f32.maximum(f32::NAN).is_nan()); -} - -#[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!(2.5f32.round(), 3.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); - 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_round_ties_even() { - assert_approx_eq!(2.5f32.round_ties_even(), 2.0f32); - assert_approx_eq!(1.0f32.round_ties_even(), 1.0f32); - assert_approx_eq!(1.3f32.round_ties_even(), 1.0f32); - assert_approx_eq!(1.5f32.round_ties_even(), 2.0f32); - assert_approx_eq!(1.7f32.round_ties_even(), 2.0f32); - assert_approx_eq!(0.0f32.round_ties_even(), 0.0f32); - assert_approx_eq!((-0.0f32).round_ties_even(), -0.0f32); - assert_approx_eq!((-1.0f32).round_ties_even(), -1.0f32); - assert_approx_eq!((-1.3f32).round_ties_even(), -1.0f32); - assert_approx_eq!((-1.5f32).round_ties_even(), -2.0f32); - assert_approx_eq!((-1.7f32).round_ties_even(), -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_next_up() { - let tiny = f32::from_bits(TINY_BITS); - let tiny_up = f32::from_bits(TINY_UP_BITS); - let max_down = f32::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f32::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f32::from_bits(SMALLEST_NORMAL_BITS); - assert_f32_biteq!(f32::NEG_INFINITY.next_up(), f32::MIN); - assert_f32_biteq!(f32::MIN.next_up(), -max_down); - assert_f32_biteq!((-1.0 - f32::EPSILON).next_up(), -1.0); - assert_f32_biteq!((-smallest_normal).next_up(), -largest_subnormal); - assert_f32_biteq!((-tiny_up).next_up(), -tiny); - assert_f32_biteq!((-tiny).next_up(), -0.0f32); - assert_f32_biteq!((-0.0f32).next_up(), tiny); - assert_f32_biteq!(0.0f32.next_up(), tiny); - assert_f32_biteq!(tiny.next_up(), tiny_up); - assert_f32_biteq!(largest_subnormal.next_up(), smallest_normal); - assert_f32_biteq!(1.0f32.next_up(), 1.0 + f32::EPSILON); - assert_f32_biteq!(f32::MAX.next_up(), f32::INFINITY); - assert_f32_biteq!(f32::INFINITY.next_up(), f32::INFINITY); - - // Check that NaNs roundtrip. - let nan0 = f32::NAN; - let nan1 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK1); - let nan2 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK2); - assert_f32_biteq!(nan0.next_up(), nan0); - assert_f32_biteq!(nan1.next_up(), nan1); - assert_f32_biteq!(nan2.next_up(), nan2); -} - -#[test] -fn test_next_down() { - let tiny = f32::from_bits(TINY_BITS); - let tiny_up = f32::from_bits(TINY_UP_BITS); - let max_down = f32::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f32::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f32::from_bits(SMALLEST_NORMAL_BITS); - assert_f32_biteq!(f32::NEG_INFINITY.next_down(), f32::NEG_INFINITY); - assert_f32_biteq!(f32::MIN.next_down(), f32::NEG_INFINITY); - assert_f32_biteq!((-max_down).next_down(), f32::MIN); - assert_f32_biteq!((-1.0f32).next_down(), -1.0 - f32::EPSILON); - assert_f32_biteq!((-largest_subnormal).next_down(), -smallest_normal); - assert_f32_biteq!((-tiny).next_down(), -tiny_up); - assert_f32_biteq!((-0.0f32).next_down(), -tiny); - assert_f32_biteq!((0.0f32).next_down(), -tiny); - assert_f32_biteq!(tiny.next_down(), 0.0f32); - assert_f32_biteq!(tiny_up.next_down(), tiny); - assert_f32_biteq!(smallest_normal.next_down(), largest_subnormal); - assert_f32_biteq!((1.0 + f32::EPSILON).next_down(), 1.0f32); - assert_f32_biteq!(f32::MAX.next_down(), max_down); - assert_f32_biteq!(f32::INFINITY.next_down(), f32::MAX); - - // Check that NaNs roundtrip. - let nan0 = f32::NAN; - let nan1 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK1); - let nan2 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK2); - assert_f32_biteq!(nan0.next_down(), nan0); - assert_f32_biteq!(nan1.next_down(), nan1); - assert_f32_biteq!(nan2.next_down(), nan2); -} - -#[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 for low accuracy from issue 104548 - assert_approx_eq!(60.0f32, 60.0f32.sinh().asinh()); - // mul needed for approximate comparison to be meaningful - assert_approx_eq!(1.0f32, 1e-15f32.sinh().asinh() * 1e15f32); -} - -#[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 for low accuracy from issue 104548 - assert_approx_eq!(60.0f32, 60.0f32.cosh().acosh()); -} - -#[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_gamma() { - // precision can differ between platforms - assert_approx_eq!(1.0f32.gamma(), 1.0f32); - assert_approx_eq!(2.0f32.gamma(), 1.0f32); - assert_approx_eq!(3.0f32.gamma(), 2.0f32); - assert_approx_eq!(4.0f32.gamma(), 6.0f32); - assert_approx_eq!(5.0f32.gamma(), 24.0f32); - assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt()); - assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt()); - assert_eq!(0.0f32.gamma(), f32::INFINITY); - assert_eq!((-0.0f32).gamma(), f32::NEG_INFINITY); - assert!((-1.0f32).gamma().is_nan()); - assert!((-2.0f32).gamma().is_nan()); - assert!(f32::NAN.gamma().is_nan()); - assert!(f32::NEG_INFINITY.gamma().is_nan()); - assert_eq!(f32::INFINITY.gamma(), f32::INFINITY); - assert_eq!(171.71f32.gamma(), f32::INFINITY); -} - -#[test] -fn test_ln_gamma() { - assert_approx_eq!(1.0f32.ln_gamma().0, 0.0f32); - assert_eq!(1.0f32.ln_gamma().1, 1); - assert_approx_eq!(2.0f32.ln_gamma().0, 0.0f32); - assert_eq!(2.0f32.ln_gamma().1, 1); - assert_approx_eq!(3.0f32.ln_gamma().0, 2.0f32.ln()); - assert_eq!(3.0f32.ln_gamma().1, 1); - assert_approx_eq!((-0.5f32).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln()); - assert_eq!((-0.5f32).ln_gamma().1, -1); -} - -#[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() ^ NAN_MASK1; - let masked_nan2 = f32::NAN.to_bits() ^ NAN_MASK2; - 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/f64.rs b/library/std/src/f64.rs index 0de55a15d48..7af646f8cfd 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -12,9 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#[cfg(test)] -mod tests; - #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::f64::{ diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs deleted file mode 100644 index f5ba2c7b594..00000000000 --- a/library/std/src/f64/tests.rs +++ /dev/null @@ -1,897 +0,0 @@ -use crate::f64::consts; -use crate::num::{FpCategory as Fp, *}; - -/// Smallest number -const TINY_BITS: u64 = 0x1; - -/// Next smallest number -const TINY_UP_BITS: u64 = 0x2; - -/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 -const MAX_DOWN_BITS: u64 = 0x7fef_ffff_ffff_fffe; - -/// Zeroed exponent, full significant -const LARGEST_SUBNORMAL_BITS: u64 = 0x000f_ffff_ffff_ffff; - -/// Exponent = 0b1, zeroed significand -const SMALLEST_NORMAL_BITS: u64 = 0x0010_0000_0000_0000; - -/// First pattern over the mantissa -const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; - -/// Second pattern over the mantissa -const NAN_MASK2: u64 = 0x0005_5555_5555_5555; - -#[allow(unused_macros)] -macro_rules! assert_f64_biteq { - ($left : expr, $right : expr) => { - let l: &f64 = &$left; - let r: &f64 = &$right; - let lb = l.to_bits(); - let rb = r.to_bits(); - assert_eq!(lb, rb, "float {l} ({lb:#018x}) is not bitequal to {r} ({rb:#018x})"); - }; -} - -#[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()); -} - -#[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()); -} - -#[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()); -} - -#[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!(2.5f64.round(), 3.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); - 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_round_ties_even() { - assert_approx_eq!(2.5f64.round_ties_even(), 2.0f64); - assert_approx_eq!(1.0f64.round_ties_even(), 1.0f64); - assert_approx_eq!(1.3f64.round_ties_even(), 1.0f64); - assert_approx_eq!(1.5f64.round_ties_even(), 2.0f64); - assert_approx_eq!(1.7f64.round_ties_even(), 2.0f64); - assert_approx_eq!(0.0f64.round_ties_even(), 0.0f64); - assert_approx_eq!((-0.0f64).round_ties_even(), -0.0f64); - assert_approx_eq!((-1.0f64).round_ties_even(), -1.0f64); - assert_approx_eq!((-1.3f64).round_ties_even(), -1.0f64); - assert_approx_eq!((-1.5f64).round_ties_even(), -2.0f64); - assert_approx_eq!((-1.7f64).round_ties_even(), -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_next_up() { - let tiny = f64::from_bits(TINY_BITS); - let tiny_up = f64::from_bits(TINY_UP_BITS); - let max_down = f64::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f64::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f64::from_bits(SMALLEST_NORMAL_BITS); - assert_f64_biteq!(f64::NEG_INFINITY.next_up(), f64::MIN); - assert_f64_biteq!(f64::MIN.next_up(), -max_down); - assert_f64_biteq!((-1.0 - f64::EPSILON).next_up(), -1.0); - assert_f64_biteq!((-smallest_normal).next_up(), -largest_subnormal); - assert_f64_biteq!((-tiny_up).next_up(), -tiny); - assert_f64_biteq!((-tiny).next_up(), -0.0f64); - assert_f64_biteq!((-0.0f64).next_up(), tiny); - assert_f64_biteq!(0.0f64.next_up(), tiny); - assert_f64_biteq!(tiny.next_up(), tiny_up); - assert_f64_biteq!(largest_subnormal.next_up(), smallest_normal); - assert_f64_biteq!(1.0f64.next_up(), 1.0 + f64::EPSILON); - assert_f64_biteq!(f64::MAX.next_up(), f64::INFINITY); - assert_f64_biteq!(f64::INFINITY.next_up(), f64::INFINITY); - - let nan0 = f64::NAN; - let nan1 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK1); - let nan2 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK2); - assert_f64_biteq!(nan0.next_up(), nan0); - assert_f64_biteq!(nan1.next_up(), nan1); - assert_f64_biteq!(nan2.next_up(), nan2); -} - -#[test] -fn test_next_down() { - let tiny = f64::from_bits(TINY_BITS); - let tiny_up = f64::from_bits(TINY_UP_BITS); - let max_down = f64::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f64::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f64::from_bits(SMALLEST_NORMAL_BITS); - assert_f64_biteq!(f64::NEG_INFINITY.next_down(), f64::NEG_INFINITY); - assert_f64_biteq!(f64::MIN.next_down(), f64::NEG_INFINITY); - assert_f64_biteq!((-max_down).next_down(), f64::MIN); - assert_f64_biteq!((-1.0f64).next_down(), -1.0 - f64::EPSILON); - assert_f64_biteq!((-largest_subnormal).next_down(), -smallest_normal); - assert_f64_biteq!((-tiny).next_down(), -tiny_up); - assert_f64_biteq!((-0.0f64).next_down(), -tiny); - assert_f64_biteq!((0.0f64).next_down(), -tiny); - assert_f64_biteq!(tiny.next_down(), 0.0f64); - assert_f64_biteq!(tiny_up.next_down(), tiny); - assert_f64_biteq!(smallest_normal.next_down(), largest_subnormal); - assert_f64_biteq!((1.0 + f64::EPSILON).next_down(), 1.0f64); - assert_f64_biteq!(f64::MAX.next_down(), max_down); - assert_f64_biteq!(f64::INFINITY.next_down(), f64::MAX); - - let nan0 = f64::NAN; - let nan1 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK1); - let nan2 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK2); - assert_f64_biteq!(nan0.next_down(), nan0); - assert_f64_biteq!(nan1.next_down(), nan1); - assert_f64_biteq!(nan2.next_down(), nan2); -} - -#[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 for low accuracy from issue 104548 - assert_approx_eq!(60.0f64, 60.0f64.sinh().asinh()); - // mul needed for approximate comparison to be meaningful - assert_approx_eq!(1.0f64, 1e-15f64.sinh().asinh() * 1e15f64); -} - -#[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 for low accuracy from issue 104548 - assert_approx_eq!(60.0f64, 60.0f64.cosh().acosh()); -} - -#[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_gamma() { - // precision can differ between platforms - assert_approx_eq!(1.0f64.gamma(), 1.0f64); - assert_approx_eq!(2.0f64.gamma(), 1.0f64); - assert_approx_eq!(3.0f64.gamma(), 2.0f64); - assert_approx_eq!(4.0f64.gamma(), 6.0f64); - assert_approx_eq!(5.0f64.gamma(), 24.0f64); - assert_approx_eq!(0.5f64.gamma(), consts::PI.sqrt()); - assert_approx_eq!((-0.5f64).gamma(), -2.0 * consts::PI.sqrt()); - assert_eq!(0.0f64.gamma(), f64::INFINITY); - assert_eq!((-0.0f64).gamma(), f64::NEG_INFINITY); - assert!((-1.0f64).gamma().is_nan()); - assert!((-2.0f64).gamma().is_nan()); - assert!(f64::NAN.gamma().is_nan()); - assert!(f64::NEG_INFINITY.gamma().is_nan()); - assert_eq!(f64::INFINITY.gamma(), f64::INFINITY); - assert_eq!(171.71f64.gamma(), f64::INFINITY); -} - -#[test] -fn test_ln_gamma() { - assert_approx_eq!(1.0f64.ln_gamma().0, 0.0f64); - assert_eq!(1.0f64.ln_gamma().1, 1); - assert_approx_eq!(2.0f64.ln_gamma().0, 0.0f64); - assert_eq!(2.0f64.ln_gamma().1, 1); - assert_approx_eq!(3.0f64.ln_gamma().0, 2.0f64.ln()); - assert_eq!(3.0f64.ln_gamma().1, 1); - assert_approx_eq!((-0.5f64).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln()); - assert_eq!((-0.5f64).ln_gamma().1, -1); -} - -#[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 - let masked_nan1 = f64::NAN.to_bits() ^ NAN_MASK1; - let masked_nan2 = f64::NAN.to_bits() ^ NAN_MASK2; - 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/macros.rs b/library/std/src/macros.rs index 1b0d7f3dbf2..e0f9f0bb5ce 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -372,18 +372,3 @@ macro_rules! dbg { ($($crate::dbg!($val)),+,) }; } - -/// Verify that floats are within a tolerance of each other, 1.0e-6 by default. -#[cfg(test)] -macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; - ($a:expr, $b:expr, $lim:expr) => {{ - let (a, b) = (&$a, &$b); - let diff = (*a - *b).abs(); - assert!( - diff < $lim, - "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, difference {diff:?})", - lim = $lim - ); - }}; -} diff --git a/library/std/src/num.rs b/library/std/src/num.rs index d2f679e7dde..ffb8789c906 100644 --- a/library/std/src/num.rs +++ b/library/std/src/num.rs @@ -6,9 +6,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#[cfg(test)] -mod tests; - #[stable(feature = "int_error_matching", since = "1.55.0")] pub use core::num::IntErrorKind; #[stable(feature = "generic_nonzero", since = "1.79.0")] @@ -29,28 +26,3 @@ pub use core::num::{FpCategory, ParseFloatError, ParseIntError, TryFromIntError} pub use core::num::{NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize}; #[stable(feature = "nonzero", since = "1.28.0")] pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; - -#[cfg(test)] -use crate::fmt; -#[cfg(test)] -use crate::ops::{Add, Div, Mul, Rem, Sub}; - -/// Helper function for testing numeric operations -#[cfg(test)] -pub fn test_num<T>(ten: T, two: T) -where - T: PartialEq - + Add<Output = T> - + Sub<Output = T> - + Mul<Output = T> - + Div<Output = T> - + Rem<Output = T> - + fmt::Debug - + Copy, -{ - assert_eq!(ten.add(two), ten + two); - assert_eq!(ten.sub(two), ten - two); - assert_eq!(ten.mul(two), ten * two); - assert_eq!(ten.div(two), ten / two); - assert_eq!(ten.rem(two), ten % two); -} diff --git a/library/std/src/num/tests.rs b/library/std/src/num/tests.rs deleted file mode 100644 index df0df3f23f7..00000000000 --- a/library/std/src/num/tests.rs +++ /dev/null @@ -1,230 +0,0 @@ -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) => { - #[test] - fn $test_name() { - 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) => { - #[test] - fn $test_name() { - 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) => { - #[test] - fn $test_name() { - 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); -} diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index d649357a56d..153189b8b03 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -529,6 +529,3 @@ pub fn get_backtrace_style() -> Option<BacktraceStyle> { Err(new) => BacktraceStyle::from_u8(new), } } - -#[cfg(test)] -mod tests; diff --git a/library/std/src/panic/tests.rs b/library/std/src/panic/tests.rs deleted file mode 100644 index b37d74011cc..00000000000 --- a/library/std/src/panic/tests.rs +++ /dev/null @@ -1,56 +0,0 @@ -#![allow(dead_code)] - -use crate::cell::RefCell; -use crate::panic::{AssertUnwindSafe, UnwindSafe}; -use crate::rc::Rc; -use crate::sync::{Arc, Mutex, RwLock}; - -struct Foo { - a: i32, -} - -fn assert<T: UnwindSafe + ?Sized>() {} - -#[test] -fn panic_safety_traits() { - assert::<i32>(); - assert::<&i32>(); - assert::<*mut i32>(); - assert::<*const i32>(); - assert::<usize>(); - assert::<str>(); - assert::<&str>(); - assert::<Foo>(); - assert::<&Foo>(); - assert::<Vec<i32>>(); - assert::<String>(); - assert::<RefCell<i32>>(); - assert::<Box<i32>>(); - assert::<Mutex<i32>>(); - assert::<RwLock<i32>>(); - assert::<&Mutex<i32>>(); - assert::<&RwLock<i32>>(); - assert::<Rc<i32>>(); - assert::<Arc<i32>>(); - assert::<Box<[u8]>>(); - - { - trait Trait: UnwindSafe {} - assert::<Box<dyn Trait>>(); - } - - fn bar<T>() { - assert::<Mutex<T>>(); - assert::<RwLock<T>>(); - } - - fn baz<T: UnwindSafe>() { - assert::<Box<T>>(); - assert::<Vec<T>>(); - assert::<RefCell<T>>(); - assert::<AssertUnwindSafe<T>>(); - assert::<&AssertUnwindSafe<T>>(); - assert::<Rc<AssertUnwindSafe<T>>>(); - assert::<Arc<AssertUnwindSafe<T>>>(); - } -} diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 7fd08a97f1f..97e17acadea 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -67,9 +67,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] -#[cfg(test)] -mod tests; - use core::clone::CloneToUninit; use crate::borrow::{Borrow, Cow}; diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs deleted file mode 100644 index 3f96ac4672a..00000000000 --- a/library/std/src/path/tests.rs +++ /dev/null @@ -1,2079 +0,0 @@ -use core::hint::black_box; - -use super::*; -use crate::collections::{BTreeSet, HashSet}; -use crate::hash::DefaultHasher; -use crate::mem::MaybeUninit; -use crate::ptr; - -#[allow(unknown_lints, unused_macro_rules)] -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, file_prefix: $file_prefix:expr, extension: $extension:expr) => ( - { - let path = Path::new($path); - - let prefix = path.file_prefix().map(|p| p.to_str().unwrap()); - let exp_prefix: Option<&str> = $file_prefix; - assert!(prefix == exp_prefix, "file_prefix: Expected {:?}, found {:?}", - exp_prefix, prefix); - - 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, - file_prefix: $file_prefix: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); - t!($path, file_prefix: $file_prefix, 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] -fn test_pathbuf_leak() { - let string = "/have/a/cake".to_owned(); - let (len, cap) = (string.len(), string.capacity()); - let buf = PathBuf::from(string); - let leaked = buf.leak(); - assert_eq!(leaked.as_os_str().as_encoded_bytes(), b"/have/a/cake"); - unsafe { drop(String::from_raw_parts(leaked.as_mut_os_str() as *mut OsStr as _, len, cap)) } -} - -#[test] -#[cfg(any(unix, target_os = "wasi"))] -pub fn test_decompositions_unix() { - t!("", - iter: [], - has_root: false, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("foo", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - t!("/", - iter: ["/"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("/foo", - iter: ["/", "foo"], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - t!("foo/", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - t!("/foo/", - iter: ["/", "foo"], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - 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, - file_prefix: Some("bar") - ); - - 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, - file_prefix: Some("bar") - ); - - t!("///foo///", - iter: ["/", "foo"], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - 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, - file_prefix: Some("bar") - ); - - t!("./.", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("/..", - iter: ["/", ".."], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("../", - iter: [".."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("foo/.", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - t!("foo/..", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("foo/./", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - 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, - file_prefix: Some("bar") - ); - - t!("foo/../", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None, - file_prefix: 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, - file_prefix: Some("bar") - ); - - t!("./a", - iter: [".", "a"], - has_root: false, - is_absolute: false, - parent: Some("."), - file_name: Some("a"), - file_stem: Some("a"), - extension: None, - file_prefix: Some("a") - ); - - t!(".", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("./", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None, - file_prefix: 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, - file_prefix: Some("b") - ); - - 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, - file_prefix: Some("b") - ); - - 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, - file_prefix: Some("b") - ); - - 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, - file_prefix: Some("c") - ); - - t!(".foo", - iter: [".foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some(".foo"), - file_stem: Some(".foo"), - extension: None, - file_prefix: Some(".foo") - ); - - t!("a/.foo", - iter: ["a", ".foo"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some(".foo"), - file_stem: Some(".foo"), - extension: None, - file_prefix: Some(".foo") - ); - - t!("a/.rustfmt.toml", - iter: ["a", ".rustfmt.toml"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some(".rustfmt.toml"), - file_stem: Some(".rustfmt"), - extension: Some("toml"), - file_prefix: Some(".rustfmt") - ); - - t!("a/.x.y.z", - iter: ["a", ".x.y.z"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some(".x.y.z"), - file_stem: Some(".x.y"), - extension: Some("z"), - file_prefix: Some(".x") - ); -} - -#[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, - file_prefix: None - ); - - t!("foo", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - t!("/", - iter: ["\\"], - has_root: true, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("\\", - iter: ["\\"], - has_root: true, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("c:", - iter: ["c:"], - has_root: false, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("c:\\", - iter: ["c:", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("c:/", - iter: ["c:", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("/foo", - iter: ["\\", "foo"], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - t!("foo/", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - t!("/foo/", - iter: ["\\", "foo"], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - 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, - file_prefix: Some("bar") - ); - - 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, - file_prefix: Some("bar") - ); - - t!("///foo///", - iter: ["\\", "foo"], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - 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, - file_prefix: Some("bar") - ); - - t!("./.", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("/..", - iter: ["\\", ".."], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("../", - iter: [".."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("foo/.", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - t!("foo/..", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("foo/./", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None, - file_prefix: Some("foo") - ); - - 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, - file_prefix: Some("bar") - ); - - t!("foo/../", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None, - file_prefix: 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, - file_prefix: Some("bar") - ); - - t!("./a", - iter: [".", "a"], - has_root: false, - is_absolute: false, - parent: Some("."), - file_name: Some("a"), - file_stem: Some("a"), - extension: None, - file_prefix: Some("a") - ); - - t!(".", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("./", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None, - file_prefix: 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, - file_prefix: Some("b") - ); - - 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, - file_prefix: Some("b") - ); - - 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, - file_prefix: Some("b") - ); - - 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, - file_prefix: Some("c") - ); - - 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, - file_prefix: Some("c") - ); - - t!("\\a", - iter: ["\\", "a"], - has_root: true, - is_absolute: false, - parent: Some("\\"), - file_name: Some("a"), - file_stem: Some("a"), - extension: None, - file_prefix: Some("a") - ); - - 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"), - file_prefix: Some("foo") - ); - - 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"), - file_prefix: Some("foo") - ); - - t!("\\\\server\\share", - iter: ["\\\\server\\share", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("\\\\server", - iter: ["\\", "server"], - has_root: true, - is_absolute: false, - parent: Some("\\"), - file_name: Some("server"), - file_stem: Some("server"), - extension: None, - file_prefix: Some("server") - ); - - 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"), - file_prefix: Some("foo") - ); - - t!("\\\\?\\bar", - iter: ["\\\\?\\bar"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("\\\\?\\", - iter: ["\\\\?\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: 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"), - file_prefix: Some("foo") - ); - - t!("\\\\?\\UNC\\server", - iter: ["\\\\?\\UNC\\server"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("\\\\?\\UNC\\", - iter: ["\\\\?\\UNC\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: 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"), - file_prefix: Some("foo") - ); - - t!("\\\\?\\C:\\", - iter: ["\\\\?\\C:", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("\\\\?\\C:", - iter: ["\\\\?\\C:"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("\\\\?\\foo/bar", - iter: ["\\\\?\\foo/bar"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: None - ); - - t!("\\\\?\\C:/foo/bar", - iter: ["\\\\?\\C:", "\\", "foo/bar"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\C:/"), - file_name: Some("foo/bar"), - file_stem: Some("foo/bar"), - extension: None, - file_prefix: Some("foo/bar") - ); - - 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, - file_prefix: Some("bar") - ); - - t!("\\\\.\\foo", - iter: ["\\\\.\\foo", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: 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, - file_prefix: Some("bar") - ); - - 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, - file_prefix: Some("baz") - ); - - t!("\\\\.\\", - iter: ["\\\\.\\", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None, - file_prefix: 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, - file_prefix: Some("b") - ); - - t!("\\\\?\\C:\\foo.txt.zip", - iter: ["\\\\?\\C:", "\\", "foo.txt.zip"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\C:\\"), - file_name: Some("foo.txt.zip"), - file_stem: Some("foo.txt"), - extension: Some("zip"), - file_prefix: Some("foo") - ); - - t!("\\\\?\\C:\\.foo.txt.zip", - iter: ["\\\\?\\C:", "\\", ".foo.txt.zip"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\C:\\"), - file_name: Some(".foo.txt.zip"), - file_stem: Some(".foo.txt"), - extension: Some("zip"), - file_prefix: Some(".foo") - ); - - t!("\\\\?\\C:\\.foo", - iter: ["\\\\?\\C:", "\\", ".foo"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\C:\\"), - file_name: Some(".foo"), - file_stem: Some(".foo"), - extension: None, - file_prefix: Some(".foo") - ); - - t!("a/.x.y.z", - iter: ["a", ".x.y.z"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some(".x.y.z"), - file_stem: Some(".x.y"), - extension: Some("z"), - file_prefix: Some(".x") - ); -} - -#[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!(".x.y.z", file_stem: Some(".x.y"), extension: Some("z")); - - t!("..x.y.z", file_stem: Some("..x.y"), extension: Some("z")); - - t!("", file_stem: None, extension: None); -} - -#[test] -pub fn test_prefix_ext() { - t!("foo", - file_prefix: Some("foo"), - extension: None - ); - - t!("foo.", - file_prefix: Some("foo"), - extension: Some("") - ); - - t!(".foo", - file_prefix: Some(".foo"), - extension: None - ); - - t!("foo.txt", - file_prefix: Some("foo"), - extension: Some("txt") - ); - - t!("foo.bar.txt", - file_prefix: Some("foo"), - extension: Some("txt") - ); - - t!("foo.bar.", - file_prefix: Some("foo"), - extension: Some("") - ); - - t!(".", file_prefix: None, extension: None); - - t!("..", file_prefix: None, extension: None); - - t!(".x.y.z", file_prefix: Some(".x"), extension: Some("z")); - - t!("..x.y.z", file_prefix: Some("."), extension: Some("z")); - - t!("", file_prefix: 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!(target_os = "wasi") - || 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 - - tp!(r"\\?\C:\bar", "../foo", r"\\?\C:\foo"); - tp!(r"\\?\C:\bar", "../../foo", r"\\?\C:\foo"); - tp!(r"\\?\C:\", "../foo", r"\\?\C:\foo"); - tp!(r"\\?\C:", r"D:\foo/./", r"D:\foo/./"); - tp!(r"\\?\C:", r"\\?\D:\foo\.\", r"\\?\D:\foo\.\"); - tp!(r"\\?\A:\x\y", "/foo", r"\\?\A:\foo"); - tp!(r"\\?\A:", r"..\foo\.", r"\\?\A:\foo"); - tp!(r"\\?\A:\x\y", r".\foo\.", r"\\?\A:\x\y\foo"); - tp!(r"\\?\A:\x\y", r"", r"\\?\A:\x\y\"); - } -} - -#[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!(target_os = "wasi") - || 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] -pub fn test_add_extension() { - macro_rules! tfe ( - ($path:expr, $ext:expr, $expected:expr, $output:expr) => ({ - let mut p = PathBuf::from($path); - let output = p.add_extension($ext); - assert!(p.to_str() == Some($expected) && output == $output, - "adding 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.bar.txt", true); - tfe!("foo.bar.baz", "txt", "foo.bar.baz.txt", true); - tfe!(".test", "txt", ".test.txt", true); - tfe!("foo.txt", "", "foo.txt", 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); - - // edge cases - tfe!("/foo.ext////", "bar", "/foo.ext.bar", true); -} - -#[test] -pub fn test_with_extension() { - macro_rules! twe ( - ($input:expr, $extension:expr, $expected:expr) => ({ - let input = Path::new($input); - let output = input.with_extension($extension); - - assert!( - output.to_str() == Some($expected), - "calling Path::new({:?}).with_extension({:?}): Expected {:?}, got {:?}", - $input, $extension, $expected, output, - ); - }); - ); - - twe!("foo", "txt", "foo.txt"); - twe!("foo.bar", "txt", "foo.txt"); - twe!("foo.bar.baz", "txt", "foo.bar.txt"); - twe!(".test", "txt", ".test.txt"); - twe!("foo.txt", "", "foo"); - twe!("foo", "", "foo"); - twe!("", "foo", ""); - twe!(".", "foo", "."); - twe!("foo/", "bar", "foo.bar"); - twe!("foo/.", "bar", "foo.bar"); - twe!("..", "foo", ".."); - twe!("foo/..", "bar", "foo/.."); - twe!("/", "foo", "/"); - - // New extension is smaller than file name - twe!("aaa_aaa_aaa", "bbb_bbb", "aaa_aaa_aaa.bbb_bbb"); - // New extension is greater than file name - twe!("bbb_bbb", "aaa_aaa_aaa", "bbb_bbb.aaa_aaa_aaa"); - - // New extension is smaller than previous extension - twe!("ccc.aaa_aaa_aaa", "bbb_bbb", "ccc.bbb_bbb"); - // New extension is greater than previous extension - twe!("ccc.bbb_bbb", "aaa_aaa_aaa", "ccc.aaa_aaa_aaa"); -} - -#[test] -pub fn test_with_added_extension() { - macro_rules! twe ( - ($input:expr, $extension:expr, $expected:expr) => ({ - let input = Path::new($input); - let output = input.with_added_extension($extension); - - assert!( - output.to_str() == Some($expected), - "calling Path::new({:?}).with_added_extension({:?}): Expected {:?}, got {:?}", - $input, $extension, $expected, output, - ); - }); - ); - - twe!("foo", "txt", "foo.txt"); - twe!("foo.bar", "txt", "foo.bar.txt"); - twe!("foo.bar.baz", "txt", "foo.bar.baz.txt"); - twe!(".test", "txt", ".test.txt"); - twe!("foo.txt", "", "foo.txt"); - twe!("foo", "", "foo"); - twe!("", "foo", ""); - twe!(".", "foo", "."); - twe!("foo/", "bar", "foo.bar"); - twe!("foo/.", "bar", "foo.bar"); - twe!("..", "foo", ".."); - twe!("foo/..", "bar", "foo/.."); - twe!("/", "foo", "/"); - - // edge cases - twe!("/foo.ext////", "bar", "/foo.ext.bar"); - - // New extension is smaller than file name - twe!("aaa_aaa_aaa", "bbb_bbb", "aaa_aaa_aaa.bbb_bbb"); - // New extension is greater than file name - twe!("bbb_bbb", "aaa_aaa_aaa", "bbb_bbb.aaa_aaa_aaa"); - - // New extension is smaller than previous extension - twe!("ccc.aaa_aaa_aaa", "bbb_bbb", "ccc.aaa_aaa_aaa.bbb_bbb"); - // New extension is greater than previous extension - twe!("ccc.bbb_bbb", "aaa_aaa_aaa", "ccc.bbb_bbb.aaa_aaa_aaa"); -} - -#[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::hash::{DefaultHasher, 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//", "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/.", "foo", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!("foo/./bar", "foo/bar", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!("foo/.//bar", "foo/bar", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!("foo//./bar", "foo/bar", - 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", "foobar", - eq: false, - starts_with: false, - ends_with: false, - relative_from: None - ); - - 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("") - ); - - tc!(r"C:\foo\.\bar.txt", r"C:\foo\bar.txt", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!(r"C:\foo\.", r"C:\foo", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!(r"\\?\C:\foo\.\bar.txt", r"\\?\C:\foo\bar.txt", - eq: false, - starts_with: false, - ends_with: false, - relative_from: None - ); - } -} - -#[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(any(unix, target_os = "wasi"))] -#[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); -} - -#[test] -fn test_ord() { - macro_rules! ord( - ($ord:ident, $left:expr, $right:expr) => ({ - use core::cmp::Ordering; - - let left = Path::new($left); - let right = Path::new($right); - assert_eq!(left.cmp(&right), Ordering::$ord); - if (core::cmp::Ordering::$ord == Ordering::Equal) { - assert_eq!(left, right); - - let mut hasher = DefaultHasher::new(); - left.hash(&mut hasher); - let left_hash = hasher.finish(); - hasher = DefaultHasher::new(); - right.hash(&mut hasher); - let right_hash = hasher.finish(); - - assert_eq!(left_hash, right_hash, "hashes for {:?} and {:?} must match", left, right); - } else { - assert_ne!(left, right); - } - }); - ); - - ord!(Less, "1", "2"); - ord!(Less, "/foo/bar", "/foo./bar"); - ord!(Less, "foo/bar", "foo/bar."); - ord!(Equal, "foo/./bar", "foo/bar/"); - ord!(Equal, "foo/bar", "foo/bar/"); - ord!(Equal, "foo/bar", "foo/bar/."); - ord!(Equal, "foo/bar", "foo/bar//"); -} - -#[test] -#[cfg(any(unix, target_os = "wasi"))] -fn test_unix_absolute() { - use crate::path::absolute; - - assert!(absolute("").is_err()); - - let relative = "a/b"; - let mut expected = crate::env::current_dir().unwrap(); - expected.push(relative); - assert_eq!(absolute(relative).unwrap().as_os_str(), expected.as_os_str()); - - // Test how components are collected. - assert_eq!(absolute("/a/b/c").unwrap().as_os_str(), Path::new("/a/b/c").as_os_str()); - assert_eq!(absolute("/a//b/c").unwrap().as_os_str(), Path::new("/a/b/c").as_os_str()); - assert_eq!(absolute("//a/b/c").unwrap().as_os_str(), Path::new("//a/b/c").as_os_str()); - assert_eq!(absolute("///a/b/c").unwrap().as_os_str(), Path::new("/a/b/c").as_os_str()); - assert_eq!(absolute("/a/b/c/").unwrap().as_os_str(), Path::new("/a/b/c/").as_os_str()); - assert_eq!( - absolute("/a/./b/../c/.././..").unwrap().as_os_str(), - Path::new("/a/b/../c/../..").as_os_str() - ); - - // Test leading `.` and `..` components - let curdir = crate::env::current_dir().unwrap(); - assert_eq!(absolute("./a").unwrap().as_os_str(), curdir.join("a").as_os_str()); - assert_eq!(absolute("../a").unwrap().as_os_str(), curdir.join("../a").as_os_str()); // return /pwd/../a -} - -#[test] -#[cfg(windows)] -fn test_windows_absolute() { - use crate::path::absolute; - // An empty path is an error. - assert!(absolute("").is_err()); - - let relative = r"a\b"; - let mut expected = crate::env::current_dir().unwrap(); - expected.push(relative); - assert_eq!(absolute(relative).unwrap().as_os_str(), expected.as_os_str()); - - macro_rules! unchanged( - ($path:expr) => { - assert_eq!(absolute($path).unwrap().as_os_str(), Path::new($path).as_os_str()); - } - ); - - unchanged!(r"C:\path\to\file"); - unchanged!(r"C:\path\to\file\"); - unchanged!(r"\\server\share\to\file"); - unchanged!(r"\\server.\share.\to\file"); - unchanged!(r"\\.\PIPE\name"); - unchanged!(r"\\.\C:\path\to\COM1"); - unchanged!(r"\\?\C:\path\to\file"); - unchanged!(r"\\?\UNC\server\share\to\file"); - unchanged!(r"\\?\PIPE\name"); - // Verbatim paths are always unchanged, no matter what. - unchanged!(r"\\?\path.\to/file.."); - - assert_eq!( - absolute(r"C:\path..\to.\file.").unwrap().as_os_str(), - Path::new(r"C:\path..\to\file").as_os_str() - ); - assert_eq!(absolute(r"COM1").unwrap().as_os_str(), Path::new(r"\\.\COM1").as_os_str()); -} - -#[test] -#[should_panic = "path separator"] -fn test_extension_path_sep() { - let mut path = PathBuf::from("path/to/file"); - path.set_extension("d/../../../../../etc/passwd"); -} - -#[test] -#[should_panic = "path separator"] -#[cfg(windows)] -fn test_extension_path_sep_alternate() { - let mut path = PathBuf::from("path/to/file"); - path.set_extension("d\\test"); -} - -#[test] -#[cfg(not(windows))] -fn test_extension_path_sep_alternate() { - let mut path = PathBuf::from("path/to/file"); - path.set_extension("d\\test"); - assert_eq!(path, Path::new("path/to/file.d\\test")); -} - -#[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... -fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) { - let prefix = "my/home"; - let mut paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); - - paths.sort(); - - b.iter(|| { - black_box(paths.as_mut_slice()).sort_unstable(); - }); -} - -#[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... -fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) { - let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; - let paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); - - let mut set = BTreeSet::new(); - - paths.iter().for_each(|p| { - set.insert(p.as_path()); - }); - - b.iter(|| { - set.remove(paths[500].as_path()); - set.insert(paths[500].as_path()); - }); -} - -#[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... -fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) { - let prefix = "my/home"; - let paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); - - let mut set = BTreeSet::new(); - - paths.iter().for_each(|p| { - set.insert(p.as_path()); - }); - - b.iter(|| { - set.remove(paths[500].as_path()); - set.insert(paths[500].as_path()); - }); -} - -#[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... -fn bench_path_hashset(b: &mut test::Bencher) { - let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; - let paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); - - let mut set = HashSet::new(); - - paths.iter().for_each(|p| { - set.insert(p.as_path()); - }); - - b.iter(|| { - set.remove(paths[500].as_path()); - set.insert(black_box(paths[500].as_path())) - }); -} - -#[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... -fn bench_path_hashset_miss(b: &mut test::Bencher) { - let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; - let paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); - - let mut set = HashSet::new(); - - paths.iter().for_each(|p| { - set.insert(p.as_path()); - }); - - let probe = PathBuf::from(prefix).join("other"); - - b.iter(|| set.remove(black_box(probe.as_path()))); -} - -#[bench] -fn bench_hash_path_short(b: &mut test::Bencher) { - let mut hasher = DefaultHasher::new(); - let path = Path::new("explorer.exe"); - - b.iter(|| black_box(path).hash(&mut hasher)); - - black_box(hasher.finish()); -} - -#[bench] -fn bench_hash_path_long(b: &mut test::Bencher) { - let mut hasher = DefaultHasher::new(); - let path = - Path::new("/aaaaa/aaaaaa/./../aaaaaaaa/bbbbbbbbbbbbb/ccccccccccc/ddddddddd/eeeeeee.fff"); - - b.iter(|| black_box(path).hash(&mut hasher)); - - black_box(hasher.finish()); -} - -#[test] -fn clone_to_uninit() { - let a = Path::new("hello.txt"); - - let mut storage = vec![MaybeUninit::<u8>::uninit(); size_of_val::<Path>(a)]; - unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()).cast()) }; - assert_eq!(a.as_os_str().as_encoded_bytes(), unsafe { storage.assume_init_ref() }); - - let mut b: Box<Path> = Path::new("world.exe").into(); - assert_eq!(size_of_val::<Path>(a), size_of_val::<Path>(&b)); - assert_ne!(a, &*b); - unsafe { a.clone_to_uninit(ptr::from_mut::<Path>(&mut b).cast()) }; - assert_eq!(a, &*b); -} diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs index 862753e4765..067ff66d9af 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -1,6 +1,3 @@ -#[cfg(test)] -mod tests; - use crate::fmt; // FIXME(nonpoison_mutex,nonpoison_condvar): switch to nonpoison versions once they are available use crate::sync::{Condvar, Mutex}; diff --git a/library/std/src/sync/barrier/tests.rs b/library/std/src/sync/barrier/tests.rs deleted file mode 100644 index 0fbcd998812..00000000000 --- a/library/std/src/sync/barrier/tests.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::sync::mpsc::{TryRecvError, channel}; -use crate::sync::{Arc, Barrier}; -use crate::thread; - -#[test] -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads -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/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 98c83d8d326..78cf8841efe 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -350,6 +350,3 @@ unsafe impl<T: Sync + Send, F: Send> Sync for LazyLock<T, F> {} impl<T: RefUnwindSafe + UnwindSafe, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> {} #[stable(feature = "lazy_cell", since = "1.80.0")] impl<T: UnwindSafe, F: UnwindSafe> UnwindSafe for LazyLock<T, F> {} - -#[cfg(test)] -mod tests; diff --git a/library/std/src/sync/lazy_lock/tests.rs b/library/std/src/sync/lazy_lock/tests.rs deleted file mode 100644 index 7d7dde54349..00000000000 --- a/library/std/src/sync/lazy_lock/tests.rs +++ /dev/null @@ -1,167 +0,0 @@ -use crate::cell::LazyCell; -use crate::sync::atomic::AtomicUsize; -use crate::sync::atomic::Ordering::SeqCst; -use crate::sync::{LazyLock, Mutex, OnceLock}; -use crate::{panic, thread}; - -fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R { - thread::spawn(f).join().unwrap() -} - -#[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: LazyCell<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] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn lazy_poisoning() { - let x: LazyCell<String> = LazyCell::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); - assert!(res.is_err()); - } -} - -#[test] -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads -fn sync_lazy_new() { - static CALLED: AtomicUsize = AtomicUsize::new(0); - static SYNC_LAZY: LazyLock<i32> = LazyLock::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: LazyLock<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] -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads -fn static_sync_lazy() { - static XS: LazyLock<Vec<i32>> = LazyLock::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: OnceLock<Vec<i32>> = OnceLock::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] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn sync_lazy_poisoning() { - let x: LazyLock<String> = LazyLock::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(|| x.len()); - assert!(res.is_err()); - } -} - -// Check that we can infer `T` from closure's type. -#[test] -fn lazy_type_inference() { - let _ = LazyCell::new(|| ()); -} - -#[test] -fn is_sync_send() { - fn assert_traits<T: Send + Sync>() {} - assert_traits::<LazyLock<String>>(); -} - -#[test] -#[should_panic = "has previously been poisoned"] -fn lazy_force_mut_panic() { - let mut lazy = LazyLock::<String>::new(|| panic!()); - crate::panic::catch_unwind(crate::panic::AssertUnwindSafe(|| { - let _ = LazyLock::force_mut(&mut lazy); - })) - .unwrap_err(); - let _ = &*lazy; -} - -#[test] -fn lazy_force_mut() { - let s = "abc".to_owned(); - let mut lazy = LazyLock::new(move || s); - LazyLock::force_mut(&mut lazy); - let p = LazyLock::force_mut(&mut lazy); - p.clear(); - LazyLock::force_mut(&mut lazy); -} diff --git a/library/std/src/sync/mpmc/tests.rs b/library/std/src/sync/mpmc/tests.rs deleted file mode 100644 index ab14050df6c..00000000000 --- a/library/std/src/sync/mpmc/tests.rs +++ /dev/null @@ -1,728 +0,0 @@ -use super::*; -use crate::{env, thread}; - -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::new(1)).unwrap(); -} - -#[test] -fn drop_full_shared() { - let (tx, _rx) = channel::<Box<isize>>(); - drop(tx.clone()); - drop(tx.clone()); - tx.send(Box::new(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 t1 = thread::spawn(move || { - for i in 0..2 { - tx.send(i).unwrap(); - } - }); - let t2 = thread::spawn(move || { - assert_eq!(rx.recv().unwrap(), 0); - assert_eq!(rx.recv().unwrap(), 1); - }); - t1.join().unwrap(); - t2.join().unwrap(); -} - -#[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 count = if cfg!(miri) { 100 } else { 10000 }; - let (tx, rx) = channel::<i32>(); - let t = thread::spawn(move || { - for _ in 0..count { - tx.send(1).unwrap(); - } - }); - for _ in 0..count { - assert_eq!(rx.recv().unwrap(), 1); - } - t.join().ok().expect("thread panicked"); -} - -#[test] -fn stress_shared() { - const AMT: u32 = if cfg!(miri) { 100 } else { 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::new(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::new(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::new(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::new(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::new(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() { - let count = if cfg!(miri) { 1000 } else { 10000 }; - // Regression test that we don't run out of stack in scheduler context - let (tx, rx) = channel(); - for _ in 0..count { - tx.send(()).unwrap(); - } - for _ in 0..count { - 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))); -} - -#[test] -fn issue_39364() { - let (tx, rx) = channel::<()>(); - let t = thread::spawn(move || { - thread::sleep(Duration::from_millis(300)); - let _ = tx.clone(); - // Don't drop; hand back to caller. - tx - }); - - let _ = rx.recv_timeout(Duration::from_millis(500)); - let _tx = t.join().unwrap(); // delay dropping until end of test - let _ = rx.recv_timeout(Duration::from_millis(500)); -} diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc.rs index c86b546e011..f942937c14d 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc.rs @@ -137,12 +137,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod tests; - -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod sync_tests; - // MPSC channels are built as a wrapper around MPMC channels, which // were ported from the `crossbeam-channel` crate. MPMC channels are // not exposed publicly, but if you are curious about the implementation, @@ -737,9 +731,10 @@ impl<T> SyncSender<T> { // Attempts to send for a value on this receiver, returning an error if the // corresponding channel has hung up, or if it waits more than `timeout`. // - // This method is currently private and only used for tests. - #[allow(unused)] - fn send_timeout(&self, t: T, timeout: Duration) -> Result<(), mpmc::SendTimeoutError<T>> { + // This method is currently only used for tests. + #[unstable(issue = "none", feature = "std_internals")] + #[doc(hidden)] + pub fn send_timeout(&self, t: T, timeout: Duration) -> Result<(), mpmc::SendTimeoutError<T>> { self.inner.send_timeout(t, timeout) } } diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs deleted file mode 100644 index 49b65c8efe6..00000000000 --- a/library/std/src/sync/mpsc/sync_tests.rs +++ /dev/null @@ -1,669 +0,0 @@ -use super::*; -use crate::rc::Rc; -use crate::sync::mpmc::SendTimeoutError; -use crate::{env, thread}; - -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::new(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 send_timeout() { - let (tx, _rx) = sync_channel::<i32>(1); - assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Ok(())); - assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Err(SendTimeoutError::Timeout(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 count = if cfg!(miri) { 100 } else { 10000 }; - let (tx, rx) = sync_channel::<i32>(0); - thread::spawn(move || { - for _ in 0..count { - tx.send(1).unwrap(); - } - }); - for _ in 0..count { - assert_eq!(rx.recv().unwrap(), 1); - } -} - -#[test] -fn stress_recv_timeout_two_threads() { - let count = if cfg!(miri) { 100 } else { 10000 }; - let (tx, rx) = sync_channel::<i32>(0); - - thread::spawn(move || { - for _ in 0..count { - 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, count); -} - -#[test] -fn stress_recv_timeout_shared() { - const AMT: u32 = if cfg!(miri) { 100 } else { 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 = if cfg!(miri) { 100 } else { 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::new(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::new(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::new(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::new(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::new(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() { - let count = if cfg!(miri) { 1000 } else { 10000 }; - // Regression test that we don't run out of stack in scheduler context - let (tx, rx) = sync_channel(count); - for _ in 0..count { - tx.send(()).unwrap(); - } - for _ in 0..count { - 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() - } -} - -#[test] -fn drop_unreceived() { - let (tx, rx) = sync_channel::<Rc<()>>(1); - let msg = Rc::new(()); - let weak = Rc::downgrade(&msg); - assert!(tx.send(msg).is_ok()); - drop(rx); - // Messages should be dropped immediately when the last receiver is destroyed. - assert!(weak.upgrade().is_none()); - drop(tx); -} diff --git a/library/std/src/sync/mpsc/tests.rs b/library/std/src/sync/mpsc/tests.rs deleted file mode 100644 index 13892fa0d18..00000000000 --- a/library/std/src/sync/mpsc/tests.rs +++ /dev/null @@ -1,721 +0,0 @@ -use super::*; -use crate::{env, thread}; - -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::new(1)).unwrap(); -} - -#[test] -fn drop_full_shared() { - let (tx, _rx) = channel::<Box<isize>>(); - drop(tx.clone()); - drop(tx.clone()); - tx.send(Box::new(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 count = if cfg!(miri) { 100 } else { 10000 }; - let (tx, rx) = channel::<i32>(); - let t = thread::spawn(move || { - for _ in 0..count { - tx.send(1).unwrap(); - } - }); - for _ in 0..count { - assert_eq!(rx.recv().unwrap(), 1); - } - t.join().ok().expect("thread panicked"); -} - -#[test] -fn stress_shared() { - const AMT: u32 = if cfg!(miri) { 100 } else { 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::new(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::new(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::new(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::new(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::new(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() { - let count = if cfg!(miri) { 1000 } else { 10000 }; - // Regression test that we don't run out of stack in scheduler context - let (tx, rx) = channel(); - for _ in 0..count { - tx.send(()).unwrap(); - } - for _ in 0..count { - 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))); -} - -#[test] -fn issue_39364() { - let (tx, rx) = channel::<()>(); - let t = thread::spawn(move || { - thread::sleep(Duration::from_millis(300)); - let _ = tx.clone(); - // Don't drop; hand back to caller. - tx - }); - - let _ = rx.recv_timeout(Duration::from_millis(500)); - let _tx = t.join().unwrap(); // delay dropping until end of test - let _ = rx.recv_timeout(Duration::from_millis(500)); -} diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 8f769f2dca3..21e6b65a744 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -681,6 +681,3 @@ unsafe impl<#[may_dangle] T> Drop for OnceLock<T> { } } } - -#[cfg(test)] -mod tests; diff --git a/library/std/src/sync/once_lock/tests.rs b/library/std/src/sync/once_lock/tests.rs deleted file mode 100644 index 5113d436c3c..00000000000 --- a/library/std/src/sync/once_lock/tests.rs +++ /dev/null @@ -1,200 +0,0 @@ -use crate::sync::OnceLock; -use crate::sync::atomic::AtomicUsize; -use crate::sync::atomic::Ordering::SeqCst; -use crate::sync::mpsc::channel; -use crate::{panic, thread}; - -fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R { - thread::spawn(f).join().unwrap() -} - -#[test] -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads -fn sync_once_cell() { - static ONCE_CELL: OnceLock<i32> = OnceLock::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!("Kaboom!")); - assert_eq!(ONCE_CELL.get(), Some(&92)); -} - -#[test] -fn sync_once_cell_get_mut() { - let mut c = OnceLock::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 = OnceLock::new(); - c.set(92).unwrap(); - unsafe { - assert_eq!(c.get_unchecked(), &92); - } -} - -#[test] -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads -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 = OnceLock::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 = OnceLock::<String>::new(); - drop(x); -} - -#[test] -fn clone() { - let s = OnceLock::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] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn get_or_try_init() { - let cell: OnceLock<String> = OnceLock::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!(OnceLock::from("value").get(), Some(&"value")); - assert_ne!(OnceLock::from("foo").get(), Some(&"bar")); -} - -#[test] -fn partialeq_impl() { - assert!(OnceLock::from("value") == OnceLock::from("value")); - assert!(OnceLock::from("foo") != OnceLock::from("bar")); - - assert!(OnceLock::<String>::new() == OnceLock::new()); - assert!(OnceLock::<String>::new() != OnceLock::from("value".to_owned())); -} - -#[test] -fn into_inner() { - let cell: OnceLock<String> = OnceLock::new(); - assert_eq!(cell.into_inner(), None); - let cell = OnceLock::new(); - cell.set("hello".to_string()).unwrap(); - assert_eq!(cell.into_inner(), Some("hello".to_string())); -} - -#[test] -fn is_sync_send() { - fn assert_traits<T: Send + Sync>() {} - assert_traits::<OnceLock<String>>(); -} - -#[test] -fn eval_once_macro() { - macro_rules! eval_once { - (|| -> $ty:ty { - $($body:tt)* - }) => {{ - static ONCE_CELL: OnceLock<$ty> = OnceLock::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] -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads -fn sync_once_cell_does_not_leak_partially_constructed_boxes() { - static ONCE_CELL: OnceLock<String> = OnceLock::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 = OnceLock::new(); - { - let s = String::new(); - cell.set(&s).unwrap(); - } -} diff --git a/library/std/src/sync/poison/condvar.rs b/library/std/src/sync/poison/condvar.rs index a6e2389c93b..7f0f3f652bc 100644 --- a/library/std/src/sync/poison/condvar.rs +++ b/library/std/src/sync/poison/condvar.rs @@ -1,6 +1,3 @@ -#[cfg(test)] -mod tests; - use crate::fmt; use crate::sync::poison::{self, LockResult, MutexGuard, PoisonError, mutex}; use crate::sys::sync as sys; diff --git a/library/std/src/sync/poison/condvar/tests.rs b/library/std/src/sync/poison/condvar/tests.rs deleted file mode 100644 index f9e9066bc92..00000000000 --- a/library/std/src/sync/poison/condvar/tests.rs +++ /dev/null @@ -1,190 +0,0 @@ -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(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads -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(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads -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(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads -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(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported -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(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported -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(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported -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(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads -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(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads -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::Relaxed); - 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::Relaxed) { - t.join().unwrap(); - continue; - } - drop(g); - - t.join().unwrap(); - - break; - } -} diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index fb43ada6375..9362c764173 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -1,6 +1,3 @@ -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod tests; - use crate::cell::UnsafeCell; use crate::fmt; use crate::marker::PhantomData; diff --git a/library/std/src/sync/poison/mutex/tests.rs b/library/std/src/sync/poison/mutex/tests.rs deleted file mode 100644 index 395c8aada08..00000000000 --- a/library/std/src/sync/poison/mutex/tests.rs +++ /dev/null @@ -1,442 +0,0 @@ -use crate::fmt::Debug; -use crate::ops::FnMut; -use crate::panic::{self, AssertUnwindSafe}; -use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::sync::mpsc::channel; -use crate::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError}; -use crate::{hint, mem, thread}; - -struct Packet<T>(Arc<(Mutex<T>, Condvar)>); - -#[derive(Eq, PartialEq, Debug)] -struct NonCopy(i32); - -#[derive(Eq, PartialEq, Debug)] -struct NonCopyNeedsDrop(i32); - -impl Drop for NonCopyNeedsDrop { - fn drop(&mut self) { - hint::black_box(()); - } -} - -#[test] -fn test_needs_drop() { - assert!(!mem::needs_drop::<NonCopy>()); - assert!(mem::needs_drop::<NonCopyNeedsDrop>()); -} - -#[derive(Clone, Eq, PartialEq, Debug)] -struct Cloneable(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() = (); -} - -fn new_poisoned_mutex<T>(value: T) -> Mutex<T> { - let mutex = Mutex::new(value); - - let catch_unwind_result = panic::catch_unwind(AssertUnwindSafe(|| { - let _guard = mutex.lock().unwrap(); - - panic!("test panic to poison mutex"); - })); - - assert!(catch_unwind_result.is_err()); - assert!(mutex.is_poisoned()); - - mutex -} - -#[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 = new_poisoned_mutex(NonCopy(10)); - - match m.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_cloned() { - let m = Mutex::new(Cloneable(10)); - - assert_eq!(m.get_cloned().unwrap(), Cloneable(10)); -} - -#[test] -fn test_get_cloned_poison() { - let m = new_poisoned_mutex(Cloneable(10)); - - match m.get_cloned() { - Err(e) => assert_eq!(e.into_inner(), ()), - Ok(x) => panic!("get 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 mut m = new_poisoned_mutex(NonCopy(10)); - - match m.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_set() { - fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) - where - T: Debug + Eq, - { - let m = Mutex::new(init()); - - assert_eq!(*m.lock().unwrap(), init()); - m.set(value()).unwrap(); - assert_eq!(*m.lock().unwrap(), value()); - } - - inner(|| NonCopy(10), || NonCopy(20)); - inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); -} - -#[test] -fn test_set_poison() { - fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) - where - T: Debug + Eq, - { - let m = new_poisoned_mutex(init()); - - match m.set(value()) { - Err(e) => { - assert_eq!(e.into_inner(), value()); - assert_eq!(m.into_inner().unwrap_err().into_inner(), init()); - } - Ok(x) => panic!("set of poisoned Mutex is Ok: {x:?}"), - } - } - - inner(|| NonCopy(10), || NonCopy(20)); - inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); -} - -#[test] -fn test_replace() { - fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) - where - T: Debug + Eq, - { - let m = Mutex::new(init()); - - assert_eq!(*m.lock().unwrap(), init()); - assert_eq!(m.replace(value()).unwrap(), init()); - assert_eq!(*m.lock().unwrap(), value()); - } - - inner(|| NonCopy(10), || NonCopy(20)); - inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); -} - -#[test] -fn test_replace_poison() { - fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) - where - T: Debug + Eq, - { - let m = new_poisoned_mutex(init()); - - match m.replace(value()) { - Err(e) => { - assert_eq!(e.into_inner(), value()); - assert_eq!(m.into_inner().unwrap_err().into_inner(), init()); - } - Ok(x) => panic!("replace of poisoned Mutex is Ok: {x:?}"), - } - } - - inner(|| NonCopy(10), || NonCopy(20)); - inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); -} - -#[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); // deliberate assertion failure to poison the mutex - }) - .join(); - assert!(arc.lock().is_err()); - assert!(arc.is_poisoned()); -} - -#[test] -fn test_mutex_arc_poison_mapped() { - let arc = Arc::new(Mutex::new(1)); - assert!(!arc.is_poisoned()); - let arc2 = arc.clone(); - let _ = thread::spawn(move || { - let lock = arc2.lock().unwrap(); - let lock = MutexGuard::map(lock, |val| val); - assert_eq!(*lock, 2); // deliberate assertion failure to poison the mutex - }) - .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); -} - -#[test] -fn test_mapping_mapped_guard() { - let arr = [0; 4]; - let mut lock = Mutex::new(arr); - let guard = lock.lock().unwrap(); - let guard = MutexGuard::map(guard, |arr| &mut arr[..2]); - let mut guard = MappedMutexGuard::map(guard, |slice| &mut slice[1..]); - assert_eq!(guard.len(), 1); - guard[0] = 42; - drop(guard); - assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]); -} - -#[test] -fn panic_while_mapping_unlocked_poison() { - let lock = Mutex::new(()); - - let _ = panic::catch_unwind(|| { - let guard = lock.lock().unwrap(); - let _guard = MutexGuard::map::<(), _>(guard, |_| panic!()); - }); - - match lock.try_lock() { - Ok(_) => panic!("panicking in a MutexGuard::map closure should poison the Mutex"), - Err(TryLockError::WouldBlock) => { - panic!("panicking in a MutexGuard::map closure should unlock the mutex") - } - Err(TryLockError::Poisoned(_)) => {} - } - - let _ = panic::catch_unwind(|| { - let guard = lock.lock().unwrap(); - let _guard = MutexGuard::try_map::<(), _>(guard, |_| panic!()); - }); - - match lock.try_lock() { - Ok(_) => panic!("panicking in a MutexGuard::try_map closure should poison the Mutex"), - Err(TryLockError::WouldBlock) => { - panic!("panicking in a MutexGuard::try_map closure should unlock the mutex") - } - Err(TryLockError::Poisoned(_)) => {} - } - - let _ = panic::catch_unwind(|| { - let guard = lock.lock().unwrap(); - let guard = MutexGuard::map::<(), _>(guard, |val| val); - let _guard = MappedMutexGuard::map::<(), _>(guard, |_| panic!()); - }); - - match lock.try_lock() { - Ok(_) => panic!("panicking in a MappedMutexGuard::map closure should poison the Mutex"), - Err(TryLockError::WouldBlock) => { - panic!("panicking in a MappedMutexGuard::map closure should unlock the mutex") - } - Err(TryLockError::Poisoned(_)) => {} - } - - let _ = panic::catch_unwind(|| { - let guard = lock.lock().unwrap(); - let guard = MutexGuard::map::<(), _>(guard, |val| val); - let _guard = MappedMutexGuard::try_map::<(), _>(guard, |_| panic!()); - }); - - match lock.try_lock() { - Ok(_) => panic!("panicking in a MappedMutexGuard::try_map closure should poison the Mutex"), - Err(TryLockError::WouldBlock) => { - panic!("panicking in a MappedMutexGuard::try_map closure should unlock the mutex") - } - Err(TryLockError::Poisoned(_)) => {} - } - - drop(lock); -} diff --git a/library/std/src/sync/poison/once.rs b/library/std/src/sync/poison/once.rs index 528b11ca0c1..d2938b7a0c1 100644 --- a/library/std/src/sync/poison/once.rs +++ b/library/std/src/sync/poison/once.rs @@ -3,9 +3,6 @@ //! This primitive is meant to be used to run one-time initialization. An //! example use case would be for initializing an FFI library. -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod tests; - use crate::fmt; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sys::sync as sys; diff --git a/library/std/src/sync/poison/once/tests.rs b/library/std/src/sync/poison/once/tests.rs deleted file mode 100644 index ce96468aeb6..00000000000 --- a/library/std/src/sync/poison/once/tests.rs +++ /dev/null @@ -1,162 +0,0 @@ -use super::Once; -use crate::sync::atomic::AtomicBool; -use crate::sync::atomic::Ordering::Relaxed; -use crate::sync::mpsc::channel; -use crate::time::Duration; -use crate::{panic, 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.is_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.is_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()); -} - -#[test] -fn wait() { - for _ in 0..50 { - let val = AtomicBool::new(false); - let once = Once::new(); - - thread::scope(|s| { - for _ in 0..4 { - s.spawn(|| { - once.wait(); - assert!(val.load(Relaxed)); - }); - } - - once.call_once(|| val.store(true, Relaxed)); - }); - } -} - -#[test] -fn wait_on_poisoned() { - let once = Once::new(); - - panic::catch_unwind(|| once.call_once(|| panic!())).unwrap_err(); - panic::catch_unwind(|| once.wait()).unwrap_err(); -} - -#[test] -fn wait_force_on_poisoned() { - let once = Once::new(); - - thread::scope(|s| { - panic::catch_unwind(|| once.call_once(|| panic!())).unwrap_err(); - - s.spawn(|| { - thread::sleep(Duration::from_millis(100)); - - once.call_once_force(|_| {}); - }); - - once.wait_force(); - }) -} diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 1519baf99a8..f9d9321f5f2 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -1,6 +1,3 @@ -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod tests; - use crate::cell::UnsafeCell; use crate::fmt; use crate::marker::PhantomData; diff --git a/library/std/src/sync/poison/rwlock/tests.rs b/library/std/src/sync/poison/rwlock/tests.rs deleted file mode 100644 index 057c2f1a5d7..00000000000 --- a/library/std/src/sync/poison/rwlock/tests.rs +++ /dev/null @@ -1,729 +0,0 @@ -use rand::Rng; - -use crate::fmt::Debug; -use crate::ops::FnMut; -use crate::panic::{self, AssertUnwindSafe}; -use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::sync::mpsc::channel; -use crate::sync::{ - Arc, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard, - TryLockError, -}; -use crate::{hint, mem, thread}; - -#[derive(Eq, PartialEq, Debug)] -struct NonCopy(i32); - -#[derive(Eq, PartialEq, Debug)] -struct NonCopyNeedsDrop(i32); - -impl Drop for NonCopyNeedsDrop { - fn drop(&mut self) { - hint::black_box(()); - } -} - -#[test] -fn test_needs_drop() { - assert!(!mem::needs_drop::<NonCopy>()); - assert!(mem::needs_drop::<NonCopyNeedsDrop>()); -} - -#[derive(Clone, Eq, PartialEq, Debug)] -struct Cloneable(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] -// FIXME: On macOS we use a provenance-incorrect implementation and Miri -// catches that issue with a chance of around 1/1000. -// See <https://github.com/rust-lang/rust/issues/121950> for details. -#[cfg_attr(all(miri, target_os = "macos"), ignore)] -fn frob() { - const N: u32 = 10; - const M: usize = if cfg!(miri) { 100 } else { 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 = crate::test_helpers::test_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_mapped_w_r() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let lock = arc2.write().unwrap(); - let _lock = RwLockWriteGuard::map(lock, |val| val); - 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_poison_mapped_w_w() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let lock = arc2.write().unwrap(); - let _lock = RwLockWriteGuard::map(lock, |val| val); - 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_mapped_r_r() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let lock = arc2.read().unwrap(); - let _lock = RwLockReadGuard::map(lock, |val| val); - 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_no_poison_mapped_r_w() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let lock = arc2.read().unwrap(); - let _lock = RwLockReadGuard::map(lock, |val| val); - 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); - let mapped_read_guard = RwLockReadGuard::map(lock.read().unwrap(), |_| &()); - - let write_result = lock.try_write(); - match write_result { - Err(TryLockError::WouldBlock) => (), - Ok(_) => assert!(false, "try_write should not succeed while mapped_read_guard is in scope"), - Err(_) => assert!(false, "unexpected error"), - } - - drop(mapped_read_guard); -} - -fn new_poisoned_rwlock<T>(value: T) -> RwLock<T> { - let lock = RwLock::new(value); - - let catch_unwind_result = panic::catch_unwind(AssertUnwindSafe(|| { - let _guard = lock.write().unwrap(); - - panic!("test panic to poison RwLock"); - })); - - assert!(catch_unwind_result.is_err()); - assert!(lock.is_poisoned()); - - lock -} - -#[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 = new_poisoned_rwlock(NonCopy(10)); - - match m.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_cloned() { - let m = RwLock::new(Cloneable(10)); - - assert_eq!(m.get_cloned().unwrap(), Cloneable(10)); -} - -#[test] -fn test_get_cloned_poison() { - let m = new_poisoned_rwlock(Cloneable(10)); - - match m.get_cloned() { - Err(e) => assert_eq!(e.into_inner(), ()), - Ok(x) => panic!("get 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 mut m = new_poisoned_rwlock(NonCopy(10)); - - match m.get_mut() { - Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), - Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {x:?}"), - } -} - -#[test] -fn test_set() { - fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) - where - T: Debug + Eq, - { - let m = RwLock::new(init()); - - assert_eq!(*m.read().unwrap(), init()); - m.set(value()).unwrap(); - assert_eq!(*m.read().unwrap(), value()); - } - - inner(|| NonCopy(10), || NonCopy(20)); - inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); -} - -#[test] -fn test_set_poison() { - fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) - where - T: Debug + Eq, - { - let m = new_poisoned_rwlock(init()); - - match m.set(value()) { - Err(e) => { - assert_eq!(e.into_inner(), value()); - assert_eq!(m.into_inner().unwrap_err().into_inner(), init()); - } - Ok(x) => panic!("set of poisoned RwLock is Ok: {x:?}"), - } - } - - inner(|| NonCopy(10), || NonCopy(20)); - inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); -} - -#[test] -fn test_replace() { - fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) - where - T: Debug + Eq, - { - let m = RwLock::new(init()); - - assert_eq!(*m.read().unwrap(), init()); - assert_eq!(m.replace(value()).unwrap(), init()); - assert_eq!(*m.read().unwrap(), value()); - } - - inner(|| NonCopy(10), || NonCopy(20)); - inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); -} - -#[test] -fn test_replace_poison() { - fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) - where - T: Debug + Eq, - { - let m = new_poisoned_rwlock(init()); - - match m.replace(value()) { - Err(e) => { - assert_eq!(e.into_inner(), value()); - assert_eq!(m.into_inner().unwrap_err().into_inner(), init()); - } - Ok(x) => panic!("replace of poisoned RwLock is Ok: {x:?}"), - } - } - - inner(|| NonCopy(10), || NonCopy(20)); - inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); -} - -#[test] -fn test_read_guard_covariance() { - fn do_stuff<'a>(_: RwLockReadGuard<'_, &'a i32>, _: &'a i32) {} - let j: i32 = 5; - let lock = RwLock::new(&j); - { - let i = 6; - do_stuff(lock.read().unwrap(), &i); - } - drop(lock); -} - -#[test] -fn test_mapped_read_guard_covariance() { - fn do_stuff<'a>(_: MappedRwLockReadGuard<'_, &'a i32>, _: &'a i32) {} - let j: i32 = 5; - let lock = RwLock::new((&j, &j)); - { - let i = 6; - let guard = lock.read().unwrap(); - let guard = RwLockReadGuard::map(guard, |(val, _val)| val); - do_stuff(guard, &i); - } - drop(lock); -} - -#[test] -fn test_mapping_mapped_guard() { - let arr = [0; 4]; - let mut lock = RwLock::new(arr); - let guard = lock.write().unwrap(); - let guard = RwLockWriteGuard::map(guard, |arr| &mut arr[..2]); - let mut guard = MappedRwLockWriteGuard::map(guard, |slice| &mut slice[1..]); - assert_eq!(guard.len(), 1); - guard[0] = 42; - drop(guard); - assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]); - - let guard = lock.read().unwrap(); - let guard = RwLockReadGuard::map(guard, |arr| &arr[..2]); - let guard = MappedRwLockReadGuard::map(guard, |slice| &slice[1..]); - assert_eq!(*guard, [42]); - drop(guard); - assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]); -} - -#[test] -fn panic_while_mapping_read_unlocked_no_poison() { - let lock = RwLock::new(()); - - let _ = panic::catch_unwind(|| { - let guard = lock.read().unwrap(); - let _guard = RwLockReadGuard::map::<(), _>(guard, |_| panic!()); - }); - - match lock.try_write() { - Ok(_) => {} - Err(TryLockError::WouldBlock) => { - panic!("panicking in a RwLockReadGuard::map closure should release the read lock") - } - Err(TryLockError::Poisoned(_)) => { - panic!("panicking in a RwLockReadGuard::map closure should not poison the RwLock") - } - } - - let _ = panic::catch_unwind(|| { - let guard = lock.read().unwrap(); - let _guard = RwLockReadGuard::try_map::<(), _>(guard, |_| panic!()); - }); - - match lock.try_write() { - Ok(_) => {} - Err(TryLockError::WouldBlock) => { - panic!("panicking in a RwLockReadGuard::try_map closure should release the read lock") - } - Err(TryLockError::Poisoned(_)) => { - panic!("panicking in a RwLockReadGuard::try_map closure should not poison the RwLock") - } - } - - let _ = panic::catch_unwind(|| { - let guard = lock.read().unwrap(); - let guard = RwLockReadGuard::map::<(), _>(guard, |val| val); - let _guard = MappedRwLockReadGuard::map::<(), _>(guard, |_| panic!()); - }); - - match lock.try_write() { - Ok(_) => {} - Err(TryLockError::WouldBlock) => { - panic!("panicking in a MappedRwLockReadGuard::map closure should release the read lock") - } - Err(TryLockError::Poisoned(_)) => { - panic!("panicking in a MappedRwLockReadGuard::map closure should not poison the RwLock") - } - } - - let _ = panic::catch_unwind(|| { - let guard = lock.read().unwrap(); - let guard = RwLockReadGuard::map::<(), _>(guard, |val| val); - let _guard = MappedRwLockReadGuard::try_map::<(), _>(guard, |_| panic!()); - }); - - match lock.try_write() { - Ok(_) => {} - Err(TryLockError::WouldBlock) => panic!( - "panicking in a MappedRwLockReadGuard::try_map closure should release the read lock" - ), - Err(TryLockError::Poisoned(_)) => panic!( - "panicking in a MappedRwLockReadGuard::try_map closure should not poison the RwLock" - ), - } - - drop(lock); -} - -#[test] -fn panic_while_mapping_write_unlocked_poison() { - let lock = RwLock::new(()); - - let _ = panic::catch_unwind(|| { - let guard = lock.write().unwrap(); - let _guard = RwLockWriteGuard::map::<(), _>(guard, |_| panic!()); - }); - - match lock.try_write() { - Ok(_) => panic!("panicking in a RwLockWriteGuard::map closure should poison the RwLock"), - Err(TryLockError::WouldBlock) => { - panic!("panicking in a RwLockWriteGuard::map closure should release the write lock") - } - Err(TryLockError::Poisoned(_)) => {} - } - - let _ = panic::catch_unwind(|| { - let guard = lock.write().unwrap(); - let _guard = RwLockWriteGuard::try_map::<(), _>(guard, |_| panic!()); - }); - - match lock.try_write() { - Ok(_) => { - panic!("panicking in a RwLockWriteGuard::try_map closure should poison the RwLock") - } - Err(TryLockError::WouldBlock) => { - panic!("panicking in a RwLockWriteGuard::try_map closure should release the write lock") - } - Err(TryLockError::Poisoned(_)) => {} - } - - let _ = panic::catch_unwind(|| { - let guard = lock.write().unwrap(); - let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val); - let _guard = MappedRwLockWriteGuard::map::<(), _>(guard, |_| panic!()); - }); - - match lock.try_write() { - Ok(_) => { - panic!("panicking in a MappedRwLockWriteGuard::map closure should poison the RwLock") - } - Err(TryLockError::WouldBlock) => panic!( - "panicking in a MappedRwLockWriteGuard::map closure should release the write lock" - ), - Err(TryLockError::Poisoned(_)) => {} - } - - let _ = panic::catch_unwind(|| { - let guard = lock.write().unwrap(); - let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val); - let _guard = MappedRwLockWriteGuard::try_map::<(), _>(guard, |_| panic!()); - }); - - match lock.try_write() { - Ok(_) => panic!( - "panicking in a MappedRwLockWriteGuard::try_map closure should poison the RwLock" - ), - Err(TryLockError::WouldBlock) => panic!( - "panicking in a MappedRwLockWriteGuard::try_map closure should release the write lock" - ), - Err(TryLockError::Poisoned(_)) => {} - } - - drop(lock); -} - -#[test] -fn test_downgrade_basic() { - let r = RwLock::new(()); - - let write_guard = r.write().unwrap(); - let _read_guard = RwLockWriteGuard::downgrade(write_guard); -} - -#[test] -// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. -// See <https://github.com/rust-lang/rust/issues/121950> for details. -#[cfg_attr(all(miri, target_os = "macos"), ignore)] -fn test_downgrade_observe() { - // Taken from the test `test_rwlock_downgrade` from: - // https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs - - const W: usize = 20; - const N: usize = if cfg!(miri) { 40 } else { 100 }; - - // This test spawns `W` writer threads, where each will increment a counter `N` times, ensuring - // that the value they wrote has not changed after downgrading. - - let rw = Arc::new(RwLock::new(0)); - - // Spawn the writers that will do `W * N` operations and checks. - let handles: Vec<_> = (0..W) - .map(|_| { - let rw = rw.clone(); - thread::spawn(move || { - for _ in 0..N { - // Increment the counter. - let mut write_guard = rw.write().unwrap(); - *write_guard += 1; - let cur_val = *write_guard; - - // Downgrade the lock to read mode, where the value protected cannot be modified. - let read_guard = RwLockWriteGuard::downgrade(write_guard); - assert_eq!(cur_val, *read_guard); - } - }) - }) - .collect(); - - for handle in handles { - handle.join().unwrap(); - } - - assert_eq!(*rw.read().unwrap(), W * N); -} - -#[test] -// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. -// See <https://github.com/rust-lang/rust/issues/121950> for details. -#[cfg_attr(all(miri, target_os = "macos"), ignore)] -fn test_downgrade_atomic() { - const NEW_VALUE: i32 = -1; - - // This test checks that `downgrade` is atomic, meaning as soon as a write lock has been - // downgraded, the lock must be in read mode and no other threads can take the write lock to - // modify the protected value. - - // `W` is the number of evil writer threads. - const W: usize = 20; - let rwlock = Arc::new(RwLock::new(0)); - - // Spawns many evil writer threads that will try and write to the locked value before the - // initial writer (who has the exclusive lock) can read after it downgrades. - // If the `RwLock` behaves correctly, then the initial writer should read the value it wrote - // itself as no other thread should be able to mutate the protected value. - - // Put the lock in write mode, causing all future threads trying to access this go to sleep. - let mut main_write_guard = rwlock.write().unwrap(); - - // Spawn all of the evil writer threads. They will each increment the protected value by 1. - let handles: Vec<_> = (0..W) - .map(|_| { - let rwlock = rwlock.clone(); - thread::spawn(move || { - // Will go to sleep since the main thread initially has the write lock. - let mut evil_guard = rwlock.write().unwrap(); - *evil_guard += 1; - }) - }) - .collect(); - - // Wait for a good amount of time so that evil threads go to sleep. - // Note: this is not strictly necessary... - let eternity = crate::time::Duration::from_millis(42); - thread::sleep(eternity); - - // Once everyone is asleep, set the value to `NEW_VALUE`. - *main_write_guard = NEW_VALUE; - - // Atomically downgrade the write guard into a read guard. - let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); - - // If the above is not atomic, then it would be possible for an evil thread to get in front of - // this read and change the value to be non-negative. - assert_eq!(*main_read_guard, NEW_VALUE, "`downgrade` was not atomic"); - - // Drop the main read guard and allow the evil writer threads to start incrementing. - drop(main_read_guard); - - for handle in handles { - handle.join().unwrap(); - } - - let final_check = rwlock.read().unwrap(); - assert_eq!(*final_check, W as i32 + NEW_VALUE); -} diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs index 0140e0d2129..e009eb410ef 100644 --- a/library/std/src/sync/reentrant_lock.rs +++ b/library/std/src/sync/reentrant_lock.rs @@ -1,6 +1,3 @@ -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod tests; - use cfg_if::cfg_if; use crate::cell::UnsafeCell; @@ -324,7 +321,10 @@ impl<T: ?Sized> ReentrantLock<T> { /// Otherwise, an RAII guard is returned. /// /// This function does not block. - pub(crate) fn try_lock(&self) -> Option<ReentrantLockGuard<'_, T>> { + // FIXME maybe make it a public part of the API? + #[unstable(issue = "none", feature = "std_internals")] + #[doc(hidden)] + pub fn try_lock(&self) -> Option<ReentrantLockGuard<'_, T>> { let this_thread = current_id(); // Safety: We only touch lock_count when we own the inner mutex. // Additionally, we only call `self.owner.set()` while holding diff --git a/library/std/src/sync/reentrant_lock/tests.rs b/library/std/src/sync/reentrant_lock/tests.rs deleted file mode 100644 index aeef0289d28..00000000000 --- a/library/std/src/sync/reentrant_lock/tests.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::ReentrantLock; -use crate::cell::RefCell; -use crate::sync::Arc; -use crate::thread; - -#[test] -fn smoke() { - let l = ReentrantLock::new(()); - { - let a = l.lock(); - { - let b = l.lock(); - { - let c = l.lock(); - assert_eq!(*c, ()); - } - assert_eq!(*b, ()); - } - assert_eq!(*a, ()); - } -} - -#[test] -fn is_mutex() { - let l = Arc::new(ReentrantLock::new(RefCell::new(0))); - let l2 = l.clone(); - let lock = l.lock(); - let child = thread::spawn(move || { - let lock = l2.lock(); - assert_eq!(*lock.borrow(), 4950); - }); - for i in 0..100 { - let lock = l.lock(); - *lock.borrow_mut() += i; - } - drop(lock); - child.join().unwrap(); -} - -#[test] -fn trylock_works() { - let l = Arc::new(ReentrantLock::new(())); - let l2 = l.clone(); - let _lock = l.try_lock(); - let _lock2 = l.try_lock(); - thread::spawn(move || { - let lock = l2.try_lock(); - assert!(lock.is_none()); - }) - .join() - .unwrap(); - let _lock3 = l.try_lock(); -} diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index c003503ca8b..ca04aa4ada4 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -2,12 +2,6 @@ #![unstable(feature = "thread_local_internals", issue = "none")] -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod tests; - -#[cfg(test)] -mod dynamic_tests; - use crate::cell::{Cell, RefCell}; use crate::error::Error; use crate::fmt; diff --git a/library/std/src/thread/local/dynamic_tests.rs b/library/std/src/thread/local/dynamic_tests.rs deleted file mode 100644 index dd180041648..00000000000 --- a/library/std/src/thread/local/dynamic_tests.rs +++ /dev/null @@ -1,40 +0,0 @@ -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 deleted file mode 100644 index 9d4f52a0921..00000000000 --- a/library/std/src/thread/local/tests.rs +++ /dev/null @@ -1,376 +0,0 @@ -use crate::cell::{Cell, UnsafeCell}; -use crate::sync::atomic::{AtomicU8, Ordering}; -use crate::sync::{Arc, Condvar, Mutex}; -use crate::thread::{self, Builder, LocalKey}; -use crate::thread_local; - -#[derive(Clone, Default)] -struct Signal(Arc<(Mutex<bool>, Condvar)>); - -impl Signal { - fn notify(&self) { - let (set, cvar) = &*self.0; - *set.lock().unwrap() = true; - cvar.notify_one(); - } - - fn wait(&self) { - let (set, cvar) = &*self.0; - let mut set = set.lock().unwrap(); - while !*set { - set = cvar.wait(set).unwrap(); - } - } -} - -struct NotifyOnDrop(Signal); - -impl Drop for NotifyOnDrop { - fn drop(&mut self) { - let NotifyOnDrop(ref f) = *self; - f.notify(); - } -} - -#[test] -fn smoke_no_dtor() { - thread_local!(static FOO: Cell<i32> = Cell::new(1)); - run(&FOO); - thread_local!(static FOO2: Cell<i32> = const { Cell::new(1) }); - run(&FOO2); - - fn run(key: &'static LocalKey<Cell<i32>>) { - key.with(|f| { - assert_eq!(f.get(), 1); - f.set(2); - }); - let t = thread::spawn(move || { - key.with(|f| { - assert_eq!(f.get(), 1); - }); - }); - t.join().unwrap(); - - key.with(|f| { - assert_eq!(f.get(), 2); - }); - } -} - -#[test] -fn states() { - struct Foo(&'static LocalKey<Foo>); - impl Drop for Foo { - fn drop(&mut self) { - assert!(self.0.try_with(|_| ()).is_err()); - } - } - - thread_local!(static FOO: Foo = Foo(&FOO)); - run(&FOO); - thread_local!(static FOO2: Foo = const { Foo(&FOO2) }); - run(&FOO2); - - fn run(foo: &'static LocalKey<Foo>) { - thread::spawn(move || { - assert!(foo.try_with(|_| ()).is_ok()); - }) - .join() - .unwrap(); - } -} - -#[test] -fn smoke_dtor() { - thread_local!(static FOO: UnsafeCell<Option<NotifyOnDrop>> = UnsafeCell::new(None)); - run(&FOO); - thread_local!(static FOO2: UnsafeCell<Option<NotifyOnDrop>> = const { UnsafeCell::new(None) }); - run(&FOO2); - - fn run(key: &'static LocalKey<UnsafeCell<Option<NotifyOnDrop>>>) { - let signal = Signal::default(); - let signal2 = signal.clone(); - let t = thread::spawn(move || unsafe { - let mut signal = Some(signal2); - key.with(|f| { - *f.get() = Some(NotifyOnDrop(signal.take().unwrap())); - }); - }); - signal.wait(); - t.join().unwrap(); - } -} - -#[test] -fn circular() { - // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint - #![allow(static_mut_refs)] - - struct S1(&'static LocalKey<UnsafeCell<Option<S1>>>, &'static LocalKey<UnsafeCell<Option<S2>>>); - struct S2(&'static LocalKey<UnsafeCell<Option<S1>>>, &'static LocalKey<UnsafeCell<Option<S2>>>); - thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None)); - thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell::new(None)); - thread_local!(static K3: UnsafeCell<Option<S1>> = const { UnsafeCell::new(None) }); - thread_local!(static K4: UnsafeCell<Option<S2>> = const { UnsafeCell::new(None) }); - static mut HITS: usize = 0; - - impl Drop for S1 { - fn drop(&mut self) { - unsafe { - HITS += 1; - if self.1.try_with(|_| ()).is_err() { - assert_eq!(HITS, 3); - } else { - if HITS == 1 { - self.1.with(|s| *s.get() = Some(S2(self.0, self.1))); - } else { - assert_eq!(HITS, 3); - } - } - } - } - } - impl Drop for S2 { - fn drop(&mut self) { - unsafe { - HITS += 1; - assert!(self.0.try_with(|_| ()).is_ok()); - assert_eq!(HITS, 2); - self.0.with(|s| *s.get() = Some(S1(self.0, self.1))); - } - } - } - - thread::spawn(move || { - drop(S1(&K1, &K2)); - }) - .join() - .unwrap(); - - unsafe { - HITS = 0; - } - - thread::spawn(move || { - drop(S1(&K3, &K4)); - }) - .join() - .unwrap(); -} - -#[test] -fn self_referential() { - struct S1(&'static LocalKey<UnsafeCell<Option<S1>>>); - - thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None)); - thread_local!(static K2: UnsafeCell<Option<S1>> = const { UnsafeCell::new(None) }); - - impl Drop for S1 { - fn drop(&mut self) { - assert!(self.0.try_with(|_| ()).is_err()); - } - } - - thread::spawn(move || unsafe { - K1.with(|s| *s.get() = Some(S1(&K1))); - }) - .join() - .unwrap(); - - thread::spawn(move || unsafe { - K2.with(|s| *s.get() = Some(S1(&K2))); - }) - .join() - .unwrap(); -} - -// 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(Signal); - thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None)); - thread_local!(static K2: UnsafeCell<Option<NotifyOnDrop>> = UnsafeCell::new(None)); - - impl Drop for S1 { - fn drop(&mut self) { - let S1(ref signal) = *self; - unsafe { - let _ = K2.try_with(|s| *s.get() = Some(NotifyOnDrop(signal.clone()))); - } - } - } - - let signal = Signal::default(); - let signal2 = signal.clone(); - let _t = thread::spawn(move || unsafe { - let mut signal = Some(signal2); - K1.with(|s| *s.get() = Some(S1(signal.take().unwrap()))); - }); - signal.wait(); -} - -#[test] -fn dtors_in_dtors_in_dtors_const_init() { - struct S1(Signal); - thread_local!(static K1: UnsafeCell<Option<S1>> = const { UnsafeCell::new(None) }); - thread_local!(static K2: UnsafeCell<Option<NotifyOnDrop>> = const { UnsafeCell::new(None) }); - - impl Drop for S1 { - fn drop(&mut self) { - let S1(ref signal) = *self; - unsafe { - let _ = K2.try_with(|s| *s.get() = Some(NotifyOnDrop(signal.clone()))); - } - } - } - - let signal = Signal::default(); - let signal2 = signal.clone(); - let _t = thread::spawn(move || unsafe { - let mut signal = Some(signal2); - K1.with(|s| *s.get() = Some(S1(signal.take().unwrap()))); - }); - signal.wait(); -} - -// This test tests that TLS destructors have run before the thread joins. The -// test has no false positives (meaning: if the test fails, there's actually -// an ordering problem). It may have false negatives, where the test passes but -// join is not guaranteed to be after the TLS destructors. However, false -// negatives should be exceedingly rare due to judicious use of -// thread::yield_now and running the test several times. -#[test] -fn join_orders_after_tls_destructors() { - // We emulate a synchronous MPSC rendezvous channel using only atomics and - // thread::yield_now. We can't use std::mpsc as the implementation itself - // may rely on thread locals. - // - // The basic state machine for an SPSC rendezvous channel is: - // FRESH -> THREAD1_WAITING -> MAIN_THREAD_RENDEZVOUS - // where the first transition is done by the “receiving” thread and the 2nd - // transition is done by the “sending” thread. - // - // We add an additional state `THREAD2_LAUNCHED` between `FRESH` and - // `THREAD1_WAITING` to block until all threads are actually running. - // - // A thread that joins on the “receiving” thread completion should never - // observe the channel in the `THREAD1_WAITING` state. If this does occur, - // we switch to the “poison” state `THREAD2_JOINED` and panic all around. - // (This is equivalent to “sending” from an alternate producer thread.) - // - // Relaxed memory ordering is fine because and spawn()/join() already provide all the - // synchronization we need here. - const FRESH: u8 = 0; - const THREAD2_LAUNCHED: u8 = 1; - const THREAD1_WAITING: u8 = 2; - const MAIN_THREAD_RENDEZVOUS: u8 = 3; - const THREAD2_JOINED: u8 = 4; - static SYNC_STATE: AtomicU8 = AtomicU8::new(FRESH); - - for _ in 0..10 { - SYNC_STATE.store(FRESH, Ordering::Relaxed); - - let jh = thread::Builder::new() - .name("thread1".into()) - .spawn(move || { - struct TlDrop; - - impl Drop for TlDrop { - fn drop(&mut self) { - let mut sync_state = SYNC_STATE.swap(THREAD1_WAITING, Ordering::Relaxed); - loop { - match sync_state { - THREAD2_LAUNCHED | THREAD1_WAITING => thread::yield_now(), - MAIN_THREAD_RENDEZVOUS => break, - THREAD2_JOINED => panic!( - "Thread 1 still running after thread 2 joined on thread 1" - ), - v => unreachable!("sync state: {}", v), - } - sync_state = SYNC_STATE.load(Ordering::Relaxed); - } - } - } - - thread_local! { - static TL_DROP: TlDrop = TlDrop; - } - - TL_DROP.with(|_| {}); - - loop { - match SYNC_STATE.load(Ordering::Relaxed) { - FRESH => thread::yield_now(), - THREAD2_LAUNCHED => break, - v => unreachable!("sync state: {}", v), - } - } - }) - .unwrap(); - - let jh2 = thread::Builder::new() - .name("thread2".into()) - .spawn(move || { - assert_eq!(SYNC_STATE.swap(THREAD2_LAUNCHED, Ordering::Relaxed), FRESH); - jh.join().unwrap(); - match SYNC_STATE.swap(THREAD2_JOINED, Ordering::Relaxed) { - MAIN_THREAD_RENDEZVOUS => return, - THREAD2_LAUNCHED | THREAD1_WAITING => { - panic!("Thread 2 running after thread 1 join before main thread rendezvous") - } - v => unreachable!("sync state: {:?}", v), - } - }) - .unwrap(); - - loop { - match SYNC_STATE.compare_exchange( - THREAD1_WAITING, - MAIN_THREAD_RENDEZVOUS, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - Ok(_) => break, - Err(FRESH) => thread::yield_now(), - Err(THREAD2_LAUNCHED) => thread::yield_now(), - Err(THREAD2_JOINED) => { - panic!("Main thread rendezvous after thread 2 joined thread 1") - } - v => unreachable!("sync state: {:?}", v), - } - } - jh2.join().unwrap(); - } -} - -// Test that thread::current is still available in TLS destructors. -#[test] -fn thread_current_in_dtor() { - // Go through one round of TLS destruction first. - struct Defer; - impl Drop for Defer { - fn drop(&mut self) { - RETRIEVE.with(|_| {}); - } - } - - struct RetrieveName; - impl Drop for RetrieveName { - fn drop(&mut self) { - *NAME.lock().unwrap() = Some(thread::current().name().unwrap().to_owned()); - } - } - - static NAME: Mutex<Option<String>> = Mutex::new(None); - - thread_local! { - static DEFER: Defer = const { Defer }; - static RETRIEVE: RetrieveName = const { RetrieveName }; - } - - Builder::new().name("test".to_owned()).spawn(|| DEFER.with(|_| {})).unwrap().join().unwrap(); - let name = NAME.lock().unwrap(); - let name = name.as_ref().unwrap(); - assert_eq!(name, "test"); -} diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 9f4f8a0d088..88b3e9e0ceb 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -31,9 +31,6 @@ #![stable(feature = "time", since = "1.3.0")] -#[cfg(test)] -mod tests; - #[stable(feature = "time", since = "1.3.0")] pub use core::time::Duration; #[stable(feature = "duration_checked_float", since = "1.66.0")] diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs deleted file mode 100644 index e88f2d5e806..00000000000 --- a/library/std/src/time/tests.rs +++ /dev/null @@ -1,274 +0,0 @@ -use core::fmt::Debug; - -#[cfg(not(target_arch = "wasm32"))] -use test::{Bencher, black_box}; - -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::from_micros(1) <= b, "{:?} is not almost equal to {:?}", a, b); - } - }}; -} - -#[test] -fn instant_monotonic() { - let a = Instant::now(); - loop { - let b = Instant::now(); - assert!(b >= a); - if b > a { - break; - } - } -} - -#[test] -#[cfg(not(target_arch = "wasm32"))] -fn instant_monotonic_concurrent() -> crate::thread::Result<()> { - let threads: Vec<_> = (0..8) - .map(|_| { - crate::thread::spawn(|| { - let mut old = Instant::now(); - let count = if cfg!(miri) { 1_000 } else { 5_000_000 }; - for _ in 0..count { - let new = Instant::now(); - assert!(new >= old); - old = new; - } - }) - }) - .collect(); - for t in threads { - t.join()?; - } - Ok(()) -} - -#[test] -fn instant_elapsed() { - let a = Instant::now(); - let _ = 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::SECOND; - 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); - - // On any platform, `Instant` should have the same resolution as `Duration` (e.g. 1 nanosecond) - // or better. Otherwise, math will be non-associative (see #91417). - let now = Instant::now(); - let provided_offset = Duration::from_nanos(1); - let later = now + provided_offset; - let measured_offset = later - now; - assert_eq!(measured_offset, provided_offset); -} - -#[test] -fn instant_duration_since_saturates() { - let a = Instant::now(); - assert_eq!((a - Duration::SECOND).duration_since(a), Duration::ZERO); -} - -#[test] -fn instant_checked_duration_since_nopanic() { - let now = Instant::now(); - let earlier = now - Duration::SECOND; - let later = now + Duration::SECOND; - assert_eq!(earlier.checked_duration_since(now), None); - assert_eq!(later.checked_duration_since(now), Some(Duration::SECOND)); - assert_eq!(now.checked_duration_since(now), Some(Duration::ZERO)); -} - -#[test] -fn instant_saturating_duration_since_nopanic() { - let a = Instant::now(); - #[allow(deprecated, deprecated_in_future)] - let ret = (a - Duration::SECOND).saturating_duration_since(a); - assert_eq!(ret, Duration::ZERO); -} - -#[test] -fn system_time_math() { - let a = SystemTime::now(); - let b = SystemTime::now(); - match b.duration_since(a) { - Ok(Duration::ZERO) => { - 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::SECOND; - 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::SECOND; - let one_second_from_epoch2 = - UNIX_EPOCH + Duration::from_millis(500) + Duration::from_millis(500); - 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::SECOND).unwrap(); - let b = ts.duration_since(UNIX_EPOCH).unwrap(); - assert!(b > a); - assert_eq!(b - a, Duration::SECOND); - - let thirty_years = Duration::SECOND * 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); -} - -#[test] -fn big_math() { - // Check that the same result occurs when adding/subtracting each duration one at a time as when - // adding/subtracting them all at once. - #[track_caller] - fn check<T: Eq + Copy + Debug>(start: Option<T>, op: impl Fn(&T, Duration) -> Option<T>) { - const DURATIONS: [Duration; 2] = - [Duration::from_secs(i64::MAX as _), Duration::from_secs(50)]; - if let Some(start) = start { - assert_eq!( - op(&start, DURATIONS.into_iter().sum()), - DURATIONS.into_iter().try_fold(start, |t, d| op(&t, d)) - ) - } - } - - check(SystemTime::UNIX_EPOCH.checked_sub(Duration::from_secs(100)), SystemTime::checked_add); - check(SystemTime::UNIX_EPOCH.checked_add(Duration::from_secs(100)), SystemTime::checked_sub); - - let instant = Instant::now(); - check(instant.checked_sub(Duration::from_secs(100)), Instant::checked_add); - check(instant.checked_sub(Duration::from_secs(i64::MAX as _)), Instant::checked_add); - check(instant.checked_add(Duration::from_secs(100)), Instant::checked_sub); - check(instant.checked_add(Duration::from_secs(i64::MAX as _)), Instant::checked_sub); -} - -macro_rules! bench_instant_threaded { - ($bench_name:ident, $thread_count:expr) => { - #[bench] - #[cfg(not(target_arch = "wasm32"))] - fn $bench_name(b: &mut Bencher) -> crate::thread::Result<()> { - use crate::sync::Arc; - use crate::sync::atomic::{AtomicBool, Ordering}; - - let running = Arc::new(AtomicBool::new(true)); - - let threads: Vec<_> = (0..$thread_count) - .map(|_| { - let flag = Arc::clone(&running); - crate::thread::spawn(move || { - while flag.load(Ordering::Relaxed) { - black_box(Instant::now()); - } - }) - }) - .collect(); - - b.iter(|| { - let a = Instant::now(); - let b = Instant::now(); - assert!(b >= a); - }); - - running.store(false, Ordering::Relaxed); - - for t in threads { - t.join()?; - } - Ok(()) - } - }; -} - -bench_instant_threaded!(instant_contention_01_threads, 0); -bench_instant_threaded!(instant_contention_02_threads, 1); -bench_instant_threaded!(instant_contention_04_threads, 3); -bench_instant_threaded!(instant_contention_08_threads, 7); -bench_instant_threaded!(instant_contention_16_threads, 15); |
