diff options
Diffstat (limited to 'src/verify.rs')
| -rw-r--r-- | src/verify.rs | 167 |
1 files changed, 74 insertions, 93 deletions
diff --git a/src/verify.rs b/src/verify.rs index dac2562..ef966f6 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -1,7 +1,19 @@ -use crate::exercise::{CompiledExercise, Exercise, Mode, State}; +use anyhow::{bail, Result}; use console::style; use indicatif::{ProgressBar, ProgressStyle}; -use std::{env, time::Duration}; +use std::{ + env, + io::{stdout, Write}, + process::Output, + time::Duration, +}; + +use crate::exercise::{Exercise, Mode, State}; + +pub enum VerifyState<'a> { + AllExercisesDone, + Failed(&'a Exercise), +} // Verify that the provided container of Exercise objects // can be compiled and run without any failures. @@ -9,11 +21,11 @@ use std::{env, time::Duration}; // 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>( - exercises: impl IntoIterator<Item = &'a Exercise>, + pending_exercises: impl IntoIterator<Item = &'a Exercise>, progress: (usize, usize), verbose: bool, success_hints: bool, -) -> Result<(), &'a Exercise> { +) -> Result<VerifyState<'a>> { let (num_done, total) = progress; let bar = ProgressBar::new(total as u64); let mut percentage = num_done as f32 / total as f32 * 100.0; @@ -26,29 +38,24 @@ pub fn verify<'a>( bar.set_position(num_done as u64); bar.set_message(format!("({percentage:.1} %)")); - for exercise in exercises { + for exercise in pending_exercises { let compile_result = match exercise.mode { - Mode::Test => compile_and_test(exercise, RunMode::Interactive, verbose, success_hints), - Mode::Compile => compile_and_run_interactively(exercise, success_hints), - Mode::Clippy => compile_only(exercise, success_hints), + Mode::Test => compile_and_test(exercise, RunMode::Interactive, verbose, success_hints)?, + Mode::Compile => compile_and_run_interactively(exercise, success_hints)?, + Mode::Clippy => compile_only(exercise, success_hints)?, }; - if !compile_result.unwrap_or(false) { - return Err(exercise); + if !compile_result { + return Ok(VerifyState::Failed(exercise)); } percentage += 100.0 / total as f32; bar.inc(1); bar.set_message(format!("({percentage:.1} %)")); - if bar.position() == total as u64 { - println!( - "Progress: You completed {} / {} exercises ({:.1} %).", - bar.position(), - total, - percentage - ); - bar.finish(); - } } - Ok(()) + + bar.finish(); + println!("You completed all exercises!"); + + Ok(VerifyState::AllExercisesDone) } #[derive(PartialEq, Eq)] @@ -58,50 +65,44 @@ enum RunMode { } // Compile and run the resulting test harness of the given Exercise -pub fn test(exercise: &Exercise, verbose: bool) -> Result<(), ()> { +pub fn test(exercise: &Exercise, verbose: bool) -> Result<()> { compile_and_test(exercise, RunMode::NonInteractive, verbose, false)?; Ok(()) } // Invoke the rust compiler without running the resulting binary -fn compile_only(exercise: &Exercise, success_hints: bool) -> Result<bool, ()> { +fn compile_only(exercise: &Exercise, success_hints: bool) -> Result<bool> { let progress_bar = ProgressBar::new_spinner(); progress_bar.set_message(format!("Compiling {exercise}...")); progress_bar.enable_steady_tick(Duration::from_millis(100)); - let _ = compile(exercise, &progress_bar)?; + let _ = exercise.run()?; progress_bar.finish_and_clear(); - Ok(prompt_for_completion(exercise, None, success_hints)) + prompt_for_completion(exercise, None, success_hints) } // Compile the given Exercise and run the resulting binary in an interactive mode -fn compile_and_run_interactively(exercise: &Exercise, success_hints: bool) -> Result<bool, ()> { +fn compile_and_run_interactively(exercise: &Exercise, success_hints: bool) -> Result<bool> { let progress_bar = ProgressBar::new_spinner(); - progress_bar.set_message(format!("Compiling {exercise}...")); + progress_bar.set_message(format!("Running {exercise}...")); progress_bar.enable_steady_tick(Duration::from_millis(100)); - let compilation = compile(exercise, &progress_bar)?; - - progress_bar.set_message(format!("Running {exercise}...")); - let result = compilation.run(); + let output = exercise.run()?; progress_bar.finish_and_clear(); - let output = match result { - Ok(output) => output, - Err(output) => { - warn!("Ran {} with errors", exercise); - println!("{}", output.stdout); - println!("{}", output.stderr); - return Err(()); + if !output.status.success() { + warn!("Ran {} with errors", exercise); + { + let mut stdout = stdout().lock(); + stdout.write_all(&output.stdout)?; + stdout.write_all(&output.stderr)?; + stdout.flush()?; } - }; + bail!("TODO"); + } - Ok(prompt_for_completion( - exercise, - Some(output.stdout), - success_hints, - )) + prompt_for_completion(exercise, Some(output), success_hints) } // Compile the given Exercise as a test harness and display @@ -111,66 +112,46 @@ fn compile_and_test( run_mode: RunMode, verbose: bool, success_hints: bool, -) -> Result<bool, ()> { +) -> Result<bool> { let progress_bar = ProgressBar::new_spinner(); progress_bar.set_message(format!("Testing {exercise}...")); progress_bar.enable_steady_tick(Duration::from_millis(100)); - let compilation = compile(exercise, &progress_bar)?; - let result = compilation.run(); + let output = exercise.run()?; progress_bar.finish_and_clear(); - match result { - Ok(output) => { - if verbose { - println!("{}", output.stdout); - } - if run_mode == RunMode::Interactive { - Ok(prompt_for_completion(exercise, None, success_hints)) - } else { - Ok(true) - } - } - Err(output) => { - warn!( - "Testing of {} failed! Please try again. Here's the output:", - exercise - ); - println!("{}", output.stdout); - Err(()) + if !output.status.success() { + warn!( + "Testing of {} failed! Please try again. Here's the output:", + exercise + ); + { + let mut stdout = stdout().lock(); + stdout.write_all(&output.stdout)?; + stdout.write_all(&output.stderr)?; + stdout.flush()?; } + bail!("TODO"); } -} -// Compile the given Exercise and return an object with information -// about the state of the compilation -fn compile<'a>( - exercise: &'a Exercise, - progress_bar: &ProgressBar, -) -> Result<CompiledExercise<'a>, ()> { - let compilation_result = exercise.compile(); - - match compilation_result { - Ok(compilation) => Ok(compilation), - Err(output) => { - progress_bar.finish_and_clear(); - warn!( - "Compiling of {} failed! Please try again. Here's the output:", - exercise - ); - println!("{}", output.stderr); - Err(()) - } + if verbose { + stdout().write_all(&output.stdout)?; + } + + if run_mode == RunMode::Interactive { + prompt_for_completion(exercise, None, success_hints) + } else { + Ok(true) } } fn prompt_for_completion( exercise: &Exercise, - prompt_output: Option<String>, + prompt_output: Option<Output>, success_hints: bool, -) -> bool { - let context = match exercise.state() { - State::Done => return true, +) -> Result<bool> { + let context = match exercise.state()? { + State::Done => return Ok(true), State::Pending(context) => context, }; match exercise.mode { @@ -200,10 +181,10 @@ fn prompt_for_completion( } if let Some(output) = prompt_output { - println!( - "Output:\n{separator}\n{output}\n{separator}\n", - separator = separator(), - ); + let separator = separator(); + println!("Output:\n{separator}"); + stdout().write_all(&output.stdout).unwrap(); + println!("\n{separator}\n"); } if success_hints { println!( @@ -234,7 +215,7 @@ fn prompt_for_completion( ); } - false + Ok(false) } fn separator() -> console::StyledObject<&'static str> { |
