diff options
| author | Roberto Vidal <vidal.roberto.j@gmail.com> | 2020-02-20 20:11:53 +0100 |
|---|---|---|
| committer | Roberto Vidal <vidal.roberto.j@gmail.com> | 2020-02-20 20:27:05 +0100 |
| commit | 43dc31193afddc15c78d2ceb57f7c68da90e8a46 (patch) | |
| tree | 83e1bc003d79916aa934d7b42f05e94ce073f2ed /src/exercise.rs | |
| parent | 83bbd9e82e98b4ec1ab81a1d55bb8688e920a905 (diff) | |
refactor: exercise evaluation
Exercise evaluation (compilation + execution) now uses Results
Success/failure messages are standardized
Diffstat (limited to 'src/exercise.rs')
| -rw-r--r-- | src/exercise.rs | 76 |
1 files changed, 63 insertions, 13 deletions
diff --git a/src/exercise.rs b/src/exercise.rs index b6c28da..d72eeb5 100644 --- a/src/exercise.rs +++ b/src/exercise.rs @@ -4,7 +4,7 @@ use std::fmt::{self, Display, Formatter}; use std::fs::{remove_file, File}; use std::io::Read; use std::path::PathBuf; -use std::process::{self, Command, Output}; +use std::process::{self, Command}; const RUSTC_COLOR_ARGS: &[&str] = &["--color", "always"]; const I_AM_DONE_REGEX: &str = r"(?m)^\s*///?\s*I\s+AM\s+NOT\s+DONE"; @@ -47,9 +47,34 @@ pub struct ContextLine { pub important: bool, } +pub struct CompiledExercise<'a> { + exercise: &'a Exercise, + _handle: FileHandle, +} + +impl<'a> CompiledExercise<'a> { + pub fn run(&self) -> Result<ExerciseOutput, ExerciseOutput> { + self.exercise.run() + } +} + +#[derive(Debug)] +pub struct ExerciseOutput { + pub stdout: String, + pub stderr: String, +} + +struct FileHandle; + +impl Drop for FileHandle { + fn drop(&mut self) { + clean(); + } +} + impl Exercise { - pub fn compile(&self) -> Output { - match self.mode { + pub fn compile(&self) -> Result<CompiledExercise, ExerciseOutput> { + let cmd = match self.mode { Mode::Compile => Command::new("rustc") .args(&[self.path.to_str().unwrap(), "-o", &temp_file()]) .args(RUSTC_COLOR_ARGS) @@ -59,17 +84,37 @@ impl Exercise { .args(RUSTC_COLOR_ARGS) .output(), } - .expect("Failed to run 'compile' command.") + .expect("Failed to run 'compile' command."); + + if cmd.status.success() { + Ok(CompiledExercise { + exercise: &self, + _handle: FileHandle, + }) + } else { + clean(); + Err(ExerciseOutput { + stdout: String::from_utf8_lossy(&cmd.stdout).to_string(), + stderr: String::from_utf8_lossy(&cmd.stderr).to_string(), + }) + } } - pub fn run(&self) -> Output { - Command::new(&temp_file()) + fn run(&self) -> Result<ExerciseOutput, ExerciseOutput> { + let cmd = Command::new(&temp_file()) .output() - .expect("Failed to run 'run' command") - } + .expect("Failed to run 'run' command"); + + let output = ExerciseOutput { + stdout: String::from_utf8_lossy(&cmd.stdout).to_string(), + stderr: String::from_utf8_lossy(&cmd.stderr).to_string(), + }; - pub fn clean(&self) { - let _ignored = remove_file(&temp_file()); + if cmd.status.success() { + Ok(output) + } else { + Err(output) + } } pub fn state(&self) -> State { @@ -121,6 +166,10 @@ impl Display for Exercise { } } +fn clean() { + let _ignored = remove_file(&temp_file()); +} + #[cfg(test)] mod test { use super::*; @@ -131,11 +180,12 @@ mod test { File::create(&temp_file()).unwrap(); let exercise = Exercise { name: String::from("example"), - path: PathBuf::from("example.rs"), - mode: Mode::Test, + path: PathBuf::from("tests/fixture/state/pending_exercise.rs"), + mode: Mode::Compile, hint: String::from(""), }; - exercise.clean(); + let compiled = exercise.compile().unwrap(); + drop(compiled); assert!(!Path::new(&temp_file()).exists()); } |
