1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package domain_test
4
5import (
6 "strings"
7 "testing"
8 "time"
9
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/require"
12
13 "bnema.dev/ermite/internal/domain"
14)
15
16func TestPendingIssueID(t *testing.T) {
17 t.Parallel()
18 id, err := domain.NewPendingIssueID()
19 require.NoError(t, err)
20 assert.Len(t, id.String(), domain.PendingIssueIDLen)
21 got, err := domain.ParsePendingIssueID(id.String())
22 require.NoError(t, err)
23 assert.Equal(t, id, got)
24 other, err := domain.NewPendingIssueID()
25 require.NoError(t, err)
26 assert.NotEqual(t, id, other)
27
28 for _, bad := range []string{
29 "", "short", strings.ToUpper(id.String()), id.String() + "a", id.String()[:25] + "1",
30 strings.Repeat("a", 25) + "b", // spare bits set
31 strings.Repeat("a", 24) + "=a", "../" + strings.Repeat("a", 23),
32 } {
33 _, err := domain.ParsePendingIssueID(bad)
34 assert.ErrorIs(t, err, domain.ErrInvalid, "%q", bad)
35 }
36 _, err = domain.ParsePendingIssueID(strings.Repeat("a", 26))
37 assert.NoError(t, err)
38}
39
40func TestParsePendingAuthor(t *testing.T) {
41 t.Parallel()
42 got, err := domain.ParsePendingAuthor("")
43 require.NoError(t, err)
44 assert.Empty(t, got)
45 got, err = domain.ParsePendingAuthor("Al\u202ee\x01x")
46 require.NoError(t, err)
47 assert.Equal(t, "Alex", got)
48 _, err = domain.ParsePendingAuthor(strings.Repeat("a", 41))
49 assert.Error(t, err)
50 _, err = domain.ParsePendingAuthor("\xff")
51 assert.Error(t, err)
52 got, err = domain.ParsePendingAuthor(strings.Repeat("é", 40))
53 require.NoError(t, err)
54 assert.Len(t, []rune(got), 40)
55}
56
57func TestIssueSubmittedKind(t *testing.T) {
58 t.Parallel()
59 assert.Equal(t, "issue.submitted", domain.IssueSubmitted{}.EventKind())
60}
61
62func TestSubmissionLimitsAreTheDocumentedOnes(t *testing.T) {
63 t.Parallel()
64 assert.Equal(t, 3, domain.SubmitPerHour)
65 assert.Equal(t, 10, domain.SubmitPerDay)
66 assert.Equal(t, 200, domain.MaxPendingIssues)
67 assert.Equal(t, 30*24*time.Hour, domain.BanDuration)
68}
69
70func TestApprovedIssue(t *testing.T) {
71 t.Parallel()
72 at := time.Date(2026, 1, 2, 3, 4, 5, 0, time.UTC)
73 now := at.Add(time.Hour)
74 title, err := domain.ParseIssueTitle("t")
75 require.NoError(t, err)
76 repo, err := domain.ParseRepoName("proj")
77 require.NoError(t, err)
78
79 named := domain.ApprovedIssue(domain.PendingIssue{Repo: repo, Title: title, Author: "Alex", CreatedAt: at}, now)
80 assert.Equal(t, domain.IssueStateOpen, named.State)
81 assert.Equal(t, "Alex", named.Author)
82 assert.True(t, named.External)
83 assert.Equal(t, repo, named.Repo)
84 assert.Equal(t, at, named.CreatedAt)
85 assert.Equal(t, now, named.UpdatedAt)
86 assert.Zero(t, named.Number, "the store numbers it")
87
88 anon := domain.ApprovedIssue(domain.PendingIssue{Repo: repo, Title: title, CreatedAt: at}, now)
89 assert.Equal(t, domain.AnonymousAuthor, anon.Author)
90}