~bigbes/sr-ht-spec

ref: f8a7a1743ad9704ff46f9e9319f8cc22b75bbdef sr-ht-spec/graph/proposals_test.go -rw-r--r-- 2.7 KiB
f8a7a174 — Eugene Blikh feat(graph): wire the proposals read to service.ListProposals (Phase 3) 26 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package graph

import (
	"context"
	"testing"
	"time"

	"sourcecraft.dev/bigbes/sr-ht-spec/core"
	"sourcecraft.dev/bigbes/sr-ht-spec/service"
)

// stubLister is a proposalLister that returns a fixed row, so the adapter's
// field mapping can be checked without a Service, a database or a repository.
type stubLister struct {
	rows     []service.Proposal
	gotSpace core.SpaceRef
	gotState core.ProposalState
}

func (s *stubLister) ListProposals(_ context.Context, space core.SpaceRef, state core.ProposalState) ([]service.Proposal, error) {
	s.gotSpace = space
	s.gotState = state
	return s.rows, nil
}

// TestNewProposalsMapsEveryField proves the adapter is a faithful rename: every
// field of a service proposal reaches the graph shape unchanged, and the query
// arguments are forwarded verbatim. A dropped field here would silently blank a
// column in the read schema.
func TestNewProposalsMapsEveryField(t *testing.T) {
	ref := core.SpaceRef{Owner: "bigbes", Name: "rfcs"}
	created := time.Date(2026, 7, 22, 12, 0, 0, 0, time.UTC)
	resolved := created.Add(time.Hour)
	want := service.Proposal{
		ID:           42,
		Space:        ref,
		Title:        "Add a note",
		Rationale:    "because",
		BaseRev:      "1f0c1d1a1e2b3c4d5e6f708192a3b4c5d6e7f809",
		Branch:       "proposals/42",
		State:        core.StateMerged,
		Approval:     core.ApprovalPolicy,
		MergedRev:    "2a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d",
		Agent:        "claude-code/spec-writer",
		AgentSession: "sess-1",
		Created:      created,
		Resolved:     &resolved,
	}
	stub := &stubLister{rows: []service.Proposal{want}}

	got, err := NewProposals(stub).ListProposals(context.Background(), ref, core.StateMerged)
	if err != nil {
		t.Fatalf("ListProposals: %v", err)
	}
	if stub.gotSpace != ref || stub.gotState != core.StateMerged {
		t.Fatalf("forwarded (%v, %s), want (%v, merged)", stub.gotSpace, stub.gotState, ref)
	}
	if len(got) != 1 {
		t.Fatalf("got %d proposals, want 1", len(got))
	}
	g := got[0]
	mismatches := []struct {
		field     string
		got, want any
	}{
		{"ID", g.ID, want.ID},
		{"Space", g.Space, want.Space},
		{"Title", g.Title, want.Title},
		{"Rationale", g.Rationale, want.Rationale},
		{"BaseRev", g.BaseRev, want.BaseRev},
		{"Branch", g.Branch, want.Branch},
		{"State", g.State, want.State},
		{"Approval", g.Approval, want.Approval},
		{"MergedRev", g.MergedRev, want.MergedRev},
		{"Agent", g.Agent, want.Agent},
		{"AgentSession", g.AgentSession, want.AgentSession},
		{"Created", g.Created, want.Created},
	}
	for _, m := range mismatches {
		if m.got != m.want {
			t.Errorf("%s = %v, want %v", m.field, m.got, m.want)
		}
	}
	if g.Resolved == nil || !g.Resolved.Equal(resolved) {
		t.Errorf("Resolved = %v, want %v", g.Resolved, resolved)
	}
}