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