2024-07-25 08:34:43 -04:00
|
|
|
use std::{
|
|
|
|
env::{self, consts::EXE_SUFFIX},
|
2024-07-25 10:14:38 -04:00
|
|
|
fs,
|
2024-07-25 08:34:43 -04:00
|
|
|
process::{Command, Stdio},
|
|
|
|
str::from_utf8,
|
|
|
|
};
|
|
|
|
|
2024-07-25 10:14:38 -04:00
|
|
|
enum Output<'a> {
|
|
|
|
FullStdout(&'a str),
|
|
|
|
PartialStdout(&'a str),
|
|
|
|
PartialStderr(&'a str),
|
|
|
|
}
|
|
|
|
|
|
|
|
use Output::*;
|
|
|
|
|
2024-07-25 08:34:43 -04:00
|
|
|
#[derive(Default)]
|
|
|
|
struct Cmd<'a> {
|
|
|
|
current_dir: Option<&'a str>,
|
|
|
|
args: &'a [&'a str],
|
2024-07-25 10:14:38 -04:00
|
|
|
output: Option<Output<'a>>,
|
2024-07-25 08:34:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Cmd<'a> {
|
|
|
|
#[inline]
|
|
|
|
fn current_dir(&mut self, current_dir: &'a str) -> &mut Self {
|
|
|
|
self.current_dir = Some(current_dir);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn args(&mut self, args: &'a [&'a str]) -> &mut Self {
|
|
|
|
self.args = args;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2024-07-25 10:14:38 -04:00
|
|
|
fn output(&mut self, output: Output<'a>) -> &mut Self {
|
|
|
|
self.output = Some(output);
|
2024-07-25 08:34:43 -04:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
fn assert(&self, success: bool) {
|
|
|
|
let rustlings_bin = {
|
|
|
|
let mut path = env::current_exe().unwrap();
|
|
|
|
// Pop test binary name
|
|
|
|
path.pop();
|
|
|
|
// Pop `/deps`
|
|
|
|
path.pop();
|
|
|
|
|
|
|
|
path.push("rustlings");
|
|
|
|
let mut path = path.into_os_string();
|
|
|
|
path.push(EXE_SUFFIX);
|
|
|
|
path
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut cmd = Command::new(rustlings_bin);
|
|
|
|
|
|
|
|
if let Some(current_dir) = self.current_dir {
|
|
|
|
cmd.current_dir(current_dir);
|
|
|
|
}
|
|
|
|
|
2024-07-25 10:14:38 -04:00
|
|
|
cmd.args(self.args).stdin(Stdio::null());
|
|
|
|
|
|
|
|
let status = match self.output {
|
|
|
|
None => cmd
|
|
|
|
.stdout(Stdio::null())
|
|
|
|
.stderr(Stdio::null())
|
|
|
|
.status()
|
|
|
|
.unwrap(),
|
|
|
|
Some(FullStdout(stdout)) => {
|
|
|
|
let output = cmd.stderr(Stdio::null()).output().unwrap();
|
|
|
|
assert_eq!(from_utf8(&output.stdout).unwrap(), stdout);
|
|
|
|
output.status
|
|
|
|
}
|
|
|
|
Some(PartialStdout(stdout)) => {
|
|
|
|
let output = cmd.stderr(Stdio::null()).output().unwrap();
|
|
|
|
assert!(from_utf8(&output.stdout).unwrap().contains(stdout));
|
|
|
|
output.status
|
|
|
|
}
|
|
|
|
Some(PartialStderr(stderr)) => {
|
|
|
|
let output = cmd.stdout(Stdio::null()).output().unwrap();
|
|
|
|
assert!(from_utf8(&output.stderr).unwrap().contains(stderr));
|
|
|
|
output.status
|
2024-07-25 08:34:43 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-07-25 10:14:38 -04:00
|
|
|
assert_eq!(status.success(), success, "{cmd:?}");
|
2024-07-25 08:34:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn success(&self) {
|
|
|
|
self.assert(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn fail(&self) {
|
|
|
|
self.assert(false);
|
|
|
|
}
|
|
|
|
}
|
2019-03-20 16:05:45 -04:00
|
|
|
|
|
|
|
#[test]
|
2024-07-25 09:12:14 -04:00
|
|
|
fn run_compilation_success() {
|
2024-07-25 08:34:43 -04:00
|
|
|
Cmd::default()
|
2024-07-25 09:12:14 -04:00
|
|
|
.current_dir("tests/test_exercises")
|
|
|
|
.args(&["run", "compilation_success"])
|
2019-03-20 16:05:45 -04:00
|
|
|
.success();
|
|
|
|
}
|
|
|
|
|
2019-04-07 12:49:34 -04:00
|
|
|
#[test]
|
2024-07-25 09:12:14 -04:00
|
|
|
fn run_compilation_failure() {
|
2024-07-25 08:34:43 -04:00
|
|
|
Cmd::default()
|
2024-07-25 09:12:14 -04:00
|
|
|
.current_dir("tests/test_exercises")
|
|
|
|
.args(&["run", "compilation_failure"])
|
2024-07-25 08:34:43 -04:00
|
|
|
.fail();
|
2019-04-07 12:49:34 -04:00
|
|
|
}
|
|
|
|
|
2019-03-20 16:05:45 -04:00
|
|
|
#[test]
|
2024-07-25 09:12:14 -04:00
|
|
|
fn run_test_success() {
|
2024-07-25 08:34:43 -04:00
|
|
|
Cmd::default()
|
2024-07-25 09:12:14 -04:00
|
|
|
.current_dir("tests/test_exercises")
|
|
|
|
.args(&["run", "test_success"])
|
2024-07-25 10:14:38 -04:00
|
|
|
.output(PartialStdout("\nOutput from `main` function\n"))
|
2019-03-20 16:05:45 -04:00
|
|
|
.success();
|
|
|
|
}
|
|
|
|
|
2019-04-07 12:49:34 -04:00
|
|
|
#[test]
|
2024-07-25 09:12:14 -04:00
|
|
|
fn run_test_failure() {
|
2024-07-25 08:34:43 -04:00
|
|
|
Cmd::default()
|
2024-07-25 09:12:14 -04:00
|
|
|
.current_dir("tests/test_exercises")
|
|
|
|
.args(&["run", "test_failure"])
|
2024-07-25 08:34:43 -04:00
|
|
|
.fail();
|
2019-04-07 12:49:34 -04:00
|
|
|
}
|
|
|
|
|
2019-05-09 13:16:06 -04:00
|
|
|
#[test]
|
2024-07-25 09:12:14 -04:00
|
|
|
fn run_exercise_not_in_info() {
|
2024-07-25 08:34:43 -04:00
|
|
|
Cmd::default()
|
2024-07-25 09:12:14 -04:00
|
|
|
.current_dir("tests/test_exercises")
|
|
|
|
.args(&["run", "not_in_info"])
|
2024-07-25 08:34:43 -04:00
|
|
|
.fail();
|
2019-05-09 13:16:06 -04:00
|
|
|
}
|
|
|
|
|
2019-03-20 16:05:45 -04:00
|
|
|
#[test]
|
2024-07-25 09:12:14 -04:00
|
|
|
fn reset_without_exercise_name() {
|
2024-07-25 08:34:43 -04:00
|
|
|
Cmd::default().args(&["reset"]).fail();
|
2022-08-17 10:43:48 -04:00
|
|
|
}
|
|
|
|
|
2019-11-11 11:19:50 -05:00
|
|
|
#[test]
|
2024-07-25 09:12:14 -04:00
|
|
|
fn hint() {
|
2024-07-25 08:34:43 -04:00
|
|
|
Cmd::default()
|
2024-07-25 09:12:14 -04:00
|
|
|
.current_dir("tests/test_exercises")
|
|
|
|
.args(&["hint", "test_failure"])
|
2024-07-25 10:14:38 -04:00
|
|
|
.output(FullStdout("The answer to everything: 42\n"))
|
2024-07-25 08:34:43 -04:00
|
|
|
.success();
|
2019-11-11 11:28:19 -05:00
|
|
|
}
|
2024-07-25 10:14:38 -04:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn init() {
|
|
|
|
let _ = fs::remove_dir_all("tests/rustlings");
|
|
|
|
|
|
|
|
Cmd::default().current_dir("tests").fail();
|
|
|
|
|
|
|
|
Cmd::default()
|
|
|
|
.current_dir("tests")
|
|
|
|
.args(&["init"])
|
|
|
|
.success();
|
|
|
|
|
|
|
|
// Running `init` after a successful initialization.
|
|
|
|
Cmd::default()
|
|
|
|
.current_dir("tests")
|
|
|
|
.args(&["init"])
|
|
|
|
.output(PartialStderr("`cd rustlings`"))
|
|
|
|
.fail();
|
|
|
|
|
|
|
|
// Running `init` in the initialized directory.
|
|
|
|
Cmd::default()
|
|
|
|
.current_dir("tests/rustlings")
|
|
|
|
.args(&["init"])
|
|
|
|
.output(PartialStderr("already initialized"))
|
|
|
|
.fail();
|
|
|
|
|
|
|
|
fs::remove_dir_all("tests/rustlings").unwrap();
|
|
|
|
}
|