// The specification, as executable tests. Do not edit this file — make it pass. // Copy to: tasks/tests/spec.rs // Run with: cargo test use tasks::command::Command; use tasks::store::Store; use tasks::task::{Priority, Status, Task}; /// Helper: build an argument list the way main() would pass it in /// (program name already stripped). fn args(list: &[&str]) -> Vec { list.iter().map(|s| s.to_string()).collect() } // ---------- task.rs ---------- #[test] fn new_task_starts_as_todo() { let task = Task::new(1, "write the spec", Priority::High); assert_eq!(task.id, 1); assert_eq!(task.title, "write the spec"); assert_eq!(task.status, Status::Todo); assert_eq!(task.priority, Priority::High); } #[test] fn status_labels() { assert_eq!(Status::Todo.label(), "todo"); assert_eq!(Status::InProgress.label(), "in-progress"); assert_eq!(Status::Done.label(), "done"); } #[test] fn priority_labels() { assert_eq!(Priority::Low.label(), "low"); assert_eq!(Priority::Medium.label(), "medium"); assert_eq!(Priority::High.label(), "high"); } #[test] fn priority_parses_known_words_only() { assert_eq!(Priority::parse("low"), Some(Priority::Low)); assert_eq!(Priority::parse("medium"), Some(Priority::Medium)); assert_eq!(Priority::parse("high"), Some(Priority::High)); assert_eq!(Priority::parse("urgent"), None); assert_eq!(Priority::parse(""), None); } // ---------- command.rs ---------- #[test] fn parses_add_with_default_priority() { let command = Command::parse(&args(&["add", "buy milk"])).unwrap(); assert_eq!( command, Command::Add { title: "buy milk".to_string(), priority: Priority::Medium, } ); } #[test] fn parses_add_with_explicit_priority() { let command = Command::parse(&args(&["add", "ship it", "high"])).unwrap(); assert_eq!( command, Command::Add { title: "ship it".to_string(), priority: Priority::High, } ); } #[test] fn parses_list_done_and_remove() { assert_eq!(Command::parse(&args(&["list"])).unwrap(), Command::List); assert_eq!( Command::parse(&args(&["done", "7"])).unwrap(), Command::Done { id: 7 } ); assert_eq!( Command::parse(&args(&["remove", "12"])).unwrap(), Command::Remove { id: 12 } ); } #[test] fn rejects_bad_input() { assert!(Command::parse(&args(&[])).is_err(), "no command at all"); assert!(Command::parse(&args(&["fly"])).is_err(), "unknown command"); assert!(Command::parse(&args(&["add"])).is_err(), "add with no title"); assert!( Command::parse(&args(&["add", "x", "urgent"])).is_err(), "unknown priority word" ); assert!(Command::parse(&args(&["done"])).is_err(), "done with no id"); assert!( Command::parse(&args(&["done", "abc"])).is_err(), "id is not a number" ); assert!( Command::parse(&args(&["remove", "-1"])).is_err(), "negative id is not a u32" ); } // ---------- store.rs ---------- #[test] fn add_returns_ids_starting_at_one() { let mut store = Store::new(); assert_eq!(store.add("first", Priority::Low), 1); assert_eq!(store.add("second", Priority::Low), 2); assert_eq!(store.add("third", Priority::Low), 3); } #[test] fn tasks_come_back_in_insertion_order() { let mut store = Store::new(); store.add("first", Priority::Low); store.add("second", Priority::High); let listed = store.tasks(); assert_eq!(listed.len(), 2); assert_eq!(listed[0].title, "first"); assert_eq!(listed[1].title, "second"); } #[test] fn new_store_is_empty() { let store = Store::new(); assert!(store.tasks().is_empty()); } #[test] fn complete_sets_status_to_done() { let mut store = Store::new(); let id = store.add("do the thing", Priority::Medium); assert_eq!(store.find(id).unwrap().status, Status::Todo); assert!(store.complete(id).is_ok()); assert_eq!(store.find(id).unwrap().status, Status::Done); } #[test] fn complete_unknown_id_is_an_error() { let mut store = Store::new(); store.add("only task", Priority::Low); assert!(store.complete(99).is_err()); } #[test] fn remove_deletes_only_that_task() { let mut store = Store::new(); let first = store.add("first", Priority::Low); let second = store.add("second", Priority::Low); assert!(store.remove(first).is_ok()); assert_eq!(store.tasks().len(), 1); assert!(store.find(first).is_none()); assert!(store.find(second).is_some()); } #[test] fn remove_unknown_id_is_an_error() { let mut store = Store::new(); assert!(store.remove(1).is_err()); } #[test] fn find_returns_none_for_missing_id() { let store = Store::new(); assert!(store.find(1).is_none()); } #[test] fn ids_are_not_reused_after_remove() { let mut store = Store::new(); let first = store.add("first", Priority::Low); store.remove(first).unwrap(); let second = store.add("second", Priority::Low); assert_ne!(first, second, "a removed id must not be handed out again"); }