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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
//! # Clearcheck: Elegant and extensible assertions in Rust
//!
//! clearcheck is designed to make assertion statements as clear and concise as possible.
//! It allows chaining multiple assertions together for a fluent and intuitive syntax, leading to more self-documenting test cases.
//!
//!```rust
//! use clearcheck::assertions::string::length::LengthAssertion;
//! use clearcheck::assertions::string::membership::MembershipAssertion;
//! use clearcheck::assertions::string::numeric::NumericAssertion;
//! use clearcheck::assertions::string::regex::RegularExpressionAssertion;
//!
//! let pass_phrase = "P@@sw0rd1 zebra alpha";
//! pass_phrase.should_not_be_empty()
//! .should_have_at_least_length(10)
//! .should_contain_all_characters(vec!['@', ' '])
//! .should_contain_a_digit()
//! .should_not_contain_ignoring_case("pass")
//! .should_not_contain_ignoring_case("word");
//!```
//! # Key features
//!
//! - **Fluent API**: Chain assertions for a natural and readable experience.
//! - **Extensive assertions**: Variety of assertions covering common validation needs.
//! - **Customizable**: Extend with your own assertions for specific domain requirements.
//! - **Type-safe**: Built with Rust's type system for reliable and expressive assertions.
//! - **Custom assertions**: Craft assertions tailored to your exact needs, ensuring comprehensive validations for various data structures.
//!
//! # Rust features
//!
//! clearcheck crate supports the following features:
//! - date enables [assertions on date](assertions::date::DateAssertion)
//! - file enables [assertions on filepath](assertions::file::FileAssertion)
//! - num enables [assertions on float](assertions::float::FloatAssertion) and [assertions on integer](assertions::int::IntAssertion)
//! - regex enables [regular expression assertions on string](assertions::string::regex)
//!
//! # Assertions vs Matchers
//!
//! **Assertions** serve as the cornerstone of the test cases, defining the exact expectations the code must fulfill.
//! They act as a contract, ensuring that each data type (/data structure) adheres to its intended behavior.
//!
//! **Matchers**, on the other hand, provide the granular tools for carrying out these assertions.
//! They examine data and verify that the data conforms to specific criteria.
//!
//! In essence, assertions orchestrate the high-level validation logic, while matchers act as the
//! code-level inspectors, ensuring every detail aligns with the expectations.
//!
//! # Unleashing the power of custom matchers and assertions
//!
//! While this crate comes loaded with a plethora of ready-made assertions, sometimes your testing needs demand a bespoke touch.
//! clearcheck allows crafting your own custom matchers and assertions!
//!
//! The possibilities are endless:
//!
//! - **Domain-specific validation**: Craft assertions that understand the nuances of your business logic.
//! - **Enhanced readability**: Write clear and concise matchers that mirror your domain vocabulary, making your tests self-documenting and understandable.
//! - **Reduced redundancy**: Eliminate repetitive code by encapsulating complex validation logic within reusable matchers.
//!
//! Let's craft a custom password matcher that enforces the following:
//!
//! - Password must not be empty.
//! - Password must have a minimum length of 10 characters.
//! - Password must contain at least one digit.
//! - Password must contain any of the following characters: '@', '#'.
//! - Password must not begin with the string "pass" (case-insensitive).
//! - Password must not contain the strings "pass" or "word" (case-insensitive).
//!
//!```rust
//! //1. Write a matcher.
//! use std::fmt::Debug;
//!
//! use clearcheck::matchers::{BoxWrap, Should};
//! use clearcheck::matchers::compose::{Matchers, MatchersBuilder};
//! use clearcheck::matchers::string::boundary::begin_with;
//! use clearcheck::matchers::string::empty::be_empty;
//! use clearcheck::matchers::string::length::have_atleast_same_length;
//! use clearcheck::matchers::string::membership::{
//! contain_a_digit,
//! contain_any_of_characters,
//! contain_ignoring_case
//! };
//!
//! fn be_a_valid_password<T: AsRef<str> + Debug>() -> Matchers<T> {
//! MatchersBuilder::start_building_with_inverted(be_empty().boxed())
//! .push(have_atleast_same_length(10).boxed())
//! .push(contain_a_digit().boxed())
//! .push(contain_any_of_characters(vec!['@', '#']).boxed())
//! .push_inverted(begin_with("pass").boxed())
//! .push_inverted(contain_ignoring_case("pass").boxed())
//! .push_inverted(contain_ignoring_case("word").boxed())
//! .combine_as_and()
//! }
//!
//! //2. Combine the matcher into a powerful assertion for valid passwords.
//! trait PasswordAssertion {
//! fn should_be_a_valid_password(&self) -> &Self;
//! }
//!
//! impl PasswordAssertion for &str {
//! fn should_be_a_valid_password(&self) -> &Self {
//! self.should(&be_a_valid_password());
//! self
//! }
//! }
//!
//! //3. That's it. Use the password assertion.
//! #[test]
//! fn should_be_a_valid_password() {
//! let password = "P@@sw0rd9082";
//! password.should_be_a_valid_password();
//! }
//! ```
pub mod assertions;
pub mod matchers;