mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-12-26 00:11:49 +02:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b0b7093e5 | ||
|
|
8387de64d3 | ||
|
|
77de6e5d6a | ||
|
|
8c867a001a | ||
|
|
d01a71f7de | ||
|
|
04d1d4c00e | ||
|
|
d7e58ee1af | ||
|
|
ffb165ce26 | ||
|
|
65cb09eb2e | ||
|
|
78552ebd7a | ||
|
|
0c7bd12372 | ||
|
|
3d11d7685b | ||
|
|
592ae6b4d2 | ||
|
|
4fa79ee02f | ||
|
|
fbd0ccbd5b | ||
|
|
8c008a0e7d | ||
|
|
11fe19d08a | ||
|
|
1b3469f236 | ||
|
|
022921168d | ||
|
|
c6765eb3eb | ||
|
|
c5a374fbf2 |
@@ -3,7 +3,7 @@ rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
script: cargo test --verbose -- --test-threads=1
|
||||
script: cargo test --verbose
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustlings"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
authors = ["Olivia <819880950@qq.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com"]
|
||||
edition = "2018"
|
||||
|
||||
@@ -11,6 +11,7 @@ console = "0.6.2"
|
||||
syntect = "3.0.2"
|
||||
notify = "4.0.0"
|
||||
toml = "0.4.10"
|
||||
serde = {version = "1.0.10", features = ["derive"]}
|
||||
|
||||
[[bin]]
|
||||
name = "rustlings"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
For this exercise check out the sections:
|
||||
- [Error Handling](https://doc.rust-lang.org/book/2018-edition/ch09-02-recoverable-errors-with-result.html)
|
||||
- [Generics](https://doc.rust-lang.org/book/2018-edition/ch10-01-syntax.html)
|
||||
- [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)
|
||||
- [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html)
|
||||
|
||||
of the Rust Book.
|
||||
of the Rust Book.
|
||||
|
||||
0
exercises/error_handling/errors1.rs
Executable file → Normal file
0
exercises/error_handling/errors1.rs
Executable file → Normal file
0
exercises/error_handling/errors2.rs
Executable file → Normal file
0
exercises/error_handling/errors2.rs
Executable file → Normal file
0
exercises/error_handling/errors3.rs
Executable file → Normal file
0
exercises/error_handling/errors3.rs
Executable file → Normal file
0
exercises/error_handling/errorsn.rs
Executable file → Normal file
0
exercises/error_handling/errorsn.rs
Executable file → Normal file
0
exercises/error_handling/option1.rs
Executable file → Normal file
0
exercises/error_handling/option1.rs
Executable file → Normal file
0
exercises/error_handling/result1.rs
Executable file → Normal file
0
exercises/error_handling/result1.rs
Executable file → Normal file
0
exercises/functions/functions1.rs
Executable file → Normal file
0
exercises/functions/functions1.rs
Executable file → Normal file
0
exercises/functions/functions2.rs
Executable file → Normal file
0
exercises/functions/functions2.rs
Executable file → Normal file
0
exercises/functions/functions3.rs
Executable file → Normal file
0
exercises/functions/functions3.rs
Executable file → Normal file
0
exercises/functions/functions4.rs
Executable file → Normal file
0
exercises/functions/functions4.rs
Executable file → Normal file
0
exercises/functions/functions5.rs
Executable file → Normal file
0
exercises/functions/functions5.rs
Executable file → Normal file
0
exercises/if/if1.rs
Executable file → Normal file
0
exercises/if/if1.rs
Executable file → Normal file
0
exercises/macros/macros1.rs
Executable file → Normal file
0
exercises/macros/macros1.rs
Executable file → Normal file
0
exercises/macros/macros2.rs
Executable file → Normal file
0
exercises/macros/macros2.rs
Executable file → Normal file
0
exercises/macros/macros3.rs
Executable file → Normal file
0
exercises/macros/macros3.rs
Executable file → Normal file
0
exercises/macros/macros4.rs
Executable file → Normal file
0
exercises/macros/macros4.rs
Executable file → Normal file
0
exercises/modules/modules1.rs
Executable file → Normal file
0
exercises/modules/modules1.rs
Executable file → Normal file
0
exercises/modules/modules2.rs
Executable file → Normal file
0
exercises/modules/modules2.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics1.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics1.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics2.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics2.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics3.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics3.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics4.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics4.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types1.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types1.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types2.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types2.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types3.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types3.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types4.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types4.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types5.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types5.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types6.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types6.rs
Executable file → Normal file
0
exercises/standard_library_types/arc1.rs
Executable file → Normal file
0
exercises/standard_library_types/arc1.rs
Executable file → Normal file
0
exercises/standard_library_types/iterator3.rs
Executable file → Normal file
0
exercises/standard_library_types/iterator3.rs
Executable file → Normal file
0
exercises/standard_library_types/iterators4.rs
Executable file → Normal file
0
exercises/standard_library_types/iterators4.rs
Executable file → Normal file
0
exercises/strings/strings1.rs
Executable file → Normal file
0
exercises/strings/strings1.rs
Executable file → Normal file
0
exercises/strings/strings2.rs
Executable file → Normal file
0
exercises/strings/strings2.rs
Executable file → Normal file
0
exercises/test2.rs
Executable file → Normal file
0
exercises/test2.rs
Executable file → Normal file
0
exercises/test3.rs
Executable file → Normal file
0
exercises/test3.rs
Executable file → Normal file
0
exercises/tests/tests1.rs
Executable file → Normal file
0
exercises/tests/tests1.rs
Executable file → Normal file
0
exercises/tests/tests2.rs
Executable file → Normal file
0
exercises/tests/tests2.rs
Executable file → Normal file
0
exercises/tests/tests3.rs
Executable file → Normal file
0
exercises/tests/tests3.rs
Executable file → Normal file
0
exercises/threads/threads1.rs
Executable file → Normal file
0
exercises/threads/threads1.rs
Executable file → Normal file
0
exercises/variables/variables1.rs
Executable file → Normal file
0
exercises/variables/variables1.rs
Executable file → Normal file
0
exercises/variables/variables2.rs
Executable file → Normal file
0
exercises/variables/variables2.rs
Executable file → Normal file
0
exercises/variables/variables3.rs
Executable file → Normal file
0
exercises/variables/variables3.rs
Executable file → Normal file
0
exercises/variables/variables4.rs
Executable file → Normal file
0
exercises/variables/variables4.rs
Executable file → Normal file
18
install.sh
18
install.sh
@@ -3,31 +3,31 @@
|
||||
echo "Let's get you set up with Rustlings!"
|
||||
|
||||
echo "Checking requirements..."
|
||||
if [ -x "$(git)" ]
|
||||
if [ -x "$(command -v git)" ]
|
||||
then
|
||||
echo "SUCCESS: Git is installed"
|
||||
else
|
||||
echo "WARNING: Git does not seem to be installed."
|
||||
echo "Please download Git using your package manager or over https://git-scm.com/!"
|
||||
exit 1
|
||||
else
|
||||
echo "SUCCESS: Git is installed"
|
||||
fi
|
||||
|
||||
if [ -x "$(rustc)" ]
|
||||
if [ -x "$(command -v rustc)" ]
|
||||
then
|
||||
echo "SUCCESS: Rust is installed"
|
||||
else
|
||||
echo "WARNING: Rust does not seem to be installed."
|
||||
echo "Please download Rust using https://rustup.rs!"
|
||||
exit 1
|
||||
else
|
||||
echo "SUCCESS: Rust is installed"
|
||||
fi
|
||||
|
||||
if [ -x "$(cargo)" ]
|
||||
if [ -x "$(command -v cargo)" ]
|
||||
then
|
||||
echo "SUCCESS: Cargo is installed"
|
||||
else
|
||||
echo "WARNING: Cargo does not seem to be installed."
|
||||
echo "Please download Rust and Cargo using https://rustup.rs!"
|
||||
exit 1
|
||||
else
|
||||
echo "SUCCESS: Cargo is installed"
|
||||
fi
|
||||
|
||||
# Function that compares two versions strings v1 and v2 given in arguments (e.g 1.31 and 1.33.0).
|
||||
|
||||
79
src/exercise.rs
Normal file
79
src/exercise.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use serde::Deserialize;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::fs::{remove_file};
|
||||
use std::path::{PathBuf};
|
||||
use std::process::{self, Command, Output};
|
||||
|
||||
const RUSTC_COLOR_ARGS: &[&str] = &["--color", "always"];
|
||||
|
||||
fn temp_file() -> String {
|
||||
format!("./temp_{}", process::id())
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum Mode {
|
||||
Compile,
|
||||
Test,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ExerciseList {
|
||||
pub exercises: Vec<Exercise>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Exercise {
|
||||
pub path: PathBuf,
|
||||
pub mode: Mode,
|
||||
}
|
||||
|
||||
impl Exercise {
|
||||
pub fn compile(&self) -> Output {
|
||||
match self.mode {
|
||||
Mode::Compile => Command::new("rustc")
|
||||
.args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
.output(),
|
||||
Mode::Test => Command::new("rustc")
|
||||
.args(&["--test", self.path.to_str().unwrap(), "-o", &temp_file()])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
.output(),
|
||||
}
|
||||
.expect("Failed to run 'compile' command.")
|
||||
}
|
||||
|
||||
pub fn run(&self) -> Output {
|
||||
Command::new(&temp_file())
|
||||
.output()
|
||||
.expect("Failed to run 'run' command")
|
||||
}
|
||||
|
||||
pub fn clean(&self) {
|
||||
let _ignored = remove_file(&temp_file());
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Exercise {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.path.to_str().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::path::Path;
|
||||
use std::fs::File;
|
||||
|
||||
#[test]
|
||||
fn test_clean() {
|
||||
File::create(&temp_file()).unwrap();
|
||||
let exercise = Exercise {
|
||||
path: PathBuf::from("example.rs"),
|
||||
mode: Mode::Test,
|
||||
};
|
||||
exercise.clean();
|
||||
assert!(!Path::new(&temp_file()).exists());
|
||||
}
|
||||
}
|
||||
47
src/main.rs
47
src/main.rs
@@ -1,9 +1,11 @@
|
||||
use crate::exercise::{Exercise, ExerciseList};
|
||||
use crate::run::run;
|
||||
use crate::verify::verify;
|
||||
use clap::{crate_version, App, Arg, SubCommand};
|
||||
use notify::DebouncedEvent;
|
||||
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::io::BufRead;
|
||||
use std::path::Path;
|
||||
use std::sync::mpsc::channel;
|
||||
@@ -13,8 +15,8 @@ use syntect::highlighting::{Style, ThemeSet};
|
||||
use syntect::parsing::SyntaxSet;
|
||||
use syntect::util::as_24_bit_terminal_escaped;
|
||||
|
||||
mod exercise;
|
||||
mod run;
|
||||
mod util;
|
||||
mod verify;
|
||||
|
||||
fn main() {
|
||||
@@ -56,19 +58,36 @@ fn main() {
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("run") {
|
||||
run(matches.clone()).unwrap();
|
||||
let toml_str = &fs::read_to_string("info.toml").unwrap();
|
||||
let exercises = toml::from_str::<ExerciseList>(toml_str).unwrap().exercises;
|
||||
|
||||
if let Some(ref matches) = matches.subcommand_matches("run") {
|
||||
let filename = matches.value_of("file").unwrap_or_else(|| {
|
||||
println!("Please supply a file name!");
|
||||
std::process::exit(1);
|
||||
});
|
||||
|
||||
let matching_exercise = |e: &&Exercise| {
|
||||
Path::new(filename)
|
||||
.canonicalize()
|
||||
.map(|p| p.ends_with(&e.path))
|
||||
.unwrap_or(false)
|
||||
};
|
||||
|
||||
let exercise = exercises.iter().find(matching_exercise).unwrap_or_else(|| {
|
||||
println!("No exercise found for your file name!");
|
||||
std::process::exit(1)
|
||||
});
|
||||
|
||||
run(&exercise).unwrap_or_else(|_| std::process::exit(1));
|
||||
}
|
||||
|
||||
if matches.subcommand_matches("verify").is_some() {
|
||||
match verify(None) {
|
||||
Ok(_) => {}
|
||||
Err(_) => std::process::exit(1),
|
||||
}
|
||||
verify(&exercises).unwrap_or_else(|_| std::process::exit(1));
|
||||
}
|
||||
|
||||
if matches.subcommand_matches("watch").is_some() {
|
||||
watch().unwrap();
|
||||
watch(&exercises).unwrap();
|
||||
}
|
||||
|
||||
if matches.subcommand_name().is_none() {
|
||||
@@ -84,13 +103,13 @@ fn main() {
|
||||
println!("\x1b[0m");
|
||||
}
|
||||
|
||||
fn watch() -> notify::Result<()> {
|
||||
fn watch(exercises: &[Exercise]) -> notify::Result<()> {
|
||||
let (tx, rx) = channel();
|
||||
|
||||
let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
|
||||
watcher.watch("./exercises", RecursiveMode::Recursive)?;
|
||||
watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?;
|
||||
|
||||
let _ignored = verify(None);
|
||||
let _ignored = verify(exercises.iter());
|
||||
|
||||
loop {
|
||||
match rx.recv() {
|
||||
@@ -98,7 +117,11 @@ fn watch() -> notify::Result<()> {
|
||||
DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
|
||||
if b.extension() == Some(OsStr::new("rs")) {
|
||||
println!("----------**********----------\n");
|
||||
let _ignored = verify(Some(b.as_path().to_str().unwrap()));
|
||||
let filepath = b.as_path().canonicalize().unwrap();
|
||||
let exercise = exercises
|
||||
.iter()
|
||||
.skip_while(|e| !filepath.ends_with(&e.path));
|
||||
let _ignored = verify(exercise);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
56
src/run.rs
56
src/run.rs
@@ -1,60 +1,40 @@
|
||||
use crate::util::clean;
|
||||
use crate::exercise::{Mode, Exercise};
|
||||
use crate::verify::test;
|
||||
use console::{style, Emoji};
|
||||
use indicatif::ProgressBar;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
use toml::Value;
|
||||
|
||||
pub fn run(matches: clap::ArgMatches) -> Result<(), ()> {
|
||||
if let Some(filename) = matches.value_of("file") {
|
||||
let toml: Value = fs::read_to_string("info.toml").unwrap().parse().unwrap();
|
||||
let tomlvec: &Vec<Value> = toml.get("exercises").unwrap().as_array().unwrap();
|
||||
let mut exercises = tomlvec.clone();
|
||||
exercises.retain(|i| i.get("path").unwrap().as_str().unwrap() == filename);
|
||||
if exercises.is_empty() {
|
||||
println!("No exercise found for your filename!");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let exercise: &Value = &exercises[0];
|
||||
match exercise.get("mode").unwrap().as_str().unwrap() {
|
||||
"test" => test(exercise.get("path").unwrap().as_str().unwrap())?,
|
||||
"compile" => compile_and_run(exercise.get("path").unwrap().as_str().unwrap())?,
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
panic!("Please supply a filename!");
|
||||
pub fn run(exercise: &Exercise) -> Result<(), ()> {
|
||||
match exercise.mode {
|
||||
Mode::Test => test(exercise)?,
|
||||
Mode::Compile => compile_and_run(exercise)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile_and_run(filename: &str) -> Result<(), ()> {
|
||||
pub fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Compiling {}...", filename).as_str());
|
||||
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
let compilecmd = Command::new("rustc")
|
||||
.args(&[filename, "-o", "temp", "--color", "always"])
|
||||
.output()
|
||||
.expect("fail");
|
||||
progress_bar.set_message(format!("Running {}...", filename).as_str());
|
||||
|
||||
let compilecmd = exercise.compile();
|
||||
progress_bar.set_message(format!("Running {}...", exercise).as_str());
|
||||
if compilecmd.status.success() {
|
||||
let runcmd = Command::new("./temp").output().expect("fail");
|
||||
let runcmd = exercise.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
if runcmd.status.success() {
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
let formatstr = format!("{} Successfully ran {}", Emoji("✅", "✓"), filename);
|
||||
let formatstr = format!("{} Successfully ran {}", Emoji("✅", "✓"), exercise);
|
||||
println!("{}", style(formatstr).green());
|
||||
clean();
|
||||
exercise.clean();
|
||||
Ok(())
|
||||
} else {
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stderr));
|
||||
|
||||
let formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), filename);
|
||||
let formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), exercise);
|
||||
println!("{}", style(formatstr).red());
|
||||
clean();
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
@@ -62,11 +42,11 @@ pub fn compile_and_run(filename: &str) -> Result<(), ()> {
|
||||
let formatstr = format!(
|
||||
"{} Compilation of {} failed! Compiler error message:\n",
|
||||
Emoji("⚠️ ", "!"),
|
||||
filename
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
|
||||
clean();
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
12
src/util.rs
12
src/util.rs
@@ -1,12 +0,0 @@
|
||||
use std::fs::remove_file;
|
||||
|
||||
pub fn clean() {
|
||||
let _ignored = remove_file("temp");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clean() {
|
||||
std::fs::File::create("temp").unwrap();
|
||||
clean();
|
||||
assert!(!std::path::Path::new("temp").exists());
|
||||
}
|
||||
@@ -1,93 +1,71 @@
|
||||
use crate::util::clean;
|
||||
use crate::exercise::{Exercise, Mode};
|
||||
use console::{style, Emoji};
|
||||
use indicatif::ProgressBar;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
use toml::Value;
|
||||
|
||||
pub fn verify(start_at: Option<&str>) -> Result<(), ()> {
|
||||
let toml: Value = fs::read_to_string("info.toml").unwrap().parse().unwrap();
|
||||
let tomlvec: &Vec<Value> = toml.get("exercises").unwrap().as_array().unwrap();
|
||||
let mut hit_start_at = false;
|
||||
|
||||
for i in tomlvec {
|
||||
let path = i.get("path").unwrap().as_str().unwrap();
|
||||
|
||||
if let Some(start_at) = start_at {
|
||||
if start_at.ends_with(path) {
|
||||
hit_start_at = true;
|
||||
} else if !hit_start_at {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
match i.get("mode").unwrap().as_str().unwrap() {
|
||||
"test" => test(path)?,
|
||||
"compile" => compile_only(path)?,
|
||||
_ => (),
|
||||
pub fn verify<'a>(start_at: impl IntoIterator<Item=&'a Exercise>) -> Result<(), ()> {
|
||||
for exercise in start_at {
|
||||
match exercise.mode {
|
||||
Mode::Test => test(&exercise)?,
|
||||
Mode::Compile => compile_only(&exercise)?,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_only(filename: &str) -> Result<(), ()> {
|
||||
fn compile_only(exercise: &Exercise) -> Result<(), ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Compiling {}...", filename).as_str());
|
||||
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
let compilecmd = Command::new("rustc")
|
||||
.args(&[filename, "-o", "temp", "--color", "always"])
|
||||
.output()
|
||||
.expect("fail");
|
||||
let compile_output = exercise.compile();
|
||||
progress_bar.finish_and_clear();
|
||||
if compilecmd.status.success() {
|
||||
if compile_output.status.success() {
|
||||
let formatstr = format!(
|
||||
"{} Successfully compiled {}!",
|
||||
Emoji("✅", "✓"),
|
||||
filename
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).green());
|
||||
clean();
|
||||
exercise.clean();
|
||||
Ok(())
|
||||
} else {
|
||||
let formatstr = format!(
|
||||
"{} Compilation of {} failed! Compiler error message:\n",
|
||||
Emoji("⚠️ ", "!"),
|
||||
filename
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
|
||||
clean();
|
||||
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test(filename: &str) -> Result<(), ()> {
|
||||
pub fn test(exercise: &Exercise) -> Result<(), ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Testing {}...", filename).as_str());
|
||||
progress_bar.set_message(format!("Testing {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
let testcmd = Command::new("rustc")
|
||||
.args(&["--test", filename, "-o", "temp", "--color", "always"])
|
||||
.output()
|
||||
.expect("fail");
|
||||
if testcmd.status.success() {
|
||||
progress_bar.set_message(format!("Running {}...", filename).as_str());
|
||||
let runcmd = Command::new("./temp").output().expect("fail");
|
||||
|
||||
let compile_output = exercise.compile();
|
||||
if compile_output.status.success() {
|
||||
progress_bar.set_message(format!("Running {}...", exercise).as_str());
|
||||
|
||||
let runcmd = exercise.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
if runcmd.status.success() {
|
||||
let formatstr = format!("{} Successfully tested {}!", Emoji("✅", "✓"), filename);
|
||||
let formatstr = format!("{} Successfully tested {}!", Emoji("✅", "✓"), exercise);
|
||||
println!("{}", style(formatstr).green());
|
||||
clean();
|
||||
exercise.clean();
|
||||
Ok(())
|
||||
} else {
|
||||
let formatstr = format!(
|
||||
"{} Testing of {} failed! Please try again. Here's the output:",
|
||||
Emoji("⚠️ ", "!"),
|
||||
filename
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
clean();
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
@@ -95,11 +73,11 @@ pub fn test(filename: &str) -> Result<(), ()> {
|
||||
let formatstr = format!(
|
||||
"{} Compiling of {} failed! Please try again. Here's the output:",
|
||||
Emoji("⚠️ ", "!"),
|
||||
filename
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&testcmd.stderr));
|
||||
clean();
|
||||
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
3
tests/fixture/failure/compFailure.rs
Normal file
3
tests/fixture/failure/compFailure.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
let
|
||||
}
|
||||
7
tests/fixture/failure/info.toml
Normal file
7
tests/fixture/failure/info.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[[exercises]]
|
||||
path = "compFailure.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "testFailure.rs"
|
||||
mode = "test"
|
||||
4
tests/fixture/failure/testFailure.rs
Normal file
4
tests/fixture/failure/testFailure.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#[test]
|
||||
fn passing() {
|
||||
asset!(true);
|
||||
}
|
||||
@@ -13,7 +13,7 @@ fn fails_when_in_wrong_dir() {
|
||||
.unwrap()
|
||||
.current_dir("tests/")
|
||||
.assert()
|
||||
.failure();
|
||||
.code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -21,31 +21,61 @@ fn verify_all_success() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.arg("v")
|
||||
.current_dir("tests/fixture/")
|
||||
.current_dir("tests/fixture/success")
|
||||
.assert()
|
||||
.success();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_all_failure() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.arg("v")
|
||||
.current_dir("tests/fixture/failure")
|
||||
.assert()
|
||||
.code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_single_compile_success() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "compSuccess.rs"])
|
||||
.current_dir("tests/fixture/")
|
||||
.current_dir("tests/fixture/success/")
|
||||
.assert()
|
||||
.success();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_single_compile_failure() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "compFailure.rs"])
|
||||
.current_dir("tests/fixture/failure/")
|
||||
.assert()
|
||||
.code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_single_test_success() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "testSuccess.rs"])
|
||||
.current_dir("tests/fixture/")
|
||||
.current_dir("tests/fixture/success/")
|
||||
.assert()
|
||||
.success();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_single_test_failure() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "testFailure.rs"])
|
||||
.current_dir("tests/fixture/failure/")
|
||||
.assert()
|
||||
.code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_single_test_no_filename() {
|
||||
Command::cargo_bin("rustlings")
|
||||
@@ -53,7 +83,7 @@ fn run_single_test_no_filename() {
|
||||
.arg("r")
|
||||
.current_dir("tests/fixture/")
|
||||
.assert()
|
||||
.failure();
|
||||
.code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -61,7 +91,7 @@ fn run_single_test_no_exercise() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "compNoExercise.rs"])
|
||||
.current_dir("tests/fixture/")
|
||||
.current_dir("tests/fixture/failure")
|
||||
.assert()
|
||||
.failure();
|
||||
.code(1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user