1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5package lunatask_test
6
7import (
8 "slices"
9 "testing"
10
11 lunatask "git.secluded.site/go-lunatask"
12)
13
14func TestParseWorkflow(t *testing.T) {
15 t.Parallel()
16
17 tests := []struct {
18 name string
19 input string
20 want lunatask.Workflow
21 wantErr bool
22 }{
23 {"priority_list_snake", "priority_list", lunatask.WorkflowPriorityList, false},
24 {"priority_list_kebab", "priority-list", lunatask.WorkflowPriorityList, false},
25 {"priority_list_upper", "PRIORITY_LIST", lunatask.WorkflowPriorityList, false},
26 {"priority_list_mixed", "Priority-List", lunatask.WorkflowPriorityList, false},
27 {"now_later_snake", "now_later", lunatask.WorkflowNowLater, false},
28 {"now_later_kebab", "now-later", lunatask.WorkflowNowLater, false},
29 {"now_later_upper", "NOW_LATER", lunatask.WorkflowNowLater, false},
30 {"kanban_lower", "kanban", lunatask.WorkflowKanban, false},
31 {"kanban_upper", "KANBAN", lunatask.WorkflowKanban, false},
32 {"plan_your_days_snake", "plan_your_days", lunatask.WorkflowPlanYourDays, false},
33 {"plan_your_days_kebab", "plan-your-days", lunatask.WorkflowPlanYourDays, false},
34 {"must_should_want_snake", "must_should_want", lunatask.WorkflowMustShouldWant, false},
35 {"must_should_want_kebab", "must-should-want", lunatask.WorkflowMustShouldWant, false},
36 {"eisenhower_lower", "eisenhower", lunatask.WorkflowEisenhower, false},
37 {"eisenhower_upper", "EISENHOWER", lunatask.WorkflowEisenhower, false},
38 {"invalid", "invalid", "", true},
39 {"empty", "", "", true},
40 {"numeric", "1", "", true},
41 {"typo", "kanbann", "", true},
42 }
43
44 for _, testCase := range tests {
45 t.Run(testCase.name, func(t *testing.T) {
46 t.Parallel()
47
48 got, err := lunatask.ParseWorkflow(testCase.input)
49 if (err != nil) != testCase.wantErr {
50 t.Errorf("ParseWorkflow(%q) error = %v, wantErr %v", testCase.input, err, testCase.wantErr)
51
52 return
53 }
54
55 if !testCase.wantErr && got != testCase.want {
56 t.Errorf("ParseWorkflow(%q) = %q, want %q", testCase.input, got, testCase.want)
57 }
58 })
59 }
60}
61
62func TestWorkflow_String(t *testing.T) {
63 t.Parallel()
64
65 tests := []struct {
66 name string
67 value lunatask.Workflow
68 want string
69 }{
70 {"priority_list", lunatask.WorkflowPriorityList, "priority_list"},
71 {"now_later", lunatask.WorkflowNowLater, "now_later"},
72 {"kanban", lunatask.WorkflowKanban, "kanban"},
73 {"plan_your_days", lunatask.WorkflowPlanYourDays, "plan_your_days"},
74 {"must_should_want", lunatask.WorkflowMustShouldWant, "must_should_want"},
75 {"eisenhower", lunatask.WorkflowEisenhower, "eisenhower"},
76 }
77
78 for _, tc := range tests {
79 t.Run(tc.name, func(t *testing.T) {
80 t.Parallel()
81
82 if got := tc.value.String(); got != tc.want {
83 t.Errorf("Workflow.String() = %q, want %q", got, tc.want)
84 }
85 })
86 }
87}
88
89func TestWorkflow_ValidStatuses(t *testing.T) {
90 t.Parallel()
91
92 tests := []struct {
93 name string
94 workflow lunatask.Workflow
95 want []lunatask.TaskStatus
96 }{
97 {
98 "priority_list",
99 lunatask.WorkflowPriorityList,
100 nil,
101 },
102 {
103 "now_later",
104 lunatask.WorkflowNowLater,
105 []lunatask.TaskStatus{lunatask.StatusLater, lunatask.StatusInProgress, lunatask.StatusCompleted},
106 },
107 {
108 "kanban",
109 lunatask.WorkflowKanban,
110 []lunatask.TaskStatus{
111 lunatask.StatusLater, lunatask.StatusNext, lunatask.StatusInProgress,
112 lunatask.StatusWaiting, lunatask.StatusCompleted,
113 },
114 },
115 {
116 "plan_your_days",
117 lunatask.WorkflowPlanYourDays,
118 []lunatask.TaskStatus{lunatask.StatusCompleted},
119 },
120 {
121 "must_should_want",
122 lunatask.WorkflowMustShouldWant,
123 []lunatask.TaskStatus{lunatask.StatusCompleted},
124 },
125 {
126 "eisenhower",
127 lunatask.WorkflowEisenhower,
128 []lunatask.TaskStatus{lunatask.StatusCompleted},
129 },
130 {
131 "unknown",
132 lunatask.Workflow("unknown"),
133 nil,
134 },
135 }
136
137 for _, testCase := range tests {
138 t.Run(testCase.name, func(t *testing.T) {
139 t.Parallel()
140
141 got := testCase.workflow.ValidStatuses()
142 if !slices.Equal(got, testCase.want) {
143 t.Errorf("Workflow.ValidStatuses() = %v, want %v", got, testCase.want)
144 }
145 })
146 }
147}
148
149func TestWorkflow_UsesMotivation(t *testing.T) {
150 t.Parallel()
151
152 tests := []struct {
153 name string
154 workflow lunatask.Workflow
155 want bool
156 }{
157 {"priority_list", lunatask.WorkflowPriorityList, false},
158 {"now_later", lunatask.WorkflowNowLater, false},
159 {"kanban", lunatask.WorkflowKanban, false},
160 {"plan_your_days", lunatask.WorkflowPlanYourDays, false},
161 {"must_should_want", lunatask.WorkflowMustShouldWant, true},
162 {"eisenhower", lunatask.WorkflowEisenhower, false},
163 }
164
165 for _, tc := range tests {
166 t.Run(tc.name, func(t *testing.T) {
167 t.Parallel()
168
169 if got := tc.workflow.UsesMotivation(); got != tc.want {
170 t.Errorf("Workflow.UsesMotivation() = %v, want %v", got, tc.want)
171 }
172 })
173 }
174}
175
176func TestWorkflow_UsesEisenhower(t *testing.T) {
177 t.Parallel()
178
179 tests := []struct {
180 name string
181 workflow lunatask.Workflow
182 want bool
183 }{
184 {"priority_list", lunatask.WorkflowPriorityList, false},
185 {"now_later", lunatask.WorkflowNowLater, false},
186 {"kanban", lunatask.WorkflowKanban, false},
187 {"plan_your_days", lunatask.WorkflowPlanYourDays, false},
188 {"must_should_want", lunatask.WorkflowMustShouldWant, false},
189 {"eisenhower", lunatask.WorkflowEisenhower, true},
190 }
191
192 for _, tc := range tests {
193 t.Run(tc.name, func(t *testing.T) {
194 t.Parallel()
195
196 if got := tc.workflow.UsesEisenhower(); got != tc.want {
197 t.Errorf("Workflow.UsesEisenhower() = %v, want %v", got, tc.want)
198 }
199 })
200 }
201}
202
203func TestWorkflow_UsesScheduling(t *testing.T) {
204 t.Parallel()
205
206 tests := []struct {
207 name string
208 workflow lunatask.Workflow
209 want bool
210 }{
211 {"priority_list", lunatask.WorkflowPriorityList, false},
212 {"now_later", lunatask.WorkflowNowLater, false},
213 {"kanban", lunatask.WorkflowKanban, false},
214 {"plan_your_days", lunatask.WorkflowPlanYourDays, true},
215 {"must_should_want", lunatask.WorkflowMustShouldWant, false},
216 {"eisenhower", lunatask.WorkflowEisenhower, false},
217 }
218
219 for _, tc := range tests {
220 t.Run(tc.name, func(t *testing.T) {
221 t.Parallel()
222
223 if got := tc.workflow.UsesScheduling(); got != tc.want {
224 t.Errorf("Workflow.UsesScheduling() = %v, want %v", got, tc.want)
225 }
226 })
227 }
228}
229
230func TestWorkflow_UsesPriority(t *testing.T) {
231 t.Parallel()
232
233 tests := []struct {
234 name string
235 workflow lunatask.Workflow
236 want bool
237 }{
238 {"priority_list", lunatask.WorkflowPriorityList, true},
239 {"now_later", lunatask.WorkflowNowLater, false},
240 {"kanban", lunatask.WorkflowKanban, false},
241 {"plan_your_days", lunatask.WorkflowPlanYourDays, false},
242 {"must_should_want", lunatask.WorkflowMustShouldWant, false},
243 {"eisenhower", lunatask.WorkflowEisenhower, false},
244 }
245
246 for _, tc := range tests {
247 t.Run(tc.name, func(t *testing.T) {
248 t.Parallel()
249
250 if got := tc.workflow.UsesPriority(); got != tc.want {
251 t.Errorf("Workflow.UsesPriority() = %v, want %v", got, tc.want)
252 }
253 })
254 }
255}
256
257func TestWorkflow_Description(t *testing.T) {
258 t.Parallel()
259
260 tests := []struct {
261 name string
262 workflow lunatask.Workflow
263 contains string
264 }{
265 {"priority_list", lunatask.WorkflowPriorityList, "priority"},
266 {"now_later", lunatask.WorkflowNowLater, "in-progress"},
267 {"kanban", lunatask.WorkflowKanban, "kanban"},
268 {"plan_your_days", lunatask.WorkflowPlanYourDays, "scheduled_on"},
269 {"must_should_want", lunatask.WorkflowMustShouldWant, "must"},
270 {"eisenhower", lunatask.WorkflowEisenhower, "Eisenhower"},
271 {"unknown", lunatask.Workflow("unknown"), "Unknown"},
272 }
273
274 for _, testCase := range tests {
275 t.Run(testCase.name, func(t *testing.T) {
276 t.Parallel()
277
278 got := testCase.workflow.Description()
279 if got == "" {
280 t.Error("Workflow.Description() returned empty string")
281 }
282
283 if !contains(got, testCase.contains) {
284 t.Errorf("Workflow.Description() = %q, want to contain %q", got, testCase.contains)
285 }
286 })
287 }
288}
289
290func TestWorkflows(t *testing.T) {
291 t.Parallel()
292
293 workflows := lunatask.Workflows()
294
295 if len(workflows) != 6 {
296 t.Errorf("Workflows() returned %d workflows, want 6", len(workflows))
297 }
298
299 expected := []lunatask.Workflow{
300 lunatask.WorkflowPriorityList,
301 lunatask.WorkflowNowLater,
302 lunatask.WorkflowKanban,
303 lunatask.WorkflowPlanYourDays,
304 lunatask.WorkflowMustShouldWant,
305 lunatask.WorkflowEisenhower,
306 }
307
308 if !slices.Equal(workflows, expected) {
309 t.Errorf("Workflows() = %v, want %v", workflows, expected)
310 }
311}
312
313func contains(s, substr string) bool {
314 return len(s) >= len(substr) && (s == substr || len(substr) == 0 ||
315 (len(s) > 0 && len(substr) > 0 && findSubstring(s, substr)))
316}
317
318func findSubstring(s, substr string) bool {
319 for i := 0; i <= len(s)-len(substr); i++ {
320 if s[i:i+len(substr)] == substr {
321 return true
322 }
323 }
324
325 return false
326}