Releases: frondeus/test-case
TestCase - v2.0.2
Bug fixes
- Fixed the fact that
match X if Y
didn't produce correct guard code which resulted in false positives.
Full Changelog: v2.0.1...v2.0.2
TestCase - v2.0.1
Bug fixes:
matches Pattern if condition
parses correctly (if condition
part wasn't allowed despite being documented)
Full Changelog: v2.0.0...v2.0.1
TestCase - v2.0.0
Overview
This crate provides the #[test_case]
procedural macro attribute that generates multiple parametrized tests using one body with different input parameters.
A test is generated for each data set passed in the test_case
attribute.
Under the hood, all test cases that share the same body are grouped into a mod, giving clear and readable test results.
What's changed
New features
=> with |x: T| assert!(x)
custom inline test assertions=> using path::to::fn
custom fn test assertionsignore
andinconclusive
can be combined with other keywords=> it|is ...
syntax is a built-in (previously requiredhamcrest2
crate integration)- Simple test cases support returning
Result<(), _>
as#[test]
attribute does #50
Improvements
- Code refactoring
- Test function is kept in its original scope so it can be reused for non-test related code #77
- Improved test case name selection
Breaking changes
- Deprecation of
inconclusive
within test description string - it will no longer act like modifier keyword - Removal of
hamcrest2
integration (it
andis
are kept, complex assertions now have different syntax)
Custom inline test assertions
Now it is possible to pass the closure which will assert the test case.
#[test_case(1.0 => with |v: f64| assert!(v.is_infinite()))]
#[test_case(0.0 => with |v: f64| assert!(v.is_nan()))]
fn divide_by_zero_f64_with_lambda(input: f64) -> f64 {
input / 0.0f64
}
Custom fn test assertions
Not only the closure is possible but also you can point to the plain function:
Given:
fn assert_is_power_of_two(input: u64) {
assert!(input.is_power_of_two())
}
You can now assert:
#[test_case(1 => using assert_is_power_of_two)]
fn power_of_two_with_using(input: u64) -> u64 {
input
}
Not only that, you can also create a higher order function like this one:
fn wrapped_pretty_assert(expected: u64) -> impl Fn(u64) {
move |actual: u64| { pretty_assertions::assert_eq!(actual, expected) }
}
to achieve even better parameterized tests:
#[test_case(1 => using wrapped_pretty_assert(1))]
fn pretty_assertions_usage(input: u64) -> u64 {
input
}
ignore
and inconclusive
can be combined with other keywords
Sometimes you might want to temporarily disable one of the test cases without removing the testing assertion.
Thanks to this release now it is possible:
#[test_case(12 => ignore matches Ok(_))]
fn ignore_supported(_value: u64) -> Result<(), Box<dyn Error>> {
todo!()
}
=> it|is ...
syntax is a built-in
Previously test-case was integrated with hamcrest2
assertion crate.
This release breaks this dependency and provides an alternative solution:
#[test_case(1.0 => is equal_to 2.0 ; "eq1")]
#[test_case(1.0 => is greater_or_equal_than 1.0 ; "geq1")]
#[test_case(1.0 => is geq 1.0 ; "geq2")]
#[test_case(1.0 => is almost_equal_to 2.1 precision 0.15 ; "almost_eq1")]
#[test_case(1.0 => is almost 2.0 precision 0.01 ; "almost_eq2")]
fn complex_tests(input: f64) -> f64 {
input * 2.0
}
It also supports asserting paths:
#[test_case("Cargo.toml" => is existing_path)]
#[test_case("src/lib.rs" => is file)]
#[test_case("src/" => is dir ; "short_dir")]
#[test_case("src/" => is directory ; "long_dir")]
fn create_path(val: &str) -> std::path::PathBuf {
std::path::PathBuf::from(val)
}
As well as collections:
#[test_case(vec![1, 2, 3, 4] => it contains 1)]
#[test_case(vec![1, 2, 3, 4] => it contains_in_order [3, 4])]
fn contains_tests(items: Vec<u64>) -> Vec<u64> {
items
}
You can also use the combinators:
#[test_case(1.0 => is gt 0.0 and lt 5.0)]
#[test_case(0.3 => is (gt 0.0 and lt 1.0) or gt 1.2)]
#[test_case(0.7 => is (gt 0.0 and lt 1.0) or gt 1.2)]
fn combinators(v: f32) -> f32 {
v * 2.0
}
Note: The combinators are still a bit unpolished. Currently
test_case
only supports one type of combinator per group.
It means that if you want to combineand
withor
you need to use(
)
to explicitly mark the precedence.
However...
We hope that in the next version we will lift this restriction by providing a full precedence parsing.
Simple test cases support returning Result<(), _>
Finally, the test_case
macro now supports the Result return type just like the #[test]
attribute does.
It means the test case would fail if the function returns Err(...)
.
#[test_case(12)]
#[test_case(13)]
fn is_even(value: u64) -> Result<(), String> {
if value % 2 == 0 {
Ok(())
} else {
Err("is odd".to_string())
}
}
TestCase - v2.0.0-rc3
TestCase - v1.2.3
- Fix regression where
panics
andinconclusive
were not allowed ontest_cases
returning a value - Fix case where
test_case
would allow to return a type when only single attribute was used
TestCase - v1.2.2
TestCase - v2.0.0-rc2
New features
complex
test_case supports nownot
,and
andor
logical combinators
Breaking changes
- Bumped MSRV to 1.49
TestCase - v2.0.0-rc1
New features
=> with |x: T| assert!(x)
custom inline test assertions=> using path::to::fn
custom fn test assertionsignore
andinconclusive
can be combined with other keywords (eg.:=> ignore matches Ok(_)
)
Improvements
- Code refactoring
Breaking changes
- Deprecation of
inconclusive
within test description string - it will no longer act like modifier keyword - Deprecation of
hamcrest2
integration (it
andis
are kept, complex assertions now have different syntax)
TestCase - v1.2.1
- Disabled clippy warning when test-case was generating
assert_eq!(bool, bool)
expression.
TestCase - v1.2.0
New features
- Allow usage of fully qualified attribute
#[test_case::test_case]
(thanks to @tomprince)
Improvements
- Stopped code from emmiting unneded
()
expression in test cases withexpected
fragment (thanks to @martinvonz)