package utils import ( "reflect" "testing" "bookhoard/internal/database" "github.com/jackc/pgx/v5/pgtype" ) func TestMergeOverrides(t *testing.T) { got := MergeOverrides([]string{"title", "tags"}, "tags", "description", "") want := []string{"title", "tags", "description"} if !reflect.DeepEqual(got, want) { t.Errorf("MergeOverrides() = %v, want %v", got, want) } if MergeOverrides(nil) == nil { t.Error("MergeOverrides(nil) must return non-nil slice") } } func TestDetectMetadataOverrides(t *testing.T) { existing := database.MediaItems{ Title: "Scanned Title", Description: pgtype.Text{String: "Scanned description", Valid: true}, Tags: []string{"foo", "bar"}, } params := database.UpdateMediaItemParams{ // unchanged Title: "Scanned Title", // changed Description: pgtype.Text{String: "My custom description", Valid: true}, Tags: []string{"foo", "bar"}, } got := DetectMetadataOverrides(params, existing) if !reflect.DeepEqual(got, []string{"description"}) { t.Errorf("DetectMetadataOverrides() = %v, want [description]", got) } // Overrides accumulate: an existing override survives a later save. existing.MetadataOverrides = []string{"publisher"} got = DetectMetadataOverrides(params, existing) want := []string{"publisher", "description"} if !reflect.DeepEqual(got, want) { t.Errorf("DetectMetadataOverrides() accumulate = %v, want %v", got, want) } // An untouched save detects nothing new. noop := database.UpdateMediaItemParams{ Title: existing.Title, Description: existing.Description, Tags: existing.Tags, } got = DetectMetadataOverrides(noop, existing) if !reflect.DeepEqual(got, []string{"publisher"}) { t.Errorf("DetectMetadataOverrides() noop = %v, want [publisher]", got) } } func TestDetectMetadataOverridesUnsetFormsEqual(t *testing.T) { // Zero-value params must not look "changed" against NULL-ish columns. existing := database.MediaItems{ PageCount: pgtype.Int4{Int32: 0, Valid: false}, SeriesNumber: pgtype.Int4{Int32: 5, Valid: true}, CommunityRating: pgtype.Float8{Float64: 0, Valid: false}, } params := database.UpdateMediaItemParams{ PageCount: pgtype.Int4{Int32: 0, Valid: false}, SeriesNumber: pgtype.Int4{Int32: 0, Valid: false}, // cleared by user -> changed CommunityRating: pgtype.Float8{Float64: 0, Valid: false}, } got := DetectMetadataOverrides(params, existing) if !reflect.DeepEqual(got, []string{"series_number"}) { t.Errorf("DetectMetadataOverrides() = %v, want [series_number]", got) } } func TestApplyMetadataOverrides(t *testing.T) { existing := database.MediaItems{ Title: "Custom Title", Description: pgtype.Text{String: "Custom desc", Valid: true}, Tags: []string{"mine"}, TagsSearch: []string{"mine"}, CoverImagePath: pgtype.Text{String: "books/x.epub.custom_cover.jpg", Valid: true}, } params := database.UpdateMediaItemParams{ Title: "Scanned Title", Description: pgtype.Text{String: "Scanned desc", Valid: true}, Tags: []string{"scanned"}, TagsSearch: []string{"scanned"}, CoverImagePath: pgtype.Text{String: "books/x.epub.cover.jpg", Valid: true}, } // Only title and tags overridden; scanned description and cover win. existing.MetadataOverrides = []string{"title", "tags"} ApplyMetadataOverrides(¶ms, existing) if params.Title != "Custom Title" { t.Errorf("Title = %q, want %q", params.Title, "Custom Title") } if !reflect.DeepEqual(params.Tags, []string{"mine"}) || !reflect.DeepEqual(params.TagsSearch, []string{"mine"}) { t.Error("Tags/TagsSearch must be restored together") } if params.Description.String != "Scanned desc" { t.Errorf("Description = %q, want scanned value", params.Description.String) } if params.CoverImagePath.String != "books/x.epub.cover.jpg" { t.Errorf("CoverImagePath = %q, want scanned value", params.CoverImagePath.String) } }