The great docs update

This commit is contained in:
Emil Fresk 2021-09-22 13:22:45 +02:00
parent c8621d78b9
commit b71df58f2f
106 changed files with 1286 additions and 1429 deletions

View file

@ -7,4 +7,3 @@ edition = "2018"
anyhow = "1.0.43"
os_pipe = "0.9.2"
structopt = "0.3.22"
tempdir = "0.3.7"

View file

@ -38,14 +38,14 @@ pub fn build_hexpath(
.map_err(|e| anyhow::Error::new(TestRunError::PathConversionError(e)))
}
pub fn compare_builds(file_1: String, file_2: String) -> anyhow::Result<()> {
let buf_1 = std::fs::read_to_string(file_1.clone())?;
let buf_2 = std::fs::read_to_string(file_2.clone())?;
pub fn compare_builds(expected: String, got: String) -> anyhow::Result<()> {
let buf_1 = std::fs::read_to_string(expected.clone())?;
let buf_2 = std::fs::read_to_string(got.clone())?;
if buf_1 != buf_2 {
return Err(anyhow::Error::new(TestRunError::FileCmpError {
file_1,
file_2,
expected,
got,
}));
}

View file

@ -1,14 +1,16 @@
use crate::RunResult;
use crate::{RunResult, TestRunError};
use core::fmt;
use os_pipe::pipe;
use std::{fs::File, io::Read, path::Path, process::Command};
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BuildMode {
Release,
Debug,
}
#[derive(Debug)]
pub enum CargoCommand<'a> {
Run {
example: &'a str,
@ -146,17 +148,26 @@ pub fn run_command(command: &CargoCommand) -> anyhow::Result<RunResult> {
/// Check if `run` was sucessful.
/// returns Ok in case the run went as expected,
/// Err otherwise
pub fn run_successful(run: &RunResult, expected_output_file: String) -> anyhow::Result<()> {
let mut file_handle = File::open(expected_output_file)?;
pub fn run_successful(run: &RunResult, expected_output_file: String) -> Result<(), TestRunError> {
let mut file_handle =
File::open(expected_output_file.clone()).map_err(|_| TestRunError::FileError {
file: expected_output_file.clone(),
})?;
let mut expected_output = String::new();
file_handle.read_to_string(&mut expected_output)?;
if expected_output == run.output && run.exit_status.success() {
Ok(())
file_handle
.read_to_string(&mut expected_output)
.map_err(|_| TestRunError::FileError {
file: expected_output_file.clone(),
})?;
if expected_output != run.output {
Err(TestRunError::FileCmpError {
expected: expected_output.clone(),
got: run.output.clone(),
})
} else if !run.exit_status.success() {
Err(TestRunError::CommandError(run.clone()))
} else {
Err(anyhow::anyhow!(
"Run failed with exit status {}: {}",
run.exit_status,
run.output
))
Ok(())
}
}

View file

@ -27,15 +27,16 @@ struct Options {
target: String,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct RunResult {
exit_status: ExitStatus,
output: String,
}
#[derive(Debug)]
enum TestRunError {
FileCmpError { file_1: String, file_2: String },
pub enum TestRunError {
FileCmpError { expected: String, got: String },
FileError { file: String },
PathConversionError(OsString),
CommandError(RunResult),
IncompatibleCommand,
@ -44,8 +45,17 @@ enum TestRunError {
impl fmt::Display for TestRunError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TestRunError::FileCmpError { file_1, file_2 } => {
write!(f, "Differing output in Files: {} {}", file_1, file_2)
TestRunError::FileCmpError { expected, got } => {
writeln!(f, "Differing output in files.")?;
writeln!(f, "")?;
writeln!(f, "Expected:")?;
writeln!(f, "{}", expected)?;
writeln!(f, "")?;
writeln!(f, "Got:")?;
write!(f, "{}", got)
}
TestRunError::FileError { file } => {
write!(f, "File error on: {}", file)
}
TestRunError::CommandError(e) => {
write!(
@ -75,25 +85,32 @@ fn main() -> anyhow::Result<()> {
}
let targets = [ARMV7M, ARMV6M];
let examples = &[
"idle",
"init",
"hardware",
"preempt",
"binds",
"resource",
"lock",
"multilock",
"only-shared-access",
"task",
"message",
"capacity",
"not-sync",
"generics",
"pool",
"ramfunc",
"peripherals-taken",
];
let examples: Vec<_> = std::fs::read_dir("./examples")?
.filter_map(|path| {
path.map(|p| p.path().file_stem().unwrap().to_str().unwrap().to_string())
.ok()
})
.collect();
// let examples = &[
// "idle",
// "init",
// "hardware",
// "preempt",
// "binds",
// "lock",
// "multilock",
// "only-shared-access",
// "task",
// "message",
// "capacity",
// "not-sync",
// "generics",
// "pool",
// "ramfunc",
// "peripherals-taken",
// ];
let opts = Options::from_args();
let target = &opts.target;
@ -102,12 +119,12 @@ fn main() -> anyhow::Result<()> {
if target == "all" {
for t in targets {
run_test(t, examples)?;
build_test(t, examples)?;
run_test(t, &examples)?;
build_test(t, &examples)?;
}
} else if targets.contains(&target.as_str()) {
run_test(&target, examples)?;
build_test(&target, examples)?;
run_test(&target, &examples)?;
build_test(&target, &examples)?;
} else {
eprintln!(
"The target you specified is not available. Available targets are:\
@ -121,115 +138,26 @@ fn main() -> anyhow::Result<()> {
Ok(())
}
fn run_test(target: &str, examples: &[&str]) -> anyhow::Result<()> {
fn run_test(target: &str, examples: &[String]) -> anyhow::Result<()> {
for example in examples {
match *example {
"pool" => {
if target != ARMV6M {
// check this one manually because addresses printed in `pool.run` may vary
let features_v7 = Some("__v7");
let cmd = CargoCommand::Run {
example,
target,
features: None,
mode: BuildMode::Release,
};
let debug_run_result = run_command(&CargoCommand::Run {
example,
target,
features: features_v7,
mode: BuildMode::Debug,
})?;
arm_example(&cmd, 1)?;
if debug_run_result.exit_status.success() {
print_from_output("foo(0x2", &debug_run_result.output);
print_from_output("bar(0x2", &debug_run_result.output);
}
let hexpath = &build_hexpath(*example, features_v7, BuildMode::Debug, 1)?;
run_command(&CargoCommand::Objcopy {
example,
target,
features: features_v7,
ihex: hexpath,
})?;
let release_run_result = run_command(&CargoCommand::Run {
example,
target,
features: features_v7,
mode: BuildMode::Release,
})?;
if release_run_result.exit_status.success() {
print_from_output("foo(0x2", &release_run_result.output);
print_from_output("bar(0x2", &release_run_result.output);
}
let hexpath = &build_hexpath(*example, features_v7, BuildMode::Release, 1)?;
run_command(&CargoCommand::Objcopy {
example,
target,
features: features_v7,
ihex: hexpath,
})?;
}
}
"types" => {
let features_v7 = Some("__v7");
// TODO this example doesn't exist anymore, can we remove this case?
if target != ARMV6M {
arm_example(
&CargoCommand::Run {
example,
target,
features: features_v7,
mode: BuildMode::Debug,
},
1,
)?;
arm_example(
&CargoCommand::Run {
example,
target,
features: features_v7,
mode: BuildMode::Release,
},
1,
)?;
}
}
_ => {
arm_example(
&CargoCommand::Run {
example,
target,
features: None,
mode: BuildMode::Debug,
},
1,
)?;
if *example == "types" {
arm_example(
&CargoCommand::Run {
example,
target,
features: None,
mode: BuildMode::Release,
},
1,
)?;
} else {
arm_example(
&CargoCommand::Build {
example,
target,
features: None,
mode: BuildMode::Release,
},
1,
)?;
}
}
}
arm_example(
&CargoCommand::Build {
example,
target,
features: None,
mode: BuildMode::Release,
},
1,
)?;
}
Ok(())
@ -264,11 +192,7 @@ fn arm_example(command: &CargoCommand, build_num: u32) -> anyhow::Result<()> {
match &command {
CargoCommand::Run { .. } => {
if run_successful(&cargo_run_result, expected_output_file).is_err() {
return Err(anyhow::Error::new(TestRunError::CommandError(
cargo_run_result,
)));
}
run_successful(&cargo_run_result, expected_output_file)?;
}
_ => (),
}
@ -289,82 +213,43 @@ fn arm_example(command: &CargoCommand, build_num: u32) -> anyhow::Result<()> {
}
}
fn build_test(target: &str, examples: &[&str]) -> anyhow::Result<()> {
fn build_test(target: &str, examples: &[String]) -> anyhow::Result<()> {
run_command(&CargoCommand::Clean)?;
let mut built = vec![];
let build_path: PathBuf = ["target", target, "debug", "examples"].iter().collect();
let build_path: PathBuf = ["target", target, "release", "examples"].iter().collect();
for example in examples {
match *example {
"pool" | "types" => {
if target != ARMV6M {
let features_v7 = Some("__v7");
let no_features = None;
arm_example(
&CargoCommand::Build {
target,
example,
mode: BuildMode::Release,
features: no_features,
},
2,
)?;
let expected = build_hexpath(example, no_features, BuildMode::Release, 1)?;
let got = build_hexpath(example, no_features, BuildMode::Release, 2)?;
arm_example(
&CargoCommand::Build {
target,
example,
mode: BuildMode::Debug,
features: features_v7,
},
2,
)?;
let file_1 = build_hexpath(example, features_v7, BuildMode::Debug, 1)?;
let file_2 = build_hexpath(example, features_v7, BuildMode::Debug, 2)?;
compare_builds(expected, got)?;
compare_builds(file_1, file_2)?;
arm_example(
&CargoCommand::Build {
target,
example,
mode: BuildMode::Release,
features: no_features,
},
2,
)?;
let expected = build_hexpath(example, no_features, BuildMode::Release, 1)?;
let got = build_hexpath(example, no_features, BuildMode::Release, 2)?;
arm_example(
&CargoCommand::Build {
target,
example,
mode: BuildMode::Release,
features: features_v7,
},
2,
)?;
let file_1 = build_hexpath(example, features_v7, BuildMode::Release, 1)?;
let file_2 = build_hexpath(example, features_v7, BuildMode::Release, 2)?;
compare_builds(expected, got)?;
compare_builds(file_1, file_2)?;
built.push(build_path.join(example));
}
}
_ => {
let no_features = None;
arm_example(
&CargoCommand::Build {
target,
example,
mode: BuildMode::Debug,
features: no_features,
},
2,
)?;
let file_1 = build_hexpath(example, no_features, BuildMode::Debug, 1)?;
let file_2 = build_hexpath(example, no_features, BuildMode::Debug, 2)?;
compare_builds(file_1, file_2)?;
arm_example(
&CargoCommand::Build {
target,
example,
mode: BuildMode::Release,
features: no_features,
},
2,
)?;
let file_1 = build_hexpath(example, no_features, BuildMode::Release, 1)?;
let file_2 = build_hexpath(example, no_features, BuildMode::Release, 2)?;
compare_builds(file_1, file_2)?;
built.push(build_path.join(example));
}
}
built.push(build_path.join(example));
}
let example_paths: Vec<&Path> = built.iter().map(|p| p.as_path()).collect();
@ -377,12 +262,12 @@ fn build_test(target: &str, examples: &[&str]) -> anyhow::Result<()> {
Ok(())
}
/// Check if lines in `output` contain `pattern` and print matching lines
fn print_from_output(pattern: &str, lines: &str) {
let lines = lines.split("\n");
for line in lines {
if line.contains(pattern) {
println!("{}", line);
}
}
}
// /// Check if lines in `output` contain `pattern` and print matching lines
// fn print_from_output(pattern: &str, lines: &str) {
// let lines = lines.split("\n");
// for line in lines {
// if line.contains(pattern) {
// println!("{}", line);
// }
// }
// }