Skip to content

Commit

Permalink
Be more consistent about tests vs. main
Browse files Browse the repository at this point in the history
The content slides all use `fn main`, with the exception of the testing
segment. But with this change, where it makes sense exercises use tests
instead, and not both tests and `fn main`.

A small change in `book.js` supports running tests when a code sample
does not have `fn main` but does have `#[test]`, so these work
naturally. Note, however, that this doesn't work for non-editable `rust`
text, as Highlightjs is responsible for running the playground in that
case. This means the exercises produce `No output.` when run, but the
solutions (which are editable) show the test results.
  • Loading branch information
djmitche committed Feb 14, 2025
1 parent 699c513 commit fa2124d
Show file tree
Hide file tree
Showing 18 changed files with 60 additions and 113 deletions.
5 changes: 0 additions & 5 deletions src/borrowing/exercise.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,12 @@ Copy the code below to <https://play.rust-lang.org/> and fill in the missing
method:

```rust
// TODO: remove this when you're done with your implementation.
#![allow(unused_variables, dead_code)]

{{#include ../../third_party/rust-on-exercism/health-statistics.rs:setup}}

{{#include ../../third_party/rust-on-exercism/health-statistics.rs:User_visit_doctor}}
todo!("Update a user's statistics based on measurements from a visit to the doctor")
}
}

{{#include ../../third_party/rust-on-exercism/health-statistics.rs:main}}

{{#include ../../third_party/rust-on-exercism/health-statistics.rs:tests}}
```
2 changes: 0 additions & 2 deletions src/control-flow-basics/exercise.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,5 @@ initial `n`.
todo!("Implement this")
}
{{#include exercise.rs:tests}}
{{#include exercise.rs:main}}
```
15 changes: 7 additions & 8 deletions src/control-flow-basics/exercise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,14 @@ fn collatz_length(mut n: i32) -> u32 {
len
}

// ANCHOR: tests
#[test]
fn test_collatz_length() {
assert_eq!(collatz_length(11), 15);
}
// ANCHOR_END: tests

// ANCHOR: main
fn main() {
println!("Length: {}", collatz_length(11));
println!("Length: {}", collatz_length(11)); // should be 15
}
// ANCHOR_END: main
// ANCHOR_END: solution

#[test]
fn test_collatz_length() {
assert_eq!(collatz_length(11), 15);
}
2 changes: 1 addition & 1 deletion src/error-handling/exercise.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Rewrite `eval` to instead use idiomatic error handling to handle this error case
and return an error when it occurs. We provide a simple `DivideByZeroError` type
to use as the error type for `eval`.

```rust,editable
```rust
{{#include exercise.rs:types}}

{{#include exercise.rs:eval}}
Expand Down
43 changes: 24 additions & 19 deletions src/error-handling/exercise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,25 +88,30 @@ fn eval(e: Expression) -> Result<i64, DivideByZeroError> {
// ANCHOR_END: solution

// ANCHOR: tests
#[test]
fn test_error() {
assert_eq!(
eval(Expression::Op {
op: Operation::Div,
left: Box::new(Expression::Value(99)),
right: Box::new(Expression::Value(0)),
}),
Err(DivideByZeroError)
);
}
#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_error() {
assert_eq!(
eval(Expression::Op {
op: Operation::Div,
left: Box::new(Expression::Value(99)),
right: Box::new(Expression::Value(0)),
}),
Err(DivideByZeroError)
);
}

fn main() {
let expr = Expression::Op {
op: Operation::Sub,
left: Box::new(Expression::Value(20)),
right: Box::new(Expression::Value(10)),
};
println!("expr: {expr:?}");
println!("result: {:?}", eval(expr));
#[test]
fn test_ok() {
let expr = Expression::Op {
op: Operation::Sub,
left: Box::new(Expression::Value(20)),
right: Box::new(Expression::Value(10)),
};
assert_eq!(eval(expr), Ok(10));
}
}
// ANCHOR_END: tests
2 changes: 0 additions & 2 deletions src/iterators/exercise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,3 @@ fn test_degenerate_cases() {
assert_eq!(offset_differences(1, empty), vec![]);
}
// ANCHOR_END: unit-tests

fn main() {}
4 changes: 2 additions & 2 deletions src/pattern-matching/exercise.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ evaluate to `85`. We represent this as a much bigger tree:

In code, we will represent the tree with two types:

```rust,editable
```rust
{{#include exercise.rs:Operation}}

{{#include exercise.rs:Expression}}
Expand All @@ -68,7 +68,7 @@ get the tests to pass one-by-one. You can also skip a test temporarily with
fn test_value() { .. }
```

```rust,editable
```rust
{{#include exercise.rs:Operation}}

{{#include exercise.rs:Expression}}
Expand Down
10 changes: 0 additions & 10 deletions src/pattern-matching/exercise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,3 @@ fn test_zeros() {
);
}
// ANCHOR_END: tests

fn main() {
let expr = Expression::Op {
op: Operation::Div,
left: Box::new(Expression::Value(10)),
right: Box::new(Expression::Value(2)),
};
println!("expr: {expr:?}");
println!("result: {:?}", eval(expr));
}
2 changes: 1 addition & 1 deletion src/smart-pointers/exercise.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Implement the following types, so that the given tests pass.
Extra Credit: implement an iterator over a binary tree that returns the values
in order.

```rust,editable,ignore
```rust,compile_fail
{{#include exercise.rs:types}}
// Implement `new`, `insert`, `len`, and `has` for `Subtree`.
Expand Down
8 changes: 0 additions & 8 deletions src/smart-pointers/exercise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,6 @@ impl<T: Ord> Node<T> {
}
}

fn main() {
let mut tree = BinaryTree::new();
tree.insert("foo");
assert_eq!(tree.len(), 1);
tree.insert("bar");
assert!(tree.has(&"foo"));
}

// ANCHOR: tests
#[cfg(test)]
mod tests {
Expand Down
2 changes: 1 addition & 1 deletion src/std-traits/exercise.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ characters, to ensure the result is still valid UTF-8.
// Implement the `Read` trait for `RotDecoder`.
{{#include exercise.rs:main }}
{{#include exercise.rs:tests }}
```

What happens if you chain two `RotDecoder` instances together, each rotating by
Expand Down
12 changes: 2 additions & 10 deletions src/std-traits/exercise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,7 @@ impl<R: Read> Read for RotDecoder<R> {
}
}

// ANCHOR: main
fn main() {
let mut rot =
RotDecoder { input: "Gb trg gb gur bgure fvqr!".as_bytes(), rot: 13 };
let mut result = String::new();
rot.read_to_string(&mut result).unwrap();
println!("{}", result);
}

// ANCHOR: tests
#[cfg(test)]
mod test {
use super::*;
Expand Down Expand Up @@ -72,4 +64,4 @@ mod test {
}
}
}
// ANCHOR_END: main
// ANCHOR_END: tests
10 changes: 1 addition & 9 deletions src/testing/exercise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.

// ANCHOR: solution
// This is the buggy version that appears in the problem.
#[cfg(never)]
// ANCHOR: luhn
Expand Down Expand Up @@ -40,6 +39,7 @@ pub fn luhn(cc_number: &str) -> bool {
// ANCHOR_END: luhn

// This is the solution and passes all of the tests below.
// ANCHOR: solution
pub fn luhn(cc_number: &str) -> bool {
let mut sum = 0;
let mut double = false;
Expand Down Expand Up @@ -69,14 +69,6 @@ pub fn luhn(cc_number: &str) -> bool {
digits >= 2 && sum % 10 == 0
}

fn main() {
let cc_number = "1234 5678 1234 5670";
println!(
"Is {cc_number} a valid credit card number? {}",
if luhn(cc_number) { "yes" } else { "no" }
);
}

// ANCHOR: unit-tests
#[cfg(test)]
mod test {
Expand Down
8 changes: 1 addition & 7 deletions src/testing/unit-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Rust and Cargo come with a simple unit test framework. Tests are marked with
`#[test]`. Unit tests are often put in a nested `tests` module, using
`#[cfg(test)]` to conditionally compile them only when building tests.

```rust,editable,ignore
```rust,editable
fn first_word(text: &str) -> &str {
match text.find(' ') {
Some(idx) => &text[..idx],
Expand Down Expand Up @@ -39,9 +39,3 @@ mod tests {

- This lets you unit test private helpers.
- The `#[cfg(test)]` attribute is only active when you run `cargo test`.

<details>

Run the tests in the playground in order to show their results.

</details>
5 changes: 0 additions & 5 deletions src/tuples-and-arrays/exercise.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,9 @@ Copy the code below to <https://play.rust-lang.org/> and implement the function.
This function only operates on 3x3 matrices.

```rust,should_panic
// TODO: remove this when you're done with your implementation.
#![allow(unused_variables, dead_code)]
{{#include exercise.rs:transpose}}
todo!()
}
{{#include exercise.rs:tests}}
{{#include exercise.rs:main}}
```
31 changes: 15 additions & 16 deletions src/tuples-and-arrays/exercise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,21 @@ fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {
result
}

// ANCHOR: tests
// ANCHOR: main
fn main() {
let matrix = [
[101, 102, 103], // <-- the comment makes rustfmt add a newline
[201, 202, 203],
[301, 302, 303],
];

println!("matrix: {:#?}", matrix);
let transposed = transpose(matrix);
println!("transposed: {:#?}", transposed);
}
// ANCHOR_END: main
// ANCHOR_END: solution

#[test]
fn test_transpose() {
let matrix = [
Expand All @@ -43,18 +57,3 @@ fn test_transpose() {
]
);
}
// ANCHOR_END: tests

// ANCHOR: main
fn main() {
let matrix = [
[101, 102, 103], // <-- the comment makes rustfmt add a newline
[201, 202, 203],
[301, 302, 303],
];

println!("matrix: {:#?}", matrix);
let transposed = transpose(matrix);
println!("transposed: {:#?}", transposed);
}
// ANCHOR_END: main
5 changes: 5 additions & 0 deletions theme/book.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ function playground_text(playground, hidden = true) {
crateType: "bin",
};

// If the code block has no `main` but does have tests, run those.
if (text.indexOf("fn main") === -1 && text.indexOf("#[test]") !== -1) {
params.tests = true;
}

if (text.indexOf("#![feature") !== -1) {
params.version = "nightly";
}
Expand Down
7 changes: 0 additions & 7 deletions third_party/rust-on-exercism/health-statistics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,6 @@ impl User {
}
}

// ANCHOR: main
fn main() {
let bob = User::new(String::from("Bob"), 32, 155.2);
println!("I'm {} and my age is {}", bob.name, bob.age);
}
// ANCHOR_END: main

// ANCHOR: tests
#[test]
fn test_visit() {
Expand Down

0 comments on commit fa2124d

Please sign in to comment.