Skip to content

Commit

Permalink
implement the qemu tests as xtask
Browse files Browse the repository at this point in the history
  • Loading branch information
Anatol Ulrich committed Feb 11, 2021
1 parent efc75b1 commit 239d025
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[alias]
xtask = "run --package xtask --"
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ members = [
"parser",
"print",
"qemu-run",
"xtask",
]
exclude = [
"firmware/*",
Expand Down
13 changes: 13 additions & 0 deletions xtask/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "xtask"
authors = ["The Knurling-rs developers"]
edition = "2018"
license = "MIT OR Apache-2.0"
publish = false
version = "0.1.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
console = "0.14.0"
similar = "1.1.0"
145 changes: 145 additions & 0 deletions xtask/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
use std::{
collections::HashMap,
process::{Command, Stdio},
};
use std::{env, fs};
use std::{io::Read, path::Path};

use console::Style;
use similar::{ChangeTag, TextDiff};

fn load_expected(name: &str, release_mode: bool) -> String {
let path = Path::new("firmware/qemu/src/bin");

let filename;
if release_mode {
filename = format!("{}.release.out", name);
} else {
filename = format!("{}.out", name);
}

let path = path.join(filename);

fs::read_to_string(path).unwrap()
}

fn capture_stdout(cmd: &mut Command) -> String {
let mut cmd = cmd.stdout(Stdio::piped()).spawn().unwrap();
let mut stdout = cmd.stdout.take().unwrap();
let mut out = String::new();
stdout.read_to_string(&mut out).unwrap();
out
}

fn rustc_is_nightly() -> bool {
let out = capture_stdout(Command::new("rustc").args(&["-V"]));
out.contains("nightly")
}

fn run_qemu(name: &str, features: &str, release_mode: bool) -> Result<(), String> {
let display_name = format!(
"{} ({})",
name,
if release_mode { "release" } else { "dev" }
);
println!("testing {}", display_name,);
let cwd = fs::canonicalize("firmware/qemu").unwrap();
let mut args;
if release_mode {
args = vec!["-q", "rrb", name]
} else {
args = vec!["-q", "rb", name]
}
if features.len() > 0 {
args.extend_from_slice(&["--features", features]);
}

let actual = capture_stdout(Command::new("cargo").args(&args).current_dir(cwd));

let expected = load_expected(name, release_mode);

let diff = TextDiff::from_lines(&expected, &actual);

// if anything isn't ChangeTag::Equal, print it and turn on error flag
let mut actual_matches_expected = true;
for op in diff.ops() {
for change in diff.iter_changes(op) {
let styled_change = match change.tag() {
ChangeTag::Delete => Some(("-", Style::new().red())),
ChangeTag::Insert => Some(("+", Style::new().green())),
ChangeTag::Equal => None,
};
match styled_change {
Some((sign, style)) => {
actual_matches_expected = false;
eprint!("{}{}", style.apply_to(sign).bold(), style.apply_to(change),);
}
None => {}
}
}
}

if actual_matches_expected {
Ok(())
} else {
eprintln!("ERROR");
Err(display_name)
}
}

fn test_all() -> Result<(), Vec<String>> {
let mut errors = Vec::new();
let mut tests = vec![
"log",
"timestamp",
"panic",
"assert",
"assert-eq",
"assert-ne",
"unwrap",
"defmt-test",
"hints",
];

if rustc_is_nightly() {
tests.push("alloc");
}

let mut features_map = HashMap::new();
features_map.insert("alloc", "alloc");
let no_features = "";

for test in &tests {
let features = features_map.get(test).unwrap_or(&no_features);

match run_qemu(test, features, false) {
Ok(_) => {}
Err(e) => errors.push(e),
}

match run_qemu(test, features, true) {
Ok(_) => {}
Err(e) => errors.push(e),
}
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}

fn main() -> Result<(), String> {
let mut args = env::args().skip(1);
let subcommand = args.next();
match subcommand.as_deref() {
Some("test_all") => test_all().map_err(|e| format!("Some tests failed: {}", e.join(", "))),
_ => {
eprintln!("usage: cargo xtask <subcommand>");
eprintln!();
eprintln!("subcommands:");
eprintln!(" test_all - run all tests");
Err("".into())
}
}
}

0 comments on commit 239d025

Please sign in to comment.