Files

185 lines
5.0 KiB
Rust

// 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<String> {
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");
}