improved test execution

This commit is contained in:
matthieu.jolimaitre 2022-09-25 13:02:16 +02:00
parent 7f694cd6c2
commit 6ef3993f8f
6 changed files with 93 additions and 56 deletions

View file

@ -14,6 +14,7 @@ pub struct Config {
main_file: String, main_file: String,
test_file: String, test_file: String,
includes: Vec<String>, includes: Vec<String>,
fascist_mode: bool,
} }
impl Config { impl Config {
@ -24,6 +25,7 @@ impl Config {
main_file: "main.c".into(), main_file: "main.c".into(),
test_file: "test.c".into(), test_file: "test.c".into(),
includes: vec![], includes: vec![],
fascist_mode: false,
} }
} }
@ -61,6 +63,10 @@ impl Config {
&self.includes &self.includes
} }
pub fn fascist_mode(&self) -> bool {
self.fascist_mode
}
fn try_get(path: &Path) -> Option<Self> { fn try_get(path: &Path) -> Option<Self> {
let path = path.to_path_buf().apply(|p| p.push(Self::CONFIG_FILE_NAME)); let path = path.to_path_buf().apply(|p| p.push(Self::CONFIG_FILE_NAME));
fs::read_to_string(path) fs::read_to_string(path)

View file

@ -63,6 +63,18 @@ fn append_includes(list: &mut Vec<String>) {
); );
} }
fn compilation_args() -> Vec<String> {
let mut args = vec![
"-Wall".to_string(),
"-Wextra".to_string(),
"-std=c99".to_string(),
];
if Config::get_current().fascist_mode() {
args.push("-Werror".to_string());
}
args
}
fn main() { fn main() {
let args: Arguments = Parser::parse(); let args: Arguments = Parser::parse();
@ -70,7 +82,8 @@ fn main() {
Commands::check { files } => check::main(files), Commands::check { files } => check::main(files),
Commands::run { mut files } => { Commands::run { mut files } => {
append_includes(&mut files); append_includes(&mut files);
run::main(files); let args = compilation_args();
run::main(files, args);
} }
Commands::test { Commands::test {
capture, capture,
@ -78,12 +91,14 @@ fn main() {
tests, tests,
} => { } => {
append_includes(&mut files); append_includes(&mut files);
let args = compilation_args();
let tests = (!tests.is_empty()).then_some(tests); let tests = (!tests.is_empty()).then_some(tests);
test::main(capture, files, tests) test::main(capture, files, tests)
} }
Commands::watch { mut files } => { Commands::watch { mut files } => {
append_includes(&mut files); append_includes(&mut files);
watch::main(files) let args = compilation_args();
watch::main(files, args)
} }
Commands::init { path } => config::create(path), Commands::init { path } => config::create(path),
} }

View file

@ -1,21 +1,21 @@
use crate::{ use crate::{
tasks::{CompileTask, RunTask}, tasks::{CompileTask, RunTask},
utils::{log_failure, log_success}, utils::{log_failure, log_process, log_success},
}; };
pub fn main(files: Vec<String>) -> Option<()> { pub fn main(files: Vec<String>, flags: Vec<String>) -> Option<()> {
let source_file = files.into_iter().map(|f| f.into()).collect(); let source_file = files.into_iter().map(|f| f.into()).collect();
let compiled = CompileTask::new(source_file) log_process("compiling");
.with_flag("-Wall") let mut task = CompileTask::new(source_file);
.with_flag("-Wextra") for flag in flags {
.with_flag("-std=c99") task = task.with_flag(flag);
.run() }
.map(Option::from) let compiled = task.run().map(Option::from).unwrap_or_else(|_| {
.unwrap_or_else(|_| {
log_failure("compilation failed"); log_failure("compilation failed");
None None
})?; })?;
log_success("compilation successful"); log_success("finished");
log_process("running");
RunTask::new(compiled) RunTask::new(compiled)
.run() .run()
.map(Option::from) .map(Option::from)
@ -23,6 +23,5 @@ pub fn main(files: Vec<String>) -> Option<()> {
log_failure("process failure"); log_failure("process failure");
None None
})?; })?;
log_success("process exited successfully");
Some(()) Some(())
} }

View file

@ -2,8 +2,6 @@ use std::{
fs, fs,
path::PathBuf, path::PathBuf,
process::{Command, ExitStatus}, process::{Command, ExitStatus},
thread,
time::Duration,
}; };
use crate::utils::{ use crate::utils::{
@ -14,6 +12,7 @@ pub struct CompileTask {
files: Vec<PathBuf>, files: Vec<PathBuf>,
addition: Vec<String>, addition: Vec<String>,
flags: Vec<String>, flags: Vec<String>,
verbose: bool,
} }
// TODO: split compile & compile raw // TODO: split compile & compile raw
@ -24,6 +23,7 @@ impl CompileTask {
files, files,
addition: vec![], addition: vec![],
flags: vec![], flags: vec![],
verbose: false,
} }
} }
@ -37,6 +37,11 @@ impl CompileTask {
self self
} }
pub fn with_verbose(mut self) -> Self {
self.verbose = true;
self
}
pub fn run(self) -> Result<PathBuf, ExitStatus> { pub fn run(self) -> Result<PathBuf, ExitStatus> {
let proc_source = self.gen_source(); let proc_source = self.gen_source();
let mut sources = self.files.clone(); let mut sources = self.files.clone();
@ -60,30 +65,46 @@ impl CompileTask {
.args(["-o", output_path_ref]) .args(["-o", output_path_ref])
.args(self.flags.clone()) .args(self.flags.clone())
.args(sources.iter().map(|s| s.to_str().unwrap())); .args(sources.iter().map(|s| s.to_str().unwrap()));
if self.verbose {
log_command_run(&command); log_command_run(&command);
log_separator_top(); log_separator_top();
}
let status = command.status().unwrap(); let status = command.status().unwrap();
if self.verbose {
log_separator_bottom(); log_separator_bottom();
thread::sleep(Duration::from_millis(100)); }
status.success().then_some(output_path).ok_or(status) status.success().then_some(output_path).ok_or(status)
} }
} }
pub struct RunTask { pub struct RunTask {
file: PathBuf, file: PathBuf,
verbose: bool,
} }
impl RunTask { impl RunTask {
pub fn new(file: PathBuf) -> Self { pub fn new(file: PathBuf) -> Self {
Self { file } Self {
file,
verbose: false,
}
}
pub fn with_verbose(mut self) -> Self {
self.verbose = true;
self
} }
pub fn run(self) -> Result<(), ExitStatus> { pub fn run(self) -> Result<(), ExitStatus> {
let mut command = Command::new(self.file); let mut command = Command::new(self.file);
if self.verbose {
log_command_run(&command); log_command_run(&command);
log_separator_top(); log_separator_top();
}
let status = command.status().unwrap(); let status = command.status().unwrap();
if self.verbose {
log_separator_bottom(); log_separator_bottom();
}
if status.success() { if status.success() {
Ok(()) Ok(())
} else { } else {
@ -100,10 +121,11 @@ impl GenTask {
pub fn new(content: String) -> Self { pub fn new(content: String) -> Self {
Self { content } Self { content }
} }
pub fn run(self) -> PathBuf { pub fn run(self) -> PathBuf {
let output_path = tmp_file_path().apply(|o| o.set_extension("c")); let output_path = tmp_file_path().apply(|o| o.set_extension("c"));
fs::write(&output_path, &self.content).unwrap(); let content = self.content.clone();
dbg!(fs::read_to_string(&output_path).unwrap()); fs::write(&output_path, &content).unwrap();
output_path output_path
} }
} }

View file

@ -1,6 +1,9 @@
use std::fs; use std::{fs, thread, time::Duration};
use crate::tasks::{CompileTask, GenTask, RunTask}; use crate::{
tasks::{CompileTask, GenTask, RunTask},
utils::{log_failure, log_process},
};
pub fn main(_capture: bool, files: Vec<String>, _test: Option<Vec<String>>) { pub fn main(_capture: bool, files: Vec<String>, _test: Option<Vec<String>>) {
// let includes = files // let includes = files
@ -13,14 +16,19 @@ pub fn main(_capture: bool, files: Vec<String>, _test: Option<Vec<String>>) {
let content = fs::read_to_string(&path).unwrap(); let content = fs::read_to_string(&path).unwrap();
let tests = find_tests(content); let tests = find_tests(content);
for test in tests { for test in tests {
log_process(&format!("running '{test}'"));
let content = gen_test_main(fs::canonicalize(&path).unwrap().to_str().unwrap(), &test); let content = gen_test_main(fs::canonicalize(&path).unwrap().to_str().unwrap(), &test);
let generated_code = GenTask::new(content).run(); let generated_code = GenTask::new(content).run();
thread::sleep(Duration::from_millis(100));
// compile with all files // compile with all files
//let files = includes.clone().apply(|v| v.insert(0, generated_code)); //let files = includes.clone().apply(|v| v.insert(0, generated_code));
let generated_bin = CompileTask::new(vec![generated_code]).run().unwrap(); let generated_bin = CompileTask::new(vec![generated_code]).run().unwrap();
// run // run
RunTask::new(generated_bin).run().unwrap(); if let Err(_) = RunTask::new(generated_bin).run() {
log_failure("test failed");
}
} }
} }
} }
@ -38,7 +46,7 @@ pub fn gen_test_main(path: &str, test: &str) -> String {
" "
void ____test(); void ____test();
int main() {{ int main(int _argc, char** _argv) {{
____test(); ____test();
return 0; return 0;
}} }}

View file

@ -8,41 +8,28 @@ use crate::{
}; };
pub struct Repeater { pub struct Repeater {
files: Vec<String>, op: Box<dyn Fn()>,
} }
impl Repeater { impl Repeater {
pub fn new(files: Vec<String>) -> Self { pub fn new(op: impl Fn() + 'static) -> Self {
Self { files } let op = Box::new(op);
Self { op }
} }
pub fn repeat(&self) -> Option<()> { pub fn repeat(&self) -> Option<()> {
let binary = CompileTask::new(self.files.clone().into_iter().map(|f| f.into()).collect()) (self.op)();
.run() log_process("waiting for changes...");
.map(Option::from)
.unwrap_or_else(|_| {
log_failure("failed compilation");
None
})?;
log_success("compilation successful");
RunTask::new(binary)
.run()
.map(Option::from)
.unwrap_or_else(|_| {
log_failure("task failure");
None
})?;
log_success("task successful");
log_process("waiting for changes before re run");
Some(()) Some(())
} }
} }
pub fn main(files: Vec<String>) { pub fn main(files: Vec<String>, args: Vec<String>) {
log_process(&format!("watching files '{files:?}'")); log_process(&format!("watching files '{files:?}'"));
let repeater = Repeater::new(files.clone()); let passed = files.clone();
let repeater = Repeater::new(move || {
crate::run::main(passed.clone(), args.clone());
});
repeater.repeat(); repeater.repeat();
let (send, rec) = mpsc::channel(); let (send, rec) = mpsc::channel();