fluent_test/
lib.rs

1//! FluentTest: A fluent, Jest-like testing library for Rust
2//!
3//! This crate provides a more expressive way to write tests in Rust,
4//! inspired by JavaScript testing frameworks like Jest.
5//!
6//! By default, assertions behave like standard Rust assertions.
7//! Enable enhanced output with:
8//!
9//! ```
10//! // In your test code:
11//! use fluent_test::prelude::*;
12//!
13//! fn my_test() {
14//!     // Enable enhanced output for this test
15//!     fluent_test::config().enhanced_output(true).apply();
16//!     
17//!     expect!(2 + 2).to_equal(4);
18//! }
19//! ```
20//!
21//! Or set the FLUENT_TEST_ENHANCED_OUTPUT=true environment variable.
22
23// Allow explicit return statements as part of the coding style
24#![allow(clippy::needless_return)]
25
26// Initialization constants and utilities
27
28// Import Once for initialization
29use std::sync::Once;
30
31// Initialization for tests
32static TEST_INIT: Once = Once::new();
33
34pub mod backend;
35pub mod config;
36pub mod events;
37pub mod frontend;
38mod reporter;
39
40// Auto-initialize for tests if enhanced output is enabled
41pub fn auto_initialize_for_tests() {
42    TEST_INIT.call_once(|| {
43        // Check environment variable to enable enhanced output
44        let config = config::Config::new();
45        if config.enhanced_output {
46            // Apply the config which will initialize the event system
47            config.apply();
48        }
49    });
50}
51
52// Re-export the initialize function
53pub use config::initialize;
54
55// Export attribute macros for fixtures
56pub use fluent_test_macros::{after_all, before_all, setup, tear_down, with_fixtures, with_fixtures_module};
57
58// Global exit handler for after_all fixtures
59#[ctor::dtor]
60fn run_after_all_fixtures() {
61    backend::fixtures::run_after_all_fixtures();
62}
63
64/// Matcher traits module for bringing the traits into scope
65pub mod matchers {
66    pub use crate::backend::matchers::boolean::BooleanMatchers;
67    pub use crate::backend::matchers::collection::{CollectionExtensions, CollectionMatchers};
68    pub use crate::backend::matchers::equality::EqualityMatchers;
69    pub use crate::backend::matchers::hashmap::HashMapMatchers;
70    pub use crate::backend::matchers::numeric::NumericMatchers;
71    pub use crate::backend::matchers::option::OptionMatchers;
72    pub use crate::backend::matchers::result::ResultMatchers;
73    pub use crate::backend::matchers::string::StringMatchers;
74}
75
76/// Main prelude module containing everything needed for fluent testing
77pub mod prelude {
78    pub use crate::backend::Assertion;
79    pub use crate::expect;
80    pub use crate::expect_not;
81
82    // Fixture attribute macros
83    pub use crate::{after_all, before_all, setup, tear_down, with_fixtures, with_fixtures_module};
84
85    // Import all matcher traits
86    pub use crate::matchers::*;
87
88    // Import modifiers
89    pub use crate::backend::modifiers::*;
90
91    // Import configuration and initialization
92    pub use crate::config;
93    pub use crate::initialize;
94
95    #[cfg(test)]
96    pub use crate::auto_initialize_for_tests;
97}
98
99// Re-exports
100pub use crate::config::Config;
101pub use crate::reporter::Reporter;
102
103/// Creates a new test configuration
104pub fn config() -> Config {
105    Config::new()
106}
107
108/// Main entry point for fluent assertions
109#[macro_export]
110macro_rules! expect {
111    ($expr:expr) => {{
112        // Always auto-initialize
113        $crate::auto_initialize_for_tests();
114
115        $crate::backend::Assertion::new($expr, stringify!($expr))
116    }};
117}
118
119/// Shorthand for creating a negated expectation
120/// This provides a more natural way to write assertions with not
121#[macro_export]
122macro_rules! expect_not {
123    ($expr:expr) => {{
124        // Always auto-initialize
125        $crate::auto_initialize_for_tests();
126
127        use $crate::backend::modifiers::NotModifier;
128        $crate::backend::Assertion::new($expr, stringify!($expr)).not()
129    }};
130}
131
132/// Run all FluentTest tests in a module
133///
134/// This can be used as a test harness to handle initialization
135/// and reporting.
136#[macro_export]
137macro_rules! fluent_test {
138    () => {
139        #[test]
140        fn _fluent_test_runner() {
141            // Auto-initialize if enhanced output is enabled
142            $crate::auto_initialize_for_tests();
143
144            // Check if enhanced output is enabled
145            let enhanced_output = $crate::config::is_enhanced_output_enabled();
146
147            // Setup reporting guard only if enhanced output is enabled
148            if enhanced_output {
149                // Use a drop guard to ensure reporter runs at the end
150                struct ReportOnDrop;
151                impl Drop for ReportOnDrop {
152                    fn drop(&mut self) {
153                        $crate::Reporter::summarize();
154                    }
155                }
156
157                let _guard = ReportOnDrop;
158            }
159
160            // The test itself runs normally
161        }
162    };
163}
164
165// Special module for test support
166#[cfg(test)]
167pub mod test_utils {
168    // Just re-export all the traits for easy importing in tests
169    pub use crate::backend::matchers::boolean::BooleanMatchers;
170    pub use crate::backend::matchers::collection::{CollectionExtensions, CollectionMatchers};
171    pub use crate::backend::matchers::equality::EqualityMatchers;
172    pub use crate::backend::matchers::hashmap::HashMapMatchers;
173    pub use crate::backend::matchers::numeric::NumericMatchers;
174    pub use crate::backend::matchers::option::OptionMatchers;
175    pub use crate::backend::matchers::result::ResultMatchers;
176    pub use crate::backend::matchers::string::StringMatchers;
177
178    // Helper function to set up testing
179    pub fn setup_tests() {
180        // Force enhanced output for internal tests
181        crate::config().enhanced_output(true).apply();
182    }
183
184    // When tests run, make sure we have enhanced output enabled
185    // by default for internal library tests
186    #[test]
187    #[ignore]
188    fn _setup_for_tests() {
189        setup_tests();
190    }
191}