package identity import ( "encoding/json" "reflect" "strings" "testing" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" ) func TestComparisonKeyNormalizesSupportedEquivalences(t *testing.T) { tests := []struct { name string left string right string }{ {name: "case", left: "Silver Key", right: "sILVER kEY"}, {name: "compatibility", left: "Silver Key", right: "Silver Key"}, {name: "whitespace", left: " Silver\u2003Key ", right: "Silver Key"}, {name: "apostrophe", left: "Healer’s Kit", right: "healer's kit"}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { if ComparisonKey(test.left) != ComparisonKey(test.right) { t.Fatalf("ComparisonKey(%q) = %q, ComparisonKey(%q) = %q", test.left, ComparisonKey(test.left), test.right, ComparisonKey(test.right)) } }) } if ComparisonKey("Silver Key") == ComparisonKey("Gold Key") { t.Fatal("different item types received the same comparison key") } } func TestDeriveIDUsesExactCompactIdentityBytes(t *testing.T) { const wantID = "item:sha256:2f211c60b9bdcf3a6dd64086cc4c05df5b3357ae02cb462f7ef8988d9bd2fa4f" const wantIdentity = `["dnd.item_registry.identity.v1","silver key"]` encoded, err := json.Marshal([]string{Policy, ComparisonKey("Silver Key")}) if err != nil || string(encoded) != wantIdentity { t.Fatalf("identity bytes = %q, %v; want %s", encoded, err, wantIdentity) } if Policy != "dnd.item_registry.identity.v1" || IdentityPolicy != Policy { t.Fatalf("identity policy = %q/%q", Policy, IdentityPolicy) } if got := DeriveID(" SILVER\u2003KEY "); got != wantID || !IsValidID(got) || got != IDFor("Silver Key") { t.Fatalf("DeriveID() = %q, want %q", got, wantID) } if DeriveID(" \u2003 ") != "" { t.Fatal("empty identity produced an ID") } for _, invalid := range []string{"", "item:sha256:", "item:sha256:ABC", "item:sha256:" + strings.Repeat("0", 63), "item:sha256:" + strings.Repeat("0", 65)} { if IsValidID(invalid) { t.Fatalf("IsValidID(%q) = true, want false", invalid) } } } func TestValidateRegistryReportsDeterministicIdentityProblemsWithoutMutation(t *testing.T) { items := []dnd.Item{ {ID: DeriveID("Silver Key"), Name: "Silver Key"}, {ID: DeriveID("Silver Key"), Name: " silver key "}, {ID: "bad", Name: "Gold Key"}, {ID: DeriveID("Silver Key"), Name: "Healer's Kit"}, {ID: "", Name: " "}, } before := append([]dnd.Item(nil), items...) issues := ValidateRegistry(items) if !reflect.DeepEqual(items, before) { t.Fatal("ValidateRegistry() mutated its input") } want := []IssueCode{ IssueDuplicateCanonical, IssueDuplicateID, IssueInvalidID, IssueIDMismatch, IssueEmptyCanonicalName, } seen := make(map[IssueCode]bool) for _, issue := range issues { seen[issue.Code] = true } for _, code := range want { if !seen[code] { t.Errorf("ValidateRegistry() issues = %#v, missing %s", issues, code) } } }