ntest-0.9.3/.cargo_vcs_info.json0000644000000001430000000000100122000ustar { "git": { "sha1": "5f025ba9cd586249c6d011d3c4580d12d551e533" }, "path_in_vcs": "ntest" }ntest-0.9.3/Cargo.toml0000644000000023360000000000100102040ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "ntest" version = "0.9.3" authors = ["Armin Becher "] description = "Testing framework for rust which enhances the built-in library with some useful features." documentation = "https://docs.rs/ntest" readme = "README.md" keywords = [ "test", "tests", "unit", "testing", ] categories = [ "development-tools", "development-tools::testing", ] license = "MIT" repository = "https://github.com/becheran/ntest" [profile.dev] panic = "unwind" [lib] path = "src/lib.rs" [dependencies.ntest_test_cases] version = "0.9.3" [dependencies.ntest_timeout] version = "0.9.3" [dev-dependencies.tokio] version = "1.6.1" features = [ "rt", "macros", ] [badges.maintenance] status = "actively-developed" ntest-0.9.3/Cargo.toml.orig000064400000000000000000000014410072674642500137110ustar 00000000000000[package] name = "ntest" version = "0.9.3" authors = [ "Armin Becher ",] edition = "2018" description = "Testing framework for rust which enhances the built-in library with some useful features." keywords = [ "test", "tests", "unit", "testing",] categories = [ "development-tools", "development-tools::testing",] readme = "README.md" license = "MIT" repository = "https://github.com/becheran/ntest" documentation = "https://docs.rs/ntest" [lib] path = "src/lib.rs" [dependencies.ntest_test_cases] version = "0.9.3" path = "../ntest_test_cases" [dependencies.ntest_timeout] version = "0.9.3" path = "../ntest_timeout" [badges.maintenance] status = "actively-developed" [profile.dev] panic = "unwind" [dev-dependencies.tokio] version = "1.6.1" features = [ "rt", "macros",] ntest-0.9.3/LICENSE000064400000000000000000000000120072674642500120200ustar 00000000000000../LICENSEntest-0.9.3/README.md000064400000000000000000000045610072674642500123070ustar 00000000000000# NTest [![docs](https://docs.rs/ntest/badge.svg)](https://docs.rs/ntest) [![crates](https://img.shields.io/badge/crates.io-ntest-orange)](https://crates.io/crates/ntest) [![downloads](https://badgen.net/crates/d/ntest)](https://crates.io/crates/ntest) [![build status](https://github.com/becheran/ntest/actions/workflows/ci.yml/badge.svg)](https://github.com/becheran/ntest/actions/workflows/ci.yml) [![license](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) Testing framework for rust which enhances the built-in library with some useful features. Inspired by the *.Net* unit-testing framework [NUnit](https://github.com/nunit/nunit). ## Getting Started Some functions of *NTest* use [procedural macros](https://doc.rust-lang.org/reference/procedural-macros.html) which are stable for rust edition 2018. If you use the library make sure that you are using the *2018 version* of rust. Update the *Cargo.toml* file: ```toml [package] edition = "2018" # .. ``` Add the *NTest library* to your developer dependencies in the *Cargo.toml* file: ```toml [dev-dependencies] ntest = "*" ``` ## Content - `#[timeout()]` Attribute used for timeouts in tests. - `#[test_case()]` Attribute used to define multiple test cases for a test function. - `assert_about_equal!()` Compare two floating point values or vectors for equality. - `assert_false!()` Expects false argument for test case. - `assert_true!()` Expects true argument for test case. - `assert_panics!()` Expects block to panic. Otherwise the test fails. For more information read the [documentation](https://docs.rs/ntest/). ## Examples ### Create test cases ```rust use ntest::test_case; #[test_case("https://doc.rust-lang.org.html")] #[test_case("http://www.website.php", name="important_test")] fn test_http_link_types(link: &str) { test_link(link, &LinkType::HTTP); } ``` ### Timeout for long running functions ```rust use ntest::timeout; #[test] #[timeout(10)] #[should_panic] fn timeout() { loop {}; } ``` ### Combine attributes ```rust use std::{thread, time}; use ntest::timeout; use ntest::test_case; #[test_case(200)] #[timeout(100)] #[should_panic] #[test_case(10)] #[timeout(100)] fn test_function(i : u32) { let sleep_time = time::Duration::from_millis(i); thread::sleep(sleep_time); } ``` ntest-0.9.3/src/lib.rs000064400000000000000000000157660072674642500127440ustar 00000000000000//! The ntest lib enhances the rust test framework with some useful functions. // Reexport procedural macros extern crate ntest_test_cases; extern crate ntest_timeout; #[doc(inline)] pub use ntest_test_cases::test_case; #[doc(inline)] pub use ntest_timeout::timeout; use std::sync::mpsc; use std::thread; use std::time::Duration; // Reexport traits mod traits; #[doc(inline)] pub use crate::traits::MaxDifference; #[doc(hidden)] /// Timeout helper for proc macro timeout pub fn execute_with_timeout( code: &'static (dyn Fn() -> T + Sync + 'static), timeout_ms: u64, ) -> Option { let (sender, receiver) = mpsc::channel(); thread::spawn(move || if let Ok(()) = sender.send(code()) {}); match receiver.recv_timeout(Duration::from_millis(timeout_ms)) { Ok(t) => Some(t), Err(_) => None, } } #[doc(hidden)] /// Difference helper for proc macro about equal pub fn about_eq(a: T, b: T, eps: f64) -> bool { a.max_diff(b) < eps } /// Compare floating point values or vectors of floating points wether they are approximately equal. /// The default value for epsilon is `1.0e-6`. /// /// # Examples /// /// Compare two floating point values which are about equal: /// ``` /// # use ntest::assert_about_eq; /// # fn main() { /// assert_about_eq!(42.00000001f32, 42.0f32); /// # } /// ``` /// /// Explicitly set an epsilon value. This test should fail: /// ``` should_panic /// # use ntest::assert_about_eq; /// # fn main() { /// assert_about_eq!(42.001f32, 42.0f32, 1.0e-4); /// # } /// ``` /// /// Compare two vectors or arrays of floats which are about equal: /// ``` /// # use ntest::assert_about_eq; /// # fn main() { /// assert_about_eq!(vec![1.100000001, 2.1], vec![1.1, 2.1], 0.001f64); /// # } /// ``` /// /// Arrays can be compared to a length of up to `32`. See the [MaxDifference](trait.MaxDifference.html) implementation for more details: /// ``` /// # use ntest::assert_about_eq; /// # fn main() { ///# // Test double usage ///# assert_about_eq!([1.100000001, 2.1], [1.1, 2.1], 0.001f64); /// assert_about_eq!([1.100000001, 2.1], [1.1, 2.1], 0.001f64); /// # } /// ``` #[macro_export] macro_rules! assert_about_eq { ($a:expr, $b:expr, $eps:expr) => { let eps = $eps; assert!( $crate::about_eq($a, $b, eps), "assertion failed: `(left !== right)` \ (left: `{:?}`, right: `{:?}`, epsilon: `{:?}`)", $a, $b, eps ); }; ($a:expr, $b:expr,$eps:expr,) => { assert_about_eq!($a, $b, $eps); }; ($a:expr, $b:expr) => { assert_about_eq!($a, $b, 1.0e-6); }; ($a:expr, $b:expr,) => { assert_about_eq!($a, $b, 1.0e-6); }; } /// Expects a true expression. Otherwise panics. /// /// Is an alias for the [assert! macro](https://doc.rust-lang.org/std/macro.assert.html). /// /// # Examples /// /// This call won't panic. /// ```rust /// # use ntest::assert_true; /// # fn main() { /// assert_true!(true); /// # } ///``` /// /// This call will panic. /// ```should_panic /// # use ntest::assert_true; /// # fn main() { /// assert_true!(false); /// # } /// ``` #[macro_export] macro_rules! assert_true { ($x:expr) => { if !$x { panic!("assertion failed: Expected 'true', but was 'false'"); } }; ($x:expr,) => { assert_true!($x); }; } /// Expects a false expression. Otherwise panics. /// /// # Examples /// /// This call won't panic. /// ```rust /// # use ntest::assert_false; /// # fn main() { /// assert_false!(false); /// # } /// ``` /// /// This call will panic. /// ```should_panic /// # use ntest::assert_false; /// # fn main() { /// assert_false!(true); /// # } /// ``` #[macro_export] macro_rules! assert_false { ($x:expr) => {{ if $x { panic!("assertion failed: Expected 'false', but was 'true'"); } }}; ($x:expr,) => {{ assert_false!($x); }}; } /// A panic in Rust is not always implemented via unwinding, but can be implemented by aborting the /// process as well. This function only catches unwinding panics, not those that abort the process. /// See the catch unwind [documentation](https://doc.rust-lang.org/std/panic/fn.catch_unwind.html) /// for more information. /// /// # Examples /// /// This call won't panic. /// ```rust /// # use ntest::assert_panics; /// # fn main() { /// // Other panics can happen before this call. /// assert_panics!({panic!("I am panicing")}); /// # } /// ``` /// /// This call will panic. /// ```should_panic /// # use ntest::assert_panics; /// # fn main() { /// assert_panics!({println!("I am not panicing")}); /// # } /// ``` #[macro_export] macro_rules! assert_panics { ($x:block) => {{ let result = std::panic::catch_unwind(|| $x); if !result.is_err() { panic!("assertion failed: code in block did not panic"); } }}; ($x:block,) => {{ assert_panics!($x); }}; } #[cfg(test)] mod tests { use super::*; #[test] fn assert_true() { assert_true!(true); } #[test] #[should_panic] fn assert_true_fails() { assert_true!(false); } #[test] fn assert_true_trailing_comma() { assert_true!(true,); } #[test] fn assert_false() { assert_false!(false); } #[test] #[should_panic] fn assert_false_fails() { assert_false!(true); } #[test] fn assert_false_trailing_comma() { assert_false!(false,); } #[test] fn assert_panics() { assert_panics!({ panic!("I am panicing!") },); } #[test] #[should_panic] fn assert_panics_fails() { assert_panics!({ println!("I am not panicing!") },); } #[test] fn assert_panics_trailing_comma() { assert_panics!({ panic!("I am panicing!") },); } #[test] fn vector() { assert_about_eq!(vec![1.1, 2.1], vec![1.1, 2.1]); } #[test] #[should_panic] fn vector_fails() { assert_about_eq!(vec![1.2, 2.1], vec![1.1, 2.1]); } #[test] fn vector_trailing_comma() { assert_about_eq!(vec![1.2, 2.1], vec![1.2, 2.1],); } #[test] fn vector_trailing_comma_with_epsilon() { assert_about_eq!(vec![1.100000001, 2.1], vec![1.1, 2.1], 0.001f64,); } #[test] fn it_should_not_panic_if_values_are_approx_equal() { assert_about_eq!(64f32.sqrt(), 8f32); } #[test] fn about_equal_f32() { assert_about_eq!(3f32, 3f32, 1f64); } #[test] fn about_equal_f64() { assert_about_eq!(3f64, 3f64); } #[test] fn compare_with_epsilon() { assert_about_eq!(42f64, 43f64, 2f64); } #[test] #[should_panic] fn fail_with_epsilon() { assert_about_eq!(3f64, 4f64, 1e-8f64); } } ntest-0.9.3/src/traits.rs000064400000000000000000000057070072674642500134760ustar 00000000000000/// Helper trait for `assert_about_equal` macro. Returns the max difference between /// two vectors of floats. Can also be used for single floats. /// /// # Examples /// /// Compare two floating numbers: /// ``` /// # use ntest::MaxDifference; /// # fn main() { /// assert!((0.1f64 - 42.1f32.max_diff(42.0f32)) < 1.0e-4f64); /// # } /// ``` /// /// Compare two vectors. Returns the maximum difference in the vectors. In this case *~0.1*.: /// ``` /// # use ntest::MaxDifference; /// # fn main() { /// assert!(0.1f64 - vec![42.0, 42.0f32, 1.001f32].max_diff(vec![42.0, 42.1f32, 1.0f32]) < 1.0e-4f64); /// # } /// ``` /// Compare two arrays. Trait implemented for arrays of length `0-32`: /// ``` /// # use ntest::MaxDifference; /// # fn main() { /// assert!(0.1f64 - [42.0, 42.0f32, 1.001f32].max_diff([42.0, 42.1f32, 1.0f32]) < 1.0e-4f64); /// # } /// ``` pub trait MaxDifference { fn max_diff(self, other: Self) -> f64; } impl MaxDifference for f32 { fn max_diff(self, other: Self) -> f64 { f64::from((self - other).abs()) } } impl MaxDifference for f64 { fn max_diff(self, other: Self) -> f64 { (self - other).abs() } } impl MaxDifference for Vec { fn max_diff(self, other: Self) -> f64 { let mut max: f64 = 0.0; for (a, b) in self.iter().zip(other.iter()) { let diff = f64::from((*a - *b).abs()); if diff > max { max = diff; } } max } } impl MaxDifference for Vec { fn max_diff(self, other: Self) -> f64 { let mut max: f64 = 0.0; for (a, b) in self.iter().zip(other.iter()) { let diff = (*a - *b).abs(); if diff > max { max = diff; } } max } } macro_rules! array_impls { ($($N:literal)+) => { $( impl MaxDifference for [f64; $N] { fn max_diff(self, other: Self) -> f64 { let mut max: f64 = 0.0; for (a, b) in self.iter().zip(other.iter()) { let diff = (*a - *b).abs(); if diff > max { max = diff; } } max } } impl MaxDifference for [f32; $N] { fn max_diff(self, other: Self) -> f64 { let mut max: f64 = 0.0; for (a, b) in self.iter().zip(other.iter()) { let diff = f64::from((*a - *b).abs()); if diff > max { max = diff; } } max } } )+ } } array_impls! { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 } ntest-0.9.3/tests/integration.rs000064400000000000000000000036560072674642500150670ustar 00000000000000use ntest::test_case; use ntest::timeout; use std::{thread, time}; const TWO_HUNDRED: u64 = 200; const TEN: u64 = 10; #[test_case(200)] #[timeout(100)] #[should_panic] #[test_case(10)] #[timeout(100)] #[test_case(TWO_HUNDRED)] #[timeout(100)] #[should_panic] #[test_case(TEN)] #[timeout(100)] fn test_function(i: u64) { let sleep_time = time::Duration::from_millis(i); thread::sleep(sleep_time); } #[test_case(1.2)] #[test_case(2.2)] fn test_f64(i: f64) { print!("{}", i); } #[test_case(-1)] #[test_case(-3)] fn test_int(i: i64) { print!("{}", i); } #[repr(u8)] enum Test { A = 200, B = 10 } #[test_case(Test::A)] #[timeout(100)] #[should_panic] #[test_case(Test::B)] #[timeout(100)] fn test_with_enum(i: Test) { let sleep_time = time::Duration::from_millis(i as u8 as _); thread::sleep(sleep_time); } #[test] #[timeout(100)] fn no_timeout() { let fifty_millis = time::Duration::from_millis(50); thread::sleep(fifty_millis); } #[test] #[timeout(10)] #[should_panic] fn timeout() { let fifty_millis = time::Duration::from_millis(50); thread::sleep(fifty_millis); } #[test] #[timeout(1)] #[should_panic] fn timeout_inf_loop() { let ten_millis = time::Duration::from_millis(10); loop{ thread::sleep(ten_millis); } } #[test] #[timeout(100)] fn timeout_with_result() -> Result<(), String> { let ten_millis = time::Duration::from_millis(10); thread::sleep(ten_millis); Ok(()) } #[tokio::test] #[timeout(100)] async fn tokio_timeout() { let ten_millis = time::Duration::from_millis(10); thread::sleep(ten_millis); } #[tokio::test] #[timeout(1)] #[should_panic] async fn tokio_should_panic_timeout() { let ten_millis = time::Duration::from_millis(10); loop{ thread::sleep(ten_millis); } } #[test] #[should_panic] #[timeout(20000)] fn panic() { panic!(); }