mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-05-20 17:33:31 +02:00
Be more consistent about tests vs. main (#2644)
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. Fixes #1581.
This commit is contained in:
parent
699c5137c7
commit
44a79741ff
@ -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:
|
||||
|
@ -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"
|
||||
|
@ -9,10 +9,7 @@ minutes: 20
|
||||
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)]
|
||||
|
||||
```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}}
|
||||
```
|
||||
|
@ -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`.
|
||||
|
@ -30,7 +30,5 @@ initial `n`.
|
||||
todo!("Implement this")
|
||||
}
|
||||
|
||||
{{#include exercise.rs:tests}}
|
||||
|
||||
{{#include exercise.rs:main}}
|
||||
```
|
||||
|
@ -25,15 +25,14 @@ fn collatz_length(mut n: i32) -> u32 {
|
||||
len
|
||||
}
|
||||
|
||||
// ANCHOR: tests
|
||||
// ANCHOR: main
|
||||
fn main() {
|
||||
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);
|
||||
}
|
||||
// ANCHOR_END: tests
|
||||
|
||||
// ANCHOR: main
|
||||
fn main() {
|
||||
println!("Length: {}", collatz_length(11));
|
||||
}
|
||||
// ANCHOR_END: main
|
||||
|
@ -8,6 +8,6 @@ publish = false
|
||||
anyhow = "*"
|
||||
thiserror = "*"
|
||||
|
||||
[[bin]]
|
||||
[lib]
|
||||
name = "parser"
|
||||
path = "exercise.rs"
|
||||
|
@ -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::*;
|
||||
|
||||
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_error() {
|
||||
assert_eq!(
|
||||
eval(Expression::Op {
|
||||
op: Operation::Div,
|
||||
left: Box::new(Expression::Value(99)),
|
||||
right: Box::new(Expression::Value(0)),
|
||||
}),
|
||||
Err(DivideByZeroError)
|
||||
);
|
||||
}
|
||||
|
||||
#[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
|
||||
|
@ -4,6 +4,6 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[[bin]]
|
||||
[lib]
|
||||
name = "generics"
|
||||
path = "exercise.rs"
|
||||
|
@ -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}}
|
||||
```
|
||||
|
||||
<details>
|
||||
|
@ -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<T: Ord>(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
|
||||
|
@ -4,6 +4,6 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[[bin]]
|
||||
name = "offset-differences"
|
||||
[lib]
|
||||
name = "offset_differences"
|
||||
path = "exercise.rs"
|
||||
|
@ -11,7 +11,7 @@ Copy the following code to <https://play.rust-lang.org/> 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!()
|
||||
}
|
||||
|
@ -51,5 +51,3 @@ fn test_degenerate_cases() {
|
||||
assert_eq!(offset_differences(1, empty), vec![]);
|
||||
}
|
||||
// ANCHOR_END: unit-tests
|
||||
|
||||
fn main() {}
|
||||
|
@ -7,6 +7,6 @@ publish = false
|
||||
[dependencies]
|
||||
thiserror = "*"
|
||||
|
||||
[[bin]]
|
||||
[lib]
|
||||
name = "protobuf"
|
||||
path = "exercise.rs"
|
||||
|
@ -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 }}
|
||||
```
|
||||
|
||||
<details>
|
||||
|
@ -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
|
||||
|
@ -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`.
|
||||
|
@ -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}}
|
||||
```
|
||||
|
||||
|
@ -4,6 +4,6 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[[bin]]
|
||||
[lib]
|
||||
name = "eval"
|
||||
path = "exercise.rs"
|
||||
|
@ -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}}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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()`.
|
||||
|
@ -4,6 +4,6 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[[bin]]
|
||||
name = "binary-tree"
|
||||
[lib]
|
||||
name = "binary_tree"
|
||||
path = "exercise.rs"
|
||||
|
@ -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`.
|
||||
|
@ -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<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 {
|
||||
|
@ -4,6 +4,6 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[[bin]]
|
||||
name = "std-traits"
|
||||
[lib]
|
||||
name = "std_traits"
|
||||
path = "exercise.rs"
|
||||
|
@ -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
|
||||
|
@ -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::*;
|
||||
@ -72,4 +64,4 @@ mod test {
|
||||
}
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: main
|
||||
// ANCHOR_END: tests
|
||||
|
@ -7,6 +7,6 @@ publish = false
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(never)'] }
|
||||
|
||||
[[bin]]
|
||||
[lib]
|
||||
name = "luhn"
|
||||
path = "exercise.rs"
|
||||
|
@ -27,7 +27,7 @@ correctly.
|
||||
Copy the code below to <https://play.rust-lang.org/> 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}}
|
||||
|
@ -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 {
|
||||
|
@ -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`.
|
||||
|
||||
<details>
|
||||
|
||||
Run the tests in the playground in order to show their results.
|
||||
|
||||
</details>
|
||||
|
@ -26,15 +26,10 @@ transpose a matrix (turn rows into columns):
|
||||
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)]
|
||||
|
||||
```rust,should_panic,editable
|
||||
{{#include exercise.rs:transpose}}
|
||||
todo!()
|
||||
}
|
||||
|
||||
{{#include exercise.rs:tests}}
|
||||
|
||||
{{#include exercise.rs:main}}
|
||||
```
|
||||
|
@ -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
|
||||
|
@ -51,7 +51,7 @@ The [Nomicon] also has a very useful chapter about FFI.
|
||||
Copy the code below to <https://play.rust-lang.org/> 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)]
|
||||
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user