package backend import ( "fmt" "reflect" "testing" ) type dedupTargetStub struct { headers []MessageHeader bodies map[uint32][]byte deleted []uint32 } func (s *dedupTargetStub) Folders() ([]TargetFolder, error) { return nil, nil } func (s *dedupTargetStub) Delim() string { return "/" } func (s *dedupTargetStub) EnsureFolder(string) error { return nil } func (s *dedupTargetStub) Append(string, RawMessage) error { return nil } func (s *dedupTargetStub) Headers(string, int, int) ([]MessageHeader, error) { return s.headers, nil } func (s *dedupTargetStub) AllHeaders(string) ([]MessageHeader, error) { return s.headers, nil } func (s *dedupTargetStub) FetchOne(_ string, uid uint32) (RawMessage, error) { body, ok := s.bodies[uid] if !ok { return RawMessage{}, fmt.Errorf("missing uid %d", uid) } return RawMessage{Body: body}, nil } func (s *dedupTargetStub) DeleteUIDs(_ string, uids []uint32) error { s.deleted = append(s.deleted, uids...) return nil } func (s *dedupTargetStub) Close() error { return nil } func TestDedupTargetFolderProtectsDifferentBodiesWithSameMessageID(t *testing.T) { sameA := []byte("Message-ID: \r\n\r\nA") sameB := []byte("Message-ID: \r\n\r\nB") dst := &dedupTargetStub{ headers: []MessageHeader{ {UID: 1, MessageID: "same@example.com"}, {UID: 2, MessageID: "same@example.com"}, {UID: 3, MessageID: "same@example.com"}, }, bodies: map[uint32][]byte{1: sameA, 2: sameA, 3: sameB}, } report, err := dedupTargetFolder(dst, "INBOX", true) if err != nil { t.Fatal(err) } if report.Groups != 1 || report.ExtraCopies != 1 || report.VariantGroups != 1 { t.Fatalf("unexpected report: %#v", report) } if !reflect.DeepEqual(dst.deleted, []uint32{2}) { t.Fatalf("deleted=%v, want only exact duplicate UID 2", dst.deleted) } } func TestDedupTargetFolderAbortsBeforeDeleteWhenBodyCannotBeVerified(t *testing.T) { dst := &dedupTargetStub{ headers: []MessageHeader{{UID: 1, MessageID: "same@example.com"}, {UID: 2, MessageID: "same@example.com"}}, bodies: map[uint32][]byte{1: []byte("Message-ID: \r\n\r\nA")}, } if _, err := dedupTargetFolder(dst, "INBOX", true); err == nil { t.Fatal("expected safe dedup to fail when a body cannot be fetched") } if len(dst.deleted) != 0 { t.Fatalf("deleted despite incomplete verification: %v", dst.deleted) } }