Local runner for GitHub autograder
1mod cli;
2mod grader;
3mod meta;
4mod runner;
5
6use std::time::Duration;
7
8use anyhow::Result;
9use clap::Parser;
10
11use cli::Cli;
12use grader::AutoGraderData;
13use indicatif::ProgressBar;
14
15fn main() -> Result<()> {
16 let cli = Cli::parse();
17
18 if cli.man_gen {
19 println!("{}", meta::gen_man_page());
20 return Ok(());
21 } else if let Some(shell) = cli.completions {
22 println!("{}", meta::gen_completions(shell.parse().unwrap()));
23 return Ok(());
24 }
25
26 let grader_data = AutoGraderData::get(cli.file)?;
27
28 let test_len = grader_data.tests.len();
29
30 let amount_passed = grader_data
31 .tests
32 .into_iter()
33 .enumerate()
34 .filter(|(i, test)| {
35 let bar = ProgressBar::new_spinner();
36 bar.set_message(format!("Running {}", test.name));
37 bar.enable_steady_tick(Duration::from_millis(100));
38 if cli.skip.map(|skip| i < &skip).unwrap_or(false)
39 || cli
40 .test
41 .as_ref()
42 .map(|target| target.to_lowercase() != test.name.to_lowercase())
43 .unwrap_or(false)
44 {
45 bar.finish_with_message(format!("〰️ Skipped {}", test.name));
46 return false;
47 }
48 match test.run() {
49 Ok((matched, result)) => {
50 if cli.verbose {
51 println!(
52 "Stdout of {}:\n{}\n\nStderr of {}:\n{}",
53 test.name, result.stdout, test.name, result.stderr
54 );
55 }
56 match result.status {
57 Ok(code) => {
58 if code != 0 {
59 bar.finish_with_message(format!(
60 "⚠️ {} Exited with code {code}",
61 test.name
62 ))
63 }
64 if matched {
65 bar.finish_with_message(format!("✅ {} passed!", test.name));
66 true
67 } else {
68 bar.finish_with_message(format!(
69 "❌ {} did not give the correct output",
70 test.name
71 ));
72 false
73 }
74 }
75 Err(why) => {
76 bar.finish_with_message(format!(
77 "❌ Failed to run {}: {why:?}",
78 test.name
79 ));
80 false
81 }
82 }
83 }
84 Err(why) => {
85 bar.finish_with_message(format!("❌ Failed to run {}: {why:?}", test.name));
86 false
87 }
88 }
89 })
90 .count();
91
92 println!("Passed {amount_passed}/{test_len} tests");
93 if cli.skip.is_some() || cli.test.is_some() {
94 println!("(Some were skipped)");
95 }
96
97 Ok(())
98}