AtlatestRepositoryfolio

folio / tree / testtest-project.sgl

1(import (sigil test)
2 (sigil struct)
3 (sigil string)
4 (sigil fs)
5 (sigil path)
6 (folio store)
7 (folio task)
8 (folio id)
9 (folio project)
10 (folio frontmatter))
12;; ============================================================
13;; Helpers
14;; ============================================================
16(define sample-project
17 (string-append
18 "---\n"
19 "status: active\n"
20 "goal: Add contact management\n"
21 "area: development\n"
22 "tags:\n- sigil\n- fastmail\n"
23 "last-updated: 2026-03-13\n"
24 "---\n"
25 "\n"
26 "# Bureau v2\n"
27 "\n"
28 "## Tasks\n"
29 "\n"
30 "- [ ] Add contact lookup tool {id: t-a3f2, priority: high, due: 2026-03-20}\n"
31 "- [ ] Improve search result ranking {id: t-b1c4, priority: medium}\n"
32 "- [x] Fix reply identity selection {id: t-c2d5, completed: 2026-03-13}\n"
33 "\n"
34 "## Log\n"
35 "\n"
36 "### 2026-03-13\n"
37 "\n"
38 "Fixed identity selection for replies.\n"
39 "\n"
40 "### 2026-03-12\n"
41 "\n"
42 "Added batch trash tool.\n"))
44;; ============================================================
45;; read-project
46;; ============================================================
48(test-group "read-project"
49 (test "parses project file"
50 (call-with-temp-directory
51 (lambda (dir)
52 (let ((file (path-join dir "bureau-v2.md")))
53 (write-file-string file sample-project)
54 (let ((proj (read-project file)))
55 (assert-equal "bureau-v2" (folio-project-name proj))
56 (assert-equal "active" (project-status proj))
57 (assert-equal "Add contact management" (project-goal proj))
58 (assert-equal "development" (project-area proj)))))))
60 (test "parses tasks"
61 (call-with-temp-directory
62 (lambda (dir)
63 (let ((file (path-join dir "test.md")))
64 (write-file-string file sample-project)
65 (let* ((proj (read-project file))
66 (tasks (folio-project-tasks proj)))
67 (assert-equal 3 (length tasks))
68 (assert-equal "Add contact lookup tool" (folio-task-text (car tasks)))
69 (assert-false (folio-task-done? (car tasks)))
70 (assert-true (folio-task-done? (caddr tasks))))))))
72 (test "parses log entries"
73 (call-with-temp-directory
74 (lambda (dir)
75 (let ((file (path-join dir "test.md")))
76 (write-file-string file sample-project)
77 (let* ((proj (read-project file))
78 (entries (folio-project-log-entries proj)))
79 (assert-equal 2 (length entries))
80 (assert-equal "2026-03-13" (caar entries))
81 (assert-true (string-contains? (cdar entries) "identity selection")))))))
83 (test "task counts"
84 (call-with-temp-directory
85 (lambda (dir)
86 (let ((file (path-join dir "test.md")))
87 (write-file-string file sample-project)
88 (let ((proj (read-project file)))
89 (let-values (((open done) (project-task-counts proj)))
90 (assert-equal 2 open)
91 (assert-equal 1 done))))))))
93;; ============================================================
94;; project-create!
95;; ============================================================
97(test-group "project-create!"
98 (test "creates project file with correct structure"
99 (call-with-temp-directory
100 (lambda (dir)
101 (let* ((store (make-folio-store dir))
102 (file (project-create! store "Bureau v2" "Add contact management" "development")))
103 (assert-true (file-exists? file))
104 (let ((proj (read-project file)))
105 (assert-equal "active" (project-status proj))
106 (assert-equal "Add contact management" (project-goal proj))
107 (assert-equal "development" (project-area proj))
108 (assert-equal 0 (length (folio-project-tasks proj)))
109 (assert-equal 1 (length (folio-project-log-entries proj)))))))))
111;; ============================================================
112;; project-add-task!
113;; ============================================================
115(test-group "project-add-task!"
116 (test "adds task to project"
117 (call-with-temp-directory
118 (lambda (dir)
119 (let* ((store (make-folio-store dir))
120 (file (project-create! store "Test" "Test goal" #f)))
121 (project-add-task! file "New task" '((priority . "high")))
122 (let* ((proj (read-project file))
123 (tasks (folio-project-tasks proj)))
124 (assert-equal 1 (length tasks))
125 (assert-equal "New task" (folio-task-text (car tasks)))
126 (assert-true (folio-task-id (car tasks)))))))))
128;; ============================================================
129;; project-add-log!
130;; ============================================================
132(test-group "project-add-log!"
133 (test "adds log entry"
134 (call-with-temp-directory
135 (lambda (dir)
136 (let* ((store (make-folio-store dir))
137 (file (project-create! store "Test" "Goal" #f)))
138 (project-add-log! file "Did some important work.")
139 (let* ((proj (read-project file))
140 (entries (folio-project-log-entries proj)))
141 ;; Should have the creation entry plus the new one
142 (assert-true (>= (length entries) 2))
143 (assert-true
144 (string-contains? (cdar entries) "important work"))))))))
146;; ============================================================
147;; project-archive!
148;; ============================================================
150(test-group "project-archive!"
151 (test "moves project to archive"
152 (call-with-temp-directory
153 (lambda (dir)
154 (let* ((store (make-folio-store dir))
155 (file (project-create! store "Old Project" "Done" #f)))
156 (assert-true (project-archive! store "old-project"))
157 (assert-false (file-exists? file))
158 (assert-true (file-exists?
159 (path-join (store-archive-project-dir store)
160 "old-project.md"))))))))
162;; ============================================================
163;; project-clean!
164;; ============================================================
166(test-group "project-clean!"
167 (test "moves completed tasks to log"
168 (call-with-temp-directory
169 (lambda (dir)
170 (let* ((store (make-folio-store dir))
171 (file (project-create! store "Test" "Goal" #f)))
172 (project-add-task! file "Task A" '((priority . "high")))
173 (project-add-task! file "Task B" '((priority . "low")))
174 ;; Complete task A
175 (let ((id (folio-task-id (car (folio-project-tasks (read-project file))))))
176 (backfill-ids! file)
177 ;; Re-read to get the id
178 (let* ((proj (read-project file))
179 (task-a-id (folio-task-id (car (folio-project-tasks proj)))))
180 ;; Manually complete it in the file
181 (let* ((content (read-file-string file))
182 (updated (string-replace content "- [ ] Task A" "- [x] Task A")))
183 (write-file-string file updated))
184 ;; Clean
185 (let ((count (project-clean! file)))
186 (assert-equal 1 count)
187 ;; Verify task list only has Task B
188 (let ((proj (read-project file)))
189 (assert-equal 1 (length (folio-project-tasks proj)))
190 (assert-equal "Task B" (folio-task-text (car (folio-project-tasks proj)))))
191 ;; Verify log has the completed task
192 (let ((content (read-file-string file)))
193 (assert-true (string-contains? content "Completed:"))
194 (assert-true (string-contains? content "Task A"))))))))))
196 (test "returns 0 when no completed tasks"
197 (call-with-temp-directory
198 (lambda (dir)
199 (let* ((store (make-folio-store dir))
200 (file (project-create! store "Test" "Goal" #f)))
201 (project-add-task! file "Open task" '())
202 (assert-equal 0 (project-clean! file)))))))