-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added code for initial custom test harness (#20).
Signed-off-by: Gerd Zellweger <mail@gerdzellweger.com>
- Loading branch information
Showing
6 changed files
with
231 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[package] | ||
name = "test" | ||
version = "0.0.1" | ||
authors = ["Gerd Zellweger <mail@gerdzellweger.com>"] | ||
|
||
[dependencies] | ||
syn = "0.11.*" | ||
quote = "0.3.*" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
#![feature(used, lang_items)] | ||
|
||
pub fn test_start(ntests: usize) { | ||
println!("KVM testing: running {} tests", ntests) | ||
} | ||
|
||
pub fn test_ignored(name: &str) { | ||
println!("test {} ... ignored", name); | ||
} | ||
|
||
pub fn test_before_run(name: &str) { | ||
print!("test {} ... ", name); | ||
} | ||
|
||
pub fn test_panic_fmt(args: std::fmt::Arguments, file: &'static str, line: u32) { | ||
print!("\npanicked at '"); | ||
use std::io::Write; | ||
std::io::stderr().write_fmt(args); | ||
println!("', {}:{}", file, line); | ||
} | ||
|
||
pub fn test_failed(_name: &str) { | ||
println!("FAILED"); | ||
} | ||
|
||
pub fn test_success(_name: &str) { | ||
println!("OK"); | ||
} | ||
|
||
pub fn test_summary(passed: usize, failed: usize, ignored: usize) { | ||
println!("\ntest result: {} {} passed; {} failed; {} ignored", | ||
if failed == 0 { "OK" } else { "FAILED" }, | ||
passed, | ||
failed, | ||
ignored); | ||
|
||
if failed != 0 { | ||
std::process::exit(101); | ||
} | ||
} | ||
|
||
#[no_mangle] | ||
#[used] | ||
pub static mut __TEST_PANICKED: bool = false; | ||
|
||
pub fn test_main_static(tests: &[TestDescAndFn]) { | ||
unsafe { | ||
test_start(tests.len()); | ||
|
||
let mut failed = 0; | ||
let mut ignored = 0; | ||
let mut passed = 0; | ||
for test in tests { | ||
if test.desc.ignore { | ||
ignored += 1; | ||
test_ignored(test.desc.name.0); | ||
} else { | ||
test_before_run(test.desc.name.0); | ||
|
||
__TEST_PANICKED = false; | ||
|
||
test.testfn.0(); | ||
|
||
if __TEST_PANICKED == (test.desc.should_panic == ShouldPanic::Yes) { | ||
passed += 1; | ||
test_success(test.desc.name.0); | ||
} else { | ||
failed += 1; | ||
test_failed(test.desc.name.0); | ||
} | ||
} | ||
|
||
} | ||
|
||
test_summary(passed, failed, ignored); | ||
} | ||
} | ||
|
||
// required for compatibility with the `rustc --test` interface | ||
pub struct TestDescAndFn { | ||
pub desc: TestDesc, | ||
pub testfn: StaticTestFn, | ||
} | ||
|
||
pub struct TestDesc { | ||
pub ignore: bool, | ||
pub name: StaticTestName, | ||
pub should_panic: ShouldPanic, | ||
} | ||
|
||
pub struct StaticTestName(pub &'static str); | ||
pub struct StaticTestFn(pub fn()); | ||
|
||
#[derive(PartialEq)] | ||
pub enum ShouldPanic { | ||
No, | ||
Yes, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "test-macros" | ||
version = "0.0.1" | ||
authors = ["Gerd Zellweger <mail@gerdzellweger.com>"] | ||
|
||
[dependencies] | ||
quote = "0.3.*" | ||
|
||
[dependencies.syn] | ||
version = "0.11.*" | ||
features = ["full"] | ||
|
||
[lib] | ||
proc-macro = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
#![feature(rustc_private)] | ||
#![feature(proc_macro)] | ||
|
||
extern crate proc_macro; | ||
extern crate syn; | ||
#[macro_use] | ||
extern crate quote; | ||
extern crate syntax; | ||
|
||
use proc_macro::TokenStream; | ||
|
||
#[proc_macro_attribute] | ||
pub fn panics_note(args: TokenStream, input: TokenStream) -> TokenStream { | ||
let args = args.to_string(); | ||
let mut input = input.to_string(); | ||
|
||
assert!(args.starts_with("= \""), | ||
"`#[panics_note]` requires an argument of the form `#[panics_note = \"panic note \ | ||
here\"]`"); | ||
|
||
// Get just the bare note string | ||
let panics_note = args.trim_matches(&['=', ' ', '"'][..]); | ||
|
||
// The input will include all docstrings regardless of where the attribute is placed, | ||
// so we need to find the last index before the start of the item | ||
let insert_idx = idx_after_last_docstring(&input); | ||
|
||
// And insert our `### Panics` note there so it always appears at the end of an item's docs | ||
input.insert_str(insert_idx, &format!("/// # Panics \n/// {}\n", panics_note)); | ||
|
||
input.parse().unwrap() | ||
} | ||
|
||
// `proc-macro` crates can contain any kind of private item still | ||
fn idx_after_last_docstring(input: &str) -> usize { | ||
// Skip docstring lines to find the start of the item proper | ||
input.lines().skip_while(|line| line.trim_left().starts_with("///")).next() | ||
// Find the index of the first non-docstring line in the input | ||
// Note: assumes this exact line is unique in the input | ||
.and_then(|line_after| input.find(line_after)) | ||
// No docstrings in the input | ||
.unwrap_or(0) | ||
} | ||
|
||
|
||
fn generate_kvm_setup(ident: syn::Ident) -> quote::Tokens { | ||
quote! { | ||
// The generated impl | ||
fn #ident() { | ||
log!("blabla"); | ||
} | ||
} | ||
} | ||
|
||
use std::string; | ||
|
||
#[proc_macro_attribute] | ||
pub fn kvmattrs(args: TokenStream, input: TokenStream) -> TokenStream { | ||
let args = args.to_string(); | ||
let mut input = input.to_string(); | ||
|
||
let ast = syn::parse_item(&input).unwrap(); | ||
let new_fn_ident = syn::Ident::new(String::from(ast.ident.as_ref()) + "_setup"); | ||
println!("{:?}", new_fn_ident); | ||
|
||
// Get just the bare note string | ||
let panics_note = args.trim_matches(&['=', ' ', '"'][..]); | ||
let new_code: TokenStream = generate_kvm_setup(new_fn_ident).parse().unwrap(); | ||
|
||
input += new_code.to_string().as_str(); | ||
input.parse().unwrap() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters