From b30b585663482de9014d1de8e4f4cf730d168d12 Mon Sep 17 00:00:00 2001 From: Michele d'Amico Date: Tue, 5 Apr 2022 13:14:30 +0200 Subject: [PATCH] #32 Moved crate doc from inner crate to rstest --- rstest_macros/src/lib.rs | 229 --------------------------------------- src/lib.rs | 229 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+), 229 deletions(-) diff --git a/rstest_macros/src/lib.rs b/rstest_macros/src/lib.rs index fff9f5c..d6cbe63 100644 --- a/rstest_macros/src/lib.rs +++ b/rstest_macros/src/lib.rs @@ -1,232 +1,3 @@ -//! This crate will help you to write simpler tests by leveraging a software testing concept called -//! [test fixtures](https://en.wikipedia.org/wiki/Test_fixture#Software). A fixture is something -//! that you can use in your tests to encapsulate a test's dependencies. -//! -//! The general idea is to have smaller tests that only describe the thing you're testing while you -//! hide the auxiliary utilities your tests make use of somewhere else. -//! For instance, if you have an application that has many tests with users, shopping baskets, and -//! products, you'd have to create a user, a shopping basket, and product every single time in -//! every test which becomes unwieldy quickly. In order to cut down on that repetition, you can -//! instead use fixtures to declare that you need those objects for your function and the fixtures -//! will take care of creating those by themselves. Focus on the important stuff in your tests! -//! -//! In `rstest` a fixture is a function that can return any kind of valid Rust type. This -//! effectively means that your fixtures are not limited by the kind of data they can return. -//! A test can consume an arbitrary number of fixtures at the same time. -//! -//! ## What -//! -//! The `rstest` crate defines the following procedural macros: -//! -//! - [`[rstest]`](macro@rstest): Declare that a test or a group of tests that may take -//! [fixtures](attr.rstest.html#injecting-fixtures), -//! [input table](attr.rstest.html#test-parametrized-cases) or -//! [list of values](attr.rstest.html#values-lists). -//! - [`[fixture]`](macro@fixture): To mark a function as a fixture. -//! -//! ## Why -//! -//! Very often in Rust we write tests like this -//! -//! ``` -//! #[test] -//! fn should_process_two_users() { -//! let mut repository = create_repository(); -//! repository.add("Bob", 21); -//! repository.add("Alice", 22); -//! -//! let processor = string_processor(); -//! processor.send_all(&repository, "Good Morning"); -//! -//! assert_eq!(2, processor.output.find("Good Morning").count()); -//! assert!(processor.output.contains("Bob")); -//! assert!(processor.output.contains("Alice")); -//! } -//! ``` -//! -//! By making use of [`[rstest]`](macro@rstest) we can isolate the dependencies `empty_repository` and -//! `string_processor` by passing them as fixtures: -//! -//! ``` -//! # use rstest::*; -//! #[rstest] -//! fn should_process_two_users(mut empty_repository: impl Repository, -//! string_processor: FakeProcessor) { -//! empty_repository.add("Bob", 21); -//! empty_repository.add("Alice", 22); -//! -//! string_processor.send_all("Good Morning"); -//! -//! assert_eq!(2, string_processor.output.find("Good Morning").count()); -//! assert!(string_processor.output.contains("Bob")); -//! assert!(string_processor.output.contains("Alice")); -//! } -//! ``` -//! -//! ... or if you use `"Alice"` and `"Bob"` in other tests, you can isolate `alice_and_bob` fixture -//! and use it directly: -//! -//! ``` -//! # use rstest::*; -//! # trait Repository { fn add(&mut self, name: &str, age: u8); } -//! # struct Rep; -//! # impl Repository for Rep { fn add(&mut self, name: &str, age: u8) {} } -//! # #[fixture] -//! # fn empty_repository() -> Rep { -//! # Rep -//! # } -//! #[fixture] -//! fn alice_and_bob(mut empty_repository: impl Repository) -> impl Repository { -//! empty_repository.add("Bob", 21); -//! empty_repository.add("Alice", 22); -//! empty_repository -//! } -//! -//! #[rstest] -//! fn should_process_two_users(alice_and_bob: impl Repository, -//! string_processor: FakeProcessor) { -//! string_processor.send_all("Good Morning"); -//! -//! assert_eq!(2, string_processor.output.find("Good Morning").count()); -//! assert!(string_processor.output.contains("Bob")); -//! assert!(string_processor.output.contains("Alice")); -//! } -//! ``` -//! -//! ## Injecting fixtures as function arguments -//! -//! `rstest` functions can receive fixtures by using them as input arguments. -//! A function decorated with [`[rstest]`](attr.rstest.html#injecting-fixtures) -//! will resolve each argument name by call the fixture function. -//! Fixtures should be annotated with the [`[fixture]`](macro@fixture) attribute. -//! -//! Fixtures will be resolved like function calls by following the standard resolution rules. -//! Therefore, an identically named fixture can be use in different context. -//! -//! ``` -//! # use rstest::*; -//! # trait Repository { } -//! # #[derive(Default)] -//! # struct DataSet {} -//! # impl Repository for DataSet { } -//! mod empty_cases { -//! # use rstest::*; -//! # trait Repository { } -//! # #[derive(Default)] -//! # struct DataSet {} -//! # impl Repository for DataSet { } -//! use super::*; -//! -//! #[fixture] -//! fn repository() -> impl Repository { -//! DataSet::default() -//! } -//! -//! #[rstest] -//! fn should_do_nothing(repository: impl Repository) { -//! //.. test impl .. -//! } -//! } -//! -//! mod non_trivial_case { -//! # use rstest::*; -//! # trait Repository { } -//! # #[derive(Default)] -//! # struct DataSet {} -//! # impl Repository for DataSet { } -//! use super::*; -//! -//! #[fixture] -//! fn repository() -> impl Repository { -//! let mut ds = DataSet::default(); -//! // Fill your dataset with interesting case -//! ds -//! } -//! -//! #[rstest] -//! fn should_notify_all_entries(repository: impl Repository) { -//! //.. test impl .. -//! } -//! } -//! -//! ``` -//! -//! Last but not least, fixtures can be injected like we saw in `alice_and_bob` example. -//! -//! ## Creating parametrized tests -//! -//! You can use also [`[rstest]`](attr.rstest.html#test-parametrized-cases) to create -//! simple table-based tests. Let's see the classic Fibonacci example: -//! -//! ``` -//! use rstest::rstest; -//! -//! #[rstest] -//! #[case(0, 0)] -//! #[case(1, 1)] -//! #[case(2, 1)] -//! #[case(3, 2)] -//! #[case(4, 3)] -//! #[case(5, 5)] -//! #[case(6, 8)] -//! fn fibonacci_test(#[case] input: u32,#[case] expected: u32) { -//! assert_eq!(expected, fibonacci(input)) -//! } -//! -//! fn fibonacci(input: u32) -> u32 { -//! match input { -//! 0 => 0, -//! 1 => 1, -//! n => fibonacci(n - 2) + fibonacci(n - 1) -//! } -//! } -//! ``` -//! This will generate a bunch of tests, one for every `#[case(a, b)]`. -//! -//! ## Creating a test for each combinations of given values -//! -//! In some cases you need to test your code for each combinations of some input values. In this -//! cases [`[rstest]`](attr.rstest.html#values-lists) give you the ability to define a list -//! of values (rust expressions) to use for an arguments. -//! -//! ``` -//! # use rstest::rstest; -//! # #[derive(PartialEq, Debug)] -//! # enum State { Init, Start, Processing, Terminated } -//! # #[derive(PartialEq, Debug)] -//! # enum Event { Error, Fatal } -//! # impl State { fn process(self, event: Event) -> Self { self } } -//! -//! #[rstest] -//! fn should_terminate( -//! #[values(State::Init, State::Start, State::Processing)] -//! state: State, -//! #[values(Event::Error, Event::Fatal)] -//! event: Event -//! ) { -//! assert_eq!(State::Terminated, state.process(event)) -//! } -//! ``` -//! -//! This will generate a test for each combination of `state` and `event`. -//! -//! ## Magic Conversion -//! -//! If you need a value where its type implement `FromStr()` trait you -//! can use a literal string to build it. -//! -//! ``` -//! # use rstest::rstest; -//! # use std::net::SocketAddr; -//! #[rstest] -//! #[case("1.2.3.4:8080", 8080)] -//! #[case("127.0.0.1:9000", 9000)] -//! fn check_port(#[case] addr: SocketAddr, #[case] expected: u16) { -//! assert_eq!(expected, addr.port()); -//! } -//! ``` -//! You can use this feature also in value list and in fixture default value. - #![cfg_attr(use_proc_macro_diagnostic, feature(proc_macro_diagnostic))] extern crate proc_macro; diff --git a/src/lib.rs b/src/lib.rs index 20c6e50..410bac0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,230 @@ +//! This crate will help you to write simpler tests by leveraging a software testing concept called +//! [test fixtures](https://en.wikipedia.org/wiki/Test_fixture#Software). A fixture is something +//! that you can use in your tests to encapsulate a test's dependencies. +//! +//! The general idea is to have smaller tests that only describe the thing you're testing while you +//! hide the auxiliary utilities your tests make use of somewhere else. +//! For instance, if you have an application that has many tests with users, shopping baskets, and +//! products, you'd have to create a user, a shopping basket, and product every single time in +//! every test which becomes unwieldy quickly. In order to cut down on that repetition, you can +//! instead use fixtures to declare that you need those objects for your function and the fixtures +//! will take care of creating those by themselves. Focus on the important stuff in your tests! +//! +//! In `rstest` a fixture is a function that can return any kind of valid Rust type. This +//! effectively means that your fixtures are not limited by the kind of data they can return. +//! A test can consume an arbitrary number of fixtures at the same time. +//! +//! ## What +//! +//! The `rstest` crate defines the following procedural macros: +//! +//! - [`[rstest]`](macro@rstest): Declare that a test or a group of tests that may take +//! [fixtures](attr.rstest.html#injecting-fixtures), +//! [input table](attr.rstest.html#test-parametrized-cases) or +//! [list of values](attr.rstest.html#values-lists). +//! - [`[fixture]`](macro@fixture): To mark a function as a fixture. +//! +//! ## Why +//! +//! Very often in Rust we write tests like this +//! +//! ``` +//! #[test] +//! fn should_process_two_users() { +//! let mut repository = create_repository(); +//! repository.add("Bob", 21); +//! repository.add("Alice", 22); +//! +//! let processor = string_processor(); +//! processor.send_all(&repository, "Good Morning"); +//! +//! assert_eq!(2, processor.output.find("Good Morning").count()); +//! assert!(processor.output.contains("Bob")); +//! assert!(processor.output.contains("Alice")); +//! } +//! ``` +//! +//! By making use of [`[rstest]`](macro@rstest) we can isolate the dependencies `empty_repository` and +//! `string_processor` by passing them as fixtures: +//! +//! ``` +//! # use rstest::*; +//! #[rstest] +//! fn should_process_two_users(mut empty_repository: impl Repository, +//! string_processor: FakeProcessor) { +//! empty_repository.add("Bob", 21); +//! empty_repository.add("Alice", 22); +//! +//! string_processor.send_all("Good Morning"); +//! +//! assert_eq!(2, string_processor.output.find("Good Morning").count()); +//! assert!(string_processor.output.contains("Bob")); +//! assert!(string_processor.output.contains("Alice")); +//! } +//! ``` +//! +//! ... or if you use `"Alice"` and `"Bob"` in other tests, you can isolate `alice_and_bob` fixture +//! and use it directly: +//! +//! ``` +//! # use rstest::*; +//! # trait Repository { fn add(&mut self, name: &str, age: u8); } +//! # struct Rep; +//! # impl Repository for Rep { fn add(&mut self, name: &str, age: u8) {} } +//! # #[fixture] +//! # fn empty_repository() -> Rep { +//! # Rep +//! # } +//! #[fixture] +//! fn alice_and_bob(mut empty_repository: impl Repository) -> impl Repository { +//! empty_repository.add("Bob", 21); +//! empty_repository.add("Alice", 22); +//! empty_repository +//! } +//! +//! #[rstest] +//! fn should_process_two_users(alice_and_bob: impl Repository, +//! string_processor: FakeProcessor) { +//! string_processor.send_all("Good Morning"); +//! +//! assert_eq!(2, string_processor.output.find("Good Morning").count()); +//! assert!(string_processor.output.contains("Bob")); +//! assert!(string_processor.output.contains("Alice")); +//! } +//! ``` +//! +//! ## Injecting fixtures as function arguments +//! +//! `rstest` functions can receive fixtures by using them as input arguments. +//! A function decorated with [`[rstest]`](attr.rstest.html#injecting-fixtures) +//! will resolve each argument name by call the fixture function. +//! Fixtures should be annotated with the [`[fixture]`](macro@fixture) attribute. +//! +//! Fixtures will be resolved like function calls by following the standard resolution rules. +//! Therefore, an identically named fixture can be use in different context. +//! +//! ``` +//! # use rstest::*; +//! # trait Repository { } +//! # #[derive(Default)] +//! # struct DataSet {} +//! # impl Repository for DataSet { } +//! mod empty_cases { +//! # use rstest::*; +//! # trait Repository { } +//! # #[derive(Default)] +//! # struct DataSet {} +//! # impl Repository for DataSet { } +//! use super::*; +//! +//! #[fixture] +//! fn repository() -> impl Repository { +//! DataSet::default() +//! } +//! +//! #[rstest] +//! fn should_do_nothing(repository: impl Repository) { +//! //.. test impl .. +//! } +//! } +//! +//! mod non_trivial_case { +//! # use rstest::*; +//! # trait Repository { } +//! # #[derive(Default)] +//! # struct DataSet {} +//! # impl Repository for DataSet { } +//! use super::*; +//! +//! #[fixture] +//! fn repository() -> impl Repository { +//! let mut ds = DataSet::default(); +//! // Fill your dataset with interesting case +//! ds +//! } +//! +//! #[rstest] +//! fn should_notify_all_entries(repository: impl Repository) { +//! //.. test impl .. +//! } +//! } +//! +//! ``` +//! +//! Last but not least, fixtures can be injected like we saw in `alice_and_bob` example. +//! +//! ## Creating parametrized tests +//! +//! You can use also [`[rstest]`](attr.rstest.html#test-parametrized-cases) to create +//! simple table-based tests. Let's see the classic Fibonacci example: +//! +//! ``` +//! use rstest::rstest; +//! +//! #[rstest] +//! #[case(0, 0)] +//! #[case(1, 1)] +//! #[case(2, 1)] +//! #[case(3, 2)] +//! #[case(4, 3)] +//! #[case(5, 5)] +//! #[case(6, 8)] +//! fn fibonacci_test(#[case] input: u32,#[case] expected: u32) { +//! assert_eq!(expected, fibonacci(input)) +//! } +//! +//! fn fibonacci(input: u32) -> u32 { +//! match input { +//! 0 => 0, +//! 1 => 1, +//! n => fibonacci(n - 2) + fibonacci(n - 1) +//! } +//! } +//! ``` +//! This will generate a bunch of tests, one for every `#[case(a, b)]`. +//! +//! ## Creating a test for each combinations of given values +//! +//! In some cases you need to test your code for each combinations of some input values. In this +//! cases [`[rstest]`](attr.rstest.html#values-lists) give you the ability to define a list +//! of values (rust expressions) to use for an arguments. +//! +//! ``` +//! # use rstest::rstest; +//! # #[derive(PartialEq, Debug)] +//! # enum State { Init, Start, Processing, Terminated } +//! # #[derive(PartialEq, Debug)] +//! # enum Event { Error, Fatal } +//! # impl State { fn process(self, event: Event) -> Self { self } } +//! +//! #[rstest] +//! fn should_terminate( +//! #[values(State::Init, State::Start, State::Processing)] +//! state: State, +//! #[values(Event::Error, Event::Fatal)] +//! event: Event +//! ) { +//! assert_eq!(State::Terminated, state.process(event)) +//! } +//! ``` +//! +//! This will generate a test for each combination of `state` and `event`. +//! +//! ## Magic Conversion +//! +//! If you need a value where its type implement `FromStr()` trait you +//! can use a literal string to build it. +//! +//! ``` +//! # use rstest::rstest; +//! # use std::net::SocketAddr; +//! #[rstest] +//! #[case("1.2.3.4:8080", 8080)] +//! #[case("127.0.0.1:9000", 9000)] +//! fn check_port(#[case] addr: SocketAddr, #[case] expected: u16) { +//! assert_eq!(expected, addr.port()); +//! } +//! ``` +//! You can use this feature also in value list and in fixture default value. + pub use rstest_macros::{rstest, fixture};