2024-04-04 15:06:11 -04:00
|
|
|
use anyhow::Result;
|
2024-04-04 21:04:53 -04:00
|
|
|
use crossterm::style::{Attribute, ContentStyle, Stylize};
|
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-09 15:16:27 -04:00
|
|
|
pub enum VerifyState {
|
2024-04-01 12:38:01 -04:00
|
|
|
AllExercisesDone,
|
2024-04-09 15:16:27 -04:00
|
|
|
Failed(&'static Exercise),
|
2024-04-01 12:38:01 -04:00
|
|
|
}
|
|
|
|
|
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.
|
2024-04-09 15:16:27 -04:00
|
|
|
pub fn verify(
|
|
|
|
exercises: &'static [Exercise],
|
|
|
|
mut current_exercise_ind: usize,
|
|
|
|
) -> Result<VerifyState> {
|
2024-04-06 19:16:56 -04:00
|
|
|
while current_exercise_ind < exercises.len() {
|
|
|
|
let exercise = &exercises[current_exercise_ind];
|
|
|
|
|
|
|
|
println!(
|
|
|
|
"Progress: {current_exercise_ind}/{} ({:.1}%)\n",
|
|
|
|
exercises.len(),
|
|
|
|
current_exercise_ind as f32 / exercises.len() as f32 * 100.0,
|
|
|
|
);
|
2023-01-03 09:24:01 -05:00
|
|
|
|
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!();
|
2024-04-04 18:49:22 -04:00
|
|
|
// TODO: Color
|
2024-04-04 15:06:11 -04:00
|
|
|
match exercise.mode {
|
2024-04-04 18:49:22 -04:00
|
|
|
Mode::Compile => println!("Successfully ran {exercise}!"),
|
|
|
|
Mode::Test => println!("Successfully tested {exercise}!"),
|
|
|
|
Mode::Clippy => println!("Successfully checked {exercise}!"),
|
2024-04-04 15:06:11 -04:00
|
|
|
}
|
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",
|
2024-04-04 21:04:53 -04:00
|
|
|
"`I AM NOT DONE`".bold()
|
2024-04-04 15:06:11 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
for context_line in context {
|
|
|
|
let formatted_line = if context_line.important {
|
2024-04-04 21:04:53 -04:00
|
|
|
format!("{}", context_line.line.bold())
|
2024-04-04 15:06:11 -04:00
|
|
|
} else {
|
|
|
|
context_line.line
|
|
|
|
};
|
|
|
|
|
|
|
|
println!(
|
|
|
|
"{:>2} {} {}",
|
2024-04-04 21:04:53 -04:00
|
|
|
ContentStyle {
|
|
|
|
foreground_color: Some(crossterm::style::Color::Blue),
|
|
|
|
background_color: None,
|
|
|
|
underline_color: None,
|
|
|
|
attributes: Attribute::Bold.into()
|
|
|
|
}
|
|
|
|
.apply(context_line.number),
|
|
|
|
"|".blue(),
|
2024-04-04 15:06:11 -04:00
|
|
|
formatted_line,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return Ok(VerifyState::Failed(exercise));
|
|
|
|
}
|
2019-11-11 07:38:24 -05:00
|
|
|
|
2024-04-06 19:16:56 -04:00
|
|
|
current_exercise_ind += 1;
|
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
|
|
|
}
|