dicetest/
macros.rs

1/// Adds a hint that contains the arguments applied to the [`format`] macro.
2///
3/// # Examples
4///
5/// ```
6/// use dicetest::hint;
7///
8/// let unknown_value = 42;
9/// hint!("Revealing the unknown value: {}", unknown_value);
10/// ```
11#[macro_export]
12macro_rules! hint {
13    ($($arg:tt)*) => {
14        $crate::hints::add(|| format!($($arg)*));
15    }
16}
17
18/// Adds a hint that contains the stringified argument and the argument value converted with
19/// [`Debug`].
20///
21/// [`Debug`]: std::fmt::Debug
22///
23/// # Examples
24///
25/// ```
26/// use dicetest::hint_debug;
27///
28/// let unknown_value = 42;
29/// hint_debug!(unknown_value);
30/// ```
31#[macro_export]
32macro_rules! hint_debug {
33    ($arg:tt) => {
34        $crate::hints::add(|| format!(concat!("{} = {:?}"), stringify!($arg), $arg));
35    };
36}
37
38/// Indents all hints in the caller's code block after this macro is called.
39///
40/// If arguments are specified, a (not indented) hint will be added with the arguments applied
41/// to the [`format`] macro. This hint is meant as the title of the section.
42///
43/// # Examples
44///
45/// ```
46/// use dicetest::{hint, hint_section};
47///
48/// hint!("Start test"); // This hint is not indented
49///
50/// {
51///     hint_section!("Test foo"); // This hint is not indented
52///     hint!("foo"); // This hint is indented
53/// }
54///
55/// {
56///     hint_section!("Test bar"); // This hint is not indented
57///     hint!("bar"); // This hint is indented
58///     
59///     hint_section!(); // No hint
60///     hint!("bar"); // This hint is indented twice
61/// }
62///
63/// hint!("Test finished"); // This hint is not indented
64/// ```
65#[macro_export]
66macro_rules! hint_section {
67    () => {
68        let _block_ident = $crate::hints::Section::start();
69    };
70    ($($arg:tt)*) => {
71        $crate::hints::add(|| format!($($arg)*));
72        let _block_ident = $crate::hints::Section::start();
73    }
74}
75
76/// Creates a stat with the first argument as stat key and the remaining arguments applied to the
77/// [`format`] macro as stat value.
78///
79/// # Examples
80///
81/// ```
82/// use dicetest::stat;
83///
84/// let random_number = 4;
85/// stat!("Is random number even?", "{}", random_number % 2 == 0);
86/// ```
87#[macro_export]
88macro_rules! stat {
89    ($key:tt, $($arg:tt)*) => {
90        $crate::stats::inc($key, || format!($($arg)*))
91    }
92}
93
94/// Creates a stat with the stringified argument as stat key and the argument value converted with
95/// [`Debug`] as stat value.
96///
97/// [`Debug`]: std::fmt::Debug
98///
99/// # Examples
100///
101/// ```
102/// use dicetest::stat_debug;
103///
104/// let random_number = 4;
105/// stat_debug!({ random_number % 2 == 0 });
106/// ```
107#[macro_export]
108macro_rules! stat_debug {
109    ($arg:tt) => {
110        $crate::stats::inc(stringify!($arg), || format!("{:?}", $arg))
111    };
112}
113
114#[cfg(test)]
115mod tests {
116    #[test]
117    fn macro_hint_produces_valid_code() {
118        if false {
119            hint!("foo");
120            hint!("bar {}", 42);
121        }
122    }
123
124    #[test]
125    fn macro_hint_debug_produces_valid_code() {
126        if false {
127            hint_debug!(42);
128            hint_debug!((0 < 20));
129            hint_debug!((if true { 1 } else { 2 }));
130        }
131    }
132
133    #[test]
134    fn macro_hint_section_produces_valid_code() {
135        if false {
136            hint_section!();
137            hint_section!("foo");
138            hint_section!("bar {}", 42);
139        }
140    }
141
142    #[test]
143    #[cfg(feature = "hints")]
144    fn macro_hint_section_produces_correct_indent() {
145        let (_, actual_hints) = crate::hints::collect(|| {
146            {
147                hint!("foo1");
148                hint_section!();
149                hint!("foo2");
150                hint_section!("bar");
151                hint!("foo3");
152            };
153            hint!("foo4");
154        });
155        let expected_hints = crate::hints::Hints(vec![
156            crate::hints::Hint {
157                indent: 0,
158                text: "foo1".to_owned(),
159            },
160            crate::hints::Hint {
161                indent: 1,
162                text: "foo2".to_owned(),
163            },
164            crate::hints::Hint {
165                indent: 1,
166                text: "bar".to_owned(),
167            },
168            crate::hints::Hint {
169                indent: 2,
170                text: "foo3".to_owned(),
171            },
172            crate::hints::Hint {
173                indent: 0,
174                text: "foo4".to_owned(),
175            },
176        ]);
177        assert_eq!(expected_hints, actual_hints)
178    }
179
180    #[test]
181    fn macro_stat_produces_valid_code() {
182        if false {
183            stat!("A", "foo");
184            stat!("B", "bar {}", 42);
185        }
186    }
187
188    #[test]
189    fn macro_stat_debug_produces_valid_code() {
190        if false {
191            stat_debug!(42);
192            stat_debug!((0 < 20));
193            stat_debug!((if true { 1 } else { 2 }));
194        }
195    }
196}