2024-04-04 15:06:11 -04:00
|
|
|
use anyhow::Result;
|
2020-02-20 14:11:53 -05:00
|
|
|
use console::style;
|
2024-04-04 15:06:11 -04:00
|
|
|
use std::io::{stdout, Write};
|
2024-03-31 10:55:33 -04:00
|
|
|
|
|
|
|
use crate::exercise::{Exercise, Mode, State};
|
2019-01-09 14:33:43 -05:00
|
|
|
|
2024-04-01 12:38:01 -04:00
|
|
|
pub enum VerifyState<'a> {
|
|
|
|
AllExercisesDone,
|
|
|
|
Failed(&'a Exercise),
|
|
|
|
}
|
|
|
|
|
2020-06-04 10:31:17 -04:00
|
|
|
// Verify that the provided container of Exercise objects
|
|
|
|
// can be compiled and run without any failures.
|
|
|
|
// Any such failures will be reported to the end user.
|
|
|
|
// If the Exercise being verified is a test, the verbose boolean
|
|
|
|
// determines whether or not the test harness outputs are displayed.
|
|
|
|
pub fn verify<'a>(
|
2024-04-01 12:21:56 -04:00
|
|
|
pending_exercises: impl IntoIterator<Item = &'a Exercise>,
|
2022-02-05 16:54:11 -05:00
|
|
|
progress: (usize, usize),
|
2024-04-01 12:38:01 -04:00
|
|
|
) -> Result<VerifyState<'a>> {
|
2024-04-04 15:06:11 -04:00
|
|
|
let (mut num_done, total) = progress;
|
|
|
|
println!(
|
|
|
|
"Progress: {num_done}/{total} ({:.1}%)\n",
|
|
|
|
num_done as f32 / total as f32 * 100.0,
|
2022-02-05 16:54:11 -05:00
|
|
|
);
|
2023-01-03 09:24:01 -05:00
|
|
|
|
2024-04-01 12:21:56 -04:00
|
|
|
for exercise in pending_exercises {
|
2024-04-04 15:06:11 -04:00
|
|
|
let output = exercise.run()?;
|
2019-01-09 14:33:43 -05:00
|
|
|
|
2024-03-31 10:55:33 -04:00
|
|
|
{
|
|
|
|
let mut stdout = stdout().lock();
|
|
|
|
stdout.write_all(&output.stdout)?;
|
|
|
|
stdout.write_all(&output.stderr)?;
|
|
|
|
stdout.flush()?;
|
2020-02-20 14:11:53 -05:00
|
|
|
}
|
2020-02-26 14:38:44 -05:00
|
|
|
|
2024-04-04 15:06:11 -04:00
|
|
|
if !output.status.success() {
|
|
|
|
return Ok(VerifyState::Failed(exercise));
|
2019-02-15 06:06:05 -05:00
|
|
|
}
|
2021-03-19 05:16:07 -04:00
|
|
|
|
2024-04-04 15:06:11 -04:00
|
|
|
println!();
|
|
|
|
match exercise.mode {
|
|
|
|
Mode::Compile => success!("Successfully ran {}!", exercise),
|
|
|
|
Mode::Test => success!("Successfully tested {}!", exercise),
|
|
|
|
Mode::Clippy => success!("Successfully checked {}!", exercise),
|
|
|
|
}
|
2020-02-26 14:38:44 -05:00
|
|
|
|
2024-04-04 15:06:11 -04:00
|
|
|
if let State::Pending(context) = exercise.state()? {
|
|
|
|
println!(
|
|
|
|
"\nYou can keep working on this exercise,
|
|
|
|
or jump into the next one by removing the {} comment:\n",
|
|
|
|
style("`I AM NOT DONE`").bold()
|
|
|
|
);
|
|
|
|
|
|
|
|
for context_line in context {
|
|
|
|
let formatted_line = if context_line.important {
|
|
|
|
format!("{}", style(context_line.line).bold())
|
|
|
|
} else {
|
|
|
|
context_line.line
|
|
|
|
};
|
|
|
|
|
|
|
|
println!(
|
|
|
|
"{:>2} {} {}",
|
|
|
|
style(context_line.number).blue().bold(),
|
|
|
|
style("|").blue(),
|
|
|
|
formatted_line,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return Ok(VerifyState::Failed(exercise));
|
|
|
|
}
|
2019-11-11 07:38:24 -05:00
|
|
|
|
2024-04-04 15:06:11 -04:00
|
|
|
num_done += 1;
|
2019-11-11 07:38:24 -05:00
|
|
|
println!(
|
2024-04-04 15:06:11 -04:00
|
|
|
"Progress: {num_done}/{total} ({:.1}%)\n",
|
|
|
|
num_done as f32 / total as f32 * 100.0,
|
2019-11-11 07:38:24 -05:00
|
|
|
);
|
|
|
|
}
|
2019-11-12 05:35:40 -05:00
|
|
|
|
2024-04-04 15:06:11 -04:00
|
|
|
Ok(VerifyState::AllExercisesDone)
|
2020-02-26 14:38:44 -05:00
|
|
|
}
|