Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

refactor

c5902451905acdaa478f8476844ccd4a510d9ca9 · Keenan Nemetz · 17d ago · parent ec2aba4b

internal/issues/issues_test.go → metadata/issues_test.go +18−40

@@ -1,12 +1,11 @@
1 package issues
1 package metadata
2 2
3 3 import (
4 4 "strings"
5 5 "testing"
6 6 "time"
7 7
8 "github.com/rodent-software/vole/internal/frontmatter"
9 "github.com/rodent-software/vole/internal/identity"
8 "github.com/rodent-software/vole/forge/identity"
10 9 )
11 10
12 11 const (
@@ -34,7 +33,7 @@ func validContents() map[string]string {
34 33
35 34 func TestParseValid(t *testing.T) {
36 35 t.Parallel()
37 list, err := Parse(validContents())
36 list, err := ParseIssues(validContents())
38 37 if err != nil {
39 38 t.Fatalf("unexpected error: %v", err)
40 39 }
@@ -67,7 +66,7 @@ func TestParseIgnoresUnrelatedFiles(t *testing.T) {
67 66 t.Parallel()
68 67 c := validContents()
69 68 c["README.md"] = "notes about the issues branch\n"
70 if _, err := Parse(c); err != nil {
69 if _, err := ParseIssues(c); err != nil {
71 70 t.Fatalf("unrelated files should be ignored: %v", err)
72 71 }
73 72 }
@@ -107,7 +106,7 @@ func TestRenderParseRoundTrip(t *testing.T) {
107 106 if err != nil {
108 107 t.Fatalf("%q: render: %v", title, err)
109 108 }
110 got, err := Parse(map[string]string{"issues/" + idA + "/issue.md": string(raw)})
109 got, err := ParseIssues(map[string]string{"issues/" + idA + "/issue.md": string(raw)})
111 110 if err != nil {
112 111 t.Fatalf("%q: parse:\n%s\nerror: %v", title, raw, err)
113 112 }
@@ -131,7 +130,7 @@ func TestAssigneesAreAccountNames(t *testing.T) {
131 130 // Build the files the way a writer would, so the validator is what refuses
132 131 // rather than YAML refusing to parse the line first.
133 132 mk := func(assignees ...string) map[string]string {
134 d := frontmatter.New()
133 d := NewDoc()
135 134 d.Text("title", "assigned")
136 135 d.Word("state", "open")
137 136 d.Word("author", "keenan")
@@ -146,7 +145,7 @@ func TestAssigneesAreAccountNames(t *testing.T) {
146 145 return c
147 146 }
148 147
149 list, err := Parse(mk("wilbur", "keenan"))
148 list, err := ParseIssues(mk("wilbur", "keenan"))
150 149 if err != nil {
151 150 t.Fatalf("valid assignees refused: %v", err)
152 151 }
@@ -155,7 +154,7 @@ func TestAssigneesAreAccountNames(t *testing.T) {
155 154 }
156 155
157 156 for _, bad := range []string{"Wilbur", "wil.bur", "@wilbur", "w", strings.Repeat("a", 33), "wil bur"} {
158 _, err := Parse(mk(bad))
157 _, err := ParseIssues(mk(bad))
159 158 ve, ok := err.(*ValidationError)
160 159 if !ok {
161 160 t.Fatalf("%q was accepted: %v", bad, err)
@@ -200,7 +199,7 @@ func TestAssigneeRoundTrip(t *testing.T) {
200 199 if !strings.Contains(string(raw), "assignees:\n - keenan\n - wilbur\n") {
201 200 t.Fatalf("assignees not written sorted, one per line:\n%s", raw)
202 201 }
203 got, err := Parse(map[string]string{"issues/" + idA + "/issue.md": string(raw)})
202 got, err := ParseIssues(map[string]string{"issues/" + idA + "/issue.md": string(raw)})
204 203 if err != nil {
205 204 t.Fatalf("parse: %v\n%s", raw, err)
206 205 }
@@ -219,7 +218,7 @@ func TestAnchorRoundTrips(t *testing.T) {
219 218 Created: time.Date(2026, 10, 23, 9, 0, 0, 0, time.UTC),
220 219 Body: "this line is wrong\n",
221 220 Anchor: &Anchor{
222 Path: "internal/hook/hook.go",
221 Path: "hook/hook.go",
223 222 Side: "new",
224 223 Line: 412,
225 224 Blob: "0123456789abcdef0123456789abcdef01234567",
@@ -301,17 +300,17 @@ func TestAuthorOfReadsAnyMetadataFile(t *testing.T) {
301 300 // about where a comment lives, or an edit commits to a path nobody reads.
302 301 func TestCommentPathMatchesTheReader(t *testing.T) {
303 302 t.Parallel()
304 path := CommentPath(idA, idB)
303 path := IssueCommentPath(idA, idB)
305 304 if path != "issues/"+idA+"/comments/"+idB+".md" {
306 305 t.Fatalf("path = %q", path)
307 306 }
308 if !IsCommentPath(path) {
307 if !IsIssueCommentPath(path) {
309 308 t.Fatal("a comment path was not recognised")
310 309 }
311 if IsCommentPath("issues/" + idA + "/issue.md") {
310 if IsIssueCommentPath("issues/" + idA + "/issue.md") {
312 311 t.Fatal("an issue file was mistaken for a comment")
313 312 }
314 if IsCommentPath("requests/" + idA + "/request.md") {
313 if IsIssueCommentPath("requests/" + idA + "/request.md") {
315 314 t.Fatal("a request file was mistaken for a comment")
316 315 }
317 316 }
@@ -323,7 +322,7 @@ func TestUnquotedTitleIsRefused(t *testing.T) {
323 322 c := validContents()
324 323 c["issues/"+idA+"/issue.md"] = "---\ntitle: fix #12 crash\nstate: open\nauthor: keenan\n" +
325 324 "created: 2026-10-22T21:00:00Z\n---\nbody\n"
326 _, err := Parse(c)
325 _, err := ParseIssues(c)
327 326 ve, ok := err.(*ValidationError)
328 327 if !ok {
329 328 t.Fatalf("error is %T, want *ValidationError: %v", err, err)
@@ -340,7 +339,7 @@ func TestTitleOnOneLine(t *testing.T) {
340 339 c := validContents()
341 340 c["issues/"+idA+"/issue.md"] = "---\ntitle: \"two\\nlines\"\nstate: open\nauthor: keenan\n" +
342 341 "created: 2026-10-22T21:00:00Z\n---\nbody\n"
343 if _, err := Parse(c); err == nil {
342 if _, err := ParseIssues(c); err == nil {
344 343 t.Fatal("a title with a newline was accepted")
345 344 }
346 345 }
@@ -400,7 +399,7 @@ func TestValidationFailures(t *testing.T) {
400 399 t.Run(name, func(t *testing.T) {
401 400 c := validContents()
402 401 mutate(c)
403 if _, err := Parse(c); err == nil {
402 if _, err := ParseIssues(c); err == nil {
404 403 t.Fatal("expected a validation error")
405 404 } else if _, ok := err.(*ValidationError); !ok {
406 405 t.Fatalf("error is %T, want *ValidationError: %v", err, err)
@@ -413,7 +412,7 @@ func TestAllProblemsReported(t *testing.T) {
413 412 t.Parallel()
414 413 c := validContents()
415 414 c["issues/"+idA+"/issue.md"] = "---\ntitle: \"\"\nstate: nope\nauthor: \"\"\ncreated: \"\"\n---\n"
416 _, err := Parse(c)
415 _, err := ParseIssues(c)
417 416 ve, ok := err.(*ValidationError)
418 417 if !ok {
419 418 t.Fatalf("error is %T: %v", err, err)
@@ -422,24 +421,3 @@ func TestAllProblemsReported(t *testing.T) {
422 421 t.Fatalf("want several problems, got %d: %v", len(ve.Problems), ve.Problems)
423 422 }
424 423 }
425
426 func TestULIDAndOrdering(t *testing.T) {
427 t.Parallel()
428 a, err := NewULID(time.Unix(1700000000, 0))
429 if err != nil {
430 t.Fatal(err)
431 }
432 b, err := NewULID(time.Unix(1700000001, 0))
433 if err != nil {
434 t.Fatal(err)
435 }
436 if !ValidULID(a) || !ValidULID(b) {
437 t.Fatalf("invalid ulids: %q %q", a, b)
438 }
439 if a >= b {
440 t.Fatalf("ulids do not sort by time: %q >= %q", a, b)
441 }
442 if ValidULID("lowercase0123456789ABCDEFGH") {
443 t.Fatal("lowercase ulid accepted")
444 }
445 }