Skip to main content

unittest/
lib.rs

1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#![cfg_attr(not(test), no_std)]
8
9// Allows for the suite macro to work within this crate's test module.
10#[cfg(test)]
11extern crate self as unittest;
12
13use core::ffi::{CStr, c_char};
14use core::slice;
15
16#[doc(hidden)]
17pub use zx_status::Status as __Status;
18#[doc(hidden)]
19pub use zx_status::sys as __sys;
20
21/// Attribute macro defining suite of unit tests defined as module. The
22/// attribute may only be used in a cfg(ktest) context.
23///
24/// Tests are idiomatically modeled as functions, and so modules of such
25/// functions make for a natural representation as a test suite.
26///
27/// Tests defined through this attribute are available to be run via `k ut`.
28///
29/// A test suite module must meet the following criteria:
30/// * It must have a one-line docstring. This line becomes the description of
31///   the suite on the kernel command-line.
32/// * It must contain at least one test function; it may contain any other items.
33///
34/// A test function must meet the following criteria:
35/// * It must be annotated with #[test].
36/// * It too must have a one-line docstring. This line becomes the description
37///   of the test on the kernel command-line.
38/// * It must have a () -> () signature.
39///
40/// A test function should make assertions only using the declarative
41/// assert_*/expect_* macros defined in the unittest module.
42///
43/// Disabling a test can be done with a further annotation of #[ignore]. Such a
44/// test will still be compiled; it just will not contribute test metadata.
45///
46/// # Example
47/// ```rust,ignore
48/// /// Brief test suite description.
49/// #[cfg(ktest)]
50/// #[unittest::suite(name = "optional_name")]
51/// mod my_suite {
52///     /* non-test items... */
53///
54///     /// Brief test case description.
55///     #[test]
56///     fn my_case() {
57///         assert_false!(false);
58///         expect_true!(1 == 1, "expectation with a message");
59///     }
60///
61///     /// This test case is currently disabled.
62///     #[test]
63///     #[ignore]
64///     fn my_disabled_case() {...}
65/// }
66/// ```
67///
68pub use unittest_macro::suite;
69
70use kprint::kprintln;
71
72#[doc(hidden)]
73#[derive(Debug, Clone, Copy)]
74pub struct ComparisonFailure<'a> {
75    pub file: &'a str,
76    pub line: u32,
77    pub expected: &'a str,
78    pub expected_val: isize,
79    pub op: &'a str,
80    pub actual: &'a str,
81    pub actual_val: isize,
82    pub msg: &'a str,
83}
84
85#[doc(hidden)]
86pub fn print_comparison_failure(failure: &ComparisonFailure<'_>) {
87    kprintln!(
88        "\n    [FAILED]\n    {:s}:{}:\n    expected {:s} ({}) {:s} {:s} ({})\n    {:s}",
89        failure.file,
90        failure.line,
91        failure.expected,
92        failure.expected_val,
93        failure.op,
94        failure.actual,
95        failure.actual_val,
96        failure.msg,
97    );
98}
99
100#[doc(hidden)]
101pub fn print_condition_failure(file: &str, line: u32, desc: &str, actual: &str, msg: &str) {
102    kprintln!(
103        "\n    [FAILED]\n    {:s}:{}:\n    {:s} {:s}\n    {:s}",
104        file,
105        line,
106        actual,
107        desc,
108        msg,
109    );
110}
111
112#[macro_export]
113#[doc(hidden)]
114macro_rules! check_comparison {
115    ($cond:expr, $early_return:expr, $op:literal, $expected:expr, $expected_val:expr, $actual:expr, $actual_val:expr, $msg:expr) => {
116        if !$cond {
117            record_failure!();
118            $crate::print_comparison_failure(&$crate::ComparisonFailure {
119                file: file!(),
120                line: line!(),
121                expected: stringify!($expected),
122                expected_val: $expected_val as isize,
123                op: $op,
124                actual: stringify!($actual),
125                actual_val: $actual_val as isize,
126                msg: $msg,
127            });
128            if $early_return {
129                return false;
130            }
131        }
132    };
133}
134
135#[macro_export]
136#[doc(hidden)]
137macro_rules! check_condition {
138    ($cond:expr, $early_return:expr, $desc:literal, $actual:expr, $msg:expr) => {
139        if !$cond {
140            record_failure!();
141            $crate::print_condition_failure(file!(), line!(), $desc, stringify!($actual), $msg);
142            if $early_return {
143                return false;
144            }
145        }
146    };
147}
148
149/// The data structure that statically defines a test suite, intended to be
150/// defined via the #[suite] macro to encoded into a special section in
151/// the kernel.
152#[doc(hidden)]
153#[repr(C)]
154#[derive(Clone, Copy)]
155pub struct TestSuiteRegistration {
156    pub name: *const c_char,
157    pub desc: *const c_char,
158    pub tests: *const TestCaseRegistration,
159    pub test_cnt: usize,
160}
161
162unsafe impl Sync for TestSuiteRegistration {}
163
164impl TestSuiteRegistration {
165    /// The name of the suite.
166    ///
167    /// Registrations are emitted by the #[suite] macro as compile-time
168    /// constants, so a missing or non-UTF-8 name is a programming error.
169    pub fn name(&self) -> &'_ str {
170        assert!(!self.name.is_null(), "test suite registration has no name");
171        // Safety: the name is a static, NUL-terminated string.
172        unsafe { CStr::from_ptr(self.name) }.to_str().expect("test suite name is not valid UTF-8")
173    }
174
175    /// The description of the suite, if it has one.
176    pub fn desc(&self) -> Option<&'_ str> {
177        if self.desc.is_null() {
178            return None;
179        }
180        // Safety: the description is a static, NUL-terminated string.
181        let desc = unsafe { CStr::from_ptr(self.desc) };
182        Some(desc.to_str().expect("test suite description is not valid UTF-8"))
183    }
184
185    /// The test cases of the suite.
186    pub fn cases(&self) -> &'_ [TestCaseRegistration] {
187        if self.test_cnt == 0 {
188            return &[];
189        }
190        assert!(!self.tests.is_null(), "test suite registration has tests but no test array");
191        // Safety: the registration records `test_cnt` contiguous test cases.
192        unsafe { slice::from_raw_parts(self.tests, self.test_cnt) }
193    }
194}
195
196/// The data structure defining a test case within a suite, also intended be
197/// defined via the #[suite] macro to encoded into a special section in
198/// the kernel
199#[doc(hidden)]
200#[repr(C)]
201#[derive(Clone, Copy)]
202pub struct TestCaseRegistration {
203    pub name: *const c_char,
204    pub fn_: extern "C" fn() -> bool,
205}
206
207unsafe impl Sync for TestCaseRegistration {}
208
209impl TestCaseRegistration {
210    /// The name of the test case.
211    ///
212    /// Registrations are emitted by the #[suite] macro as compile-time
213    /// constants, so a missing or non-UTF-8 name is a programming error.
214    pub fn name(&self) -> &'_ str {
215        assert!(!self.name.is_null(), "test case registration has no name");
216        // Safety: the name is a static, NUL-terminated string.
217        unsafe { CStr::from_ptr(self.name) }.to_str().expect("test case name is not valid UTF-8")
218    }
219}
220
221/// Asserts that two expressions are equal, but does not short-circuit on failure.
222#[macro_export]
223macro_rules! expect_eq {
224    ($expected:expr, $actual:expr) => {
225        $crate::expect_eq!($expected, $actual, "")
226    };
227    ($expected:expr, $actual:expr, $msg:expr) => {
228        let e = $expected;
229        let a = $actual;
230        $crate::check_comparison!(e == a, false, "==", $expected, e, $actual, a, $msg);
231    };
232}
233
234/// Asserts that two expressions are equal and short-circuits on failure.
235#[macro_export]
236macro_rules! assert_eq {
237    ($expected:expr, $actual:expr) => {
238        $crate::assert_eq!($expected, $actual, "")
239    };
240    ($expected:expr, $actual:expr, $msg:expr) => {
241        let e = $expected;
242        let a = $actual;
243        $crate::check_comparison!(e == a, true, "==", $expected, e, $actual, a, $msg);
244    };
245}
246
247/// Asserts that two expressions are not equal, but does not short-circuit on failure.
248#[macro_export]
249macro_rules! expect_ne {
250    ($expected:expr, $actual:expr) => {
251        $crate::expect_ne!($expected, $actual, "")
252    };
253    ($expected:expr, $actual:expr, $msg:expr) => {
254        let e = $expected;
255        let a = $actual;
256        $crate::check_comparison!(e != a, false, "!=", $expected, e, $actual, a, $msg);
257    };
258}
259
260/// Asserts that two expressions are not equal and short-circuits on failure.
261#[macro_export]
262macro_rules! assert_ne {
263    ($expected:expr, $actual:expr) => {
264        $crate::assert_ne!($expected, $actual, "")
265    };
266    ($expected:expr, $actual:expr, $msg:expr) => {
267        let e = $expected;
268        let a = $actual;
269        $crate::check_comparison!(e != a, true, "!=", $expected, e, $actual, a, $msg);
270    };
271}
272
273/// Asserts that the first expression is less than the second, but does not short-circuit on failure.
274#[macro_export]
275macro_rules! expect_lt {
276    ($expected:expr, $actual:expr) => {
277        $crate::expect_lt!($expected, $actual, "")
278    };
279    ($expected:expr, $actual:expr, $msg:expr) => {
280        let e = $expected;
281        let a = $actual;
282        $crate::check_comparison!(e < a, false, "<", $expected, e, $actual, a, $msg);
283    };
284}
285
286/// Asserts that the first expression is less than the second and short-circuits on failure.
287#[macro_export]
288macro_rules! assert_lt {
289    ($expected:expr, $actual:expr) => {
290        $crate::assert_lt!($expected, $actual, "")
291    };
292    ($expected:expr, $actual:expr, $msg:expr) => {
293        let e = $expected;
294        let a = $actual;
295        $crate::check_comparison!(e < a, true, "<", $expected, e, $actual, a, $msg);
296    };
297}
298
299/// Asserts that the first expression is less than or equal to the second, but does not short-circuit on failure.
300#[macro_export]
301macro_rules! expect_le {
302    ($expected:expr, $actual:expr) => {
303        $crate::expect_le!($expected, $actual, "")
304    };
305    ($expected:expr, $actual:expr, $msg:expr) => {
306        let e = $expected;
307        let a = $actual;
308        $crate::check_comparison!(e <= a, false, "<=", $expected, e, $actual, a, $msg);
309    };
310}
311
312/// Asserts that the first expression is less than or equal to the second and short-circuits on failure.
313#[macro_export]
314macro_rules! assert_le {
315    ($expected:expr, $actual:expr) => {
316        $crate::assert_le!($expected, $actual, "")
317    };
318    ($expected:expr, $actual:expr, $msg:expr) => {
319        let e = $expected;
320        let a = $actual;
321        $crate::check_comparison!(e <= a, true, "<=", $expected, e, $actual, a, $msg);
322    };
323}
324
325/// Asserts that the first expression is greater than the second, but does not short-circuit on failure.
326#[macro_export]
327macro_rules! expect_gt {
328    ($expected:expr, $actual:expr) => {
329        $crate::expect_gt!($expected, $actual, "")
330    };
331    ($expected:expr, $actual:expr, $msg:expr) => {
332        let e = $expected;
333        let a = $actual;
334        $crate::check_comparison!(e > a, false, ">", $expected, e, $actual, a, $msg);
335    };
336}
337
338/// Asserts that the first expression is greater than the second and short-circuits on failure.
339#[macro_export]
340macro_rules! assert_gt {
341    ($expected:expr, $actual:expr) => {
342        $crate::assert_gt!($expected, $actual, "")
343    };
344    ($expected:expr, $actual:expr, $msg:expr) => {
345        let e = $expected;
346        let a = $actual;
347        $crate::check_comparison!(e > a, true, ">", $expected, e, $actual, a, $msg);
348    };
349}
350
351/// Asserts that the first expression is greater than or equal to the second, but does not short-circuit on failure.
352#[macro_export]
353macro_rules! expect_ge {
354    ($expected:expr, $actual:expr) => {
355        $crate::expect_ge!($expected, $actual, "")
356    };
357    ($expected:expr, $actual:expr, $msg:expr) => {
358        let e = $expected;
359        let a = $actual;
360        $crate::check_comparison!(e >= a, false, ">=", $expected, e, $actual, a, $msg);
361    };
362}
363
364/// Asserts that the first expression is greater than or equal to the second and short-circuits on failure.
365#[macro_export]
366macro_rules! assert_ge {
367    ($expected:expr, $actual:expr) => {
368        $crate::assert_ge!($expected, $actual, "")
369    };
370    ($expected:expr, $actual:expr, $msg:expr) => {
371        let e = $expected;
372        let a = $actual;
373        $crate::check_comparison!(e >= a, true, ">=", $expected, e, $actual, a, $msg);
374    };
375}
376
377/// Asserts that the expression evaluates to true, but does not short-circuit on failure.
378#[macro_export]
379macro_rules! expect_true {
380    ($actual:expr) => {
381        $crate::expect_true!($actual, "")
382    };
383    ($actual:expr, $msg:expr) => {
384        let a = $actual;
385        $crate::check_condition!(a, false, "is false", $actual, $msg);
386    };
387}
388
389/// Asserts that the expression evaluates to true and short-circuits on failure.
390#[macro_export]
391macro_rules! assert_true {
392    ($actual:expr) => {
393        $crate::assert_true!($actual, "")
394    };
395    ($actual:expr, $msg:expr) => {
396        let a = $actual;
397        $crate::check_condition!(a, true, "is false", $actual, $msg);
398    };
399}
400
401/// Asserts that the expression evaluates to false, but does not short-circuit on failure.
402#[macro_export]
403macro_rules! expect_false {
404    ($actual:expr) => {
405        $crate::expect_false!($actual, "")
406    };
407    ($actual:expr, $msg:expr) => {
408        let a = $actual;
409        $crate::check_condition!(!a, false, "is true", $actual, $msg);
410    };
411}
412
413/// Asserts that the expression evaluates to false and short-circuits on failure.
414#[macro_export]
415macro_rules! assert_false {
416    ($actual:expr) => {
417        $crate::assert_false!($actual, "")
418    };
419    ($actual:expr, $msg:expr) => {
420        let a = $actual;
421        $crate::check_condition!(!a, true, "is true", $actual, $msg);
422    };
423}
424
425/// Asserts that the pointer is null, but does not short-circuit on failure.
426#[macro_export]
427macro_rules! expect_null {
428    ($actual:expr) => {
429        $crate::expect_null!($actual, "")
430    };
431    ($actual:expr, $msg:expr) => {
432        let a = $actual;
433        $crate::check_condition!(a.is_null(), false, "is non-null!", $actual, $msg);
434    };
435}
436
437/// Asserts that the pointer is null and short-circuits on failure.
438#[macro_export]
439macro_rules! assert_null {
440    ($actual:expr) => {
441        $crate::assert_null!($actual, "")
442    };
443    ($actual:expr, $msg:expr) => {
444        let a = $actual;
445        $crate::check_condition!(a.is_null(), true, "is non-null!", $actual, $msg);
446    };
447}
448
449/// Asserts that the pointer is non-null, but does not short-circuit on failure.
450#[macro_export]
451macro_rules! expect_nonnull {
452    ($actual:expr) => {
453        $crate::expect_nonnull!($actual, "")
454    };
455    ($actual:expr, $msg:expr) => {
456        let a = $actual;
457        $crate::check_condition!(!a.is_null(), false, "is null!", $actual, $msg);
458    };
459}
460
461/// Asserts that the pointer is non-null and short-circuits on failure.
462#[macro_export]
463macro_rules! assert_nonnull {
464    ($actual:expr) => {
465        $crate::assert_nonnull!($actual, "")
466    };
467    ($actual:expr, $msg:expr) => {
468        let a = $actual;
469        $crate::check_condition!(!a.is_null(), true, "is null!", $actual, $msg);
470    };
471}
472
473#[doc(hidden)]
474pub fn status_name_and_raw<T>(res: Result<T, __Status>) -> (&'static str, core::ffi::c_int) {
475    match res {
476        Ok(_) => ("OK", __sys::ZX_OK),
477        Err(err) => (err.as_str(), err.into_raw()),
478    }
479}
480
481#[doc(hidden)]
482pub fn print_status_comparison_failure<T>(
483    file: &str,
484    line: u32,
485    expected: &str,
486    expected_status: Result<T, __Status>,
487    actual: &str,
488    actual_status: Result<T, __Status>,
489    msg: &str,
490) {
491    let (expected_name, expected_raw) = status_name_and_raw(expected_status);
492    let (actual_name, actual_raw) = status_name_and_raw(actual_status);
493    kprintln!(
494        "\n    [FAILED]\n    {:s}:{}:\n    expected {:s} ({:s}, {}) == {:s} ({:s}, {})\n    {:s}",
495        file,
496        line,
497        expected,
498        expected_name,
499        expected_raw,
500        actual,
501        actual_name,
502        actual_raw,
503        msg,
504    );
505}
506
507#[macro_export]
508#[doc(hidden)]
509macro_rules! check_status_comparison {
510    (
511        $cond:expr,
512        $early_return:expr,
513        $expected_expr:expr,
514        $expected_status:expr,
515        $actual_expr:expr,
516        $actual_status:expr,
517        $msg:expr
518    ) => {
519        if !$cond {
520            record_failure!();
521            $crate::print_status_comparison_failure(
522                file!(),
523                line!(),
524                stringify!($expected_expr),
525                $expected_status,
526                stringify!($actual_expr),
527                $actual_status,
528                $msg,
529            );
530            if $early_return {
531                return false;
532            }
533        }
534    };
535}
536
537/// Asserts that the expression evaluates to OK, but does not short-circuit on failure.
538#[macro_export]
539macro_rules! expect_ok {
540    ($actual:expr) => {
541        $crate::expect_ok!($actual, "")
542    };
543    ($actual:expr, $msg:expr) => {
544        let a: Result<(), ::unittest::__Status> = $actual.into();
545        $crate::check_status_comparison!(a.is_ok(), false, "Ok(())", Ok(()), $actual, a, $msg);
546    };
547}
548
549/// Asserts that the expression evaluates to OK and short-circuits on failure.
550#[macro_export]
551macro_rules! assert_ok {
552    ($actual:expr) => {
553        $crate::assert_ok!($actual, "")
554    };
555    ($actual:expr, $msg:expr) => {
556        let a: Result<(), ::unittest::__Status> = $actual.into();
557        $crate::check_status_comparison!(a.is_ok(), true, "Ok(())", Ok(()), $actual, a, $msg);
558    };
559}
560
561/// Asserts that the expression evaluates to the specified error status, but does not short-circuit
562/// on failure.
563#[macro_export]
564macro_rules! expect_err {
565    ($actual:expr, $expected_err:expr) => {
566        $crate::expect_err!($actual, $expected_err, "")
567    };
568    ($actual:expr, $expected_err:expr, $msg:expr) => {
569        let a: Result<_, ::unittest::__Status> = $actual.into();
570        let e: ::unittest::__Status = $expected_err.into();
571        $crate::check_status_comparison!(
572            a.as_ref().is_err_and(|err| *err == e),
573            false,
574            $expected_err,
575            Err(e),
576            $actual,
577            a,
578            $msg
579        );
580    };
581}
582
583/// Asserts that the expression evaluates to the specified error status and short-circuits on
584/// failure.
585#[macro_export]
586macro_rules! assert_err {
587    ($actual:expr, $expected_err:expr) => {
588        $crate::assert_err!($actual, $expected_err, "")
589    };
590    ($actual:expr, $expected_err:expr, $msg:expr) => {
591        let a: Result<_, ::unittest::__Status> = $actual.into();
592        let e: ::unittest::__Status = $expected_err.into();
593        $crate::check_status_comparison!(
594            a.as_ref().is_err_and(|err| *err == e),
595            true,
596            $expected_err,
597            Err(e),
598            $actual,
599            a,
600            $msg
601        );
602    };
603}
604
605/// Asserts that the expression evaluates to Result::Ok and returns the resulting value, otherwise
606/// short-circuits.
607#[macro_export]
608macro_rules! unwrap_ok {
609    ($actual:expr) => {
610        $crate::unwrap_ok!($actual, "")
611    };
612    ($actual:expr, $msg:expr) => {
613        match ($actual) {
614            Ok(r) => r,
615            Err(err) => {
616                let err: ::unittest::__Status = err.into();
617                $crate::check_status_comparison!(
618                    false,
619                    true,
620                    "Ok(())",
621                    Ok(()),
622                    $actual,
623                    Err(err),
624                    $msg
625                );
626                return false;
627            }
628        }
629    };
630}
631
632/// Asserts that the expression evaluates to Option::Some and returns the resulting value, otherwise
633/// short-circuits.
634#[macro_export]
635macro_rules! unwrap_some {
636    ($actual:expr) => {
637        $crate::unwrap_some!($actual, "")
638    };
639    ($actual:expr, $msg:expr) => {
640        match ($actual) {
641            Option::Some(val) => val,
642            Option::None => {
643                $crate::check_condition!(false, true, "is None!", $actual, $msg);
644                return false;
645            }
646        }
647    };
648}
649
650/// Creates an isolated subtest closure with its own failure tracking.
651///
652/// Within a subtest, assertions (`expect_*!`, `assert_*!`, `unwrap_*!`) record failures to the
653/// subtest's local status flag rather than the enclosing test's flag. Hard assertions (`assert_*!`,
654/// `unwrap_*!`) return `false` early from the subtest without returning from the enclosing test.
655///
656/// Returns `bool`: `true` if all assertions in the subtest passed, `false` otherwise.
657#[macro_export]
658macro_rules! subtest {
659    (|$($param:ident : $ty:ty),* $(,)?| $body:block) => {
660        |$($param : $ty),*| -> bool {
661            // Unused when the subtest body contains no soft assertions.
662            #[allow(unused_mut)]
663            let mut all_ok = true;
664            macro_rules! record_failure {
665                () => {
666                    // Unused when an early-return assertion mutates all_ok before returning.
667                    #[allow(unused_assignments)]
668                    {
669                        all_ok = false;
670                    }
671                };
672            }
673            $body
674            all_ok
675        }
676    };
677}
678
679// When building this crate with unit tests we also pass `--cfg ktest` to
680// enable the unconditional use of #[suite] below.
681#[cfg(test)]
682mod tests {
683    use core::ffi::CStr;
684    use core::{ptr, slice};
685    use std::cell::Cell;
686    use std::vec::Vec;
687
688    use super::{TestSuiteRegistration, suite};
689
690    unsafe extern "C" {
691        static __start_unittest_testcases: TestSuiteRegistration;
692        static __stop_unittest_testcases: TestSuiteRegistration;
693    }
694
695    // Thread-local since #[test] instances are run in parallel.
696    thread_local! {
697        static END_REACHED: Cell<bool> = Cell::new(false);
698    }
699
700    fn mark_end_as_reached() {
701        END_REACHED.with(|cell| cell.set(true));
702    }
703
704    fn mark_end_as_not_reached() {
705        END_REACHED.with(|cell| cell.set(false));
706    }
707
708    fn expect_end_reached() {
709        std::assert_eq!(END_REACHED.with(|cell| cell.get()), true);
710    }
711
712    fn expect_end_not_reached() {
713        std::assert_eq!(END_REACHED.with(|cell| cell.get()), false);
714    }
715
716    fn get_suites() -> Vec<TestSuiteRegistration> {
717        let start = unsafe { &__start_unittest_testcases as *const TestSuiteRegistration };
718        let stop = unsafe { &__stop_unittest_testcases as *const TestSuiteRegistration };
719
720        let count = unsafe { stop.offset_from(start) } as usize;
721
722        let suites_rodata = unsafe { slice::from_raw_parts(start, count) };
723
724        let mut suites = Vec::from(suites_rodata);
725
726        suites.sort_by(|a, b| {
727            let a_name = unsafe { CStr::from_ptr(a.name) };
728            let b_name = unsafe { CStr::from_ptr(b.name) };
729            a_name.cmp(b_name)
730        });
731        suites
732    }
733
734    /// Suite with one function description.
735    #[suite(name = "one_function")]
736    mod suite_with_one_function {
737        /// Empty function description.
738        #[test]
739        fn empty() {}
740    }
741
742    /// Suite with non-test items.
743    #[suite]
744    mod suite_with_other_items {
745        use std::vec;
746
747        trait Countable {
748            fn count(&self) -> usize;
749        }
750
751        impl<T> Countable for Vec<T> {
752            fn count(&self) -> usize {
753                self.len()
754            }
755        }
756
757        fn get_count<T: Countable>(countable: T) -> usize {
758            countable.count()
759        }
760
761        /// Check use statement.
762        #[test]
763        fn check_other_items() {
764            let v = vec![1, 2, 3];
765            expect_eq!(get_count(v), 3);
766        }
767    }
768
769    /// Suite with ignored test.
770    #[suite(name = "with_ignored")]
771    mod suite_with_ignored {
772        /// Ignored test.
773        #[ignore]
774        #[test]
775        fn ignored_test() {
776            assert_true!(false);
777        }
778
779        /// Normal test.
780        #[test]
781        fn normal_test() {}
782    }
783
784    /// Assertion tests description.
785    #[suite]
786    mod assertions {
787        /// Success cases.
788        #[test]
789        fn test_success() {
790            assert_eq!(1, 1);
791            assert_ne!(1, 2);
792            assert_lt!(1, 2);
793            assert_le!(1, 1);
794            assert_gt!(2, 1);
795            assert_ge!(2, 2);
796
797            assert_true!(true);
798            assert_false!(false);
799
800            let null_ptr: *const i32 = ptr::null();
801            let nonnull_ptr: *const i32 = &42 as *const i32;
802            assert_null!(null_ptr);
803            assert_nonnull!(nonnull_ptr);
804
805            assert_ok!(Ok::<(), zx_status::Status>(()));
806            assert_err!(
807                Err::<(), _>(zx_status::Status::INVALID_ARGS),
808                zx_status::Status::INVALID_ARGS
809            );
810            assert_err!(zx_status::Status::INVALID_ARGS, zx_status::Status::INVALID_ARGS);
811
812            let _ = unwrap_ok!(Ok::<(), zx_status::Status>(()));
813            let _ = unwrap_some!(Some(42));
814
815            mark_end_as_reached();
816        }
817
818        /// Test that assert_eq fails on inequality.
819        #[test]
820        fn fail_assert_eq() {
821            assert_eq!(1, 2);
822            mark_end_as_reached();
823        }
824
825        /// Test that assert_ne fails on equality.
826        #[test]
827        fn fail_assert_ne() {
828            assert_ne!(1, 1);
829            mark_end_as_reached();
830        }
831
832        /// Test that assert_lt fails when not less-than.
833        #[test]
834        fn fail_assert_lt() {
835            assert_lt!(2, 1);
836            mark_end_as_reached();
837        }
838
839        /// Test that assert_le fails when greater.
840        #[test]
841        fn fail_assert_le() {
842            assert_le!(2, 1);
843            mark_end_as_reached();
844        }
845
846        /// Test that assert_gt fails when not greater-than.
847        #[test]
848        fn fail_assert_gt() {
849            assert_gt!(1, 2);
850            mark_end_as_reached();
851        }
852
853        /// Test that assert_ge fails when less.
854        #[test]
855        fn fail_assert_ge() {
856            assert_ge!(1, 2);
857            mark_end_as_reached();
858        }
859
860        /// Test that assert_true fails when value is false.
861        #[test]
862        fn fail_assert_true() {
863            assert_true!(false);
864            mark_end_as_reached();
865        }
866
867        /// Test that assert_false fails when value is true.
868        #[test]
869        fn fail_assert_false() {
870            assert_false!(true);
871            mark_end_as_reached();
872        }
873
874        /// Test that assert_null fails when pointer is non-null.
875        #[test]
876        fn fail_assert_null() {
877            assert_null!(&42 as *const i32);
878            mark_end_as_reached();
879        }
880
881        /// Test that assert_nonnull fails when pointer is null.
882        #[test]
883        fn fail_assert_nonnull() {
884            assert_nonnull!(ptr::null::<i32>());
885            mark_end_as_reached();
886        }
887
888        /// Test that assert_ok fails when value is non-zero.
889        #[test]
890        fn fail_assert_ok() {
891            assert_ok!(Err::<(), _>(zx_status::Status::INTERNAL));
892            mark_end_as_reached();
893        }
894
895        /// Test that assert_err fails when error does not match.
896        #[test]
897        fn fail_assert_err() {
898            assert_err!(Ok::<(), _>(()), zx_status::Status::INTERNAL);
899            mark_end_as_reached();
900        }
901
902        /// Test that unwrap_ok fails when value is an error.
903        #[test]
904        fn test_unwrap_ok() {
905            let _: () = unwrap_ok!(Err(zx_status::Status::INTERNAL));
906            mark_end_as_reached();
907        }
908
909        /// Test that unwrap_some fails when value is None.
910        #[test]
911        fn test_unwrap_some() {
912            let _: () = unwrap_some!(None::<()>);
913            mark_end_as_reached();
914        }
915    }
916
917    /// Expectation tests description.
918    #[suite]
919    mod expectations {
920        /// Success cases.
921        #[test]
922        fn test_success() {
923            expect_eq!(1, 1);
924            expect_eq!(1, 1, "one should be one");
925            expect_ne!(1, 2);
926            expect_ne!(1, 2, "one should not be two");
927            expect_lt!(1, 2);
928            expect_lt!(1, 2, "one should be less than two");
929            expect_le!(1, 1);
930            expect_le!(1, 2);
931            expect_gt!(2, 1);
932            expect_ge!(2, 2);
933
934            expect_true!(true);
935            expect_true!(true, "should be true");
936            expect_false!(false);
937            expect_false!(false, "should be false");
938
939            let null_ptr: *const i32 = ptr::null();
940            let nonnull_ptr: *const i32 = &42 as *const i32;
941            expect_null!(null_ptr);
942            expect_null!(null_ptr, "should be null");
943            expect_nonnull!(nonnull_ptr);
944            expect_nonnull!(nonnull_ptr, "should be non-null");
945
946            expect_ok!(Ok::<(), zx_status::Status>(()));
947            expect_ok!(Ok::<(), zx_status::Status>(()), "should be OK");
948            expect_err!(
949                Err::<(), _>(zx_status::Status::INVALID_ARGS),
950                zx_status::Status::INVALID_ARGS
951            );
952            expect_err!(
953                zx_status::Status::INVALID_ARGS,
954                zx_status::Status::INVALID_ARGS,
955                "should be INVALID_ARGS"
956            );
957
958            mark_end_as_reached();
959        }
960
961        /// Test that expect_eq fails on inequality.
962        #[test]
963        fn fail_expect_eq() {
964            expect_eq!(1, 2);
965            mark_end_as_reached();
966        }
967
968        /// Test that expect_ne fails on equality.
969        #[test]
970        fn fail_expect_ne() {
971            expect_ne!(1, 1);
972            mark_end_as_reached();
973        }
974
975        /// Test that expect_lt fails when not less-than.
976        #[test]
977        fn fail_expect_lt() {
978            expect_lt!(2, 1);
979            mark_end_as_reached();
980        }
981
982        /// Test that expect_le fails when greater.
983        #[test]
984        fn fail_expect_le() {
985            expect_le!(2, 1);
986            mark_end_as_reached();
987        }
988
989        /// Test that expect_gt fails when not greater-than.
990        #[test]
991        fn fail_expect_gt() {
992            expect_gt!(1, 2);
993            mark_end_as_reached();
994        }
995
996        /// Test that expect_ge fails when less.
997        #[test]
998        fn fail_expect_ge() {
999            expect_ge!(1, 2);
1000            mark_end_as_reached();
1001        }
1002
1003        /// Test that expect_true fails when value is false.
1004        #[test]
1005        fn fail_expect_true() {
1006            expect_true!(false);
1007            mark_end_as_reached();
1008        }
1009
1010        /// Test that expect_false fails when value is true.
1011        #[test]
1012        fn fail_expect_false() {
1013            expect_false!(true);
1014            mark_end_as_reached();
1015        }
1016
1017        /// Test that expect_null fails when pointer is non-null.
1018        #[test]
1019        fn fail_expect_null() {
1020            expect_null!(&42 as *const i32);
1021            mark_end_as_reached();
1022        }
1023
1024        /// Test that expect_nonnull fails when pointer is null.
1025        #[test]
1026        fn fail_expect_nonnull() {
1027            expect_nonnull!(ptr::null::<i32>());
1028            mark_end_as_reached();
1029        }
1030
1031        /// Test that expect_ok fails when value is non-zero.
1032        #[test]
1033        fn fail_expect_ok() {
1034            expect_ok!(zx_status::Status::INTERNAL);
1035            mark_end_as_reached();
1036        }
1037
1038        /// Test that expect_err fails when error does not match.
1039        #[test]
1040        fn fail_expect_err() {
1041            expect_err!(Ok::<(), _>(()), zx_status::Status::INTERNAL);
1042            mark_end_as_reached();
1043        }
1044    }
1045
1046    /// Subtests description.
1047    #[suite(name = "subtests")]
1048    mod subtests {
1049        /// Test that record_failure inside a subtest does not fail the outer test.
1050        #[test]
1051        fn test_shadowing() {
1052            let failing = subtest!(|should_fail: bool| {
1053                if should_fail {
1054                    record_failure!();
1055                }
1056            });
1057            expect_false!(failing(true));
1058            expect_true!(failing(false));
1059        }
1060    }
1061
1062    #[test]
1063    fn check_suite_count() {
1064        let suites = get_suites();
1065        std::assert_eq!(suites.len(), 6);
1066    }
1067
1068    #[test]
1069    fn check_suite_assertions() {
1070        let suites = get_suites();
1071        std::assert!(suites.len() > 0);
1072        let suite = &suites[0];
1073
1074        std::assert_eq!(unsafe { CStr::from_ptr(suite.name) }.to_bytes(), b"assertions");
1075        std::assert_eq!(suite.test_cnt, 15);
1076
1077        let cases_rodata = unsafe { slice::from_raw_parts(suite.tests, suite.test_cnt) };
1078        for case in cases_rodata {
1079            mark_end_as_not_reached();
1080            let name = unsafe { CStr::from_ptr(case.name) }.to_str().unwrap();
1081            let res = (case.fn_)();
1082            if name == "test_success" {
1083                std::assert_eq!(res, true, "assertions::test_success should pass");
1084                expect_end_reached();
1085            } else {
1086                std::assert_eq!(res, false, "assertions::{} should fail", name);
1087                expect_end_not_reached();
1088            }
1089        }
1090    }
1091
1092    #[test]
1093    fn check_suite_expectations() {
1094        let suites = get_suites();
1095        std::assert!(suites.len() > 1);
1096        let suite = &suites[1];
1097
1098        std::assert_eq!(unsafe { CStr::from_ptr(suite.name) }.to_bytes(), b"expectations");
1099        std::assert_eq!(suite.test_cnt, 13);
1100
1101        let cases = unsafe { slice::from_raw_parts(suite.tests, suite.test_cnt) };
1102        for case in cases {
1103            mark_end_as_not_reached();
1104            let name = unsafe { CStr::from_ptr(case.name) }.to_str().unwrap();
1105            let res = (case.fn_)();
1106            if name == "test_success" {
1107                std::assert_eq!(res, true, "expectations::test_success should pass");
1108            } else {
1109                std::assert_eq!(res, false, "expectations::{} should fail", name);
1110            }
1111            expect_end_reached();
1112        }
1113    }
1114
1115    #[test]
1116    fn check_suite_with_one_function() {
1117        let suites = get_suites();
1118        std::assert!(suites.len() > 2);
1119        let suite = &suites[2];
1120
1121        std::assert_eq!(unsafe { CStr::from_ptr(suite.name) }.to_bytes(), b"one_function");
1122        std::assert_eq!(
1123            unsafe { CStr::from_ptr(suite.desc) }.to_str().unwrap(),
1124            "Suite with one function description."
1125        );
1126        std::assert_eq!(suite.test_cnt, 1);
1127        let case = unsafe { &*suite.tests };
1128        std::assert_eq!(unsafe { CStr::from_ptr(case.name) }.to_bytes(), b"empty");
1129        assert!((case.fn_)());
1130    }
1131
1132    #[test]
1133    fn check_suite_subtests() {
1134        let suites = get_suites();
1135        std::assert!(suites.len() > 3);
1136        let suite = &suites[3];
1137
1138        std::assert_eq!(unsafe { CStr::from_ptr(suite.name) }.to_bytes(), b"subtests");
1139        std::assert_eq!(
1140            unsafe { CStr::from_ptr(suite.desc) }.to_str().unwrap(),
1141            "Subtests description."
1142        );
1143        std::assert_eq!(suite.test_cnt, 1);
1144        let case = unsafe { &*suite.tests };
1145        std::assert_eq!(unsafe { CStr::from_ptr(case.name) }.to_bytes(), b"test_shadowing");
1146        assert!((case.fn_)());
1147    }
1148
1149    #[test]
1150    fn check_suite_with_other_items() {
1151        let suites = get_suites();
1152        std::assert!(suites.len() > 4);
1153        let suite = &suites[4];
1154
1155        std::assert_eq!(
1156            unsafe { CStr::from_ptr(suite.name) }.to_bytes(),
1157            b"suite_with_other_items"
1158        );
1159        std::assert_eq!(
1160            unsafe { CStr::from_ptr(suite.desc) }.to_str().unwrap(),
1161            "Suite with non-test items."
1162        );
1163        std::assert_eq!(suite.test_cnt, 1);
1164        let case = unsafe { &*suite.tests };
1165        std::assert_eq!(unsafe { CStr::from_ptr(case.name) }.to_bytes(), b"check_other_items");
1166        assert!((case.fn_)());
1167    }
1168
1169    #[test]
1170    fn check_suite_with_ignored() {
1171        let suites = get_suites();
1172        std::assert!(suites.len() > 5);
1173        let suite = &suites[5];
1174
1175        std::assert_eq!(unsafe { CStr::from_ptr(suite.name) }.to_bytes(), b"with_ignored");
1176        std::assert_eq!(suite.test_cnt, 1);
1177        let case = unsafe { &*suite.tests };
1178        std::assert_eq!(unsafe { CStr::from_ptr(case.name) }.to_bytes(), b"normal_test");
1179    }
1180}