summaryrefslogtreecommitdiff
path: root/src/exercise.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/exercise.rs')
-rw-r--r--src/exercise.rs76
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());
}