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)
}
}