From 79ca821e26711123c959e919eed2a630fa102cd5 Mon Sep 17 00:00:00 2001 From: mo8it Date: Sat, 30 Mar 2024 20:48:30 +0100 Subject: Fix tests --- tests/fixture/failure/compFailure.rs | 3 --- tests/fixture/failure/compNoExercise.rs | 2 -- tests/fixture/failure/exercises/compFailure.rs | 3 +++ tests/fixture/failure/exercises/compNoExercise.rs | 2 ++ tests/fixture/failure/exercises/testFailure.rs | 4 ++++ tests/fixture/failure/exercises/testNotPassed.rs | 4 ++++ tests/fixture/failure/info.toml | 4 ++-- tests/fixture/failure/testFailure.rs | 4 ---- tests/fixture/failure/testNotPassed.rs | 4 ---- 9 files changed, 15 insertions(+), 15 deletions(-) delete mode 100644 tests/fixture/failure/compFailure.rs delete mode 100644 tests/fixture/failure/compNoExercise.rs create mode 100644 tests/fixture/failure/exercises/compFailure.rs create mode 100644 tests/fixture/failure/exercises/compNoExercise.rs create mode 100644 tests/fixture/failure/exercises/testFailure.rs create mode 100644 tests/fixture/failure/exercises/testNotPassed.rs delete mode 100644 tests/fixture/failure/testFailure.rs delete mode 100644 tests/fixture/failure/testNotPassed.rs (limited to 'tests/fixture/failure') diff --git a/tests/fixture/failure/compFailure.rs b/tests/fixture/failure/compFailure.rs deleted file mode 100644 index 566856a..0000000 --- a/tests/fixture/failure/compFailure.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - let -} \ No newline at end of file diff --git a/tests/fixture/failure/compNoExercise.rs b/tests/fixture/failure/compNoExercise.rs deleted file mode 100644 index f79c691..0000000 --- a/tests/fixture/failure/compNoExercise.rs +++ /dev/null @@ -1,2 +0,0 @@ -fn main() { -} diff --git a/tests/fixture/failure/exercises/compFailure.rs b/tests/fixture/failure/exercises/compFailure.rs new file mode 100644 index 0000000..566856a --- /dev/null +++ b/tests/fixture/failure/exercises/compFailure.rs @@ -0,0 +1,3 @@ +fn main() { + let +} \ No newline at end of file diff --git a/tests/fixture/failure/exercises/compNoExercise.rs b/tests/fixture/failure/exercises/compNoExercise.rs new file mode 100644 index 0000000..f79c691 --- /dev/null +++ b/tests/fixture/failure/exercises/compNoExercise.rs @@ -0,0 +1,2 @@ +fn main() { +} diff --git a/tests/fixture/failure/exercises/testFailure.rs b/tests/fixture/failure/exercises/testFailure.rs new file mode 100644 index 0000000..b33a5d2 --- /dev/null +++ b/tests/fixture/failure/exercises/testFailure.rs @@ -0,0 +1,4 @@ +#[test] +fn passing() { + asset!(true); +} diff --git a/tests/fixture/failure/exercises/testNotPassed.rs b/tests/fixture/failure/exercises/testNotPassed.rs new file mode 100644 index 0000000..a9fe88d --- /dev/null +++ b/tests/fixture/failure/exercises/testNotPassed.rs @@ -0,0 +1,4 @@ +#[test] +fn not_passing() { + assert!(false); +} diff --git a/tests/fixture/failure/info.toml b/tests/fixture/failure/info.toml index e5949f9..9474ee3 100644 --- a/tests/fixture/failure/info.toml +++ b/tests/fixture/failure/info.toml @@ -1,11 +1,11 @@ [[exercises]] name = "compFailure" -path = "compFailure.rs" +path = "exercises/compFailure.rs" mode = "compile" hint = "" [[exercises]] name = "testFailure" -path = "testFailure.rs" +path = "exercises/testFailure.rs" mode = "test" hint = "Hello!" diff --git a/tests/fixture/failure/testFailure.rs b/tests/fixture/failure/testFailure.rs deleted file mode 100644 index b33a5d2..0000000 --- a/tests/fixture/failure/testFailure.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn passing() { - asset!(true); -} diff --git a/tests/fixture/failure/testNotPassed.rs b/tests/fixture/failure/testNotPassed.rs deleted file mode 100644 index a9fe88d..0000000 --- a/tests/fixture/failure/testNotPassed.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn not_passing() { - assert!(false); -} -- cgit v1.2.3 From 7090fffeae88a2afdeb42ae3301c4842416ab729 Mon Sep 17 00:00:00 2001 From: mo8it Date: Sun, 31 Mar 2024 18:59:01 +0200 Subject: Fix tests --- .gitignore | 7 +++---- Cargo.toml | 5 +++++ tests/fixture/failure/Cargo.toml | 21 +++++++++++++++++++++ tests/fixture/state/Cargo.toml | 17 +++++++++++++++++ tests/fixture/success/Cargo.toml | 13 +++++++++++++ 5 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 tests/fixture/failure/Cargo.toml create mode 100644 tests/fixture/state/Cargo.toml create mode 100644 tests/fixture/success/Cargo.toml (limited to 'tests/fixture/failure') diff --git a/.gitignore b/.gitignore index f319d39..d6c7708 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,10 @@ -*.swp target/ +tests/fixture/*/Cargo.lock + +*.swp **/*.rs.bk .DS_Store *.pdb -exercises/clippy/Cargo.toml -exercises/clippy/Cargo.lock -rust-project.json .idea .vscode/* !.vscode/extensions.json diff --git a/Cargo.toml b/Cargo.toml index 9224364..5fc75f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,10 @@ [workspace] resolver = "2" +exclude = [ + "tests/fixture/failure", + "tests/fixture/state", + "tests/fixture/success", +] [workspace.package] version = "6.0.0" diff --git a/tests/fixture/failure/Cargo.toml b/tests/fixture/failure/Cargo.toml new file mode 100644 index 0000000..dd728c3 --- /dev/null +++ b/tests/fixture/failure/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "tests" +version = "0.0.0" +edition = "2021" +publish = false + +[[bin]] +name = "compFailure" +path = "exercises/compFailure.rs" + +[[bin]] +name = "compNoExercise" +path = "exercises/compNoExercise.rs" + +[[bin]] +name = "testFailure" +path = "exercises/testFailure.rs" + +[[bin]] +name = "testNotPassed" +path = "exercises/testNotPassed.rs" diff --git a/tests/fixture/state/Cargo.toml b/tests/fixture/state/Cargo.toml new file mode 100644 index 0000000..5cfa42b --- /dev/null +++ b/tests/fixture/state/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "tests" +version = "0.0.0" +edition = "2021" +publish = false + +[[bin]] +name = "pending_exercise" +path = "exercises/pending_exercise.rs" + +[[bin]] +name = "pending_test_exercise" +path = "exercises/pending_test_exercise.rs" + +[[bin]] +name = "finished_exercise" +path = "exercises/finished_exercise.rs" diff --git a/tests/fixture/success/Cargo.toml b/tests/fixture/success/Cargo.toml new file mode 100644 index 0000000..c005928 --- /dev/null +++ b/tests/fixture/success/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "tests" +version = "0.0.0" +edition = "2021" +publish = false + +[[bin]] +name = "compSuccess" +path = "exercises/compSuccess.rs" + +[[bin]] +name = "testSuccess" +path = "exercises/testSuccess.rs" -- cgit v1.2.3 From b6c434c445d91a9e886e5639b078635e5eca4eb3 Mon Sep 17 00:00:00 2001 From: mo8it Date: Thu, 4 Apr 2024 15:45:53 +0200 Subject: Remove optional version field --- dev/Cargo.toml | 1 - src/bin/gen-dev-cargo-toml.rs | 1 - src/init.rs | 1 - tests/fixture/failure/Cargo.toml | 1 - tests/fixture/state/Cargo.toml | 1 - tests/fixture/success/Cargo.toml | 1 - 6 files changed, 6 deletions(-) (limited to 'tests/fixture/failure') diff --git a/dev/Cargo.toml b/dev/Cargo.toml index e4e7be7..7868b97 100644 --- a/dev/Cargo.toml +++ b/dev/Cargo.toml @@ -102,6 +102,5 @@ bin = [ [package] name = "rustlings" -version = "0.0.0" edition = "2021" publish = false diff --git a/src/bin/gen-dev-cargo-toml.rs b/src/bin/gen-dev-cargo-toml.rs index 65cc244..ff8f31d 100644 --- a/src/bin/gen-dev-cargo-toml.rs +++ b/src/bin/gen-dev-cargo-toml.rs @@ -49,7 +49,6 @@ bin = [\n", [package] name = "rustlings" -version = "0.0.0" edition = "2021" publish = false "#, diff --git a/src/init.rs b/src/init.rs index b52b613..6af3235 100644 --- a/src/init.rs +++ b/src/init.rs @@ -24,7 +24,6 @@ fn create_cargo_toml(exercises: &[Exercise]) -> io::Result<()> { [package] name = "rustlings" -version = "0.0.0" edition = "2021" publish = false "#, diff --git a/tests/fixture/failure/Cargo.toml b/tests/fixture/failure/Cargo.toml index dd728c3..e111cf2 100644 --- a/tests/fixture/failure/Cargo.toml +++ b/tests/fixture/failure/Cargo.toml @@ -1,6 +1,5 @@ [package] name = "tests" -version = "0.0.0" edition = "2021" publish = false diff --git a/tests/fixture/state/Cargo.toml b/tests/fixture/state/Cargo.toml index 5cfa42b..c8d74e4 100644 --- a/tests/fixture/state/Cargo.toml +++ b/tests/fixture/state/Cargo.toml @@ -1,6 +1,5 @@ [package] name = "tests" -version = "0.0.0" edition = "2021" publish = false diff --git a/tests/fixture/success/Cargo.toml b/tests/fixture/success/Cargo.toml index c005928..f26a44f 100644 --- a/tests/fixture/success/Cargo.toml +++ b/tests/fixture/success/Cargo.toml @@ -1,6 +1,5 @@ [package] name = "tests" -version = "0.0.0" edition = "2021" publish = false -- cgit v1.2.3 From 60155294e94acd661e4fe20cf8b72412167c772d Mon Sep 17 00:00:00 2001 From: mo8it Date: Sat, 6 Apr 2024 01:45:54 +0200 Subject: Rename packages --- dev/Cargo.toml | 2 +- gen-dev-cargo-toml/src/main.rs | 2 +- tests/fixture/failure/Cargo.toml | 2 +- tests/fixture/state/Cargo.toml | 2 +- tests/fixture/success/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'tests/fixture/failure') diff --git a/dev/Cargo.toml b/dev/Cargo.toml index ed9b3ed..1d230eb 100644 --- a/dev/Cargo.toml +++ b/dev/Cargo.toml @@ -101,6 +101,6 @@ bin = [ ] [package] -name = "rustlings" +name = "rustlings-dev" edition = "2021" publish = false diff --git a/gen-dev-cargo-toml/src/main.rs b/gen-dev-cargo-toml/src/main.rs index 622762a..9a7c1bb 100644 --- a/gen-dev-cargo-toml/src/main.rs +++ b/gen-dev-cargo-toml/src/main.rs @@ -48,7 +48,7 @@ bin = [\n", br#"] [package] -name = "rustlings" +name = "rustlings-dev" edition = "2021" publish = false "#, diff --git a/tests/fixture/failure/Cargo.toml b/tests/fixture/failure/Cargo.toml index e111cf2..7ee2f06 100644 --- a/tests/fixture/failure/Cargo.toml +++ b/tests/fixture/failure/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "tests" +name = "failure" edition = "2021" publish = false diff --git a/tests/fixture/state/Cargo.toml b/tests/fixture/state/Cargo.toml index c8d74e4..adbd8ab 100644 --- a/tests/fixture/state/Cargo.toml +++ b/tests/fixture/state/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "tests" +name = "state" edition = "2021" publish = false diff --git a/tests/fixture/success/Cargo.toml b/tests/fixture/success/Cargo.toml index f26a44f..028cf35 100644 --- a/tests/fixture/success/Cargo.toml +++ b/tests/fixture/success/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "tests" +name = "success" edition = "2021" publish = false -- cgit v1.2.3 From 9831cbb13975cd0f5ee4c295156102e3573ede1a Mon Sep 17 00:00:00 2001 From: mo8it Date: Sun, 14 Apr 2024 03:13:33 +0200 Subject: Fix tests --- gen-dev-cargo-toml/src/main.rs | 24 ++++++++++++++---------- tests/dev_cargo_bins.rs | 39 ++++++++++++++++++++++----------------- tests/fixture/failure/info.toml | 4 +--- tests/fixture/state/info.toml | 7 ++----- tests/fixture/success/info.toml | 4 +--- 5 files changed, 40 insertions(+), 38 deletions(-) (limited to 'tests/fixture/failure') diff --git a/gen-dev-cargo-toml/src/main.rs b/gen-dev-cargo-toml/src/main.rs index 9a7c1bb..792fe5f 100644 --- a/gen-dev-cargo-toml/src/main.rs +++ b/gen-dev-cargo-toml/src/main.rs @@ -10,18 +10,18 @@ use std::{ }; #[derive(Deserialize)] -struct Exercise { +struct ExerciseInfo { name: String, - path: String, + dir: Option, } #[derive(Deserialize)] -struct InfoToml { - exercises: Vec, +struct InfoFile { + exercises: Vec, } fn main() -> Result<()> { - let exercises = toml_edit::de::from_str::( + let exercise_infos = toml_edit::de::from_str::( &fs::read_to_string("info.toml").context("Failed to read `info.toml`")?, ) .context("Failed to deserialize `info.toml`")? @@ -36,12 +36,16 @@ fn main() -> Result<()> { bin = [\n", ); - for exercise in exercises { + for exercise_info in exercise_infos { buf.extend_from_slice(b" { name = \""); - buf.extend_from_slice(exercise.name.as_bytes()); - buf.extend_from_slice(b"\", path = \"../"); - buf.extend_from_slice(exercise.path.as_bytes()); - buf.extend_from_slice(b"\" },\n"); + buf.extend_from_slice(exercise_info.name.as_bytes()); + buf.extend_from_slice(b"\", path = \"../exercises/"); + if let Some(dir) = &exercise_info.dir { + buf.extend_from_slice(dir.as_bytes()); + buf.extend_from_slice(b"/"); + } + buf.extend_from_slice(exercise_info.name.as_bytes()); + buf.extend_from_slice(b".rs\" },\n"); } buf.extend_from_slice( diff --git a/tests/dev_cargo_bins.rs b/tests/dev_cargo_bins.rs index c3faea9..81f48b1 100644 --- a/tests/dev_cargo_bins.rs +++ b/tests/dev_cargo_bins.rs @@ -5,34 +5,39 @@ use serde::Deserialize; use std::fs; #[derive(Deserialize)] -struct Exercise { +struct ExerciseInfo { name: String, - path: String, + dir: Option, } #[derive(Deserialize)] -struct InfoToml { - exercises: Vec, +struct InfoFile { + exercises: Vec, } #[test] fn dev_cargo_bins() { - let content = fs::read_to_string("dev/Cargo.toml").unwrap(); + let cargo_toml = fs::read_to_string("dev/Cargo.toml").unwrap(); - let exercises = toml_edit::de::from_str::(&fs::read_to_string("info.toml").unwrap()) - .unwrap() - .exercises; + let exercise_infos = + toml_edit::de::from_str::(&fs::read_to_string("info.toml").unwrap()) + .unwrap() + .exercises; let mut start_ind = 0; - for exercise in exercises { - let name_start = start_ind + content[start_ind..].find('"').unwrap() + 1; - let name_end = name_start + content[name_start..].find('"').unwrap(); - assert_eq!(exercise.name, &content[name_start..name_end]); - - // +3 to skip `../` at the begeinning of the path. - let path_start = name_end + content[name_end + 1..].find('"').unwrap() + 5; - let path_end = path_start + content[path_start..].find('"').unwrap(); - assert_eq!(exercise.path, &content[path_start..path_end]); + for exercise_info in exercise_infos { + let name_start = start_ind + cargo_toml[start_ind..].find('"').unwrap() + 1; + let name_end = name_start + cargo_toml[name_start..].find('"').unwrap(); + assert_eq!(exercise_info.name, &cargo_toml[name_start..name_end]); + + let path_start = name_end + cargo_toml[name_end + 1..].find('"').unwrap() + 2; + let path_end = path_start + cargo_toml[path_start..].find('"').unwrap(); + let expected_path = if let Some(dir) = exercise_info.dir { + format!("../exercises/{dir}/{}.rs", exercise_info.name) + } else { + format!("../exercises/{}.rs", exercise_info.name) + }; + assert_eq!(expected_path, &cargo_toml[path_start..path_end]); start_ind = path_end + 1; } diff --git a/tests/fixture/failure/info.toml b/tests/fixture/failure/info.toml index 9474ee3..94ec6ea 100644 --- a/tests/fixture/failure/info.toml +++ b/tests/fixture/failure/info.toml @@ -1,11 +1,9 @@ [[exercises]] name = "compFailure" -path = "exercises/compFailure.rs" -mode = "compile" +mode = "run" hint = "" [[exercises]] name = "testFailure" -path = "exercises/testFailure.rs" mode = "test" hint = "Hello!" diff --git a/tests/fixture/state/info.toml b/tests/fixture/state/info.toml index 8de5d60..e5c4d8f 100644 --- a/tests/fixture/state/info.toml +++ b/tests/fixture/state/info.toml @@ -1,17 +1,14 @@ [[exercises]] name = "pending_exercise" -path = "exercises/pending_exercise.rs" -mode = "compile" +mode = "run" hint = """""" [[exercises]] name = "pending_test_exercise" -path = "exercises/pending_test_exercise.rs" mode = "test" hint = """""" [[exercises]] name = "finished_exercise" -path = "exercises/finished_exercise.rs" -mode = "compile" +mode = "run" hint = """""" diff --git a/tests/fixture/success/info.toml b/tests/fixture/success/info.toml index 17ed8c6..674ba26 100644 --- a/tests/fixture/success/info.toml +++ b/tests/fixture/success/info.toml @@ -1,11 +1,9 @@ [[exercises]] name = "compSuccess" -path = "exercises/compSuccess.rs" -mode = "compile" +mode = "run" hint = """""" [[exercises]] name = "testSuccess" -path = "exercises/testSuccess.rs" mode = "test" hint = """""" -- cgit v1.2.3 From d1ebbaa6f610ec492422806beb34e0dc7e4fc466 Mon Sep 17 00:00:00 2001 From: mo8it Date: Tue, 16 Apr 2024 03:18:22 +0200 Subject: Add format_version to test info.toml files --- tests/fixture/failure/info.toml | 2 ++ tests/fixture/state/info.toml | 2 ++ tests/fixture/success/info.toml | 2 ++ 3 files changed, 6 insertions(+) (limited to 'tests/fixture/failure') diff --git a/tests/fixture/failure/info.toml b/tests/fixture/failure/info.toml index 94ec6ea..ef99a07 100644 --- a/tests/fixture/failure/info.toml +++ b/tests/fixture/failure/info.toml @@ -1,3 +1,5 @@ +format_version = 1 + [[exercises]] name = "compFailure" mode = "run" diff --git a/tests/fixture/state/info.toml b/tests/fixture/state/info.toml index e5c4d8f..eec24ea 100644 --- a/tests/fixture/state/info.toml +++ b/tests/fixture/state/info.toml @@ -1,3 +1,5 @@ +format_version = 1 + [[exercises]] name = "pending_exercise" mode = "run" diff --git a/tests/fixture/success/info.toml b/tests/fixture/success/info.toml index 674ba26..88650ec 100644 --- a/tests/fixture/success/info.toml +++ b/tests/fixture/success/info.toml @@ -1,3 +1,5 @@ +format_version = 1 + [[exercises]] name = "compSuccess" mode = "run" -- cgit v1.2.3 From 2af0cd9ccef07edf27abf7046dbe15e32d1b476d Mon Sep 17 00:00:00 2001 From: mo8it Date: Thu, 25 Apr 2024 03:25:45 +0200 Subject: Replace `mode` by `test` and `strict_clippy` --- info.toml | 143 +++++++++++++--------------------------- src/app_state.rs | 5 +- src/dev/new.rs | 13 ++-- src/exercise.rs | 131 +++++++++++++++++++++--------------- src/info_file.rs | 22 +++---- tests/fixture/failure/info.toml | 3 +- tests/fixture/state/info.toml | 5 +- tests/fixture/success/info.toml | 3 +- 8 files changed, 147 insertions(+), 178 deletions(-) (limited to 'tests/fixture/failure') diff --git a/info.toml b/info.toml index d5369d5..1494472 100644 --- a/info.toml +++ b/info.toml @@ -39,7 +39,7 @@ https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md [[exercises]] name = "intro1" dir = "00_intro" -mode = "run" +test = false # TODO: Fix hint hint = """ Remove the `I AM NOT DONE` comment in the `exercises/intro00/intro1.rs` file @@ -48,7 +48,7 @@ to move on to the next exercise.""" [[exercises]] name = "intro2" dir = "00_intro" -mode = "run" +test = false hint = """ The compiler is informing us that we've got the name of the print macro wrong, and has suggested an alternative.""" @@ -57,7 +57,7 @@ The compiler is informing us that we've got the name of the print macro wrong, a [[exercises]] name = "variables1" dir = "01_variables" -mode = "run" +test = false hint = """ The declaration in the first line in the main function is missing a keyword that is needed in Rust to create a new variable binding.""" @@ -65,7 +65,7 @@ that is needed in Rust to create a new variable binding.""" [[exercises]] name = "variables2" dir = "01_variables" -mode = "run" +test = false hint = """ The compiler message is saying that Rust cannot infer the type that the variable binding `x` has with what is given here. @@ -84,7 +84,7 @@ What if `x` is the same type as `10`? What if it's a different type?""" [[exercises]] name = "variables3" dir = "01_variables" -mode = "run" +test = false hint = """ Oops! In this exercise, we have a variable binding that we've created on in the first line in the `main` function, and we're trying to use it in the next line, @@ -98,7 +98,7 @@ programming language -- thankfully the Rust compiler has caught this for us!""" [[exercises]] name = "variables4" dir = "01_variables" -mode = "run" +test = false hint = """ In Rust, variable bindings are immutable by default. But here we're trying to reassign a different value to `x`! There's a keyword we can use to make @@ -107,7 +107,7 @@ a variable binding mutable instead.""" [[exercises]] name = "variables5" dir = "01_variables" -mode = "run" +test = false hint = """ In `variables4` we already learned how to make an immutable variable mutable using a special keyword. Unfortunately this doesn't help us much in this @@ -125,7 +125,7 @@ Try to solve this exercise afterwards using this technique.""" [[exercises]] name = "variables6" dir = "01_variables" -mode = "run" +test = false hint = """ We know about variables and mutability, but there is another important type of variable available: constants. @@ -145,7 +145,7 @@ https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#constants [[exercises]] name = "functions1" dir = "02_functions" -mode = "run" +test = false hint = """ This main function is calling a function that it expects to exist, but the function doesn't exist. It expects this function to have the name `call_me`. @@ -155,7 +155,7 @@ Sounds a lot like `main`, doesn't it?""" [[exercises]] name = "functions2" dir = "02_functions" -mode = "run" +test = false hint = """ Rust requires that all parts of a function's signature have type annotations, but `call_me` is missing the type annotation of `num`.""" @@ -163,7 +163,7 @@ but `call_me` is missing the type annotation of `num`.""" [[exercises]] name = "functions3" dir = "02_functions" -mode = "run" +test = false hint = """ This time, the function *declaration* is okay, but there's something wrong with the place where we're calling the function.""" @@ -171,7 +171,7 @@ with the place where we're calling the function.""" [[exercises]] name = "functions4" dir = "02_functions" -mode = "run" +test = false hint = """ The error message points to the function `sale_price` and says it expects a type after the `->`. This is where the function's return type should be -- take a @@ -180,7 +180,7 @@ look at the `is_even` function for an example!""" [[exercises]] name = "functions5" dir = "02_functions" -mode = "run" +test = false hint = """ This is a really common error that can be fixed by removing one character. It happens because Rust distinguishes between expressions and statements: @@ -199,7 +199,6 @@ They are not the same. There are two solutions: [[exercises]] name = "if1" dir = "03_if" -mode = "test" hint = """ It's possible to do this in one line if you would like! @@ -215,7 +214,6 @@ Remember in Rust that: [[exercises]] name = "if2" dir = "03_if" -mode = "test" hint = """ For that first compiler error, it's important in Rust that each conditional block returns the same type! To get the tests passing, you will need a couple @@ -224,7 +222,6 @@ conditions checking different input values.""" [[exercises]] name = "if3" dir = "03_if" -mode = "test" hint = """ In Rust, every arm of an `if` expression has to return the same type of value. Make sure the type is consistent across all arms.""" @@ -234,7 +231,6 @@ Make sure the type is consistent across all arms.""" [[exercises]] name = "quiz1" dir = "quizzes" -mode = "test" hint = "No hints this time ;)" # PRIMITIVE TYPES @@ -242,19 +238,19 @@ hint = "No hints this time ;)" [[exercises]] name = "primitive_types1" dir = "04_primitive_types" -mode = "run" +test = false hint = "No hints this time ;)" [[exercises]] name = "primitive_types2" dir = "04_primitive_types" -mode = "run" +test = false hint = "No hints this time ;)" [[exercises]] name = "primitive_types3" dir = "04_primitive_types" -mode = "run" +test = false hint = """ There's a shorthand to initialize Arrays with a certain size that does not require you to type in 100 items (but you certainly can if you want!). @@ -270,7 +266,6 @@ for `a.len() >= 100`?""" [[exercises]] name = "primitive_types4" dir = "04_primitive_types" -mode = "test" hint = """ Take a look at the 'Understanding Ownership -> Slices -> Other Slices' section of the book: https://doc.rust-lang.org/book/ch04-03-slices.html and use the @@ -285,7 +280,7 @@ https://doc.rust-lang.org/nomicon/coercions.html""" [[exercises]] name = "primitive_types5" dir = "04_primitive_types" -mode = "run" +test = false hint = """ Take a look at the 'Data Types -> The Tuple Type' section of the book: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type @@ -298,7 +293,6 @@ of the tuple. You can do it!!""" [[exercises]] name = "primitive_types6" dir = "04_primitive_types" -mode = "test" hint = """ While you could use a destructuring `let` for the tuple here, try indexing into it instead, as explained in the last example of the @@ -311,7 +305,6 @@ Now you have another tool in your toolbox!""" [[exercises]] name = "vecs1" dir = "05_vecs" -mode = "test" hint = """ In Rust, there are two ways to define a Vector. 1. One way is to use the `Vec::new()` function to create a new vector @@ -326,7 +319,6 @@ of the Rust book to learn more. [[exercises]] name = "vecs2" dir = "05_vecs" -mode = "test" hint = """ In the first function we are looping over the Vector and getting a reference to one `element` at a time. @@ -349,7 +341,6 @@ What do you think is the more commonly used pattern under Rust developers? [[exercises]] name = "move_semantics1" dir = "06_move_semantics" -mode = "test" hint = """ So you've got the "cannot borrow immutable local variable `vec` as mutable" error on the line where we push an element to the vector, right? @@ -363,7 +354,6 @@ happens!""" [[exercises]] name = "move_semantics2" dir = "06_move_semantics" -mode = "test" hint = """ When running this exercise for the first time, you'll notice an error about "borrow of moved value". In Rust, when an argument is passed to a function and @@ -384,7 +374,6 @@ try them all: [[exercises]] name = "move_semantics3" dir = "06_move_semantics" -mode = "test" hint = """ The difference between this one and the previous ones is that the first line of `fn fill_vec` that had `let mut vec = vec;` is no longer there. You can, @@ -394,7 +383,6 @@ an existing binding to be a mutable binding instead of an immutable one :)""" [[exercises]] name = "move_semantics4" dir = "06_move_semantics" -mode = "test" hint = """ Stop reading whenever you feel like you have enough direction :) Or try doing one step and then fixing the compiler errors that result! @@ -408,7 +396,6 @@ So the end goal is to: [[exercises]] name = "move_semantics5" dir = "06_move_semantics" -mode = "test" hint = """ Carefully reason about the range in which each mutable reference is in scope. Does it help to update the value of referent (`x`) immediately after @@ -420,7 +407,7 @@ https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#mutable-ref [[exercises]] name = "move_semantics6" dir = "06_move_semantics" -mode = "run" +test = false hint = """ To find the answer, you can consult the book section "References and Borrowing": https://doc.rust-lang.org/stable/book/ch04-02-references-and-borrowing.html @@ -441,7 +428,6 @@ Another hint: it has to do with the `&` character.""" [[exercises]] name = "structs1" dir = "07_structs" -mode = "test" hint = """ Rust has more than one type of struct. Three actually, all variants are used to package related data together. @@ -461,7 +447,6 @@ https://doc.rust-lang.org/book/ch05-01-defining-structs.html""" [[exercises]] name = "structs2" dir = "07_structs" -mode = "test" hint = """ Creating instances of structs is easy, all you need to do is assign some values to its fields. @@ -473,7 +458,6 @@ https://doc.rust-lang.org/stable/book/ch05-01-defining-structs.html#creating-ins [[exercises]] name = "structs3" dir = "07_structs" -mode = "test" hint = """ For `is_international`: What makes a package international? Seems related to the places it goes through right? @@ -489,13 +473,13 @@ https://doc.rust-lang.org/book/ch05-03-method-syntax.html""" [[exercises]] name = "enums1" dir = "08_enums" -mode = "run" +test = false hint = "No hints this time ;)" [[exercises]] name = "enums2" dir = "08_enums" -mode = "run" +test = false hint = """ You can create enumerations that have different variants with different types such as no data, anonymous structs, a single string, tuples, ...etc""" @@ -503,7 +487,6 @@ such as no data, anonymous structs, a single string, tuples, ...etc""" [[exercises]] name = "enums3" dir = "08_enums" -mode = "test" hint = """ As a first step, you can define enums to compile this code without errors. @@ -517,7 +500,7 @@ to get value in the variant.""" [[exercises]] name = "strings1" dir = "09_strings" -mode = "run" +test = false hint = """ The `current_favorite_color` function is currently returning a string slice with the `'static` lifetime. We know this because the data of the string lives @@ -531,7 +514,7 @@ another way that uses the `From` trait.""" [[exercises]] name = "strings2" dir = "09_strings" -mode = "run" +test = false hint = """ Yes, it would be really easy to fix this by just changing the value bound to `word` to be a string slice instead of a `String`, wouldn't it?? There is a way @@ -546,7 +529,6 @@ https://doc.rust-lang.org/stable/book/ch15-02-deref.html#implicit-deref-coercion [[exercises]] name = "strings3" dir = "09_strings" -mode = "test" hint = """ There's tons of useful standard library functions for strings. Let's try and use some of them: https://doc.rust-lang.org/std/string/struct.String.html#method.trim @@ -557,7 +539,7 @@ the string slice into an owned string, which you can then freely extend.""" [[exercises]] name = "strings4" dir = "09_strings" -mode = "run" +test = false hint = "No hints this time ;)" # MODULES @@ -565,7 +547,7 @@ hint = "No hints this time ;)" [[exercises]] name = "modules1" dir = "10_modules" -mode = "run" +test = false hint = """ Everything is private in Rust by default-- but there's a keyword we can use to make something public! The compiler error should point to the thing that @@ -574,7 +556,7 @@ needs to be public.""" [[exercises]] name = "modules2" dir = "10_modules" -mode = "run" +test = false hint = """ The delicious_snacks module is trying to present an external interface that is different than its internal structure (the `fruits` and `veggies` modules and @@ -586,7 +568,7 @@ Learn more at https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-w [[exercises]] name = "modules3" dir = "10_modules" -mode = "run" +test = false hint = """ `UNIX_EPOCH` and `SystemTime` are declared in the `std::time` module. Add a `use` statement for these two to bring them into scope. You can use nested @@ -597,7 +579,6 @@ paths or the glob operator to bring these two in using only one line.""" [[exercises]] name = "hashmaps1" dir = "11_hashmaps" -mode = "test" hint = """ Hint 1: Take a look at the return type of the function to figure out the type for the `basket`. @@ -609,7 +590,6 @@ Hint 2: Number of fruits should be at least 5. And you have to put [[exercises]] name = "hashmaps2" dir = "11_hashmaps" -mode = "test" hint = """ Use the `entry()` and `or_insert()` methods of `HashMap` to achieve this. Learn more at https://doc.rust-lang.org/stable/book/ch08-03-hash-maps.html#only-inserting-a-value-if-the-key-has-no-value @@ -618,7 +598,6 @@ Learn more at https://doc.rust-lang.org/stable/book/ch08-03-hash-maps.html#only- [[exercises]] name = "hashmaps3" dir = "11_hashmaps" -mode = "test" hint = """ Hint 1: Use the `entry()` and `or_insert()` methods of `HashMap` to insert entries corresponding to each team in the scores table. @@ -636,7 +615,6 @@ Learn more at https://doc.rust-lang.org/book/ch08-03-hash-maps.html#updating-a-v [[exercises]] name = "quiz2" dir = "quizzes" -mode = "test" hint = "No hints this time ;)" # OPTIONS @@ -644,7 +622,6 @@ hint = "No hints this time ;)" [[exercises]] name = "options1" dir = "12_options" -mode = "test" hint = """ Options can have a `Some` value, with an inner value, or a `None` value, without an inner value. @@ -656,7 +633,6 @@ it doesn't panic in your face later?""" [[exercises]] name = "options2" dir = "12_options" -mode = "test" hint = """ Check out: @@ -673,7 +649,7 @@ Also see `Option::flatten` [[exercises]] name = "options3" dir = "12_options" -mode = "run" +test = false hint = """ The compiler says a partial move happened in the `match` statement. How can this be avoided? The compiler shows the correction needed. @@ -686,7 +662,6 @@ https://doc.rust-lang.org/std/keyword.ref.html""" [[exercises]] name = "errors1" dir = "13_error_handling" -mode = "test" hint = """ `Ok` and `Err` are the two variants of `Result`, so what the tests are saying is that `generate_nametag_text` should return a `Result` instead of an `Option`. @@ -702,7 +677,6 @@ To make this change, you'll need to: [[exercises]] name = "errors2" dir = "13_error_handling" -mode = "test" hint = """ One way to handle this is using a `match` statement on `item_quantity.parse::()` where the cases are `Ok(something)` and @@ -718,7 +692,7 @@ and give it a try!""" [[exercises]] name = "errors3" dir = "13_error_handling" -mode = "run" +test = false hint = """ If other functions can return a `Result`, why shouldn't `main`? It's a fairly common convention to return something like `Result<(), ErrorType>` from your @@ -730,7 +704,6 @@ positive results.""" [[exercises]] name = "errors4" dir = "13_error_handling" -mode = "test" hint = """ `PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result. @@ -742,7 +715,7 @@ everything is... okay :)""" [[exercises]] name = "errors5" dir = "13_error_handling" -mode = "run" +test = false hint = """ There are two different possible `Result` types produced within `main()`, which are propagated using `?` operators. How do we declare a return type from @@ -766,7 +739,6 @@ https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reen [[exercises]] name = "errors6" dir = "13_error_handling" -mode = "test" hint = """ This exercise uses a completed version of `PositiveNonzeroInteger` from errors4. @@ -788,7 +760,7 @@ https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err""" [[exercises]] name = "generics1" dir = "14_generics" -mode = "run" +test = false hint = """ Vectors in Rust make use of generics to create dynamically sized arrays of any type. @@ -798,7 +770,6 @@ You need to tell the compiler what type we are pushing onto this vector.""" [[exercises]] name = "generics2" dir = "14_generics" -mode = "test" hint = """ Currently we are wrapping only values of type `u32`. @@ -812,7 +783,6 @@ If you are still stuck https://doc.rust-lang.org/stable/book/ch10-01-syntax.html [[exercises]] name = "traits1" dir = "15_traits" -mode = "test" hint = """ A discussion about Traits in Rust can be found at: https://doc.rust-lang.org/book/ch10-02-traits.html @@ -821,7 +791,6 @@ https://doc.rust-lang.org/book/ch10-02-traits.html [[exercises]] name = "traits2" dir = "15_traits" -mode = "test" hint = """ Notice how the trait takes ownership of `self`, and returns `Self`. @@ -834,7 +803,6 @@ the documentation at: https://doc.rust-lang.org/std/vec/struct.Vec.html""" [[exercises]] name = "traits3" dir = "15_traits" -mode = "test" hint = """ Traits can have a default implementation for functions. Structs that implement the trait can then use the default version of these functions if they choose not @@ -846,7 +814,6 @@ See the documentation at: https://doc.rust-lang.org/book/ch10-02-traits.html#def [[exercises]] name = "traits4" dir = "15_traits" -mode = "test" hint = """ Instead of using concrete types as parameters you can use traits. Try replacing the '??' with 'impl ' @@ -857,7 +824,7 @@ See the documentation at: https://doc.rust-lang.org/book/ch10-02-traits.html#tra [[exercises]] name = "traits5" dir = "15_traits" -mode = "run" +test = false hint = """ To ensure a parameter implements multiple traits use the '+ syntax'. Try replacing the '??' with 'impl <> + <>'. @@ -870,7 +837,6 @@ See the documentation at: https://doc.rust-lang.org/book/ch10-02-traits.html#spe [[exercises]] name = "quiz3" dir = "quizzes" -mode = "test" hint = """ To find the best solution to this challenge you're going to need to think back to your knowledge of traits, specifically 'Trait Bound Syntax' @@ -882,7 +848,7 @@ You may also need this: `use std::fmt::Display;`.""" [[exercises]] name = "lifetimes1" dir = "16_lifetimes" -mode = "run" +test = false hint = """ Let the compiler guide you. Also take a look at the book if you need help: https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html""" @@ -890,7 +856,7 @@ https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html""" [[exercises]] name = "lifetimes2" dir = "16_lifetimes" -mode = "run" +test = false hint = """ Remember that the generic lifetime `'a` will get the concrete lifetime that is equal to the smaller of the lifetimes of `x` and `y`. @@ -904,7 +870,7 @@ inner block: [[exercises]] name = "lifetimes3" dir = "16_lifetimes" -mode = "run" +test = false hint = """ If you use a lifetime annotation in a struct's fields, where else does it need to be added?""" @@ -914,7 +880,6 @@ to be added?""" [[exercises]] name = "tests1" dir = "17_tests" -mode = "test" hint = """ You don't even need to write any code to test -- you can just test values and run that, even though you wouldn't do that in real life. :) @@ -929,7 +894,6 @@ ones pass, and which ones fail :)""" [[exercises]] name = "tests2" dir = "17_tests" -mode = "test" hint = """ Like the previous exercise, you don't need to write any code to get this test to compile and run. @@ -942,7 +906,6 @@ argument comes first and which comes second!""" [[exercises]] name = "tests3" dir = "17_tests" -mode = "test" hint = """ You can call a function right where you're passing arguments to `assert!`. So you could do something like `assert!(having_fun())`. @@ -953,7 +916,6 @@ what you're doing using `!`, like `assert!(!having_fun())`.""" [[exercises]] name = "tests4" dir = "17_tests" -mode = "test" hint = """ We expect method `Rectangle::new()` to panic for negative values. @@ -967,7 +929,6 @@ https://doc.rust-lang.org/stable/book/ch11-01-writing-tests.html#checking-for-pa [[exercises]] name = "iterators1" dir = "18_iterators" -mode = "test" hint = """ Step 1: @@ -990,7 +951,6 @@ https://doc.rust-lang.org/std/iter/trait.Iterator.html for some ideas. [[exercises]] name = "iterators2" dir = "18_iterators" -mode = "test" hint = """ Step 1: @@ -1016,7 +976,6 @@ powerful and very general. Rust just needs to know the desired type.""" [[exercises]] name = "iterators3" dir = "18_iterators" -mode = "test" hint = """ The `divide` function needs to return the correct error when even division is not possible. @@ -1035,7 +994,6 @@ powerful! It can make the solution to this exercise infinitely easier.""" [[exercises]] name = "iterators4" dir = "18_iterators" -mode = "test" hint = """ In an imperative language, you might write a `for` loop that updates a mutable variable. Or, you might write code utilizing recursion and a match clause. In @@ -1047,7 +1005,6 @@ Hint 2: Check out the `fold` and `rfold` methods!""" [[exercises]] name = "iterators5" dir = "18_iterators" -mode = "test" hint = """ The documentation for the `std::iter::Iterator` trait contains numerous methods that would be helpful here. @@ -1066,7 +1023,6 @@ a different method that could make your code more compact than using `fold`.""" [[exercises]] name = "box1" dir = "19_smart_pointers" -mode = "test" hint = """ Step 1: @@ -1090,7 +1046,6 @@ definition and try other types! [[exercises]] name = "rc1" dir = "19_smart_pointers" -mode = "test" hint = """ This is a straightforward exercise to use the `Rc` type. Each `Planet` has ownership of the `Sun`, and uses `Rc::clone()` to increment the reference count @@ -1109,7 +1064,7 @@ See more at: https://doc.rust-lang.org/book/ch15-04-rc.html [[exercises]] name = "arc1" dir = "19_smart_pointers" -mode = "run" +test = false hint = """ Make `shared_numbers` be an `Arc` from the numbers vector. Then, in order to avoid creating a copy of `numbers`, you'll need to create `child_numbers` @@ -1127,7 +1082,6 @@ https://doc.rust-lang.org/stable/book/ch16-00-concurrency.html [[exercises]] name = "cow1" dir = "19_smart_pointers" -mode = "test" hint = """ If `Cow` already owns the data it doesn't need to clone it when `to_mut()` is called. @@ -1141,7 +1095,7 @@ on the `Cow` type. [[exercises]] name = "threads1" dir = "20_threads" -mode = "run" +test = false hint = """ `JoinHandle` is a struct that is returned from a spawned thread: https://doc.rust-lang.org/std/thread/fn.spawn.html @@ -1159,7 +1113,7 @@ https://doc.rust-lang.org/std/thread/struct.JoinHandle.html [[exercises]] name = "threads2" dir = "20_threads" -mode = "run" +test = false hint = """ `Arc` is an Atomic Reference Counted pointer that allows safe, shared access to **immutable** data. But we want to *change* the number of `jobs_completed` @@ -1181,7 +1135,6 @@ https://doc.rust-lang.org/book/ch16-03-shared-state.html#sharing-a-mutext-betwee [[exercises]] name = "threads3" dir = "20_threads" -mode = "test" hint = """ An alternate way to handle concurrency between threads is to use an `mpsc` (multiple producer, single consumer) channel to communicate. @@ -1200,7 +1153,7 @@ See https://doc.rust-lang.org/book/ch16-02-message-passing.html for more info. [[exercises]] name = "macros1" dir = "21_macros" -mode = "run" +test = false hint = """ When you call a macro, you need to add something special compared to a regular function call. If you're stuck, take a look at what's inside @@ -1209,7 +1162,7 @@ regular function call. If you're stuck, take a look at what's inside [[exercises]] name = "macros2" dir = "21_macros" -mode = "run" +test = false hint = """ Macros don't quite play by the same rules as the rest of Rust, in terms of what's available where. @@ -1220,7 +1173,7 @@ Unlike other things in Rust, the order of "where you define a macro" versus [[exercises]] name = "macros3" dir = "21_macros" -mode = "run" +test = false hint = """ In order to use a macro outside of its module, you need to do something special to the module to lift the macro out into its parent. @@ -1231,7 +1184,7 @@ exported macros, if you've seen any of those around.""" [[exercises]] name = "macros4" dir = "21_macros" -mode = "run" +test = false hint = """ You only need to add a single character to make this compile. @@ -1248,7 +1201,8 @@ https://veykril.github.io/tlborm/""" [[exercises]] name = "clippy1" dir = "22_clippy" -mode = "clippy" +test = false +strict_clippy = true hint = """ Rust stores the highest precision version of any long or infinite precision mathematical constants in the Rust standard library: @@ -1264,14 +1218,16 @@ appropriate replacement constant from `std::f32::consts`...""" [[exercises]] name = "clippy2" dir = "22_clippy" -mode = "clippy" +test = false +strict_clippy = true hint = """ `for` loops over `Option` values are more clearly expressed as an `if let`""" [[exercises]] name = "clippy3" dir = "22_clippy" -mode = "clippy" +test = false +strict_clippy = true hint = "No hints this time!" # TYPE CONVERSIONS @@ -1279,7 +1235,6 @@ hint = "No hints this time!" [[exercises]] name = "using_as" dir = "23_conversions" -mode = "test" hint = """ Use the `as` operator to cast one of the operands in the last line of the `average` function into the expected return type.""" @@ -1287,14 +1242,12 @@ Use the `as` operator to cast one of the operands in the last line of the [[exercises]] name = "from_into" dir = "23_conversions" -mode = "test" hint = """ Follow the steps provided right before the `From` implementation""" [[exercises]] name = "from_str" dir = "23_conversions" -mode = "test" hint = """ The implementation of `FromStr` should return an `Ok` with a `Person` object, or an `Err` with an error if the string is not valid. @@ -1315,7 +1268,6 @@ https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reen [[exercises]] name = "try_from_into" dir = "23_conversions" -mode = "test" hint = """ Follow the steps provided right before the `TryFrom` implementation. You can also use the example at @@ -1338,6 +1290,5 @@ Challenge: Can you make the `TryFrom` implementations generic over many integer [[exercises]] name = "as_ref_mut" dir = "23_conversions" -mode = "test" hint = """ Add `AsRef` or `AsMut` as a trait bound to the functions.""" diff --git a/src/app_state.rs b/src/app_state.rs index 11ac8ee..476b5a9 100644 --- a/src/app_state.rs +++ b/src/app_state.rs @@ -112,7 +112,8 @@ impl AppState { dir, name, path, - mode: exercise_info.mode, + test: exercise_info.test, + strict_clippy: exercise_info.strict_clippy, hint, done: false, } @@ -329,8 +330,6 @@ impl AppState { } writeln!(writer, "{}", "ok".green())?; - - output.clear(); } writer.execute(Clear(ClearType::All))?; diff --git a/src/dev/new.rs b/src/dev/new.rs index 82aba42..8f87010 100644 --- a/src/dev/new.rs +++ b/src/dev/new.rs @@ -99,10 +99,15 @@ name = "???" # Otherwise, the path is `exercises/NAME.rs` # dir = "???" -# The mode to run the exercise in. -# The mode "test" (preferred) runs the exercise's tests. -# The mode "run" only checks if the exercise compiles and runs it. -mode = "test" +# Rustlings expects the exercise to contain tests and run them. +# You can optionally disable testing by setting `test` to `false` (the default is `true`). +# In that case, the exercise will be considered done when it just successfully compiles. +# test = true + +# Rustlings will always run Clippy on exercises. +# You can optionally set `strict_clippy` to `true` (the default is `false`) to only consider +# the exercise as done when there are no warnings left. +# strict_clippy = false # A multi-line hint to be shown to users on request. hint = """???""" diff --git a/src/exercise.rs b/src/exercise.rs index 17cc8d7..366dc2b 100644 --- a/src/exercise.rs +++ b/src/exercise.rs @@ -3,24 +3,38 @@ use crossterm::style::{style, StyledContent, Stylize}; use std::{ fmt::{self, Display, Formatter}, io::{Read, Write}, - process::Command, + process::{Command, Stdio}, }; -use crate::{in_official_repo, info_file::Mode, terminal_link::TerminalFileLink, DEBUG_PROFILE}; +use crate::{in_official_repo, terminal_link::TerminalFileLink, DEBUG_PROFILE}; // TODO pub const OUTPUT_CAPACITY: usize = 1 << 12; -fn run_command(mut cmd: Command, cmd_description: &str, output: &mut Vec) -> Result { +fn run_command( + mut cmd: Command, + cmd_description: &str, + output: &mut Vec, + stderr: bool, +) -> Result { let (mut reader, writer) = os_pipe::pipe().with_context(|| { format!("Failed to create a pipe to run the command `{cmd_description}``") })?; + let (stdout, stderr) = if stderr { + ( + Stdio::from(writer.try_clone().with_context(|| { + format!("Failed to clone the pipe writer for the command `{cmd_description}`") + })?), + Stdio::from(writer), + ) + } else { + (Stdio::from(writer), Stdio::null()) + }; + let mut handle = cmd - .stdout(writer.try_clone().with_context(|| { - format!("Failed to clone the pipe writer for the command `{cmd_description}`") - })?) - .stderr(writer) + .stdout(stdout) + .stderr(stderr) .spawn() .with_context(|| format!("Failed to run the command `{cmd_description}`"))?; @@ -45,8 +59,8 @@ pub struct Exercise { pub name: &'static str, // Exercise's path pub path: &'static str, - // The mode of the exercise - pub mode: Mode, + pub test: bool, + pub strict_clippy: bool, // The hint text associated with the exercise pub hint: String, pub done: bool, @@ -54,10 +68,22 @@ pub struct Exercise { impl Exercise { fn run_bin(&self, output: &mut Vec) -> Result { - writeln!(output, "{}", "Output".bold().magenta().underlined())?; + writeln!(output, "{}", "Output".underlined())?; let bin_path = format!("target/debug/{}", self.name); - run_command(Command::new(&bin_path), &bin_path, output) + let success = run_command(Command::new(&bin_path), &bin_path, output, true)?; + + if !success { + writeln!( + output, + "{}", + "The exercise didn't run successfully (nonzero exit code)" + .bold() + .red() + )?; + } + + Ok(success) } fn cargo_cmd( @@ -67,6 +93,7 @@ impl Exercise { cmd_description: &str, output: &mut Vec, dev: bool, + stderr: bool, ) -> Result { let mut cmd = Command::new("cargo"); cmd.arg(command); @@ -86,25 +113,7 @@ impl Exercise { .arg(self.name) .args(args); - run_command(cmd, cmd_description, output) - } - - fn cargo_cmd_with_bin_output( - &self, - command: &str, - args: &[&str], - cmd_description: &str, - output: &mut Vec, - dev: bool, - ) -> Result { - // Discard the output of `cargo build` because it will be shown again by the Cargo command. - output.clear(); - - let cargo_cmd_success = self.cargo_cmd(command, args, cmd_description, output, dev)?; - - let run_success = self.run_bin(output)?; - - Ok(cargo_cmd_success && run_success) + run_command(cmd, cmd_description, output, stderr) } pub fn run(&self, output: &mut Vec) -> Result { @@ -113,35 +122,49 @@ impl Exercise { // Developing the official Rustlings. let dev = DEBUG_PROFILE && in_official_repo(); - let build_success = self.cargo_cmd("build", &[], "cargo build …", output, dev)?; + let build_success = self.cargo_cmd("build", &[], "cargo build …", output, dev, true)?; if !build_success { return Ok(false); } - match self.mode { - Mode::Run => self.run_bin(output), - Mode::Test => self.cargo_cmd_with_bin_output( - "test", - &[ - "--", - "--color", - "always", - "--nocapture", - "--format", - "pretty", - ], - "cargo test …", - output, - dev, - ), - Mode::Clippy => self.cargo_cmd_with_bin_output( - "clippy", - &["--", "-D", "warnings"], - "cargo clippy …", - output, - dev, - ), + // Discard the output of `cargo build` because it will be shown again by the Cargo command. + output.clear(); + + let clippy_args: &[&str] = if self.strict_clippy { + &["--", "-D", "warnings"] + } else { + &[] + }; + let clippy_success = + self.cargo_cmd("clippy", clippy_args, "cargo clippy …", output, dev, true)?; + if !clippy_success { + return Ok(false); + } + + if !self.test { + return self.run_bin(output); } + + let test_success = self.cargo_cmd( + "test", + &[ + "--", + "--color", + "always", + "--nocapture", + "--format", + "pretty", + ], + "cargo test …", + output, + dev, + // Hide warnings because they are shown by Clippy. + false, + )?; + + let run_success = self.run_bin(output)?; + + Ok(test_success && run_success) } pub fn terminal_link(&self) -> StyledContent> { diff --git a/src/info_file.rs b/src/info_file.rs index 6938cd0..dbe4f08 100644 --- a/src/info_file.rs +++ b/src/info_file.rs @@ -2,18 +2,6 @@ use anyhow::{bail, Context, Error, Result}; use serde::Deserialize; use std::{fs, io::ErrorKind}; -// The mode of the exercise. -#[derive(Deserialize, Copy, Clone)] -#[serde(rename_all = "lowercase")] -pub enum Mode { - // The exercise should be compiled as a binary - Run, - // The exercise should be compiled as a test harness - Test, - // The exercise should be linted with clippy - Clippy, -} - // Deserialized from the `info.toml` file. #[derive(Deserialize)] pub struct ExerciseInfo { @@ -21,11 +9,17 @@ pub struct ExerciseInfo { pub name: String, // The exercise's directory inside the `exercises` directory pub dir: Option, - // The mode of the exercise - pub mode: Mode, + #[serde(default = "default_true")] + pub test: bool, + #[serde(default)] + pub strict_clippy: bool, // The hint text associated with the exercise pub hint: String, } +#[inline] +const fn default_true() -> bool { + true +} impl ExerciseInfo { pub fn path(&self) -> String { diff --git a/tests/fixture/failure/info.toml b/tests/fixture/failure/info.toml index ef99a07..554607a 100644 --- a/tests/fixture/failure/info.toml +++ b/tests/fixture/failure/info.toml @@ -2,10 +2,9 @@ format_version = 1 [[exercises]] name = "compFailure" -mode = "run" +test = false hint = "" [[exercises]] name = "testFailure" -mode = "test" hint = "Hello!" diff --git a/tests/fixture/state/info.toml b/tests/fixture/state/info.toml index eec24ea..ff0b932 100644 --- a/tests/fixture/state/info.toml +++ b/tests/fixture/state/info.toml @@ -2,15 +2,14 @@ format_version = 1 [[exercises]] name = "pending_exercise" -mode = "run" +test = false hint = """""" [[exercises]] name = "pending_test_exercise" -mode = "test" hint = """""" [[exercises]] name = "finished_exercise" -mode = "run" +test = false hint = """""" diff --git a/tests/fixture/success/info.toml b/tests/fixture/success/info.toml index 88650ec..d66d7d4 100644 --- a/tests/fixture/success/info.toml +++ b/tests/fixture/success/info.toml @@ -2,10 +2,9 @@ format_version = 1 [[exercises]] name = "compSuccess" -mode = "run" +test = false hint = """""" [[exercises]] name = "testSuccess" -mode = "test" hint = """""" -- cgit v1.2.3 From d26f47ddddaabcde36d5cb02ec220ccd1c141f10 Mon Sep 17 00:00:00 2001 From: mo8it Date: Thu, 25 Apr 2024 03:27:41 +0200 Subject: Fix tests --- tests/fixture/failure/exercises/compNoExercise.rs | 3 +-- tests/fixture/failure/exercises/testFailure.rs | 2 ++ tests/fixture/failure/exercises/testNotPassed.rs | 2 ++ tests/fixture/state/exercises/finished_exercise.rs | 6 +----- tests/fixture/state/exercises/pending_exercise.rs | 6 +----- tests/fixture/state/exercises/pending_test_exercise.rs | 2 ++ tests/fixture/success/exercises/testSuccess.rs | 2 ++ 7 files changed, 11 insertions(+), 12 deletions(-) (limited to 'tests/fixture/failure') diff --git a/tests/fixture/failure/exercises/compNoExercise.rs b/tests/fixture/failure/exercises/compNoExercise.rs index f79c691..f328e4d 100644 --- a/tests/fixture/failure/exercises/compNoExercise.rs +++ b/tests/fixture/failure/exercises/compNoExercise.rs @@ -1,2 +1 @@ -fn main() { -} +fn main() {} diff --git a/tests/fixture/failure/exercises/testFailure.rs b/tests/fixture/failure/exercises/testFailure.rs index b33a5d2..fcbcf90 100644 --- a/tests/fixture/failure/exercises/testFailure.rs +++ b/tests/fixture/failure/exercises/testFailure.rs @@ -1,3 +1,5 @@ +fn main() {} + #[test] fn passing() { asset!(true); diff --git a/tests/fixture/failure/exercises/testNotPassed.rs b/tests/fixture/failure/exercises/testNotPassed.rs index a9fe88d..de0d61c 100644 --- a/tests/fixture/failure/exercises/testNotPassed.rs +++ b/tests/fixture/failure/exercises/testNotPassed.rs @@ -1,3 +1,5 @@ +fn main() {} + #[test] fn not_passing() { assert!(false); diff --git a/tests/fixture/state/exercises/finished_exercise.rs b/tests/fixture/state/exercises/finished_exercise.rs index 016b827..f328e4d 100644 --- a/tests/fixture/state/exercises/finished_exercise.rs +++ b/tests/fixture/state/exercises/finished_exercise.rs @@ -1,5 +1 @@ -// fake_exercise - -fn main() { - -} +fn main() {} diff --git a/tests/fixture/state/exercises/pending_exercise.rs b/tests/fixture/state/exercises/pending_exercise.rs index 016b827..f328e4d 100644 --- a/tests/fixture/state/exercises/pending_exercise.rs +++ b/tests/fixture/state/exercises/pending_exercise.rs @@ -1,5 +1 @@ -// fake_exercise - -fn main() { - -} +fn main() {} diff --git a/tests/fixture/state/exercises/pending_test_exercise.rs b/tests/fixture/state/exercises/pending_test_exercise.rs index 2002ef1..718e1db 100644 --- a/tests/fixture/state/exercises/pending_test_exercise.rs +++ b/tests/fixture/state/exercises/pending_test_exercise.rs @@ -1,2 +1,4 @@ +fn main() {} + #[test] fn it_works() {} diff --git a/tests/fixture/success/exercises/testSuccess.rs b/tests/fixture/success/exercises/testSuccess.rs index 7139b50..4296cf6 100644 --- a/tests/fixture/success/exercises/testSuccess.rs +++ b/tests/fixture/success/exercises/testSuccess.rs @@ -1,3 +1,5 @@ +fn main() {} + #[test] fn passing() { println!("THIS TEST TOO SHALL PASS"); -- cgit v1.2.3