1#![cfg_attr(not(test), no_std)]
8
9#[cfg(test)]
11extern crate self as unittest;
12
13#[cfg(feature = "kernel")]
14mod user_memory;
15#[cfg(feature = "kernel")]
16pub use user_memory::UserMemory;
17
18use core::ffi::c_char;
19
20#[doc(hidden)]
21pub use zx_status::Status as __Status;
22
23pub use unittest_macro::test_suite;
71
72unsafe extern "C" {
75 pub fn printf(format: *const c_char, ...) -> core::ffi::c_int;
76}
77
78#[macro_export]
79#[doc(hidden)]
80macro_rules! c_str_lit {
81 ($s:expr) => {
82 concat!($s, "\0").as_ptr() as *const core::ffi::c_char
83 };
84}
85
86#[macro_export]
87#[doc(hidden)]
88macro_rules! check_comparison {
89 ($cond:expr, $early_return:expr, $op:literal, $expected:expr, $expected_val:expr, $actual:expr, $actual_val:expr, $msg:expr) => {
90 if !$cond {
91 record_failure!();
92 let format = $crate::failed_format!(concat!("expected %s (%ld) ", $op, " %s (%ld)"));
93 let file_c_str = $crate::c_str_lit!(file!());
94 let expected_str = $crate::c_str_lit!(stringify!($expected));
95 let actual_str = $crate::c_str_lit!(stringify!($actual));
96 let msg_c_str = $crate::c_str_lit!($msg);
97 unsafe {
98 $crate::printf(
99 format,
100 file_c_str,
101 line!() as core::ffi::c_int,
102 expected_str,
103 $expected_val as isize,
104 actual_str,
105 $actual_val as isize,
106 msg_c_str,
107 );
108 }
109 if $early_return {
110 return false;
111 }
112 }
113 };
114}
115
116#[macro_export]
117#[doc(hidden)]
118macro_rules! check_condition {
119 ($cond:expr, $early_return:expr, $desc:literal, $actual:expr, $msg:expr) => {
120 if !$cond {
121 record_failure!();
122 let format = $crate::failed_format!($desc);
123 let file_c_str = $crate::c_str_lit!(file!());
124 let actual_str = $crate::c_str_lit!(stringify!($actual));
125 let msg_c_str = $crate::c_str_lit!($msg);
126 unsafe {
127 $crate::printf(
128 format,
129 file_c_str,
130 line!() as core::ffi::c_int,
131 actual_str,
132 msg_c_str,
133 );
134 }
135 if $early_return {
136 return false;
137 }
138 }
139 };
140}
141
142#[macro_export]
143#[doc(hidden)]
144macro_rules! failed_format {
145 ($body:expr) => {
146 $crate::c_str_lit!(concat!(
147 "\n",
148 " [FAILED]\n",
149 " %s:%d:\n",
150 " ",
151 $body,
152 "\n",
153 " %s\n"
154 ))
155 };
156}
157
158#[doc(hidden)]
162#[repr(C)]
163#[derive(Clone, Copy)]
164pub struct TestSuiteRegistration {
165 pub name: *const c_char,
166 pub desc: *const c_char,
167 pub tests: *const TestCaseRegistration,
168 pub test_cnt: usize,
169}
170
171unsafe impl Sync for TestSuiteRegistration {}
172
173#[doc(hidden)]
177#[repr(C)]
178#[derive(Clone, Copy)]
179pub struct TestCaseRegistration {
180 pub name: *const c_char,
181 pub fn_: extern "C" fn() -> bool,
182}
183
184unsafe impl Sync for TestCaseRegistration {}
185
186#[macro_export]
188macro_rules! expect_eq {
189 ($expected:expr, $actual:expr) => {
190 $crate::expect_eq!($expected, $actual, "")
191 };
192 ($expected:expr, $actual:expr, $msg:expr) => {
193 let e = $expected;
194 let a = $actual;
195 $crate::check_comparison!(e == a, false, "==", $expected, e, $actual, a, $msg);
196 };
197}
198
199#[macro_export]
201macro_rules! assert_eq {
202 ($expected:expr, $actual:expr) => {
203 $crate::assert_eq!($expected, $actual, "")
204 };
205 ($expected:expr, $actual:expr, $msg:expr) => {
206 let e = $expected;
207 let a = $actual;
208 $crate::check_comparison!(e == a, true, "==", $expected, e, $actual, a, $msg);
209 };
210}
211
212#[macro_export]
214macro_rules! expect_ne {
215 ($expected:expr, $actual:expr) => {
216 $crate::expect_ne!($expected, $actual, "")
217 };
218 ($expected:expr, $actual:expr, $msg:expr) => {
219 let e = $expected;
220 let a = $actual;
221 $crate::check_comparison!(e != a, false, "!=", $expected, e, $actual, a, $msg);
222 };
223}
224
225#[macro_export]
227macro_rules! assert_ne {
228 ($expected:expr, $actual:expr) => {
229 $crate::assert_ne!($expected, $actual, "")
230 };
231 ($expected:expr, $actual:expr, $msg:expr) => {
232 let e = $expected;
233 let a = $actual;
234 $crate::check_comparison!(e != a, true, "!=", $expected, e, $actual, a, $msg);
235 };
236}
237
238#[macro_export]
240macro_rules! expect_lt {
241 ($expected:expr, $actual:expr) => {
242 $crate::expect_lt!($expected, $actual, "")
243 };
244 ($expected:expr, $actual:expr, $msg:expr) => {
245 let e = $expected;
246 let a = $actual;
247 $crate::check_comparison!(e < a, false, "<", $expected, e, $actual, a, $msg);
248 };
249}
250
251#[macro_export]
253macro_rules! assert_lt {
254 ($expected:expr, $actual:expr) => {
255 $crate::assert_lt!($expected, $actual, "")
256 };
257 ($expected:expr, $actual:expr, $msg:expr) => {
258 let e = $expected;
259 let a = $actual;
260 $crate::check_comparison!(e < a, true, "<", $expected, e, $actual, a, $msg);
261 };
262}
263
264#[macro_export]
266macro_rules! expect_le {
267 ($expected:expr, $actual:expr) => {
268 $crate::expect_le!($expected, $actual, "")
269 };
270 ($expected:expr, $actual:expr, $msg:expr) => {
271 let e = $expected;
272 let a = $actual;
273 $crate::check_comparison!(e <= a, false, "<=", $expected, e, $actual, a, $msg);
274 };
275}
276
277#[macro_export]
279macro_rules! assert_le {
280 ($expected:expr, $actual:expr) => {
281 $crate::assert_le!($expected, $actual, "")
282 };
283 ($expected:expr, $actual:expr, $msg:expr) => {
284 let e = $expected;
285 let a = $actual;
286 $crate::check_comparison!(e <= a, true, "<=", $expected, e, $actual, a, $msg);
287 };
288}
289
290#[macro_export]
292macro_rules! expect_gt {
293 ($expected:expr, $actual:expr) => {
294 $crate::expect_gt!($expected, $actual, "")
295 };
296 ($expected:expr, $actual:expr, $msg:expr) => {
297 let e = $expected;
298 let a = $actual;
299 $crate::check_comparison!(e > a, false, ">", $expected, e, $actual, a, $msg);
300 };
301}
302
303#[macro_export]
305macro_rules! assert_gt {
306 ($expected:expr, $actual:expr) => {
307 $crate::assert_gt!($expected, $actual, "")
308 };
309 ($expected:expr, $actual:expr, $msg:expr) => {
310 let e = $expected;
311 let a = $actual;
312 $crate::check_comparison!(e > a, true, ">", $expected, e, $actual, a, $msg);
313 };
314}
315
316#[macro_export]
318macro_rules! expect_ge {
319 ($expected:expr, $actual:expr) => {
320 $crate::expect_ge!($expected, $actual, "")
321 };
322 ($expected:expr, $actual:expr, $msg:expr) => {
323 let e = $expected;
324 let a = $actual;
325 $crate::check_comparison!(e >= a, false, ">=", $expected, e, $actual, a, $msg);
326 };
327}
328
329#[macro_export]
331macro_rules! assert_ge {
332 ($expected:expr, $actual:expr) => {
333 $crate::assert_ge!($expected, $actual, "")
334 };
335 ($expected:expr, $actual:expr, $msg:expr) => {
336 let e = $expected;
337 let a = $actual;
338 $crate::check_comparison!(e >= a, true, ">=", $expected, e, $actual, a, $msg);
339 };
340}
341
342#[macro_export]
344macro_rules! expect_true {
345 ($actual:expr) => {
346 $crate::expect_true!($actual, "")
347 };
348 ($actual:expr, $msg:expr) => {
349 let a = $actual;
350 $crate::check_condition!(a, false, "%s is false", $actual, $msg);
351 };
352}
353
354#[macro_export]
356macro_rules! assert_true {
357 ($actual:expr) => {
358 $crate::assert_true!($actual, "")
359 };
360 ($actual:expr, $msg:expr) => {
361 let a = $actual;
362 $crate::check_condition!(a, true, "%s is false", $actual, $msg);
363 };
364}
365
366#[macro_export]
368macro_rules! expect_false {
369 ($actual:expr) => {
370 $crate::expect_false!($actual, "")
371 };
372 ($actual:expr, $msg:expr) => {
373 let a = $actual;
374 $crate::check_condition!(!a, false, "%s is true", $actual, $msg);
375 };
376}
377
378#[macro_export]
380macro_rules! assert_false {
381 ($actual:expr) => {
382 $crate::assert_false!($actual, "")
383 };
384 ($actual:expr, $msg:expr) => {
385 let a = $actual;
386 $crate::check_condition!(!a, true, "%s is true", $actual, $msg);
387 };
388}
389
390#[macro_export]
392macro_rules! expect_null {
393 ($actual:expr) => {
394 $crate::expect_null!($actual, "")
395 };
396 ($actual:expr, $msg:expr) => {
397 let a = $actual;
398 $crate::check_condition!(a.is_null(), false, "%s is non-null!", $actual, $msg);
399 };
400}
401
402#[macro_export]
404macro_rules! assert_null {
405 ($actual:expr) => {
406 $crate::assert_null!($actual, "")
407 };
408 ($actual:expr, $msg:expr) => {
409 let a = $actual;
410 $crate::check_condition!(a.is_null(), true, "%s is non-null!", $actual, $msg);
411 };
412}
413
414#[macro_export]
416macro_rules! expect_nonnull {
417 ($actual:expr) => {
418 $crate::expect_nonnull!($actual, "")
419 };
420 ($actual:expr, $msg:expr) => {
421 let a = $actual;
422 $crate::check_condition!(!a.is_null(), false, "%s is null!", $actual, $msg);
423 };
424}
425
426#[macro_export]
428macro_rules! assert_nonnull {
429 ($actual:expr) => {
430 $crate::assert_nonnull!($actual, "")
431 };
432 ($actual:expr, $msg:expr) => {
433 let a = $actual;
434 $crate::check_condition!(!a.is_null(), true, "%s is null!", $actual, $msg);
435 };
436}
437
438#[macro_export]
440macro_rules! expect_ok {
441 ($actual:expr) => {
442 $crate::expect_ok!($actual, "")
443 };
444 ($actual:expr, $msg:expr) => {
445 let a: ::unittest::__Status = $actual.into();
446 $crate::check_comparison!(
447 a == ::unittest::__Status::OK,
448 false,
449 "==",
450 ::unittest::__Status::OK,
451 ::unittest::__Status::OK.into_raw(),
452 a,
453 a.into_raw(),
454 $msg
455 );
456 };
457}
458
459#[macro_export]
461macro_rules! assert_ok {
462 ($actual:expr) => {
463 $crate::assert_ok!($actual, "")
464 };
465 ($actual:expr, $msg:expr) => {
466 let a: ::unittest::__Status = $actual.into();
467 $crate::check_comparison!(
468 a == ::unittest::__Status::OK,
469 true,
470 "==",
471 ::unittest::__Status::OK,
472 ::unittest::__Status::OK.into_raw(),
473 a,
474 a.into_raw(),
475 $msg
476 );
477 };
478}
479
480#[macro_export]
483macro_rules! unwrap_ok {
484 ($actual:expr) => {
485 $crate::unwrap_ok!($actual, "")
486 };
487 ($actual:expr, $msg:expr) => {
488 match ($actual) {
489 Ok(r) => r,
490 Err(err) => {
491 let err: ::unittest::__Status = err.into();
492 $crate::check_comparison!(
493 err == ::unittest::__Status::OK,
494 true,
495 "==",
496 ::unittest::__Status::OK,
497 ::unittest::__Status::OK.into_raw(),
498 err,
499 err.into_raw(),
500 $msg
501 );
502 return false;
503 }
504 }
505 };
506}
507
508#[cfg(test)]
511mod tests {
512 use core::ffi::CStr;
513 use core::{ptr, slice};
514 use std::cell::Cell;
515 use std::vec::Vec;
516
517 use super::{TestSuiteRegistration, test_suite};
518
519 unsafe extern "C" {
520 static __start_unittest_testcases: TestSuiteRegistration;
521 static __stop_unittest_testcases: TestSuiteRegistration;
522 }
523
524 thread_local! {
526 static END_REACHED: Cell<bool> = Cell::new(false);
527 }
528
529 fn mark_end_as_reached() {
530 END_REACHED.with(|cell| cell.set(true));
531 }
532
533 fn mark_end_as_not_reached() {
534 END_REACHED.with(|cell| cell.set(false));
535 }
536
537 fn expect_end_reached() {
538 std::assert_eq!(END_REACHED.with(|cell| cell.get()), true);
539 }
540
541 fn expect_end_not_reached() {
542 std::assert_eq!(END_REACHED.with(|cell| cell.get()), false);
543 }
544
545 fn get_test_suites() -> Vec<TestSuiteRegistration> {
546 let start = unsafe { &__start_unittest_testcases as *const TestSuiteRegistration };
547 let stop = unsafe { &__stop_unittest_testcases as *const TestSuiteRegistration };
548
549 let count = unsafe { stop.offset_from(start) } as usize;
550
551 let test_suites_rodata = unsafe { slice::from_raw_parts(start, count) };
552
553 let mut suites = Vec::from(test_suites_rodata);
554
555 suites.sort_by(|a, b| {
556 let a_name = unsafe { CStr::from_ptr(a.name) };
557 let b_name = unsafe { CStr::from_ptr(b.name) };
558 a_name.cmp(b_name)
559 });
560 suites
561 }
562
563 #[test_suite(name = "one_function")]
565 mod suite_with_one_function {
566 #[test]
568 fn empty() {}
569 }
570
571 #[test_suite]
573 mod suite_with_other_items {
574 use std::vec;
575
576 trait Countable {
577 fn count(&self) -> usize;
578 }
579
580 impl<T> Countable for Vec<T> {
581 fn count(&self) -> usize {
582 self.len()
583 }
584 }
585
586 fn get_count<T: Countable>(countable: T) -> usize {
587 countable.count()
588 }
589
590 #[test]
592 fn check_other_items() {
593 let v = vec![1, 2, 3];
594 expect_eq!(get_count(v), 3);
595 }
596 }
597
598 #[test_suite(name = "with_ignored")]
600 mod suite_with_ignored {
601 #[ignore]
603 #[test]
604 fn ignored_test() {
605 assert_true!(false);
606 }
607
608 #[test]
610 fn normal_test() {}
611 }
612
613 #[test_suite]
615 mod assertions {
616 #[test]
618 fn test_success() {
619 assert_eq!(1, 1);
620 assert_ne!(1, 2);
621 assert_lt!(1, 2);
622 assert_le!(1, 1);
623 assert_gt!(2, 1);
624 assert_ge!(2, 2);
625
626 assert_true!(true);
627 assert_false!(false);
628
629 let null_ptr: *const i32 = ptr::null();
630 let nonnull_ptr: *const i32 = &42 as *const i32;
631 assert_null!(null_ptr);
632 assert_nonnull!(nonnull_ptr);
633
634 assert_ok!(zx_status::Status::OK);
635
636 let _ = unwrap_ok!(Ok::<(), zx_status::Status>(()));
637
638 mark_end_as_reached();
639 }
640
641 #[test]
643 fn fail_assert_eq() {
644 assert_eq!(1, 2);
645 mark_end_as_reached();
646 }
647
648 #[test]
650 fn fail_assert_ne() {
651 assert_ne!(1, 1);
652 mark_end_as_reached();
653 }
654
655 #[test]
657 fn fail_assert_lt() {
658 assert_lt!(2, 1);
659 mark_end_as_reached();
660 }
661
662 #[test]
664 fn fail_assert_le() {
665 assert_le!(2, 1);
666 mark_end_as_reached();
667 }
668
669 #[test]
671 fn fail_assert_gt() {
672 assert_gt!(1, 2);
673 mark_end_as_reached();
674 }
675
676 #[test]
678 fn fail_assert_ge() {
679 assert_ge!(1, 2);
680 mark_end_as_reached();
681 }
682
683 #[test]
685 fn fail_assert_true() {
686 assert_true!(false);
687 mark_end_as_reached();
688 }
689
690 #[test]
692 fn fail_assert_false() {
693 assert_false!(true);
694 mark_end_as_reached();
695 }
696
697 #[test]
699 fn fail_assert_null() {
700 assert_null!(&42 as *const i32);
701 mark_end_as_reached();
702 }
703
704 #[test]
706 fn fail_assert_nonnull() {
707 assert_nonnull!(ptr::null::<i32>());
708 mark_end_as_reached();
709 }
710
711 #[test]
713 fn fail_assert_ok() {
714 assert_ok!(zx_status::Status::INTERNAL);
715 mark_end_as_reached();
716 }
717
718 #[test]
720 fn test_unwrap_ok() {
721 let _: () = unwrap_ok!(Err(zx_status::Status::INTERNAL));
722 mark_end_as_reached();
723 }
724 }
725
726 #[test_suite]
728 mod expectations {
729 #[test]
731 fn test_success() {
732 expect_eq!(1, 1);
733 expect_eq!(1, 1, "one should be one");
734 expect_ne!(1, 2);
735 expect_ne!(1, 2, "one should not be two");
736 expect_lt!(1, 2);
737 expect_lt!(1, 2, "one should be less than two");
738 expect_le!(1, 1);
739 expect_le!(1, 2);
740 expect_gt!(2, 1);
741 expect_ge!(2, 2);
742
743 expect_true!(true);
744 expect_true!(true, "should be true");
745 expect_false!(false);
746 expect_false!(false, "should be false");
747
748 let null_ptr: *const i32 = ptr::null();
749 let nonnull_ptr: *const i32 = &42 as *const i32;
750 expect_null!(null_ptr);
751 expect_null!(null_ptr, "should be null");
752 expect_nonnull!(nonnull_ptr);
753 expect_nonnull!(nonnull_ptr, "should be non-null");
754
755 expect_ok!(zx_status::Status::OK);
756 expect_ok!(zx_status::Status::OK, "should be OK");
757
758 mark_end_as_reached();
759 }
760
761 #[test]
763 fn fail_expect_eq() {
764 expect_eq!(1, 2);
765 mark_end_as_reached();
766 }
767
768 #[test]
770 fn fail_expect_ne() {
771 expect_ne!(1, 1);
772 mark_end_as_reached();
773 }
774
775 #[test]
777 fn fail_expect_lt() {
778 expect_lt!(2, 1);
779 mark_end_as_reached();
780 }
781
782 #[test]
784 fn fail_expect_le() {
785 expect_le!(2, 1);
786 mark_end_as_reached();
787 }
788
789 #[test]
791 fn fail_expect_gt() {
792 expect_gt!(1, 2);
793 mark_end_as_reached();
794 }
795
796 #[test]
798 fn fail_expect_ge() {
799 expect_ge!(1, 2);
800 mark_end_as_reached();
801 }
802
803 #[test]
805 fn fail_expect_true() {
806 expect_true!(false);
807 mark_end_as_reached();
808 }
809
810 #[test]
812 fn fail_expect_false() {
813 expect_false!(true);
814 mark_end_as_reached();
815 }
816
817 #[test]
819 fn fail_expect_null() {
820 expect_null!(&42 as *const i32);
821 mark_end_as_reached();
822 }
823
824 #[test]
826 fn fail_expect_nonnull() {
827 expect_nonnull!(ptr::null::<i32>());
828 mark_end_as_reached();
829 }
830
831 #[test]
833 fn fail_expect_ok() {
834 expect_ok!(zx_status::Status::INTERNAL);
835 mark_end_as_reached();
836 }
837 }
838
839 #[test]
840 fn check_suite_count() {
841 let suites = get_test_suites();
842 std::assert_eq!(suites.len(), 5);
843 }
844
845 #[test]
846 fn check_suite_assertions() {
847 let suites = get_test_suites();
848 std::assert!(suites.len() > 0);
849 let suite = &suites[0];
850
851 std::assert_eq!(unsafe { CStr::from_ptr(suite.name) }.to_bytes(), b"assertions");
852 std::assert_eq!(suite.test_cnt, 13);
853
854 let cases_rodata = unsafe { slice::from_raw_parts(suite.tests, suite.test_cnt) };
855 for case in cases_rodata {
856 mark_end_as_not_reached();
857 let name = unsafe { CStr::from_ptr(case.name) }.to_str().unwrap();
858 let res = (case.fn_)();
859 if name == "test_success" {
860 std::assert_eq!(res, true, "assertions::test_success should pass");
861 expect_end_reached();
862 } else {
863 std::assert_eq!(res, false, "assertions::{} should fail", name);
864 expect_end_not_reached();
865 }
866 }
867 }
868
869 #[test]
870 fn check_suite_expectations() {
871 let suites = get_test_suites();
872 std::assert!(suites.len() > 1);
873 let suite = &suites[1];
874
875 std::assert_eq!(unsafe { CStr::from_ptr(suite.name) }.to_bytes(), b"expectations");
876 std::assert_eq!(suite.test_cnt, 12);
877
878 let cases = unsafe { slice::from_raw_parts(suite.tests, suite.test_cnt) };
879 for case in cases {
880 mark_end_as_not_reached();
881 let name = unsafe { CStr::from_ptr(case.name) }.to_str().unwrap();
882 let res = (case.fn_)();
883 if name == "test_success" {
884 std::assert_eq!(res, true, "expectations::test_success should pass");
885 } else {
886 std::assert_eq!(res, false, "expectations::{} should fail", name);
887 }
888 expect_end_reached();
889 }
890 }
891
892 #[test]
893 fn check_suite_with_one_function() {
894 let suites = get_test_suites();
895 std::assert!(suites.len() > 2);
896 let suite = &suites[2];
897
898 std::assert_eq!(unsafe { CStr::from_ptr(suite.name) }.to_bytes(), b"one_function");
899 std::assert_eq!(
900 unsafe { CStr::from_ptr(suite.desc) }.to_str().unwrap(),
901 "Suite with one function description."
902 );
903 std::assert_eq!(suite.test_cnt, 1);
904 let case = unsafe { &*suite.tests };
905 std::assert_eq!(unsafe { CStr::from_ptr(case.name) }.to_bytes(), b"empty");
906 assert!((case.fn_)());
907 }
908
909 #[test]
910 fn check_suite_with_other_items() {
911 let suites = get_test_suites();
912 std::assert!(suites.len() > 3);
913 let suite = &suites[3];
914
915 std::assert_eq!(
916 unsafe { CStr::from_ptr(suite.name) }.to_bytes(),
917 b"suite_with_other_items"
918 );
919 std::assert_eq!(
920 unsafe { CStr::from_ptr(suite.desc) }.to_str().unwrap(),
921 "Suite with non-test items."
922 );
923 std::assert_eq!(suite.test_cnt, 1);
924 let case = unsafe { &*suite.tests };
925 std::assert_eq!(unsafe { CStr::from_ptr(case.name) }.to_bytes(), b"check_other_items");
926 assert!((case.fn_)());
927 }
928
929 #[test]
930 fn check_suite_with_ignored() {
931 let suites = get_test_suites();
932 std::assert!(suites.len() > 4);
933 let suite = &suites[4];
934
935 std::assert_eq!(unsafe { CStr::from_ptr(suite.name) }.to_bytes(), b"with_ignored");
936 std::assert_eq!(suite.test_cnt, 1);
937 let case = unsafe { &*suite.tests };
938 std::assert_eq!(unsafe { CStr::from_ptr(case.name) }.to_bytes(), b"normal_test");
939 }
940}