Phase 0: The Toolchain and the Loop
Before any Panoptes code, we verify one thing: that you can write a failing test, see it fail legibly, fix it, and see it pass. The entire course runs on that loop being fast and trustworthy. This phase is deliberately trivial — that is the point. We are testing the machinery, not your ability.
Objective
- Confirm a working Rust toolchain (
rustc,cargo). - Create a throwaway crate.
- Write one deliberately failing test, watch it fail, fix it, watch it pass.
- Internalize what
cargo testoutput looks like when things break.
Install the toolchain
Rust is installed through rustup, which manages compiler versions:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# accept the defaults, then:
source "$HOME/.cargo/env"
rustc --version
cargo --version
You want a recent stable toolchain. If you already have one, rustup update brings it current.
Create a throwaway crate
cargo new hello-loop
cd hello-loop
cargo new scaffolds a tiny package: a Cargo.toml manifest and a src/main.rs. Open src/main.rs. Replace its contents with a single function and a test:
fn add(a: i32, b: i32) -> i32 { a + b } fn main() { println!("{}", add(2, 2)); } #[cfg(test)] mod tests { use super::*; #[test] fn two_plus_two_is_five() { assert_eq!(add(2, 2), 5); // deliberately wrong } }
The failing run
cargo test print? Not just "it fails" — what specifically will it show you about why? Where will the line number point? Decide, then run.
cargo test
You will see something close to this:
running 1 test
test tests::two_plus_two_is_five ... FAILED
failures:
---- tests::two_plus_two_is_five stdout ----
thread 'tests::two_plus_two_is_five' panicked at src/main.rs:15:9:
assertion `left == right` failed
left: 4
right: 5
Read that carefully, because you will read a hundred of these. It tells you the exact test, the exact file and line, and — critically — left: 4, right: 5, the actual value against the expected value. assert_eq! always reports both sides. This is why we write assertions with the computed value on the left and the expected on the right: the output reads naturally.
The fix
Change the 5 to a 4:
#![allow(unused)] fn main() { assert_eq!(add(2, 2), 4); }
Run again:
test tests::two_plus_two_is_five ... ok
test result: ok. 1 passed; 0 failed; 0 ignored
That is the loop. Every build chapter is this, with more interesting types in the middle.
What just happened, named
#[cfg(test)]means "only compile this module when running tests" — your test code is not in your shipped binary.mod tests { }is a module, a namespace. Tests conventionally live in a nestedtestsmodule.use super::*;pulls in everything from the parent module so the test can seeadd.#[test]marks a function as a test case forcargo testto discover and run.
Every one of these appears in the very first Panoptes task, so you have now seen the whole skeleton.
Done when
You can run cargo test, read a failure, and fix it without thinking about the mechanics. When that loop is automatic, turn the page: Part II begins with the concept that makes the whole harness worth building in Rust.