1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
package task
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
)
// TestSetDebugLog exercises the lifecycle of the debug logger: enable,
// disable, and re-enable. It also covers the negative case where the
// target directory does not exist.
func TestSetDebugLog(t *testing.T) {
// Ensure the package-level state is clean before and after.
t.Cleanup(func() { SetDebugLog("") }) //nolint:errcheck
// Negative: directory does not exist — must return an error.
if err := SetDebugLog("/nonexistent-dir-xyz/debug.log"); err == nil {
t.Error("expected error for non-existent directory, got nil")
}
// After a failed open the package state must remain empty.
if dbg.writer != nil || dbg.file != nil {
t.Error("dbg fields must be nil after a failed SetDebugLog call")
}
// Positive: enable logging to a temp file.
tmp := t.TempDir()
logPath := filepath.Join(tmp, "debug.log")
if err := SetDebugLog(logPath); err != nil {
t.Fatalf("SetDebugLog failed: %v", err)
}
if dbg.writer == nil || dbg.file == nil {
t.Fatal("dbg fields must be set after a successful SetDebugLog call")
}
// The run helper uses dbg.writer — verify that a write actually reaches
// the log file. We fake a task invocation by writing directly.
fmt.Fprintln(dbg.writer, "test-entry")
content, err := os.ReadFile(logPath)
if err != nil {
t.Fatalf("read log file: %v", err)
}
if !strings.Contains(string(content), "test-entry") {
t.Errorf("expected log entry in file, got: %q", string(content))
}
// Re-enable with a different path — old file must be closed, new one opened.
logPath2 := filepath.Join(tmp, "debug2.log")
if err := SetDebugLog(logPath2); err != nil {
t.Fatalf("second SetDebugLog failed: %v", err)
}
if dbg.file == nil {
t.Error("dbg.file must be non-nil after re-enabling debug log")
}
// Disable — both fields must return to nil, no error expected.
if err := SetDebugLog(""); err != nil {
t.Fatalf("disable SetDebugLog failed: %v", err)
}
if dbg.writer != nil || dbg.file != nil {
t.Error("dbg fields must be nil after disabling SetDebugLog")
}
}
func TestAddAndExport(t *testing.T) {
if _, err := exec.LookPath("task"); err != nil {
t.Skip("task command not available")
}
tmp := t.TempDir()
if err := os.Setenv("TASKDATA", tmp); err != nil {
t.Fatal(err)
}
if err := os.Setenv("TASKRC", "/dev/null"); err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
os.Unsetenv("TASKDATA")
os.Unsetenv("TASKRC")
})
if err := Add("hello world", []string{"tag", "anothertag", "tasksamuraitesting"}); err != nil {
t.Fatalf("add task 1: %v", err)
}
if err := Add("hello universe", []string{"foo", "tasksamuraitesting"}); err != nil {
t.Fatalf("add task 2: %v", err)
}
tasks, err := Export()
if err != nil {
t.Fatalf("export: %v", err)
}
found := make(map[string]bool)
for _, task := range tasks {
hasTag := false
for _, tag := range task.Tags {
if tag == "tasksamuraitesting" {
hasTag = true
break
}
}
if hasTag {
found[task.Description] = true
}
}
if len(found) != 2 {
t.Fatalf("expected 2 tasks with tag, got %d", len(found))
}
if !found["hello world"] {
t.Errorf("missing task 'hello world'")
}
if !found["hello universe"] {
t.Errorf("missing task 'hello universe'")
}
}
func TestModifyHelpers(t *testing.T) {
if _, err := exec.LookPath("task"); err != nil {
t.Skip("task command not available")
}
tmp := t.TempDir()
if err := os.Setenv("TASKDATA", tmp); err != nil {
t.Fatal(err)
}
if err := os.Setenv("TASKRC", "/dev/null"); err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
os.Unsetenv("TASKDATA")
os.Unsetenv("TASKRC")
})
if err := Add("hello", nil); err != nil {
t.Fatalf("add task: %v", err)
}
if err := SetPriority(1, "H"); err != nil {
t.Fatalf("set priority: %v", err)
}
if err := AddTags(1, []string{"foo"}); err != nil {
t.Fatalf("add tags: %v", err)
}
if err := SetDescription(1, "hello there"); err != nil {
t.Fatalf("set description: %v", err)
}
if err := Annotate(1, "note"); err != nil {
t.Fatalf("annotate: %v", err)
}
tasks, err := Export()
if err != nil {
t.Fatalf("export: %v", err)
}
if len(tasks) != 1 {
t.Fatalf("expected 1 task, got %d", len(tasks))
}
t1 := tasks[0]
if t1.Priority != "H" {
t.Errorf("priority not set: %v", t1.Priority)
}
found := false
for _, tag := range t1.Tags {
if tag == "foo" {
found = true
break
}
}
if !found {
t.Errorf("tag not added")
}
if t1.Description != "hello there" {
t.Errorf("description not set: %v", t1.Description)
}
annFound := false
for _, a := range t1.Annotations {
if a.Description == "note" {
annFound = true
break
}
}
if !annFound {
t.Errorf("annotation not added")
}
}
|