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)
}
}