package routing // This file holds in-memory fakes for the two injected dependencies. It must // import no HTTP and no DB package (SPEC-002 §5, the purity assertion). import ( "fmt" "testing" ) // fakeResolver is an in-memory Resolver: guid -> enrolled. A missing guid is // "not found". It records the guids it was asked about. type fakeResolver struct { users map[string]bool // guid -> enrolled calls []string } func (f *fakeResolver) GUID(guid string) (bool, bool) { f.calls = append(f.calls, guid) enrolled, found := f.users[guid] return found, enrolled } // forbiddenResolver fails the test if it is ever called. It proves the reserved // switch never touches identity (SPEC-002 §3.5 / test row 2). type forbiddenResolver struct { t *testing.T } func (r forbiddenResolver) GUID(guid string) (bool, bool) { r.t.Helper() r.t.Errorf("resolver must not be called (guid=%q)", guid) return false, false } // fakeModule is an in-memory Module: a function whitelist, an optional numeric // classifier, a default function, and an action whitelist. type fakeModule struct { name string deflt string // function for an empty/absent PARAM3 routes map[string]string // PARAM3 -> function numeric bool // classify numeric PARAM3 as "detail" actions map[string]string // action -> function } func (m *fakeModule) Name() string { return m.name } func (m *fakeModule) Route(function string, tail Params) (string, Params, bool) { if function == "" { return m.deflt, tail, true } if fn, ok := m.routes[function]; ok { return fn, tail, true } if m.numeric && IsNumeric(function) { return "detail", Params{function}, true } return "", nil, false } func (m *fakeModule) Action(action string) (string, bool) { fn, ok := m.actions[action] return fn, ok } // fakeRegistry is an in-memory Registry. type fakeRegistry map[string]Module func (r fakeRegistry) Module(name string) (Module, bool) { m, ok := r[name] return m, ok } // The module set used by the test matrix (SPEC-002 §3.7 uses `requests`). var ( homeModule = &fakeModule{name: "home", deflt: "dashboard"} requestsModule = &fakeModule{ name: "requests", deflt: "list", routes: map[string]string{ "open": "open", "closed": "closed", "pto": "pto", "equipment": "equipment", }, numeric: true, actions: map[string]string{"submit": "submit"}, } hrModule = &fakeModule{ name: "hr", routes: map[string]string{"save-data": "save-data"}, actions: map[string]string{"save-data": "save-data"}, } ) var testRegistry = fakeRegistry{ "home": homeModule, "requests": requestsModule, "hr": hrModule, } // resolveFmt renders a Resolution compactly for failure messages. func resolveFmt(r Resolution) string { return fmt.Sprintf( "{Kind:%s Workflow:%q Module:%q Function:%q Params:%v Redirect:%q}", r.Kind, r.Workflow, r.Module, r.Function, []string(r.Params), r.Redirect, ) }