put the "unit test" logic into libtest
Also make `std::termination` module public and rename feature. The lib feature needs a different name from the language feature.
This commit is contained in:
parent
0625d4c282
commit
e446f706a8
@ -501,11 +501,10 @@ mod memchr;
|
||||
// The runtime entry point and a few unstable public functions used by the
|
||||
// compiler
|
||||
pub mod rt;
|
||||
// The trait to support returning arbitrary types in the main function
|
||||
mod termination;
|
||||
|
||||
// The trait to support returning arbitrary types in the main function
|
||||
#[unstable(feature = "termination_trait", issue = "43301")]
|
||||
pub use self::termination::Termination;
|
||||
pub mod termination;
|
||||
|
||||
// Include a number of private modules that exist solely to provide
|
||||
// the rustdoc documentation for primitive types. Using `include!`
|
||||
|
@ -8,7 +8,11 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Defines the meaning of the return value from `main`, and hence
|
||||
//! controls what happens in a Rust program after `main` returns.
|
||||
|
||||
use fmt::Debug;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod exit {
|
||||
pub const SUCCESS: i32 = 0;
|
||||
@ -30,28 +34,21 @@ mod exit {
|
||||
/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate
|
||||
/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned.
|
||||
#[cfg_attr(not(test), lang = "termination")]
|
||||
#[unstable(feature = "termination_trait", issue = "43301")]
|
||||
#[unstable(feature = "termination_trait_lib", issue = "43301")]
|
||||
#[rustc_on_unimplemented =
|
||||
"`main` can only return types that implement {Termination}, not `{Self}`"]
|
||||
pub trait Termination {
|
||||
/// Is called to get the representation of the value as status code.
|
||||
/// This status code is returned to the operating system.
|
||||
fn report(self) -> i32;
|
||||
|
||||
/// Invoked when unit tests terminate. Should panic if the unit
|
||||
/// test is considered a failure. By default, invokes `report()`
|
||||
/// and checks for a `0` result.
|
||||
fn assert_unit_test_successful(self) where Self: Sized {
|
||||
assert_eq!(self.report(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "termination_trait", issue = "43301")]
|
||||
#[unstable(feature = "termination_trait_lib", issue = "43301")]
|
||||
impl Termination for () {
|
||||
fn report(self) -> i32 { exit::SUCCESS }
|
||||
}
|
||||
|
||||
#[unstable(feature = "termination_trait", issue = "43301")]
|
||||
#[unstable(feature = "termination_trait_lib", issue = "43301")]
|
||||
impl<T: Termination, E: Debug> Termination for Result<T, E> {
|
||||
fn report(self) -> i32 {
|
||||
match self {
|
||||
@ -64,19 +61,19 @@ impl<T: Termination, E: Debug> Termination for Result<T, E> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "termination_trait", issue = "43301")]
|
||||
#[unstable(feature = "termination_trait_lib", issue = "43301")]
|
||||
impl Termination for ! {
|
||||
fn report(self) -> i32 { unreachable!(); }
|
||||
}
|
||||
|
||||
#[unstable(feature = "termination_trait", issue = "43301")]
|
||||
#[unstable(feature = "termination_trait_lib", issue = "43301")]
|
||||
impl Termination for bool {
|
||||
fn report(self) -> i32 {
|
||||
if self { exit::SUCCESS } else { exit::FAILURE }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "termination_trait", issue = "43301")]
|
||||
#[unstable(feature = "termination_trait_lib", issue = "43301")]
|
||||
impl Termination for i32 {
|
||||
fn report(self) -> i32 {
|
||||
self
|
||||
|
@ -746,48 +746,36 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P<ast::Expr> {
|
||||
};
|
||||
visible_path.extend(path);
|
||||
|
||||
// If termination feature is enabled, create a wrapper that invokes the fn
|
||||
// like this:
|
||||
// Rather than directly give the test function to the test
|
||||
// harness, we create a wrapper like this:
|
||||
//
|
||||
// fn wrapper() {
|
||||
// assert_eq!(0, real_function().report());
|
||||
// }
|
||||
// || test::assert_test_result(real_function())
|
||||
//
|
||||
// and then put a reference to `wrapper` into the test descriptor. Otherwise,
|
||||
// just put a direct reference to `real_function`.
|
||||
// this will coerce into a fn pointer that is specialized to the
|
||||
// actual return type of `real_function` (Typically `()`, but not always).
|
||||
let fn_expr = {
|
||||
let base_fn_expr = ecx.expr_path(ecx.path_global(span, visible_path));
|
||||
if cx.features.termination_trait {
|
||||
// ::std::Termination::assert_unit_test_successful
|
||||
let assert_unit_test_successful = ecx.path_global(
|
||||
// construct `real_function()` (this will be inserted into the overall expr)
|
||||
let real_function_expr = ecx.expr_path(ecx.path_global(span, visible_path));
|
||||
// construct path `test::assert_test_result`
|
||||
let assert_test_result = test_path("assert_test_result");
|
||||
// construct `|| {..}`
|
||||
ecx.lambda(
|
||||
span,
|
||||
vec![],
|
||||
// construct `assert_test_result(..)`
|
||||
ecx.expr_call(
|
||||
span,
|
||||
ecx.expr_path(assert_test_result),
|
||||
vec![
|
||||
ecx.ident_of("std"),
|
||||
ecx.ident_of("Termination"),
|
||||
ecx.ident_of("assert_unit_test_successful"),
|
||||
// construct `real_function()`
|
||||
ecx.expr_call(
|
||||
span,
|
||||
real_function_expr,
|
||||
vec![],
|
||||
)
|
||||
],
|
||||
);
|
||||
// || {..}
|
||||
ecx.lambda(
|
||||
span,
|
||||
vec![],
|
||||
// ::std::Termination::assert_unit_test_successful(..)
|
||||
ecx.expr_call(
|
||||
span,
|
||||
ecx.expr_path(assert_unit_test_successful),
|
||||
vec![
|
||||
// $base_fn_expr()
|
||||
ecx.expr_call(
|
||||
span,
|
||||
base_fn_expr,
|
||||
vec![],
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
} else {
|
||||
base_fn_expr
|
||||
}
|
||||
),
|
||||
)
|
||||
};
|
||||
|
||||
let variant_name = if test.bench { "StaticBenchFn" } else { "StaticTestFn" };
|
||||
|
@ -40,6 +40,7 @@
|
||||
#![feature(set_stdio)]
|
||||
#![feature(panic_unwind)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(termination_trait_lib)]
|
||||
|
||||
extern crate getopts;
|
||||
extern crate term;
|
||||
@ -69,6 +70,7 @@ use std::iter::repeat;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::mpsc::{channel, Sender};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::termination::Termination;
|
||||
use std::thread;
|
||||
use std::time::{Instant, Duration};
|
||||
use std::borrow::Cow;
|
||||
@ -322,6 +324,13 @@ pub fn test_main_static(tests: &[TestDescAndFn]) {
|
||||
test_main(&args, owned_tests, Options::new())
|
||||
}
|
||||
|
||||
/// Invoked when unit tests terminate. Should panic if the unit
|
||||
/// test is considered a failure. By default, invokes `report()`
|
||||
/// and checks for a `0` result.
|
||||
pub fn assert_test_result<T: Termination>(result: T) {
|
||||
assert_eq!(result.report(), 0);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ColorConfig {
|
||||
AutoColor,
|
||||
|
@ -10,6 +10,6 @@
|
||||
#![feature(termination_trait)]
|
||||
|
||||
fn main() -> char {
|
||||
//~^ ERROR: the trait bound `char: std::Termination` is not satisfied
|
||||
//~^ ERROR: the trait bound `char: std::termination::Termination` is not satisfied
|
||||
' '
|
||||
}
|
||||
|
@ -12,6 +12,6 @@
|
||||
|
||||
struct ReturnType {}
|
||||
|
||||
fn main() -> ReturnType { //~ ERROR `ReturnType: std::Termination` is not satisfied
|
||||
fn main() -> ReturnType { //~ ERROR `ReturnType: std::termination::Termination` is not satisfied
|
||||
ReturnType {}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user