libcnb_test/
macros.rs

1/// Asserts that `left` contains `right`.
2///
3/// Commonly used when asserting `pack` output in integration tests. Expands to a [`str::contains`]
4/// call and logs `left` (in unescaped and escaped form) as well as `right` on failure.
5///
6/// # Example
7///
8/// ```
9/// use libcnb_test::assert_contains;
10///
11/// let output = "Hello World!\nHello Integration Test!";
12/// assert_contains!(output, "Integration");
13/// ```
14#[macro_export]
15macro_rules! assert_contains {
16    ($left:expr, $right:expr $(,)?) => {{
17        if !$left.contains($right) {
18            ::std::panic!(
19                r"assertion failed: `(left contains right)`
20left (unescaped):
21{}
22
23left (escaped): `{:?}`
24right: `{:?}`",
25                $left,
26                $left,
27                $right,
28            )
29        }
30    }};
31
32    ($left:expr, $right:expr, $($arg:tt)+) => {{
33        if !$left.contains($right) {
34            ::std::panic!(
35                r"assertion failed: `(left contains right)`
36left (unescaped):
37{}
38
39left (escaped): `{:?}`
40right: `{:?}`: {}",
41                $left,
42                $left,
43                $right,
44                ::core::format_args!($($arg)+)
45            )
46        }
47    }};
48}
49
50/// Asserts that `left` does not contain `right`.
51///
52/// Commonly used when asserting `pack` output in integration tests. Expands to a [`str::contains`]
53/// call and logs `left` (in unescaped and escaped form) as well as `right` on failure.
54///
55/// # Example
56///
57/// ```
58/// use libcnb_test::assert_not_contains;
59///
60/// let output = "Hello World!\nHello Integration Test!";
61/// assert_not_contains!(output, "Bahamas");
62/// ```
63#[macro_export]
64macro_rules! assert_not_contains {
65    ($left:expr, $right:expr $(,)?) => {{
66        if $left.contains($right) {
67            ::std::panic!(
68                r"assertion failed: `(left does not contain right)`
69left (unescaped):
70{}
71
72left (escaped): `{:?}`
73right: `{:?}`",
74                $left,
75                $left,
76                $right,
77            )
78        }
79    }};
80
81    ($left:expr, $right:expr, $($arg:tt)+) => {{
82        if $left.contains($right) {
83            ::std::panic!(
84                r"assertion failed: `(left does not contain right)`
85left (unescaped):
86{}
87
88left (escaped): `{:?}`
89right: `{:?}`: {}",
90                $left,
91                $left,
92                $right,
93                ::core::format_args!($($arg)+)
94            )
95        }
96    }};
97}
98
99/// Asserts that the provided value is empty.
100///
101/// Commonly used when asserting `pack` output in integration tests. Expands to a [`str::is_empty`]
102/// call and logs the value (in unescaped and escaped form) on failure.
103///
104/// # Example
105///
106/// ```
107/// use libcnb_test::assert_empty;
108///
109/// let output = "";
110/// assert_empty!(output);
111/// ```
112#[macro_export]
113macro_rules! assert_empty {
114    ($value:expr $(,)?) => {{
115        if !$value.is_empty() {
116            ::std::panic!(
117                r"assertion failed: `(is empty)`
118value (unescaped):
119{}
120
121value (escaped): `{:?}`",
122                $value,
123                $value,
124            )
125        }
126    }};
127
128    ($value:expr, $($arg:tt)+) => {{
129        if !$value.is_empty() {
130            ::std::panic!(
131                r"assertion failed: `(is empty)`
132value (unescaped):
133{}
134
135value (escaped): `{:?}`: {}",
136                $value,
137                $value,
138                ::core::format_args!($($arg)+)
139            )
140        }
141    }};
142}
143
144/// Asserts that `left` contains the `right` pattern (regular expression).
145///
146/// Commonly used when asserting `pack` output in integration tests. Expands to a regular
147/// expression match test and logs `left` (in unescaped and escaped form) as well as `right`
148/// on failure.
149///
150/// Multi-line mode is automatically enabled on regular expressions. If this is not what you
151/// want it can be disabled by adding `(?-m)` to the start of your pattern.
152///
153/// # Example
154///
155/// ```
156/// use libcnb_test::assert_contains_match;
157///
158/// let output = "Hello World!\nHello Integration Test!";
159/// assert_contains_match!(output, "Test!$");
160/// ```
161#[macro_export]
162macro_rules! assert_contains_match {
163    ($left:expr, $right:expr $(,)?) => {{
164        let regex = regex::Regex::new(&format!("(?m){}", $right)).expect("should be a valid regex");
165        if !regex.is_match(&$left) {
166            ::std::panic!(
167                r"assertion failed: `(left matches right pattern)`
168left (unescaped):
169{}
170
171left (escaped): `{:?}`
172right: `{:?}`",
173                $left,
174                $left,
175                regex
176            )
177        }
178    }};
179
180    ($left:expr, $right:expr, $($arg:tt)+) => {{
181        let regex = regex::Regex::new(&format!("(?m){}", $right)).expect("should be a valid regex");
182        if !regex.is_match(&$left) {
183            ::std::panic!(
184                r"assertion failed: `(left matches right pattern)`
185left (unescaped):
186{}
187
188left (escaped): `{:?}`
189right: `{:?}`: {}",
190                $left,
191                $left,
192                regex,
193                ::core::format_args!($($arg)+)
194            )
195        }
196    }};
197}
198
199/// Asserts that `left` does not contain the `right` pattern (regular expression).
200///
201/// Commonly used when asserting `pack` output in integration tests. Expands to a regular
202/// expression match test and logs `left` (in unescaped and escaped form) as well as `right`
203/// on failure.
204///
205/// Multi-line mode is automatically enabled on regular expressions. If this is not what you
206/// want it can be disabled by adding `(?-m)` to the start of your pattern.
207///
208/// # Example
209///
210/// ```
211/// use libcnb_test::assert_not_contains_match;
212///
213/// let output = "Hello World!\nHello Integration Test!";
214/// assert_not_contains_match!(output, "^Test!");
215/// ```
216#[macro_export]
217macro_rules! assert_not_contains_match {
218    ($left:expr, $right:expr $(,)?) => {{
219        let regex = regex::Regex::new(&format!("(?m){}", $right)).expect("should be a valid regex");
220        if regex.is_match(&$left) {
221            ::std::panic!(
222                r"assertion failed: `(left does not match right pattern)`
223left (unescaped):
224{}
225
226left (escaped): `{:?}`
227right: `{:?}`",
228                $left,
229                $left,
230                regex
231            )
232        }
233    }};
234
235    ($left:expr, $right:expr, $($arg:tt)+) => {{
236        let regex = regex::Regex::new(&format!("(?m){}", $right)).expect("should be a valid regex");
237        if regex.is_match(&$left) {
238            ::std::panic!(
239                r"assertion failed: `(left does not match right pattern)`
240left (unescaped):
241{}
242
243left (escaped): `{:?}`
244right: `{:?}`: {}",
245                $left,
246                $left,
247                regex,
248                ::core::format_args!($($arg)+)
249            )
250        }
251    }};
252}
253
254#[cfg(test)]
255mod tests {
256    #[test]
257    fn contains_simple() {
258        assert_contains!("Hello World!", "World");
259    }
260
261    #[test]
262    fn contains_simple_with_args() {
263        assert_contains!("Hello World!", "World", "World must be greeted!");
264    }
265
266    #[test]
267    #[should_panic(expected = "assertion failed: `(left contains right)`
268left (unescaped):
269foo
270
271left (escaped): `\"foo\"`
272right: `\"bar\"`")]
273    fn contains_simple_failure() {
274        assert_contains!("foo", "bar");
275    }
276
277    #[test]
278    #[should_panic(expected = "assertion failed: `(left contains right)`
279left (unescaped):
280Hello Germany!
281
282left (escaped): `\"Hello Germany!\"`
283right: `\"World\"`: World must be greeted!")]
284    fn contains_simple_failure_with_args() {
285        assert_contains!("Hello Germany!", "World", "World must be greeted!");
286    }
287
288    #[test]
289    fn contains_multiline() {
290        assert_contains!("Hello World!\nFoo\nBar\nBaz", "Bar");
291    }
292
293    #[test]
294    #[should_panic(expected = "assertion failed: `(left contains right)`
295left (unescaped):
296Hello World!
297Foo
298Bar
299Baz
300
301left (escaped): `\"Hello World!\\nFoo\\nBar\\nBaz\"`
302right: `\"Eggs\"`")]
303    fn contains_multiline_failure() {
304        assert_contains!("Hello World!\nFoo\nBar\nBaz", "Eggs");
305    }
306
307    #[test]
308    #[should_panic(expected = "assertion failed: `(left contains right)`
309left (unescaped):
310Hello World!
311Foo
312Bar
313Baz
314
315left (escaped): `\"Hello World!\\nFoo\\nBar\\nBaz\"`
316right: `\"Eggs\"`: We need eggs!")]
317    fn contains_multiline_failure_with_args() {
318        assert_contains!("Hello World!\nFoo\nBar\nBaz", "Eggs", "We need eggs!");
319    }
320
321    #[test]
322    fn not_contains_simple() {
323        assert_not_contains!("Hello World!", "Bahamas");
324    }
325
326    #[test]
327    fn not_contains_simple_with_args() {
328        assert_not_contains!("Hello World!", "Bahamas", "Bahamas must not be greeted!");
329    }
330
331    #[test]
332    #[should_panic(expected = "assertion failed: `(left does not contain right)`
333left (unescaped):
334foobar
335
336left (escaped): `\"foobar\"`
337right: `\"bar\"`")]
338    fn not_contains_simple_failure() {
339        assert_not_contains!("foobar", "bar");
340    }
341
342    #[test]
343    #[should_panic(expected = "assertion failed: `(left does not contain right)`
344left (unescaped):
345Hello Germany!
346
347left (escaped): `\"Hello Germany!\"`
348right: `\"Germany\"`: Germany must be greeted!")]
349    fn not_contains_simple_failure_with_args() {
350        assert_not_contains!("Hello Germany!", "Germany", "Germany must be greeted!");
351    }
352
353    #[test]
354    fn not_contains_multiline() {
355        assert_not_contains!("Hello World!\nFoo\nBar\nBaz", "Germany");
356    }
357
358    #[test]
359    #[should_panic(expected = "assertion failed: `(left does not contain right)`
360left (unescaped):
361Hello World!
362Foo
363Bar
364Baz
365
366left (escaped): `\"Hello World!\\nFoo\\nBar\\nBaz\"`
367right: `\"Bar\"`")]
368    fn not_contains_multiline_failure() {
369        assert_not_contains!("Hello World!\nFoo\nBar\nBaz", "Bar");
370    }
371
372    #[test]
373    #[should_panic(expected = "assertion failed: `(left does not contain right)`
374left (unescaped):
375Hello Eggs!
376Foo
377Bar
378Baz
379
380left (escaped): `\"Hello Eggs!\\nFoo\\nBar\\nBaz\"`
381right: `\"Eggs\"`: We must not have eggs!")]
382    fn not_contains_multiline_failure_with_args() {
383        assert_not_contains!(
384            "Hello Eggs!\nFoo\nBar\nBaz",
385            "Eggs",
386            "We must not have eggs!"
387        );
388    }
389
390    #[test]
391    fn empty_simple() {
392        assert_empty!("");
393    }
394
395    #[test]
396    fn empty_simple_with_args() {
397        assert_empty!("", "Value must be empty!");
398    }
399
400    #[test]
401    #[should_panic(expected = "assertion failed: `(is empty)`
402value (unescaped):
403foo
404
405value (escaped): `\"foo\"`")]
406    fn empty_simple_failure() {
407        assert_empty!("foo");
408    }
409
410    #[test]
411    #[should_panic(expected = "assertion failed: `(is empty)`
412value (unescaped):
413Hello World!
414
415value (escaped): `\"Hello World!\"`: Greeting must be empty!")]
416    fn empty_simple_failure_with_args() {
417        assert_empty!("Hello World!", "Greeting must be empty!");
418    }
419
420    #[test]
421    #[should_panic(expected = "assertion failed: `(is empty)`
422value (unescaped):
423Hello World!
424Foo
425Bar
426Baz
427
428value (escaped): `\"Hello World!\\nFoo\\nBar\\nBaz\"`")]
429    fn empty_multiline_failure() {
430        assert_empty!("Hello World!\nFoo\nBar\nBaz");
431    }
432
433    #[test]
434    #[should_panic(expected = "assertion failed: `(is empty)`
435value (unescaped):
436Hello World!
437Foo
438Bar
439Baz
440
441value (escaped): `\"Hello World!\\nFoo\\nBar\\nBaz\"`: Greeting must be empty!")]
442    fn empty_multiline_failure_with_args() {
443        assert_empty!("Hello World!\nFoo\nBar\nBaz", "Greeting must be empty!");
444    }
445
446    #[test]
447    fn contains_match_simple() {
448        assert_contains_match!("Hello World!", "(?i)hello world!");
449    }
450
451    #[test]
452    fn contains_match_simple_with_args() {
453        assert_contains_match!("Hello World!", "(?i)hello world!", "World must be greeted");
454    }
455
456    #[test]
457    #[should_panic(expected = "assertion failed: `(left matches right pattern)`
458left (unescaped):
459foo
460
461left (escaped): `\"foo\"`
462right: `Regex(\"(?m)bar\")`")]
463    fn contains_match_simple_failure() {
464        assert_contains_match!("foo", "bar");
465    }
466
467    #[test]
468    #[should_panic(expected = "assertion failed: `(left matches right pattern)`
469left (unescaped):
470Hello World!
471
472left (escaped): `\"Hello World!\"`
473right: `Regex(\"(?m)(?-i)world\")`: World must be case-sensitively greeted!")]
474    fn contains_match_simple_failure_with_args() {
475        assert_contains_match!(
476            "Hello World!",
477            "(?-i)world",
478            "World must be case-sensitively greeted!"
479        );
480    }
481
482    #[test]
483    fn contains_match_multiline() {
484        assert_contains_match!("Hello World!\nFoo\nBar\nBaz", "^Bar$");
485    }
486
487    #[test]
488    #[should_panic(expected = "assertion failed: `(left matches right pattern)`
489left (unescaped):
490Hello World!
491Foo
492Bar
493Baz
494
495left (escaped): `\"Hello World!\\nFoo\\nBar\\nBaz\"`
496right: `Regex(\"(?m)Eggs\")`")]
497    fn contains_match_multiline_failure() {
498        assert_contains_match!("Hello World!\nFoo\nBar\nBaz", "Eggs");
499    }
500
501    #[test]
502    #[should_panic(expected = "assertion failed: `(left matches right pattern)`
503left (unescaped):
504Hello World!
505Foo
506Bar
507Baz
508
509left (escaped): `\"Hello World!\\nFoo\\nBar\\nBaz\"`
510right: `Regex(\"(?m)Eggs\")`: We need eggs!")]
511    fn contains_match_multiline_failure_with_args() {
512        assert_contains_match!("Hello World!\nFoo\nBar\nBaz", "Eggs", "We need eggs!");
513    }
514
515    #[test]
516    #[should_panic(expected = "should be a valid regex: Syntax(
517~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
518regex parse error:
519    (?m)(unclosed group
520        ^
521error: unclosed group
522~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
523)")]
524    fn contains_match_with_invalid_regex() {
525        assert_contains_match!("Hello World!", "(unclosed group");
526    }
527
528    #[test]
529    #[should_panic(expected = "should be a valid regex: Syntax(
530~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
531regex parse error:
532    (?m)(unclosed group
533        ^
534error: unclosed group
535~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
536)")]
537    fn contains_match_with_invalid_regex_and_args() {
538        assert_contains_match!("Hello World!", "(unclosed group", "This should fail.");
539    }
540
541    #[test]
542    fn not_contains_match_simple() {
543        assert_not_contains_match!("Hello World!", "^World");
544    }
545
546    #[test]
547    fn not_contains_match_simple_with_args() {
548        assert_not_contains_match!("Hello World!", "^World", "World must not be at the start!");
549    }
550
551    #[test]
552    #[should_panic(expected = "assertion failed: `(left does not match right pattern)`
553left (unescaped):
554foobar
555
556left (escaped): `\"foobar\"`
557right: `Regex(\"(?m)bar\")`")]
558    fn not_contains_match_simple_failure() {
559        assert_not_contains_match!("foobar", "bar");
560    }
561
562    #[test]
563    #[should_panic(expected = "assertion failed: `(left does not match right pattern)`
564left (unescaped):
565Hello Germany!
566
567left (escaped): `\"Hello Germany!\"`
568right: `Regex(\"(?m)Germany!$\")`: Germany must not be greeted!")]
569    fn not_contains_match_simple_failure_with_args() {
570        assert_not_contains_match!(
571            "Hello Germany!",
572            "Germany!$",
573            "Germany must not be greeted!"
574        );
575    }
576
577    #[test]
578    fn not_contains_match_multiline() {
579        assert_not_contains_match!("Hello World!\nFoo\nBar\nBaz", "^Germany$");
580    }
581
582    #[test]
583    #[should_panic(expected = "assertion failed: `(left does not match right pattern)`
584left (unescaped):
585Hello World!
586Foo
587Bar
588Baz
589
590left (escaped): `\"Hello World!\\nFoo\\nBar\\nBaz\"`
591right: `Regex(\"(?m)^Bar$\")`")]
592    fn not_contains_match_multiline_failure() {
593        assert_not_contains_match!("Hello World!\nFoo\nBar\nBaz", "^Bar$");
594    }
595
596    #[test]
597    #[should_panic(expected = "assertion failed: `(left does not match right pattern)`
598left (unescaped):
599Hello Eggs!
600Foo
601Bar
602Baz
603
604left (escaped): `\"Hello Eggs!\\nFoo\\nBar\\nBaz\"`
605right: `Regex(\"(?m)Eggs!$\")`: We must not have eggs!")]
606    fn not_contains_match_multiline_failure_with_args() {
607        assert_not_contains_match!(
608            "Hello Eggs!\nFoo\nBar\nBaz",
609            "Eggs!$",
610            "We must not have eggs!"
611        );
612    }
613
614    #[test]
615    #[should_panic(expected = "should be a valid regex: Syntax(
616~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
617regex parse error:
618    (?m)(unclosed group
619        ^
620error: unclosed group
621~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
622)")]
623    fn not_contains_match_with_invalid_regex() {
624        assert_not_contains_match!("Hello World!", "(unclosed group");
625    }
626
627    #[test]
628    #[should_panic(expected = "should be a valid regex: Syntax(
629~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
630regex parse error:
631    (?m)(unclosed group
632        ^
633error: unclosed group
634~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
635)")]
636    fn not_contains_match_with_invalid_regex_and_args() {
637        assert_not_contains_match!("Hello World!", "(unclosed group", "This will fail");
638    }
639}