cli_list_show.rs

  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
 15/// Create a task and return its JSON id.
 16fn create_task(dir: &TempDir, title: &str) -> String {
 17    let out = td()
 18        .args(["--json", "create", title])
 19        .current_dir(dir)
 20        .output()
 21        .unwrap();
 22    let v: serde_json::Value = serde_json::from_slice(&out.stdout).unwrap();
 23    v["id"].as_str().unwrap().to_string()
 24}
 25
 26// ── list ─────────────────────────────────────────────────────────────
 27
 28#[test]
 29fn list_shows_created_tasks() {
 30    let tmp = init_tmp();
 31    create_task(&tmp, "Alpha");
 32    create_task(&tmp, "Bravo");
 33
 34    td().arg("list")
 35        .current_dir(&tmp)
 36        .assert()
 37        .success()
 38        .stdout(predicate::str::contains("Alpha"))
 39        .stdout(predicate::str::contains("Bravo"));
 40}
 41
 42#[test]
 43fn list_json_returns_array() {
 44    let tmp = init_tmp();
 45    create_task(&tmp, "One");
 46
 47    let out = td()
 48        .args(["--json", "list"])
 49        .current_dir(&tmp)
 50        .output()
 51        .unwrap();
 52    let v: serde_json::Value = serde_json::from_slice(&out.stdout).unwrap();
 53    assert!(v.is_array(), "expected JSON array, got: {v}");
 54    assert_eq!(v.as_array().unwrap().len(), 1);
 55    assert_eq!(v[0]["title"].as_str().unwrap(), "One");
 56}
 57
 58#[test]
 59fn list_filter_by_status() {
 60    let tmp = init_tmp();
 61    create_task(&tmp, "Open task");
 62
 63    // No closed tasks yet.
 64    let out = td()
 65        .args(["--json", "list", "-s", "closed"])
 66        .current_dir(&tmp)
 67        .output()
 68        .unwrap();
 69    let v: serde_json::Value = serde_json::from_slice(&out.stdout).unwrap();
 70    assert_eq!(v.as_array().unwrap().len(), 0);
 71}
 72
 73#[test]
 74fn list_filter_by_priority() {
 75    let tmp = init_tmp();
 76
 77    td().args(["create", "Low prio", "-p", "low"])
 78        .current_dir(&tmp)
 79        .assert()
 80        .success();
 81    td().args(["create", "High prio", "-p", "high"])
 82        .current_dir(&tmp)
 83        .assert()
 84        .success();
 85
 86    let out = td()
 87        .args(["--json", "list", "-p", "high"])
 88        .current_dir(&tmp)
 89        .output()
 90        .unwrap();
 91    let v: serde_json::Value = serde_json::from_slice(&out.stdout).unwrap();
 92    let tasks = v.as_array().unwrap();
 93    assert_eq!(tasks.len(), 1);
 94    assert_eq!(tasks[0]["title"].as_str().unwrap(), "High prio");
 95}
 96
 97#[test]
 98fn list_filter_by_label() {
 99    let tmp = init_tmp();
100
101    td().args(["create", "Tagged", "-l", "urgent"])
102        .current_dir(&tmp)
103        .assert()
104        .success();
105    td().args(["create", "Untagged"])
106        .current_dir(&tmp)
107        .assert()
108        .success();
109
110    let out = td()
111        .args(["--json", "list", "-l", "urgent"])
112        .current_dir(&tmp)
113        .output()
114        .unwrap();
115    let v: serde_json::Value = serde_json::from_slice(&out.stdout).unwrap();
116    let tasks = v.as_array().unwrap();
117    assert_eq!(tasks.len(), 1);
118    assert_eq!(tasks[0]["title"].as_str().unwrap(), "Tagged");
119}
120
121#[test]
122fn list_filter_by_effort() {
123    let tmp = init_tmp();
124
125    td().args(["create", "Easy", "-e", "low"])
126        .current_dir(&tmp)
127        .assert()
128        .success();
129    td().args(["create", "Hard", "-e", "high"])
130        .current_dir(&tmp)
131        .assert()
132        .success();
133
134    let out = td()
135        .args(["--json", "list", "-e", "low"])
136        .current_dir(&tmp)
137        .output()
138        .unwrap();
139    let v: serde_json::Value = serde_json::from_slice(&out.stdout).unwrap();
140    let tasks = v.as_array().unwrap();
141    assert_eq!(tasks.len(), 1);
142    assert_eq!(tasks[0]["title"].as_str().unwrap(), "Easy");
143}
144
145// ── show ─────────────────────────────────────────────────────────────
146
147#[test]
148fn show_displays_task() {
149    let tmp = init_tmp();
150    let id = create_task(&tmp, "Details here");
151
152    td().args(["show", &id])
153        .current_dir(&tmp)
154        .assert()
155        .success()
156        .stdout(predicate::str::contains("Details here"))
157        .stdout(predicate::str::contains(&id));
158}
159
160#[test]
161fn show_json_includes_labels_and_blockers() {
162    let tmp = init_tmp();
163
164    td().args(["create", "With labels", "-l", "bug,ui"])
165        .current_dir(&tmp)
166        .assert()
167        .success();
168
169    // Get the id via list.
170    let out = td()
171        .args(["--json", "list"])
172        .current_dir(&tmp)
173        .output()
174        .unwrap();
175    let list: serde_json::Value = serde_json::from_slice(&out.stdout).unwrap();
176    let id = list[0]["id"].as_str().unwrap();
177
178    let out = td()
179        .args(["--json", "show", id])
180        .current_dir(&tmp)
181        .output()
182        .unwrap();
183    let v: serde_json::Value = serde_json::from_slice(&out.stdout).unwrap();
184    assert_eq!(v["title"].as_str().unwrap(), "With labels");
185
186    let labels = v["labels"].as_array().unwrap();
187    assert!(labels.contains(&serde_json::Value::String("bug".into())));
188    assert!(labels.contains(&serde_json::Value::String("ui".into())));
189
190    // Blockers should be present (even if empty).
191    assert!(v["blockers"].is_array());
192}
193
194#[test]
195fn show_nonexistent_task_fails() {
196    let tmp = init_tmp();
197
198    td().args(["show", "td-nope"])
199        .current_dir(&tmp)
200        .assert()
201        .failure()
202        .stderr(predicate::str::contains("not found"));
203}