Skip to main content

tui_piechart/macros/
test.rs

1//! Test utility macros for reducing boilerplate code.
2//!
3//! This module contains macros specifically designed for testing patterns,
4//! helping eliminate repetitive test code across the crate.
5//!
6//! # Overview
7//!
8//! The macros in this module help with:
9//! - Enum testing (default, clone, debug)
10//! - Assertion tests
11//! - Debug format verification
12//! - Type conversions
13//! - String transformations
14//! - Render/visual tests (widget rendering without panics)
15//!
16//! # Organization
17//!
18//! This is part of the `macros` module family:
19//! - **`macros::test`** - Test utilities (this module)
20//! - Module-specific macros live in their respective files (e.g., `unicode_converter!` in `title.rs`)
21//!
22//! # Usage Examples
23//!
24//! ## Testing Enums
25//!
26//! ```
27//! # use tui_piechart::enum_tests;
28//! #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
29//! enum MyPosition {
30//!     #[default]
31//!     Top,
32//!     Bottom,
33//! }
34//!
35//! mod tests {
36//!     use super::*;
37//!
38//!     enum_tests! {
39//!         enum_type: MyPosition,
40//!         default_test: (test_default, MyPosition::Top),
41//!         clone_test: (test_clone, MyPosition::Bottom),
42//!         debug_test: (test_debug, MyPosition::Bottom, "Bottom"),
43//!     }
44//! }
45//! # fn main() {}
46//! ```
47//!
48//! ## Testing Multiple Debug Formats
49//!
50//! ```
51//! # use tui_piechart::debug_format_tests;
52//! # #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
53//! # enum MyAlignment {
54//! #     #[default]
55//! #     Start,
56//! #     Center,
57//! #     End,
58//! # }
59//! mod tests {
60//!     use super::*;
61//!
62//!     debug_format_tests! {
63//!         enum_type: MyAlignment,
64//!         tests: [
65//!             (test_start_debug, MyAlignment::Start, "Start"),
66//!             (test_center_debug, MyAlignment::Center, "Center"),
67//!             (test_end_debug, MyAlignment::End, "End"),
68//!         ]
69//!     }
70//! }
71//! # fn main() {}
72//! ```
73//!
74//! ## Simple Assertions
75//!
76//! ```
77//! # use tui_piechart::assert_test;
78//! # use tui_piechart::assert_eq_test;
79//! mod tests {
80//!     use super::*;
81//!     assert_test!(test_is_empty, "".is_empty());
82//!     assert_eq_test!(test_addition, 2 + 2, 4);
83//! }
84//! # fn main() {}
85//! ```
86//!
87//! ## Render Tests
88//!
89//! ```
90//! use tui_piechart::{render_test, render_with_size_test, render_empty_test};
91//! use tui_piechart::PieChart;
92//! use ratatui::layout::Rect;
93//!
94//! mod tests {
95//!     use super::*;
96//!     render_test!(test_basic_render, PieChart::default(), Rect::new(0, 0, 40, 20));
97//!     render_with_size_test!(test_small_size, PieChart::default(), width: 20, height: 10);
98//!     render_empty_test!(test_empty_area, PieChart::default());
99//! }
100//! # fn main() {}
101//! ```
102//!
103//! # Benefits
104//!
105//! - **Reduces boilerplate**: Write less repetitive test code
106//! - **Consistency**: All tests follow the same pattern
107//! - **Maintainability**: Change patterns in one place
108//! - **Readability**: Declarative test definitions
109//! - **Visual testing**: Ensure widgets render without panics
110
111/// Generate standard enum tests (default, clone, debug).
112///
113/// This macro generates common test cases for enums that implement Default, Clone,
114/// Copy, Debug, and `PartialEq`. It reduces boilerplate in test modules.
115///
116/// # Examples
117///
118/// ```
119/// # use tui_piechart::{enum_tests};
120/// mod tests {
121///     use super::*;
122///
123///     enum_tests! {
124///         enum_type: MyEnum,
125///         default_test: (test_default, MyEnum::DefaultVariant),
126///         clone_test: (test_clone, MyEnum::OtherVariant),
127///         debug_test: (test_debug, MyEnum::OtherVariant, "OtherVariant"),
128///     }
129/// }
130/// # fn main() {}
131/// ```
132#[macro_export]
133macro_rules! enum_tests {
134    (
135        enum_type: $enum_name:ty,
136        default_test: ($default_test_name:ident, $default_variant:expr),
137        clone_test: ($clone_test_name:ident, $test_variant:expr),
138        debug_test: ($debug_test_name:ident, $debug_variant:expr, $debug_str:expr $(,)?),
139    ) => {
140        #[test]
141        fn $default_test_name() {
142            assert_eq!(<$enum_name>::default(), $default_variant);
143        }
144
145        #[test]
146        fn $clone_test_name() {
147            let value = $test_variant;
148            let cloned = value;
149            assert_eq!(value, cloned);
150        }
151
152        #[test]
153        fn $debug_test_name() {
154            let value = $debug_variant;
155            let debug = format!("{:?}", value);
156            assert_eq!(debug, $debug_str);
157        }
158    };
159}
160
161/// Generate a simple assertion test.
162///
163/// Creates a test function with a given name and assertion.
164///
165/// # Examples
166///
167/// ```
168/// # use tui_piechart::{assert_test};
169/// assert_test!(test_addition, 2 + 2 == 4);
170/// assert_test!(test_string, "hello".len() == 5);
171/// # fn main() {}
172/// ```
173#[macro_export]
174macro_rules! assert_test {
175    ($test_name:ident, $assertion:expr) => {
176        #[test]
177        fn $test_name() {
178            assert!($assertion);
179        }
180    };
181}
182
183/// Generate an equality assertion test.
184///
185/// Creates a test that checks if two expressions are equal.
186///
187/// # Examples
188///
189/// ```
190/// # use tui_piechart::{assert_eq_test};
191/// assert_eq_test!(test_math, 2 + 2, 4);
192/// assert_eq_test!(test_default, MyType::default().value(), 0);
193/// # fn main() {}
194/// ```
195#[macro_export]
196macro_rules! assert_eq_test {
197    ($test_name:ident, $left:expr, $right:expr) => {
198        #[test]
199        fn $test_name() {
200            assert_eq!($left, $right);
201        }
202    };
203}
204
205/// Generate a test asserting that an expression matches a pattern.
206///
207/// This is ideal for verifying that a builder-style setter stored the expected
208/// enum variant, collapsing many near-identical tests into single lines.
209///
210/// # Examples
211///
212/// ```
213/// # use tui_piechart::{matches_test};
214/// matches_test!(
215///     test_resolution_braille,
216///     PieChart::default().resolution(Resolution::Braille).resolution,
217///     Resolution::Braille
218/// );
219/// # fn main() {}
220/// ```
221#[macro_export]
222macro_rules! matches_test {
223    ($test_name:ident, $value:expr, $pattern:pat $(,)?) => {
224        #[test]
225        fn $test_name() {
226            assert!(matches!($value, $pattern));
227        }
228    };
229}
230
231/// Generate debug format tests for multiple enum variants.
232///
233/// This macro creates a test for each variant that checks its Debug output.
234///
235/// # Examples
236///
237/// ```
238/// # use tui_piechart::{debug_format_tests};
239/// debug_format_tests! {
240///     enum_type: MyEnum,
241///     tests: [
242///         (test_first_debug, MyEnum::First, "First"),
243///         (test_second_debug, MyEnum::Second, "Second"),
244///         (test_third_debug, MyEnum::Third, "Third"),
245///     ]
246/// }
247/// # fn main() {}
248/// ```
249#[macro_export]
250macro_rules! debug_format_tests {
251    (
252        enum_type: $enum_name:ty,
253        tests: [
254            $(($test_name:ident, $variant:expr, $expected:expr)),+ $(,)?
255        ]
256    ) => {
257        $(
258            #[test]
259            fn $test_name() {
260                let value = $variant;
261                let debug = format!("{:?}", value);
262                assert_eq!(debug, $expected);
263            }
264        )+
265    };
266}
267
268/// Test that a conversion (From/Into) works correctly.
269///
270/// # Examples
271///
272/// ```
273/// # use tui_piechart::{conversion_test};
274/// conversion_test!(
275///     test_alignment_to_ratatui,
276///     TitleAlignment::Start,
277///     Alignment,
278///     Alignment::Left
279/// );
280/// # fn main() {}
281/// ```
282#[macro_export]
283macro_rules! conversion_test {
284    ($test_name:ident, $from:expr, $to_type:ty, $expected:expr) => {
285        #[test]
286        fn $test_name() {
287            let result: $to_type = $from.into();
288            assert_eq!(result, $expected);
289        }
290    };
291}
292
293/// Test that multiple enum variants can be instantiated.
294///
295/// Useful for compile-time verification that all variants are accessible.
296///
297/// # Examples
298///
299/// ```
300/// # use tui_piechart::{instantiate_variants_test};
301/// instantiate_variants_test!(
302///     test_all_border_styles,
303///     BorderStyle,
304///     [Standard, Rounded, Dashed, CornerGapped]
305/// );
306/// # fn main() {}
307/// ```
308#[macro_export]
309macro_rules! instantiate_variants_test {
310    ($test_name:ident, $enum_name:ident, [$($variant:ident),+ $(,)?]) => {
311        #[test]
312        fn $test_name() {
313            $(
314                let _ = $enum_name::$variant;
315            )+
316        }
317    };
318}
319
320/// Test that a method doesn't panic with a given input.
321///
322/// # Examples
323///
324/// ```
325/// # use tui_piechart::{no_panic_test};
326/// no_panic_test!(test_apply_bold, {
327///     let result = TitleStyle::Bold.apply("Test");
328///     assert!(!result.is_empty());
329/// });
330/// # fn main() {}
331/// ```
332#[macro_export]
333macro_rules! no_panic_test {
334    ($test_name:ident, $body:block) => {
335        #[test]
336        fn $test_name() {
337            $body
338        }
339    };
340}
341
342/// Test that a string transformation preserves certain properties.
343///
344/// # Examples
345///
346/// ```
347/// # use tui_piechart::{string_transform_test};
348/// string_transform_test!(
349///     test_bold_preserves_length,
350///     TitleStyle::Bold.apply("Test"),
351///     original: "Test",
352///     length_preserved: true
353/// );
354/// # fn main() {}
355/// ```
356#[macro_export]
357macro_rules! string_transform_test {
358    (
359        $test_name:ident,
360        $transform:expr,
361        original: $original:expr,
362        length_preserved: $should_preserve:expr
363    ) => {
364        #[test]
365        fn $test_name() {
366            let original = $original;
367            let result = $transform;
368            if $should_preserve {
369                assert_eq!(result.chars().count(), original.chars().count());
370            }
371        }
372    };
373}
374
375/// Test that rendering to a buffer doesn't panic.
376///
377/// This macro creates a test that ensures a widget can be rendered without
378/// panicking, which is useful for visual regression testing.
379///
380/// # Examples
381///
382/// ```
383/// # use tui_piechart::{render_test};
384/// use ratatui::buffer::Buffer;
385/// use ratatui::layout::Rect;
386///
387/// render_test!(
388///     test_piechart_renders,
389///     PieChart::default(),
390///     Rect::new(0, 0, 40, 20)
391/// );
392/// # fn main() {}
393/// ```
394#[macro_export]
395macro_rules! render_test {
396    ($test_name:ident, $widget:expr, $area:expr) => {
397        #[test]
398        fn $test_name() {
399            use ratatui::buffer::Buffer;
400            let mut buffer = Buffer::empty($area);
401            ratatui::widgets::Widget::render($widget, buffer.area, &mut buffer);
402        }
403    };
404}
405
406/// Test that rendering with specific dimensions doesn't panic.
407///
408/// This is a convenience wrapper around `render_test` that creates the Rect for you.
409///
410/// # Examples
411///
412/// ```
413/// # use tui_piechart::{render_with_size_test};
414/// render_with_size_test!(
415///     test_chart_small,
416///     PieChart::default(),
417///     width: 20,
418///     height: 10
419/// );
420/// # fn main() {}
421/// ```
422#[macro_export]
423macro_rules! render_with_size_test {
424    (
425        $test_name:ident,
426        $widget:expr,
427        width: $width:expr,
428        height: $height:expr
429    ) => {
430        #[test]
431        fn $test_name() {
432            use ratatui::buffer::Buffer;
433            use ratatui::layout::Rect;
434            let area = Rect::new(0, 0, $width, $height);
435            let mut buffer = Buffer::empty(area);
436            ratatui::widgets::Widget::render($widget, buffer.area, &mut buffer);
437        }
438    };
439}
440
441/// Test rendering with multiple widget configurations.
442///
443/// Useful for testing that various configurations all render without panicking.
444///
445/// # Examples
446///
447/// ```
448/// # use tui_piechart::{multi_render_test};
449/// multi_render_test!(test_pie_configurations, [
450///     (PieChart::default(), Rect::new(0, 0, 20, 10)),
451///     (PieChart::default().show_legend(false), Rect::new(0, 0, 30, 15)),
452/// ]);
453/// # fn main() {}
454/// ```
455#[macro_export]
456macro_rules! multi_render_test {
457    ($test_name:ident, [$(($widget:expr, $area:expr)),+ $(,)?]) => {
458        #[test]
459        fn $test_name() {
460            use ratatui::buffer::Buffer;
461            $(
462                let mut buffer = Buffer::empty($area);
463                ratatui::widgets::Widget::render($widget, buffer.area, &mut buffer);
464            )+
465        }
466    };
467}
468
469/// Test that rendering to an empty area doesn't panic.
470///
471/// # Examples
472///
473/// ```
474/// # use tui_piechart::{render_empty_test};
475/// render_empty_test!(test_chart_empty, PieChart::default());
476/// # fn main() {}
477/// ```
478#[macro_export]
479macro_rules! render_empty_test {
480    ($test_name:ident, $widget:expr) => {
481        #[test]
482        fn $test_name() {
483            use ratatui::buffer::Buffer;
484            use ratatui::layout::Rect;
485            let mut buffer = Buffer::empty(Rect::new(0, 0, 0, 0));
486            ratatui::widgets::Widget::render($widget, buffer.area, &mut buffer);
487        }
488    };
489}
490
491#[cfg(test)]
492#[allow(unnameable_test_items)]
493mod tests {
494    #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
495    enum TestEnum {
496        #[default]
497        First,
498        Second,
499        Third,
500    }
501
502    // Test the macros themselves
503    assert_test!(macro_assert_test_works, true);
504    assert_eq_test!(macro_assert_eq_test_works, 2 + 2, 4);
505    matches_test!(macro_matches_test_works, TestEnum::Second, TestEnum::Second);
506
507    instantiate_variants_test!(test_enum_variants, TestEnum, [First, Second, Third]);
508
509    debug_format_tests! {
510        enum_type: TestEnum,
511        tests: [
512            (test_first_fmt, TestEnum::First, "First"),
513            (test_second_fmt, TestEnum::Second, "Second"),
514        ]
515    }
516
517    enum_tests! {
518        enum_type: TestEnum,
519        default_test: (test_enum_default, TestEnum::First),
520        clone_test: (test_enum_clone, TestEnum::Second),
521        debug_test: (test_enum_debug, TestEnum::Third, "Third"),
522    }
523}