Files
learn-rust/learning-records/0003-library-solid-main-untested.md

2.3 KiB

0003 landed: structs/enums/packages are owned; the untested file is where the gap moved

Lesson 0003 came back with 17/17 tests green and code that is genuinely idiomatic: ? with ok_or, iter().find(|task| task.id == id) with a closure, iter_mut() to mutate in place, a private Vec<Task> behind pub fn tasks(&self) -> &[Task]. Structs, enums with data, impl, the two-crate package and cross-module crate:: paths can be treated as produced, not just recognised — the first topics in this workspace to earn that. Self-reported weakness on those three is resolved.

The gap moved to the file no test could reach. src/main.rs violates the spec's error contract in three ways, all confirmed by running the crate:

  • cargo run -- fly → message on stdout, exit 0 (spec: stderr, exit 1)
  • cargo run -- done 9 → .unwrap() panic, exit 101
  • errors formatted by hand in main instead of by the type

This is exactly the mission's "errors with Result, not panic!", and it went unnoticed because the 17 tests are integration tests against the library crate — by design they cannot see main.rs. Implication for future specs: any behaviour stated in prose but unreachable by the test suite will not get done. Either test it (a spec test shelling out to the binary) or make it the explicit drill of the following lesson. Lesson 0005 takes the second route, deliberately, because the fix needs traits.

Sequencing decision. Traits were chosen over collections/iterators or async as the next topic, because: the user's own code now has two visible trait-shaped holes (hand-built display strings, String errors), every backend crate they will meet (serde, axum, tokio) is trait-driven, and ch10 is the next unread chapter. Per LR-0002's ordering rule, 0005 is the concept lesson; the String → TaskError enum conversion is the project lesson (0006) and is explicitly deferred in 0005's text so the drill stays inside working memory.

Format note that worked and should continue: the drill in 0005 targets the crate the user already wrote, with a shell-level check per step (echo $?) rather than a new test file. Feedback is immediate, and the reward is their own project getting better rather than a throwaway exercise. Reference impl proved in a temp copy first: 17/17 still pass after the drill's three steps.