diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9fb9974b77c7..a5ecccc37889 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,6 +8,27 @@ the [instructions in the README]. [instructions in the README]: README.md#building +## Writing Exercises + +Each segment ends with an exercise. Exercises are typically structured as an +`exercise.rs` containing the problem and solution. This is referenced from +`exercise.md` and `solution.md`, using `{{#include exercise.rs:anchor_name}}` to +match ANCHOR comments in the `exercise.rs` file. Each segment also has a +`Cargo.toml` file containing a `[[bin]]` or `[lib]` section referring to +`exercise.rs`, and that Cargo package is referenced from the workspace the root +`Cargo.toml`. The result is that `exercise.rs` is built and tested by +`cargo test`. + +For segments on day 1, exercises should use `fn main() { .. }` and `println!`, +with students visually verifying the correct output. On subsequent days, prefer +tests and omit `fn main() { .. }`. However, where tests would be difficult and +visual verification is more natural (such as in the Logger exercise), using +`fn main { .. }` is OK. + +Especially for exercises without tests, consider including tests in +`exercise.rs` that do not appear in either `exercise.md` or `solution.md`, as +these can ensure the solution is correct. + ## Testing We test the course material in several ways: diff --git a/src/borrowing/Cargo.toml b/src/borrowing/Cargo.toml index 4d791ebba5ad..df8e7ff941fb 100644 --- a/src/borrowing/Cargo.toml +++ b/src/borrowing/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2021" publish = false -[[bin]] +[lib] name = "borrowing" path = "../../third_party/rust-on-exercism/health-statistics.rs" diff --git a/src/borrowing/exercise.md b/src/borrowing/exercise.md index a6b9cd3a2e88..3d8a28f1f939 100644 --- a/src/borrowing/exercise.md +++ b/src/borrowing/exercise.md @@ -9,10 +9,7 @@ minutes: 20 Copy the code below to and fill in the missing method: -```rust -// TODO: remove this when you're done with your implementation. -#![allow(unused_variables, dead_code)] - +```rust,editable {{#include ../../third_party/rust-on-exercism/health-statistics.rs:setup}} {{#include ../../third_party/rust-on-exercism/health-statistics.rs:User_visit_doctor}} @@ -20,7 +17,5 @@ method: } } -{{#include ../../third_party/rust-on-exercism/health-statistics.rs:main}} - {{#include ../../third_party/rust-on-exercism/health-statistics.rs:tests}} ``` diff --git a/src/closures/exercise.md b/src/closures/exercise.md index af8049ca54a4..6b064cb7846e 100644 --- a/src/closures/exercise.md +++ b/src/closures/exercise.md @@ -4,7 +4,7 @@ Building on the generic logger from this morning, implement a `Filter` which uses a closure to filter log messages, sending those which pass the filtering predicate to an inner logger. -```rust,compile_fail +```rust,compile_fail,editable {{#include exercise.rs:setup}} // TODO: Define and implement `Filter`. diff --git a/src/control-flow-basics/exercise.md b/src/control-flow-basics/exercise.md index 45d0e32ab307..812d4f98fd6d 100644 --- a/src/control-flow-basics/exercise.md +++ b/src/control-flow-basics/exercise.md @@ -30,7 +30,5 @@ initial `n`. todo!("Implement this") } -{{#include exercise.rs:tests}} - {{#include exercise.rs:main}} ``` diff --git a/src/control-flow-basics/exercise.rs b/src/control-flow-basics/exercise.rs index 4cb79df34b5a..818a70dbe05d 100644 --- a/src/control-flow-basics/exercise.rs +++ b/src/control-flow-basics/exercise.rs @@ -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); +} diff --git a/src/error-handling/Cargo.toml b/src/error-handling/Cargo.toml index 90e7f11686a4..639cfe815fa3 100644 --- a/src/error-handling/Cargo.toml +++ b/src/error-handling/Cargo.toml @@ -8,6 +8,6 @@ publish = false anyhow = "*" thiserror = "*" -[[bin]] +[lib] name = "parser" path = "exercise.rs" diff --git a/src/error-handling/exercise.rs b/src/error-handling/exercise.rs index 395773806141..e39b1d19cd89 100644 --- a/src/error-handling/exercise.rs +++ b/src/error-handling/exercise.rs @@ -88,25 +88,30 @@ fn eval(e: Expression) -> Result { // 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 diff --git a/src/generics/Cargo.toml b/src/generics/Cargo.toml index 65af53b67772..80a38c250117 100644 --- a/src/generics/Cargo.toml +++ b/src/generics/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2021" publish = false -[[bin]] +[lib] name = "generics" path = "exercise.rs" diff --git a/src/generics/exercise.md b/src/generics/exercise.md index 801ddd54ce4c..c41490368554 100644 --- a/src/generics/exercise.md +++ b/src/generics/exercise.md @@ -7,12 +7,12 @@ minutes: 10 In this short exercise, you will implement a generic `min` function that determines the minimum of two values, using the [`Ord`] trait. -```rust,compile_fail +```rust,editable use std::cmp::Ordering; -// TODO: implement the `min` function used in `main`. +// TODO: implement the `min` function used in the tests. -{{#include exercise.rs:main}} +{{#include exercise.rs:tests}} ```
diff --git a/src/generics/exercise.rs b/src/generics/exercise.rs index dc28c39eae90..33b8315b7de5 100644 --- a/src/generics/exercise.rs +++ b/src/generics/exercise.rs @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#![allow(dead_code)] // ANCHOR: solution use std::cmp::Ordering; @@ -22,15 +23,22 @@ fn min(l: T, r: T) -> T { } } -// ANCHOR: main -fn main() { +// ANCHOR: tests +#[test] +fn integers() { assert_eq!(min(0, 10), 0); assert_eq!(min(500, 123), 123); +} +#[test] +fn chars() { assert_eq!(min('a', 'z'), 'a'); assert_eq!(min('7', '1'), '1'); +} +#[test] +fn strings() { assert_eq!(min("hello", "goodbye"), "goodbye"); assert_eq!(min("bat", "armadillo"), "armadillo"); } -// ANCHOR_END: main +// ANCHOR_END: tests diff --git a/src/iterators/Cargo.toml b/src/iterators/Cargo.toml index c1bd937100d8..c379e76d4d3c 100644 --- a/src/iterators/Cargo.toml +++ b/src/iterators/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2021" publish = false -[[bin]] -name = "offset-differences" +[lib] +name = "offset_differences" path = "exercise.rs" diff --git a/src/iterators/exercise.md b/src/iterators/exercise.md index 9594f4f73d3d..b4ba5c03f221 100644 --- a/src/iterators/exercise.md +++ b/src/iterators/exercise.md @@ -11,7 +11,7 @@ Copy the following code to and make the tests pass. Use an iterator expression and `collect` the result to construct the return value. -```rust +```rust,editable {{#include exercise.rs:offset_differences}} todo!() } diff --git a/src/iterators/exercise.rs b/src/iterators/exercise.rs index 63c6a9b63b76..7e4ff829821c 100644 --- a/src/iterators/exercise.rs +++ b/src/iterators/exercise.rs @@ -51,5 +51,3 @@ fn test_degenerate_cases() { assert_eq!(offset_differences(1, empty), vec![]); } // ANCHOR_END: unit-tests - -fn main() {} diff --git a/src/lifetimes/Cargo.toml b/src/lifetimes/Cargo.toml index 323eea3e69ee..9f9921768ae0 100644 --- a/src/lifetimes/Cargo.toml +++ b/src/lifetimes/Cargo.toml @@ -7,6 +7,6 @@ publish = false [dependencies] thiserror = "*" -[[bin]] +[lib] name = "protobuf" path = "exercise.rs" diff --git a/src/lifetimes/exercise.md b/src/lifetimes/exercise.md index dcc18394a95a..acd8999cf2af 100644 --- a/src/lifetimes/exercise.md +++ b/src/lifetimes/exercise.md @@ -83,7 +83,7 @@ What remains for you is to implement the `parse_field` function and the // TODO: Implement ProtoMessage for Person and PhoneNumber. -{{#include exercise.rs:main }} +{{#include exercise.rs:tests }} ```
diff --git a/src/lifetimes/exercise.rs b/src/lifetimes/exercise.rs index 8973a1435d4c..ace81e25abb6 100644 --- a/src/lifetimes/exercise.rs +++ b/src/lifetimes/exercise.rs @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#![allow(dead_code)] // ANCHOR: solution // ANCHOR: preliminaries @@ -193,21 +194,31 @@ impl<'a> ProtoMessage<'a> for PhoneNumber<'a> { } } -// ANCHOR: main -fn main() { +// ANCHOR: tests +#[test] +fn test_id() { let person_id: Person = parse_message(&[0x10, 0x2a]); assert_eq!(person_id, Person { name: "", id: 42, phone: vec![] }); +} +#[test] +fn test_name() { let person_name: Person = parse_message(&[ 0x0a, 0x0e, 0x62, 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6c, 0x20, 0x6e, 0x61, 0x6d, 0x65, ]); assert_eq!(person_name, Person { name: "beautiful name", id: 0, phone: vec![] }); +} +#[test] +fn test_just_person() { let person_name_id: Person = parse_message(&[0x0a, 0x04, 0x45, 0x76, 0x61, 0x6e, 0x10, 0x16]); assert_eq!(person_name_id, Person { name: "Evan", id: 22, phone: vec![] }); +} +#[test] +fn test_phone() { let phone: Person = parse_message(&[ 0x0a, 0x00, 0x10, 0x00, 0x1a, 0x16, 0x0a, 0x0e, 0x2b, 0x31, 0x32, 0x33, 0x34, 0x2d, 0x37, 0x37, 0x37, 0x2d, 0x39, 0x30, 0x39, 0x30, 0x12, 0x04, @@ -221,8 +232,11 @@ fn main() { phone: vec![PhoneNumber { number: "+1234-777-9090", type_: "home" },], } ); +} - // Put that all together into a single parse. +// Put that all together into a single parse. +#[test] +fn test_full_person() { let person: Person = parse_message(&[ 0x0a, 0x07, 0x6d, 0x61, 0x78, 0x77, 0x65, 0x6c, 0x6c, 0x10, 0x2a, 0x1a, 0x16, 0x0a, 0x0e, 0x2b, 0x31, 0x32, 0x30, 0x32, 0x2d, 0x35, 0x35, 0x35, @@ -243,4 +257,4 @@ fn main() { } ); } -// ANCHOR_END: main +// ANCHOR_END: tests diff --git a/src/methods-and-traits/exercise.md b/src/methods-and-traits/exercise.md index 56a14b5eb36f..018b89f95c91 100644 --- a/src/methods-and-traits/exercise.md +++ b/src/methods-and-traits/exercise.md @@ -18,7 +18,7 @@ implementing that same trait, adding behavior in the process. In the "Generics" segment this afternoon, we will see how to make the wrapper generic over the wrapped type. -```rust,compile_fail +```rust,compile_fail,editable {{#include exercise.rs:setup}} // TODO: Implement the `Logger` trait for `VerbosityFilter`. diff --git a/src/modules/exercise.md b/src/modules/exercise.md index 5a5a7b5fcccf..b5acd9761898 100644 --- a/src/modules/exercise.md +++ b/src/modules/exercise.md @@ -29,7 +29,7 @@ files in the `src` directory. Here's the single-module implementation of the GUI library: -```rust +```rust,editable {{#include exercise.rs:single-module}} ``` diff --git a/src/pattern-matching/Cargo.toml b/src/pattern-matching/Cargo.toml index dc619b2ecb61..35fb9d8b07b9 100644 --- a/src/pattern-matching/Cargo.toml +++ b/src/pattern-matching/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2021" publish = false -[[bin]] +[lib] name = "eval" path = "exercise.rs" diff --git a/src/pattern-matching/exercise.md b/src/pattern-matching/exercise.md index bbe303474b67..6dae8d63c6f3 100644 --- a/src/pattern-matching/exercise.md +++ b/src/pattern-matching/exercise.md @@ -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}} diff --git a/src/pattern-matching/exercise.rs b/src/pattern-matching/exercise.rs index 273a740f7131..bf590a297083 100644 --- a/src/pattern-matching/exercise.rs +++ b/src/pattern-matching/exercise.rs @@ -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)); -} diff --git a/src/references/exercise.md b/src/references/exercise.md index 3b41f217c16b..9500ef62bc11 100644 --- a/src/references/exercise.md +++ b/src/references/exercise.md @@ -7,7 +7,7 @@ minutes: 20 We will create a few utility functions for 3-dimensional geometry, representing a point as `[f64;3]`. It is up to you to determine the function signatures. -```rust,compile_fail +```rust,compile_fail,editable // Calculate the magnitude of a vector by summing the squares of its coordinates // and taking the square root. Use the `sqrt()` method to calculate the square // root, like `v.sqrt()`. diff --git a/src/smart-pointers/Cargo.toml b/src/smart-pointers/Cargo.toml index f183a4cf176b..c5262152af91 100644 --- a/src/smart-pointers/Cargo.toml +++ b/src/smart-pointers/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2021" publish = false -[[bin]] -name = "binary-tree" +[lib] +name = "binary_tree" path = "exercise.rs" diff --git a/src/smart-pointers/exercise.md b/src/smart-pointers/exercise.md index 6eb2b01ab06d..35060f82261f 100644 --- a/src/smart-pointers/exercise.md +++ b/src/smart-pointers/exercise.md @@ -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,editable {{#include exercise.rs:types}} // Implement `new`, `insert`, `len`, and `has` for `Subtree`. diff --git a/src/smart-pointers/exercise.rs b/src/smart-pointers/exercise.rs index bd060e79ce1c..be92422f8d2a 100644 --- a/src/smart-pointers/exercise.rs +++ b/src/smart-pointers/exercise.rs @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#![allow(dead_code)] // ANCHOR: solution use std::cmp::Ordering; @@ -96,14 +97,6 @@ impl Node { } } -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 { diff --git a/src/std-traits/Cargo.toml b/src/std-traits/Cargo.toml index e00c67b4b925..bc9dec7f5271 100644 --- a/src/std-traits/Cargo.toml +++ b/src/std-traits/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2021" publish = false -[[bin]] -name = "std-traits" +[lib] +name = "std_traits" path = "exercise.rs" diff --git a/src/std-traits/exercise.md b/src/std-traits/exercise.md index 400ad45b364b..dcc484f9a3ae 100644 --- a/src/std-traits/exercise.md +++ b/src/std-traits/exercise.md @@ -9,12 +9,12 @@ In this example, you will implement the classic playground, and implement the missing bits. Only rotate ASCII alphabetic characters, to ensure the result is still valid UTF-8. -```rust,compile_fail +```rust,editable {{#include exercise.rs:head }} // 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 diff --git a/src/std-traits/exercise.rs b/src/std-traits/exercise.rs index 961b261e42ec..a569485bb787 100644 --- a/src/std-traits/exercise.rs +++ b/src/std-traits/exercise.rs @@ -36,15 +36,7 @@ impl Read for RotDecoder { } } -// 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::*; @@ -72,4 +64,4 @@ mod test { } } } -// ANCHOR_END: main +// ANCHOR_END: tests diff --git a/src/testing/Cargo.toml b/src/testing/Cargo.toml index a4eaf5fc0adb..c6abcf21018a 100644 --- a/src/testing/Cargo.toml +++ b/src/testing/Cargo.toml @@ -7,6 +7,6 @@ publish = false [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(never)'] } -[[bin]] +[lib] name = "luhn" path = "exercise.rs" diff --git a/src/testing/exercise.md b/src/testing/exercise.md index b42c9f5b29b8..c255c770271d 100644 --- a/src/testing/exercise.md +++ b/src/testing/exercise.md @@ -27,7 +27,7 @@ correctly. Copy the code below to and write additional tests to uncover bugs in the provided implementation, fixing any bugs you find. -```rust +```rust,editable {{#include exercise.rs:luhn}} {{#include exercise.rs:unit-tests}} diff --git a/src/testing/exercise.rs b/src/testing/exercise.rs index 8ba9c97fd979..34872e618f7f 100644 --- a/src/testing/exercise.rs +++ b/src/testing/exercise.rs @@ -11,8 +11,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#![allow(dead_code)] -// ANCHOR: solution // This is the buggy version that appears in the problem. #[cfg(never)] // ANCHOR: luhn @@ -40,6 +40,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; @@ -69,14 +70,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 { diff --git a/src/testing/unit-tests.md b/src/testing/unit-tests.md index d9681b499b3d..debf1e5ef858 100644 --- a/src/testing/unit-tests.md +++ b/src/testing/unit-tests.md @@ -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], @@ -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`. - -
- -Run the tests in the playground in order to show their results. - -
diff --git a/src/tuples-and-arrays/exercise.md b/src/tuples-and-arrays/exercise.md index a6af0b97c486..f519c2b826ce 100644 --- a/src/tuples-and-arrays/exercise.md +++ b/src/tuples-and-arrays/exercise.md @@ -26,15 +26,10 @@ transpose a matrix (turn rows into columns): Copy the code below to 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)] - +```rust,should_panic,editable {{#include exercise.rs:transpose}} todo!() } -{{#include exercise.rs:tests}} - {{#include exercise.rs:main}} ``` diff --git a/src/tuples-and-arrays/exercise.rs b/src/tuples-and-arrays/exercise.rs index 43291f5fe596..4b90449bfb10 100644 --- a/src/tuples-and-arrays/exercise.rs +++ b/src/tuples-and-arrays/exercise.rs @@ -25,7 +25,23 @@ 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 + +// This test does not appear in the exercise, as this is very early in the course, but it verifies +// that the solution is correct. #[test] fn test_transpose() { let matrix = [ @@ -43,18 +59,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 diff --git a/src/unsafe-rust/exercise.md b/src/unsafe-rust/exercise.md index 4fd5b1af5faf..208ec97f732d 100644 --- a/src/unsafe-rust/exercise.md +++ b/src/unsafe-rust/exercise.md @@ -51,7 +51,7 @@ The [Nomicon] also has a very useful chapter about FFI. Copy the code below to and fill in the missing functions and methods: -```rust,should_panic +```rust,should_panic,editable // TODO: remove this when you're done with your implementation. #![allow(unused_imports, unused_variables, dead_code)] diff --git a/theme/book.js b/theme/book.js index 69a0fc67a337..fb4f7a939156 100644 --- a/theme/book.js +++ b/theme/book.js @@ -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"; } diff --git a/third_party/rust-on-exercism/health-statistics.rs b/third_party/rust-on-exercism/health-statistics.rs index a9ed8cdb10c8..c91ed2479afd 100644 --- a/third_party/rust-on-exercism/health-statistics.rs +++ b/third_party/rust-on-exercism/health-statistics.rs @@ -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() {