mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-12-26 00:11:49 +02:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ff3f7ae13 | ||
|
|
2b80f6ed41 | ||
|
|
3ab084a421 | ||
|
|
495174ff7c | ||
|
|
b049fa2c84 | ||
|
|
052f0aa7d4 | ||
|
|
60393999b8 | ||
|
|
b3a3351e8e | ||
|
|
86b5c08b9b | ||
|
|
dab90f7b91 | ||
|
|
71d31256a6 | ||
|
|
3b6d5c3aaa | ||
|
|
7ce42941ea | ||
|
|
3f8171475c | ||
|
|
b135b589e0 | ||
|
|
05ca3d77f7 | ||
|
|
6deee7e3e9 | ||
|
|
9dc404077a | ||
|
|
30e6af6069 | ||
|
|
9788496a85 | ||
|
|
6d3a412d47 | ||
|
|
700b236f4d | ||
|
|
bc22ec382f | ||
|
|
135e5d47a7 | ||
|
|
0f8001ea44 | ||
|
|
5b6e23c323 | ||
|
|
29b30ec946 | ||
|
|
76be5e4e99 |
11
.travis.yml
11
.travis.yml
@@ -1,11 +0,0 @@
|
||||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
script: cargo test --verbose
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
fast_finish: true
|
||||
cache: cargo
|
||||
23
CHANGELOG.md
23
CHANGELOG.md
@@ -1,3 +1,26 @@
|
||||
<a name="3.0.0"></a>
|
||||
## 3.0.0 (2020-04-11)
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
* make "compile" exercises print output (#278) ([3b6d5c](https://github.com/fmoko/rustlings/commit/3b6d5c3aaa27a242a832799eb66e96897d26fde3))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* **primitive_types:** revert primitive_types4 (#296) ([b3a3351e](https://github.com/rust-lang/rustlings/commit/b3a3351e8e6a0bdee07077d7b0382953821649ae))
|
||||
* **run:** compile clippy exercise files (#295) ([3ab084a4](https://github.com/rust-lang/rustlings/commit/3ab084a421c0f140ae83bf1fc3f47b39342e7373))
|
||||
* **conversions:**
|
||||
* add additional test to meet exercise rules (#284) ([bc22ec3](https://github.com/fmoko/rustlings/commit/bc22ec382f843347333ef1301fc1bad773657f38))
|
||||
* remove duplicate not done comment (#292) ([dab90f](https://github.com/fmoko/rustlings/commit/dab90f7b91a6000fe874e3d664f244048e5fa342))
|
||||
* don't hardcode documentation version for traits (#288) ([30e6af](https://github.com/fmoko/rustlings/commit/30e6af60690c326fb5d3a9b7335f35c69c09137d))
|
||||
|
||||
#### Features
|
||||
|
||||
* add Option2 exercise (#290) ([86b5c08b](https://github.com/rust-lang/rustlings/commit/86b5c08b9bea1576127a7c5f599f5752072c087d))
|
||||
* add excercise for option (#282) ([135e5d47](https://github.com/rust-lang/rustlings/commit/135e5d47a7c395aece6f6022117fb20c82f2d3d4))
|
||||
* add new exercises for generics (#280) ([76be5e4e](https://github.com/rust-lang/rustlings/commit/76be5e4e991160f5fd9093f03ee2ba260e8f7229))
|
||||
* **ci:** add buildkite config ([b049fa2c](https://github.com/rust-lang/rustlings/commit/b049fa2c84dba0f0c8906ac44e28fd45fba51a71))
|
||||
|
||||
<a name="2.2.1"></a>
|
||||
### 2.2.1 (2020-02-27)
|
||||
|
||||
|
||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -592,7 +592,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustlings"
|
||||
version = "2.2.0"
|
||||
version = "2.2.1"
|
||||
dependencies = [
|
||||
"assert_cmd 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "rustlings"
|
||||
version = "2.2.1"
|
||||
authors = ["Marisa <mokou@posteo.de>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com"]
|
||||
version = "3.0.0"
|
||||
authors = ["Marisa <mokou@posteo.de>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||

|
||||
|
||||
# rustlings 🦀❤️
|
||||
# rustlings 🦀❤️ [](https://buildkite.com/mokou/rustlings)
|
||||
|
||||
Greetings and welcome to `rustlings`. This project contains small exercises to get you used to reading and writing Rust code. This includes reading and responding to compiler messages!
|
||||
|
||||
@@ -54,7 +54,7 @@ Basically: Clone the repository, checkout to the latest tag, run `cargo install`
|
||||
```bash
|
||||
git clone https://github.com/rust-lang/rustlings
|
||||
cd rustlings
|
||||
git checkout tags/2.2.1 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
|
||||
git checkout tags/3.0.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
|
||||
cargo install --force --path .
|
||||
```
|
||||
|
||||
|
||||
5
buildkite.yml
Normal file
5
buildkite.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
steps:
|
||||
- label: "Test with stable"
|
||||
command: rustup run stable cargo test
|
||||
- label: "Test with beta"
|
||||
command: rustup run beta cargo test
|
||||
@@ -9,7 +9,6 @@ fn byte_counter<T>(arg: T) -> usize {
|
||||
arg.as_ref().as_bytes().len()
|
||||
}
|
||||
|
||||
// I AM NOT DONE
|
||||
// Obtain the number of characters (not bytes) in the given argument
|
||||
// Add the AsRef trait appropriately as a trait bound
|
||||
fn char_counter<T>(arg: T) -> usize {
|
||||
|
||||
@@ -70,4 +70,11 @@ mod tests {
|
||||
assert_eq!(p.name, "Mark");
|
||||
assert_eq!(p.age, 20);
|
||||
}
|
||||
#[test]
|
||||
fn test_bad_age() {
|
||||
// Test that "Mark.twenty" will return the default person due to an error in parsing age
|
||||
let p = Person::from("Mark,twenty");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
}
|
||||
|
||||
7
exercises/generics/README.md
Normal file
7
exercises/generics/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
### Generics
|
||||
|
||||
In this section you'll learn about saving yourself many lines of code with generics!
|
||||
|
||||
### Book Sections
|
||||
|
||||
- [Generic Data Types](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html)
|
||||
10
exercises/generics/generics1.rs
Normal file
10
exercises/generics/generics1.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
// This shopping list program isn't compiling!
|
||||
// Use your knowledge of generics to fix it.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let mut shopping_list: Vec<?> = Vec::new();
|
||||
shopping_list.push("milk");
|
||||
}
|
||||
|
||||
30
exercises/generics/generics2.rs
Normal file
30
exercises/generics/generics2.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
// This powerful wrapper provides the ability to store a positive integer value.
|
||||
// Rewrite it using generics so that it supports wrapping ANY type.
|
||||
|
||||
// I AM NOT DONE
|
||||
struct Wrapper<u32> {
|
||||
value: u32
|
||||
}
|
||||
|
||||
impl<u32> Wrapper<u32> {
|
||||
pub fn new(value: u32) -> Self {
|
||||
Wrapper { value }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn store_u32_in_wrapper() {
|
||||
assert_eq!(Wrapper::new(42).value, 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn store_str_in_wrapper() {
|
||||
// TODO: Delete this assert and uncomment the one below once you have finished the exercise.
|
||||
assert!(false);
|
||||
// assert_eq!(Wrapper::new("Foo").value, "Foo");
|
||||
}
|
||||
}
|
||||
46
exercises/generics/generics3.rs
Normal file
46
exercises/generics/generics3.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
// An imaginary magical school has a new report card generation system written in rust!
|
||||
// Currently the system only supports creating report cards where the student's grade
|
||||
// is represented numerically (e.g. 1.0 -> 5.5). However, the school also issues alphabetical grades
|
||||
// (A+ -> F-) and needs to be able to print both types of report card!
|
||||
|
||||
// Make the necessary code changes to support alphabetical report cards, thereby making the second
|
||||
// test pass.
|
||||
|
||||
// I AM NOT DONE
|
||||
pub struct ReportCard {
|
||||
pub grade: f32,
|
||||
pub student_name: String,
|
||||
pub student_age: u8,
|
||||
}
|
||||
|
||||
impl ReportCard {
|
||||
pub fn print(&self) -> String {
|
||||
format!("{} ({}) - achieved a grade of {}", &self.student_name, &self.student_age, &self.grade)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn generate_numeric_report_card() {
|
||||
let report_card = ReportCard {
|
||||
grade: 2.1,
|
||||
student_name: "Tom Wriggle".to_string(),
|
||||
student_age: 12,
|
||||
};
|
||||
assert_eq!(report_card.print(), "Tom Wriggle (12) - achieved a grade of 2.1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_alphabetic_report_card() {
|
||||
// TODO: Make sure to change the grade here after you finish the exercise.
|
||||
let report_card = ReportCard {
|
||||
grade: 2.1,
|
||||
student_name: "Gary Plotter".to_string(),
|
||||
student_age: 11,
|
||||
};
|
||||
assert_eq!(report_card.print(), "Gary Plotter (11) - achieved a grade of A+");
|
||||
}
|
||||
}
|
||||
9
exercises/option/README.md
Normal file
9
exercises/option/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
### Option
|
||||
|
||||
#### Book Sections
|
||||
|
||||
To learn about Option<T>, check out these links:
|
||||
|
||||
- [Option Enum Format](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-enum-definitions)
|
||||
- [Option Module Documentation](https://doc.rust-lang.org/std/option/)
|
||||
- [Option Enum Documentation](https://doc.rust-lang.org/std/option/enum.Option.html)
|
||||
23
exercises/option/option1.rs
Normal file
23
exercises/option/option1.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
// option1.rs
|
||||
// Make me compile! Execute `rustlings hint option1` for hints
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// you can modify anything EXCEPT for this function's sig
|
||||
fn print_number(maybe_number: Option<u16>) {
|
||||
println!("printing: {}", maybe_number.unwrap());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
print_number(13);
|
||||
print_number(99);
|
||||
|
||||
let mut numbers: [Option<u16>; 5];
|
||||
for iter in 0..5 {
|
||||
let number_to_add: u16 = {
|
||||
((iter * 5) + 2) / (4 * 16)
|
||||
};
|
||||
|
||||
numbers[iter] = number_to_add;
|
||||
}
|
||||
}
|
||||
25
exercises/option/option2.rs
Normal file
25
exercises/option/option2.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
// option2.rs
|
||||
// Make me compile! Execute `rustlings hint option2` for hints
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let optional_value = Some(String::from("rustlings"));
|
||||
// Make this an if let statement whose value is "Some" type
|
||||
value = optional_value {
|
||||
println!("the value of optional value is: {}", value);
|
||||
} else {
|
||||
println!("The optional value doesn't contain anything!");
|
||||
}
|
||||
|
||||
let mut optional_values_vec: Vec<Option<i8>> = Vec::new();
|
||||
for x in 1..10 {
|
||||
optional_values_vec.push(Some(x));
|
||||
}
|
||||
|
||||
// make this a while let statement - remember that vector.pop also adds another layer of Option<T>
|
||||
// You can stack `Option<T>`'s into while let and if let
|
||||
value = optional_values_vec.pop() {
|
||||
println!("current value: {}", value);
|
||||
}
|
||||
}
|
||||
68
info.toml
68
info.toml
@@ -511,14 +511,32 @@ https://doc.rust-lang.org/std/result/#results-must-be-used"""
|
||||
|
||||
[[exercises]]
|
||||
name = "option1"
|
||||
path = "exercises/error_handling/option1.rs"
|
||||
mode = "test"
|
||||
path = "exercises/option/option1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Try using a `match` statement where the arms are `Some(thing)` and `None`.
|
||||
Or set a default value to print out if you get `None` by using the
|
||||
function `unwrap_or`.
|
||||
Or use an `if let` statement on the result of `pop()` to both destructure
|
||||
a `Some` value and only print out something if we have a value!"""
|
||||
Check out some functions of Option:
|
||||
is_some
|
||||
is_none
|
||||
unwrap
|
||||
|
||||
and:
|
||||
pattern matching
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "option2"
|
||||
path = "exercises/option/option2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
check out:
|
||||
https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html
|
||||
https://doc.rust-lang.org/rust-by-example/flow_control/while_let.html
|
||||
|
||||
Remember that Options can be stacked in if let and while let.
|
||||
For example: Some(Some(variable)) = variable2
|
||||
|
||||
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "result1"
|
||||
@@ -610,7 +628,7 @@ path = "exercises/traits/traits1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
A discussion about Traits in Rust can be found at:
|
||||
https://doc.rust-lang.org/1.30.0/book/second-edition/ch10-02-traits.html
|
||||
https://doc.rust-lang.org/book/ch10-02-traits.html
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
@@ -624,6 +642,38 @@ Try mutating the incoming string vector.
|
||||
Vectors provide suitable methods for adding an element at the end. See
|
||||
the documentation at: https://doc.rust-lang.org/std/vec/struct.Vec.html"""
|
||||
|
||||
# Generics
|
||||
|
||||
[[exercises]]
|
||||
name = "generics1"
|
||||
path = "exercises/generics/generics1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Vectors in rust make use of generics to create dynamically sized arrays of any type.
|
||||
You need to tell the compiler what type we are pushing onto this vector."""
|
||||
|
||||
[[exercises]]
|
||||
name = "generics2"
|
||||
path = "exercises/generics/generics2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Think carefully about what we need to do here. Currently we are wrapping only values of
|
||||
type 'u32'. Maybe we need to update the explicit references to this data type somehow?
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "generics3"
|
||||
path = "exercises/generics/generics3.rs"
|
||||
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 - you may also need this: "use std::fmt::Display;"
|
||||
|
||||
This is definitely harder than the last two exercises! You need to think about not only making the
|
||||
ReportCard struct generic, but also the correct property - you will need to change the implementation
|
||||
of the struct slightly too...you can do it!
|
||||
"""
|
||||
|
||||
# THREADS
|
||||
|
||||
[[exercises]]
|
||||
@@ -701,4 +751,4 @@ path = "exercises/conversions/from_str.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
If you've already solved try_from_into.rs, then this is almost a copy-paste.
|
||||
Otherwise, go ahead and solve try_from_into.rs first."""
|
||||
Otherwise, go ahead and solve try_from_into.rs first."""
|
||||
|
||||
@@ -98,6 +98,15 @@ path = "{}.rs""#,
|
||||
);
|
||||
fs::write(CLIPPY_CARGO_TOML_PATH, cargo_toml)
|
||||
.expect("Failed to write 📎 Clippy 📎 Cargo.toml file.");
|
||||
// To support the ability to run the clipy exercises, build
|
||||
// an executable, in addition to running clippy. With a
|
||||
// compilation failure, this would silently fail. But we expect
|
||||
// clippy to reflect the same failure while compiling later.
|
||||
Command::new("rustc")
|
||||
.args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
.output()
|
||||
.expect("Failed to compile!");
|
||||
// Due to an issue with Clippy, a cargo clean is required to catch all lints.
|
||||
// See https://github.com/rust-lang/rust-clippy/issues/2604
|
||||
// This is already fixed on master branch. See this issue to track merging into Cargo:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::exercise::{Exercise, Mode, State};
|
||||
use crate::exercise::{CompiledExercise, Exercise, Mode, State};
|
||||
use console::style;
|
||||
use indicatif::ProgressBar;
|
||||
|
||||
@@ -6,7 +6,7 @@ pub fn verify<'a>(start_at: impl IntoIterator<Item = &'a Exercise>) -> Result<()
|
||||
for exercise in start_at {
|
||||
let compile_result = match exercise.mode {
|
||||
Mode::Test => compile_and_test(&exercise, RunMode::Interactive),
|
||||
Mode::Compile => compile_only(&exercise),
|
||||
Mode::Compile => compile_and_run_interactively(&exercise),
|
||||
Mode::Clippy => compile_only(&exercise),
|
||||
};
|
||||
if !compile_result.unwrap_or(false) {
|
||||
@@ -30,23 +30,37 @@ fn compile_only(exercise: &Exercise) -> Result<bool, ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
let compilation_result = exercise.compile();
|
||||
|
||||
let _ = compile(&exercise, &progress_bar)?;
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
match compilation_result {
|
||||
Ok(_) => {
|
||||
success!("Successfully compiled {}!", exercise);
|
||||
Ok(prompt_for_completion(&exercise))
|
||||
}
|
||||
success!("Successfully compiled {}!", exercise);
|
||||
Ok(prompt_for_completion(&exercise, None))
|
||||
}
|
||||
|
||||
fn compile_and_run_interactively(exercise: &Exercise) -> Result<bool, ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
|
||||
let compilation = compile(&exercise, &progress_bar)?;
|
||||
|
||||
progress_bar.set_message(format!("Running {}...", exercise).as_str());
|
||||
let result = compilation.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
let output = match result {
|
||||
Ok(output) => output,
|
||||
Err(output) => {
|
||||
warn!(
|
||||
"Compilation of {} failed! Compiler error message:\n",
|
||||
exercise
|
||||
);
|
||||
println!("{}", output.stderr);
|
||||
Err(())
|
||||
warn!("Ran {} with errors", exercise);
|
||||
println!("{}", output.stdout);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
success!("Successfully ran {}!", exercise);
|
||||
|
||||
Ok(prompt_for_completion(&exercise, Some(output.stdout)))
|
||||
}
|
||||
|
||||
fn compile_and_test(exercise: &Exercise, run_mode: RunMode) -> Result<bool, ()> {
|
||||
@@ -54,28 +68,15 @@ fn compile_and_test(exercise: &Exercise, run_mode: RunMode) -> Result<bool, ()>
|
||||
progress_bar.set_message(format!("Testing {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
|
||||
let compilation_result = exercise.compile();
|
||||
|
||||
let compilation = match compilation_result {
|
||||
Ok(compilation) => compilation,
|
||||
Err(output) => {
|
||||
progress_bar.finish_and_clear();
|
||||
warn!(
|
||||
"Compiling of {} failed! Please try again. Here's the output:",
|
||||
exercise
|
||||
);
|
||||
println!("{}", output.stderr);
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
let compilation = compile(exercise, &progress_bar)?;
|
||||
let result = compilation.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
match result {
|
||||
Ok(_) => {
|
||||
success!("Successfully tested {}", &exercise);
|
||||
if let RunMode::Interactive = run_mode {
|
||||
Ok(prompt_for_completion(&exercise))
|
||||
Ok(prompt_for_completion(&exercise, None))
|
||||
} else {
|
||||
Ok(true)
|
||||
}
|
||||
@@ -91,7 +92,27 @@ fn compile_and_test(exercise: &Exercise, run_mode: RunMode) -> Result<bool, ()>
|
||||
}
|
||||
}
|
||||
|
||||
fn prompt_for_completion(exercise: &Exercise) -> bool {
|
||||
fn compile<'a, 'b>(
|
||||
exercise: &'a Exercise,
|
||||
progress_bar: &'b ProgressBar,
|
||||
) -> Result<CompiledExercise<'a>, ()> {
|
||||
let compilation_result = exercise.compile();
|
||||
|
||||
match compilation_result {
|
||||
Ok(compilation) => Ok(compilation),
|
||||
Err(output) => {
|
||||
progress_bar.finish_and_clear();
|
||||
warn!(
|
||||
"Compiling of {} failed! Please try again. Here's the output:",
|
||||
exercise
|
||||
);
|
||||
println!("{}", output.stderr);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn prompt_for_completion(exercise: &Exercise, prompt_output: Option<String>) -> bool {
|
||||
let context = match exercise.state() {
|
||||
State::Done => return true,
|
||||
State::Pending(context) => context,
|
||||
@@ -106,6 +127,15 @@ fn prompt_for_completion(exercise: &Exercise) -> bool {
|
||||
println!("");
|
||||
println!("🎉 🎉 {} 🎉 🎉", success_msg);
|
||||
println!("");
|
||||
|
||||
if let Some(output) = prompt_output {
|
||||
println!("Output:");
|
||||
println!("{}", separator());
|
||||
println!("{}", output);
|
||||
println!("{}", separator());
|
||||
println!("");
|
||||
}
|
||||
|
||||
println!("You can keep working on this exercise,");
|
||||
println!(
|
||||
"or jump into the next one by removing the {} comment:",
|
||||
@@ -129,3 +159,7 @@ fn prompt_for_completion(exercise: &Exercise) -> bool {
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn separator() -> console::StyledObject<&'static str> {
|
||||
style("====================").bold()
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ fn verify_all_success() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_all_failure() {
|
||||
fn verify_fails_if_some_fails() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.arg("v")
|
||||
|
||||
Reference in New Issue
Block a user