Files
comic-hasher/ch/associate_ids_test.go

147 lines
4.8 KiB
Go

package ch
import (
"bytes"
"errors"
"testing"
"gitea.narnian.us/lordwelch/goimagehash"
"github.com/google/go-cmp/cmp"
)
func TestAssociateIDsMergesGroups(t *testing.T) {
cvID := ID{Domain: NewSource("comicvine.gamespot.com"), ID: "1"}
metronID := ID{Domain: NewSource("metron.cloud"), ID: "2"}
gcdID := ID{Domain: NewSource("comics.org"), ID: "3"}
otherID := ID{Domain: NewSource("example.org"), ID: "4"}
hashes, err := NewSavedHashesV3(&SavedHashesV2{
IDs: [][]ID{{cvID, metronID}, {gcdID, otherID}},
Hashes: []SavedHashV2{
{ID: cvID, Hash: Hash{Kind: goimagehash.AHash, Hash: 1}},
},
})
if err != nil {
t.Fatal(err)
}
if err := hashes.AssociateIDs(metronID, gcdID); err != nil {
t.Fatal("failed to associate IDs:", err)
}
index, found := hashes.FindID(cvID)
if !found {
t.Fatal("failed to find CV ID")
}
if got := len(hashes.GetAllIDs(index)); got != 4 {
t.Fatalf("expected all 4 IDs to be in one group, got %d", got)
}
// Merging leaves an unused group behind. Encoding must compact or it will write an invalid file.
// We ensure that we can encode and decode after merging groups
buf := &bytes.Buffer{}
if err := EncodeHashesV3(hashes, buf); err != nil {
t.Fatal("failed to encode merged ID groups:", err)
}
loaded, err := DecodeHashesV3(buf)
if err != nil {
t.Fatal("failed to decode merged ID groups:", err)
}
index, found = loaded.FindID(cvID)
if !found {
t.Fatal("failed to find CV ID after round trip")
}
if got := len(loaded.GetAllIDs(index)); got != 4 {
t.Fatalf("expected all 4 IDs to be in one group after round trip, got %d", got)
}
}
func TestAssociateIDsCreatesGroup(t *testing.T) {
cvID := ID{Domain: NewSource("comicvine.gamespot.com"), ID: "1"}
metronID := ID{Domain: NewSource("metron.cloud"), ID: "2"}
hashes, err := NewSavedHashesV3(&SavedHashesV2{Hashes: []SavedHashV2{
{ID: cvID, Hash: Hash{Kind: goimagehash.AHash, Hash: 1}},
{ID: metronID, Hash: Hash{Kind: goimagehash.AHash, Hash: 1}},
}})
if err != nil {
t.Fatal(err)
}
if err := hashes.AssociateIDs(cvID, metronID); err != nil {
t.Fatal(err)
}
index, found := hashes.FindID(cvID)
if !found {
t.Fatal("failed to find CV ID")
}
if got := len(hashes.GetAllIDs(index)); got != 2 {
t.Fatalf("expected 2 equivalent IDs, got %d", got)
}
}
func TestAssociateIDsAddsUngroupedID(t *testing.T) {
cvID := ID{Domain: NewSource("comicvine.gamespot.com"), ID: "1"}
metronID := ID{Domain: NewSource("metron.cloud"), ID: "2"}
gcdID := ID{Domain: NewSource("comics.org"), ID: "3"}
tests := []struct {
name string
oldID ID
newID ID
ungrouped ID
}{
{name: "old ID is already grouped", oldID: metronID, newID: gcdID, ungrouped: gcdID},
{name: "new ID is already grouped", oldID: gcdID, newID: metronID, ungrouped: gcdID},
}
for _, test := range tests {
// Note that we have to create this on both iterations otherwise AssociateIDs does nothing on the second test
hashes, err := NewSavedHashesV3(&SavedHashesV2{
IDs: [][]ID{{cvID, metronID}},
Hashes: []SavedHashV2{
{ID: cvID, Hash: Hash{Kind: goimagehash.AHash, Hash: 1}},
{ID: gcdID, Hash: Hash{Kind: goimagehash.AHash, Hash: 2}},
},
})
t.Run(test.name, func(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if err := hashes.AssociateIDs(test.oldID, test.newID); err != nil {
t.Fatal("failed to associate grouped and ungrouped IDs:", err)
}
index, found := hashes.FindID(test.ungrouped)
if !found {
t.Fatal("failed to find formerly ungrouped ID:", test.ungrouped)
}
if diff := cmp.Diff([]ID{cvID, metronID, gcdID}, hashes.GetAllIDs(index), cmpOpts...); diff != "" {
t.Errorf("Expected all 3 (-want +got):\n%s", diff)
}
})
}
}
func TestAssociateIDsSameSourceConflict(t *testing.T) {
cvID := ID{Domain: NewSource("comicvine.gamespot.com"), ID: "1"}
metronID := ID{Domain: NewSource("metron.cloud"), ID: "2"}
cvOther := ID{Domain: NewSource("comicvine.gamespot.com"), ID: "3"}
hashes := SavedHashesV3{}
hashes.InsertID(metronID)
hashes.InsertHash(Hash{Kind: goimagehash.AHash, Hash: 1}, cvID)
hashes.InsertHash(Hash{Kind: goimagehash.AHash, Hash: 2}, cvOther)
if err := hashes.AssociateIDs(metronID, cvID); err != nil {
t.Fatal("unable to prepare test:", err)
}
// metron:2 already belongs to a group that contains a comicvine ID so
// comicvine:3 cannot be added to it.
if err := hashes.AssociateIDs(cvOther, metronID); !errors.Is(err, ErrIDConflict) {
t.Fatal("expected associating two IDs from the same source to fail: error:", err)
}
if err := hashes.AssociateIDs(metronID, cvOther); !errors.Is(err, ErrIDConflict) {
t.Fatal("expected the reversed association to fail for the same source conflict: error:", err)
}
index, found := hashes.FindID(cvOther)
if !found {
t.Fatal("failed to find CV ID")
}
if got := hashes.IDs[index].Group; got != NoIDGroup {
t.Fatalf("failed association modified the ID group: %d", got)
}
}