1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! *Drone* support crate for rustc's built in unit-test and micro-benchmarking
//! framework.
#![feature(core_intrinsics)]
#![feature(lang_items)]
#![no_std]
#![deny(missing_docs)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", allow(precedence, doc_markdown))]

#[macro_use]
extern crate sc;

pub use TestFn::*;
pub use TestName::*;
use core::{fmt, intrinsics, ptr};

#[macro_use]
pub mod macros;
pub mod io;
pub mod panicking;

static mut TEST_PANICKED: bool = false;

/// Test function with description.
pub struct TestDescAndFn {
  #[doc(hidden)] pub desc: TestDesc,
  #[doc(hidden)] pub testfn: TestFn,
}

/// The definition of a single test.
pub struct TestDesc {
  #[doc(hidden)] pub name: TestName,
  #[doc(hidden)] pub ignore: bool,
  #[doc(hidden)] pub should_panic: ShouldPanic,
}

/// The name of a test.
pub enum TestName {
  #[doc(hidden)] StaticTestName(&'static str),
}

/// A function that runs a test.
pub enum TestFn {
  #[doc(hidden)] StaticTestFn(fn()),
}

/// A `should_panic` attribute handler.
#[derive(PartialEq)]
pub enum ShouldPanic {
  #[doc(hidden)] No,
  #[doc(hidden)] Yes,
}

/// The test runner.
pub fn test_main_static(tests: &[TestDescAndFn]) {
  let mut failed = 0;
  let mut ignored = 0;
  let mut passed = 0;
  eprintln!("running {} tests", tests.len());

  for test in tests {
    let name = match test.desc.name {
      StaticTestName(name) => name,
    };
    let testfn = match test.testfn {
      StaticTestFn(testfn) => testfn,
    };
    if test.desc.ignore {
      ignored += 1;
      eprintln!("test {} ... ignored", name);
    } else {
      eprint!("test {} ... ", name);
      reset_panicked();
      testfn();
      if has_panicked() == (test.desc.should_panic == ShouldPanic::Yes) {
        passed += 1;
        eprintln!("OK");
      } else {
        failed += 1;
        eprintln!("FAILED");
      }
    }
  }

  eprintln!();
  eprintln!(
    "test result: {}. {} passed; {} failed; {} ignored",
    if failed == 0 { "OK" } else { "FAILED" },
    passed,
    failed,
    ignored,
  );

  if failed != 0 {
    exit(101);
  }
}

/// Overridden panic routine.
pub fn test_panic(args: fmt::Arguments, file: &'static str, line: u32) {
  unsafe {
    TEST_PANICKED = true;
  }
  eprintln!();
  eprint!("panicked at '");
  io::write_fmt(args);
  eprintln!("', {}:{}", file, line);
}

/// Entry point.
#[no_mangle]
pub unsafe extern "C" fn _start() -> ! {
  extern "C" {
    fn main(argc: isize, argv: *const *const u8) -> isize;
  }
  main(0, ptr::null());
  exit(0);
}

/// Lang item required to run `main`.
#[lang = "start"]
extern "C" fn start(
  main: fn(),
  _argc: isize,
  _argv: *const *const u8,
) -> isize {
  main();
  0
}

#[doc(hidden)]
#[no_mangle]
pub extern "C" fn __aeabi_unwind_cpp_pr0() {}

#[doc(hidden)]
#[no_mangle]
pub extern "C" fn __aeabi_unwind_cpp_pr1() {}

fn reset_panicked() {
  unsafe {
    TEST_PANICKED = false;
  }
}

fn has_panicked() -> bool {
  unsafe { TEST_PANICKED }
}

fn exit(code: i32) -> ! {
  unsafe {
    syscall!(EXIT, code as usize);
    intrinsics::unreachable()
  }
}