1use assert_cmd::Command;
2use predicates::prelude::*;
3use tempfile::TempDir;
4
5fn td() -> Command {
6 Command::cargo_bin("td").unwrap()
7}
8
9fn init_tmp() -> TempDir {
10 let tmp = TempDir::new().unwrap();
11 td().arg("init").current_dir(&tmp).assert().success();
12 tmp
13}
14
15fn create_task(dir: &TempDir, title: &str) -> String {
16 let out = td()
17 .args(["--json", "create", title])
18 .current_dir(dir)
19 .output()
20 .unwrap();
21 let v: serde_json::Value = serde_json::from_slice(&out.stdout).unwrap();
22 v["id"].as_str().unwrap().to_string()
23}
24
25fn get_task_json(dir: &TempDir, id: &str) -> serde_json::Value {
26 let out = td()
27 .args(["--json", "show", id])
28 .current_dir(dir)
29 .output()
30 .unwrap();
31 serde_json::from_slice(&out.stdout).unwrap()
32}
33
34// ── update ───────────────────────────────────────────────────────────
35
36#[test]
37fn update_changes_status() {
38 let tmp = init_tmp();
39 let id = create_task(&tmp, "In progress");
40
41 td().args(["update", &id, "-s", "in_progress"])
42 .current_dir(&tmp)
43 .assert()
44 .success()
45 .stdout(predicate::str::contains("updated"));
46
47 let t = get_task_json(&tmp, &id);
48 assert_eq!(t["status"].as_str().unwrap(), "in_progress");
49}
50
51#[test]
52fn update_changes_priority() {
53 let tmp = init_tmp();
54 let id = create_task(&tmp, "Reprioritise");
55
56 td().args(["update", &id, "-p", "high"])
57 .current_dir(&tmp)
58 .assert()
59 .success();
60
61 let t = get_task_json(&tmp, &id);
62 assert_eq!(t["priority"].as_i64().unwrap(), 1);
63}
64
65#[test]
66fn update_changes_title() {
67 let tmp = init_tmp();
68 let id = create_task(&tmp, "Old title");
69
70 td().args(["update", &id, "-t", "New title"])
71 .current_dir(&tmp)
72 .assert()
73 .success();
74
75 let t = get_task_json(&tmp, &id);
76 assert_eq!(t["title"].as_str().unwrap(), "New title");
77}
78
79#[test]
80fn update_changes_description() {
81 let tmp = init_tmp();
82 let id = create_task(&tmp, "Describe me");
83
84 td().args(["update", &id, "-d", "Now with details"])
85 .current_dir(&tmp)
86 .assert()
87 .success();
88
89 let t = get_task_json(&tmp, &id);
90 assert_eq!(t["description"].as_str().unwrap(), "Now with details");
91}
92
93#[test]
94fn update_json_returns_task() {
95 let tmp = init_tmp();
96 let id = create_task(&tmp, "JSON update");
97
98 let out = td()
99 .args(["--json", "update", &id, "-p", "high"])
100 .current_dir(&tmp)
101 .output()
102 .unwrap();
103 let v: serde_json::Value = serde_json::from_slice(&out.stdout).unwrap();
104 assert_eq!(v["priority"].as_i64().unwrap(), 1);
105}
106
107// ── done ─────────────────────────────────────────────────────────────
108
109#[test]
110fn done_closes_task() {
111 let tmp = init_tmp();
112 let id = create_task(&tmp, "Close me");
113
114 td().args(["done", &id])
115 .current_dir(&tmp)
116 .assert()
117 .success()
118 .stdout(predicate::str::contains("closed"));
119
120 let t = get_task_json(&tmp, &id);
121 assert_eq!(t["status"].as_str().unwrap(), "closed");
122}
123
124#[test]
125fn done_closes_multiple_tasks() {
126 let tmp = init_tmp();
127 let id1 = create_task(&tmp, "First");
128 let id2 = create_task(&tmp, "Second");
129
130 td().args(["done", &id1, &id2])
131 .current_dir(&tmp)
132 .assert()
133 .success();
134
135 assert_eq!(get_task_json(&tmp, &id1)["status"], "closed");
136 assert_eq!(get_task_json(&tmp, &id2)["status"], "closed");
137}
138
139// ── reopen ───────────────────────────────────────────────────────────
140
141#[test]
142fn reopen_reopens_closed_task() {
143 let tmp = init_tmp();
144 let id = create_task(&tmp, "Reopen me");
145
146 td().args(["done", &id])
147 .current_dir(&tmp)
148 .assert()
149 .success();
150 assert_eq!(get_task_json(&tmp, &id)["status"], "closed");
151
152 td().args(["reopen", &id])
153 .current_dir(&tmp)
154 .assert()
155 .success()
156 .stdout(predicate::str::contains("reopened"));
157
158 assert_eq!(get_task_json(&tmp, &id)["status"], "open");
159}