package tests import ( "fmt" "os" "os/exec" "path/filepath" "strings" "testing" ) // buildDew compiles the cli once so the tests can drive it as a real process // instead of reaching into the internals. func buildDew(t *testing.T) string { t.Helper() bin := filepath.Join(t.TempDir(), "dew") cmd := exec.Command("go", "build", "-o", bin, "../cmd/dew") if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("building dew: %v\n%s", err, out) } return bin } // newHome writes a throwaway config pointing at temp files and returns the // HOME to run under, so the tests never touch the real config. func newHome(t *testing.T) (home, todo, done string) { t.Helper() dir := t.TempDir() home = t.TempDir() todo = filepath.Join(dir, "todo.txt") done = filepath.Join(dir, "done.txt") cfgDir := filepath.Join(home, ".config", "dew") if err := os.MkdirAll(cfgDir, 0755); err != nil { t.Fatalf("creating config dir: %v", err) } cfg := fmt.Sprintf("{\"todo_file\": %q, \"done_file\": %q}", todo, done) if err := os.WriteFile(filepath.Join(cfgDir, "config.json"), []byte(cfg), 0644); err != nil { t.Fatalf("writing config: %v", err) } return home, todo, done } func runDew(t *testing.T, bin, home string, args ...string) (string, error) { t.Helper() env := []string{} for _, e := range os.Environ() { if !strings.HasPrefix(e, "HOME=") { env = append(env, e) } } cmd := exec.Command(bin, args...) cmd.Env = append(env, "HOME="+home) out, err := cmd.CombinedOutput() return string(out), err } func TestCLIAddAndList(t *testing.T) { bin := buildDew(t) home, _, _ := newHome(t) out, err := runDew(t, bin, home, "add", "buy", "catnip", "+metsa", "@chores") if err != nil { t.Fatalf("dew add: %v\n%s", err, out) } if !strings.Contains(out, "added task: buy catnip +metsa @chores") { t.Errorf("add output = %q", out) } out, err = runDew(t, bin, home, "ls") if err != nil { t.Fatalf("dew ls: %v\n%s", err, out) } if !strings.Contains(out, "buy catnip") || !strings.Contains(out, "metsa") { t.Errorf("ls output missing the task: %q", out) } } func TestCLIDoneArchives(t *testing.T) { bin := buildDew(t) home, todo, done := newHome(t) for _, desc := range []string{"first task +home", "second task +home"} { if out, err := runDew(t, bin, home, "add", desc); err != nil { t.Fatalf("dew add %q: %v\n%s", desc, err, out) } } if out, err := runDew(t, bin, home, "do", "1"); err != nil { t.Fatalf("dew do 1: %v\n%s", err, out) } todoBytes, err := os.ReadFile(todo) if err != nil { t.Fatalf("reading todo: %v", err) } if got := strings.TrimSpace(string(todoBytes)); got != "second task +home" { t.Errorf("todo = %q, want just the second task", got) } doneBytes, err := os.ReadFile(done) if err != nil { t.Fatalf("reading done: %v", err) } if !strings.Contains(string(doneBytes), "first task +home") { t.Errorf("done.txt = %q, want the archived first task", doneBytes) } }