This repository has no description
1package models
2
3import (
4 "testing"
5 "time"
6
7 "github.com/bluesky-social/indigo/atproto/syntax"
8 "tangled.org/core/api/tangled"
9)
10
11const testIssueSubject = "at://did:plc:anemone/sh.tangled.repo.issue/i1"
12
13func TestIssueStateFromRecord(t *testing.T) {
14 const rkey = "3jzfcijpj2z2a"
15
16 if _, err := IssueStateFromRecord("did:plc:akshay", rkey, tangled.RepoIssueState{
17 Issue: testIssueSubject,
18 State: "sh.tangled.repo.issue.state.reopened",
19 CreatedAt: "2026-06-01T00:00:00Z",
20 }); err == nil {
21 t.Fatal("unknown state variant must be rejected")
22 }
23
24 created := "2026-06-01T12:30:00Z"
25 rec, err := IssueStateFromRecord("did:plc:akshay", rkey, tangled.RepoIssueState{
26 Issue: testIssueSubject,
27 State: tangled.RepoIssueStateClosed,
28 CreatedAt: created,
29 })
30 if err != nil {
31 t.Fatalf("IssueStateFromRecord: %v", err)
32 }
33 want, _ := time.Parse(time.RFC3339, created)
34 if rec.Value != StateClosed || rec.SortMicros != want.UnixMicro() {
35 t.Fatalf("got value=%q micros=%d, want closed with createdAt as the sort key", rec.Value, rec.SortMicros)
36 }
37
38 tidRec, err := IssueStateFromRecord("did:plc:akshay", rkey, tangled.RepoIssueState{
39 Issue: testIssueSubject,
40 State: tangled.RepoIssueStateOpen,
41 CreatedAt: "not-a-datetime",
42 })
43 if err != nil {
44 t.Fatalf("IssueStateFromRecord tid fallback: %v", err)
45 }
46 tid, _ := syntax.ParseTID(rkey)
47 if tidRec.SortMicros != tid.Time().UnixMicro() {
48 t.Fatalf("SortMicros = %d, want TID micros %d when createdAt is unparseable", tidRec.SortMicros, tid.Time().UnixMicro())
49 }
50}
51
52func TestPullStatusFromRecord_Variants(t *testing.T) {
53 subject := "at://did:plc:limpet/sh.tangled.repo.pull/p1"
54 cases := map[string]StateValue{
55 tangled.RepoPullStatusOpen: StateOpen,
56 tangled.RepoPullStatusClosed: StateClosed,
57 tangled.RepoPullStatusMerged: StateMerged,
58 }
59 for wire, want := range cases {
60 rec, err := PullStatusFromRecord("did:plc:akshay", "3jzfcijpj2z2a", tangled.RepoPullStatus{
61 Pull: subject,
62 Status: wire,
63 CreatedAt: "2026-06-01T00:00:00Z",
64 })
65 if err != nil {
66 t.Fatalf("PullStatusFromRecord(%q): %v", wire, err)
67 }
68 if rec.Value != want {
69 t.Fatalf("PullStatusFromRecord(%q) value = %q, want %q", wire, rec.Value, want)
70 }
71 }
72
73 if _, err := PullStatusFromRecord("did:plc:akshay", "3jzfcijpj2z2a", tangled.RepoPullStatus{
74 Pull: subject,
75 Status: "sh.tangled.repo.pull.status.draft",
76 CreatedAt: "2026-06-01T00:00:00Z",
77 }); err == nil {
78 t.Fatal("unknown pull status variant must be rejected")
79 }
80}
81
82func TestAsIssueStateRecord_RoundTrip(t *testing.T) {
83 const rkey = "3jzfcijpj2z2a"
84 subject := syntax.ATURI(testIssueSubject)
85 created := time.Date(2026, 6, 30, 12, 30, 15, int(123*time.Millisecond), time.UTC)
86
87 for _, value := range []StateValue{StateOpen, StateClosed} {
88 rec, err := AsIssueStateRecord(subject, value, created)
89 if err != nil {
90 t.Fatalf("AsIssueStateRecord(%q): %v", value, err)
91 }
92 if rec.Issue != testIssueSubject {
93 t.Fatalf("Issue = %q, want %q", rec.Issue, testIssueSubject)
94 }
95
96 back, err := IssueStateFromRecord("did:plc:akshay", rkey, rec)
97 if err != nil {
98 t.Fatalf("IssueStateFromRecord after AsIssueStateRecord(%q): %v", value, err)
99 }
100 if back.Value != value {
101 t.Fatalf("round-trip value = %q, want %q", back.Value, value)
102 }
103 if back.SortMicros != created.UnixMicro() {
104 t.Fatalf("round-trip SortMicros = %d, want %d", back.SortMicros, created.UnixMicro())
105 }
106 }
107
108 if _, err := AsIssueStateRecord(subject, StateMerged, created); err == nil {
109 t.Fatal("merged is not a valid issue state and must be rejected")
110 }
111}
112
113func TestAsPullStatusRecords_RoundTrip(t *testing.T) {
114 const rkey = "3jzfcijpj2z2a"
115 subject := syntax.ATURI("at://did:plc:limpet/sh.tangled.repo.pull/p1")
116 created := time.Date(2026, 6, 30, 12, 30, 15, int(123*time.Millisecond), time.UTC)
117
118 for _, value := range []StateValue{StateOpen, StateClosed, StateMerged} {
119 recs, err := AsPullStatusRecords([]syntax.ATURI{subject}, value, created)
120 if err != nil {
121 t.Fatalf("AsPullStatusRecords(%q): %v", value, err)
122 }
123 if len(recs) != 1 {
124 t.Fatalf("AsPullStatusRecords(%q) returned %d records, want 1", value, len(recs))
125 }
126 rec := recs[0]
127 if rec.Pull != subject.String() {
128 t.Fatalf("Pull = %q, want %q", rec.Pull, subject)
129 }
130
131 back, err := PullStatusFromRecord("did:plc:akshay", rkey, rec)
132 if err != nil {
133 t.Fatalf("PullStatusFromRecord after AsPullStatusRecords(%q): %v", value, err)
134 }
135 if back.Value != value {
136 t.Fatalf("round-trip value = %q, want %q", back.Value, value)
137 }
138 if back.SortMicros != created.UnixMicro() {
139 t.Fatalf("round-trip SortMicros = %d, want %d", back.SortMicros, created.UnixMicro())
140 }
141 }
142
143 if _, err := AsPullStatusRecords([]syntax.ATURI{subject}, "bogus", created); err == nil {
144 t.Fatal("invalid pull status value must be rejected")
145 }
146}