package performer import ( "testing" "github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/models/mocks" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) func nameFilter(n string) *models.PerformerFilterType { return &models.PerformerFilterType{ Name: &models.StringCriterionInput{ Value: n, Modifier: models.CriterionModifierEquals, }, } } func disambigFilter(n string, d string) *models.PerformerFilterType { return &models.PerformerFilterType{ Name: &models.StringCriterionInput{ Value: n, Modifier: models.CriterionModifierEquals, }, Disambiguation: &models.StringCriterionInput{ Value: d, Modifier: models.CriterionModifierEquals, }, } } func TestValidateName(t *testing.T) { db := mocks.NewDatabase() const ( name1 = "name 1" name2 = "name 2" disambig = "disambiguation" newName = "new name" newDisambig = "new disambiguation" ) // existing1 := models.Performer{ // Name: name1, // } // existing2 := models.Performer{ // Name: name2, // Disambiguation: disambig, // } pp := 1 findFilter := &models.FindFilterType{ PerPage: &pp, } db.Performer.On("QueryCount", testCtx, nameFilter(name1), findFilter).Return(1, nil) db.Performer.On("QueryCount", testCtx, nameFilter(name2), findFilter).Return(1, nil) db.Performer.On("QueryCount", testCtx, disambigFilter(name2, disambig), findFilter).Return(1, nil) db.Performer.On("QueryCount", testCtx, mock.Anything, findFilter).Return(0, nil) tests := []struct { tName string name string disambig string want error }{ {"missing name", "", newDisambig, ErrNameMissing}, {"new name", newName, "", nil}, {"new name new disambig", newName, newDisambig, nil}, {"new name existing disambig", newName, disambig, nil}, {"existing name", name1, "", &NameExistsError{name1, ""}}, {"existing name new disambig", name1, newDisambig, nil}, {"existing name existing disambig", name1, disambig, nil}, {"existing name and disambig", name2, disambig, &NameExistsError{name2, disambig}}, } for _, tt := range tests { t.Run(tt.tName, func(t *testing.T) { got := ValidateName(testCtx, tt.name, tt.disambig, db.Performer) assert.Equal(t, tt.want, got) }) } } func TestValidateUpdateName(t *testing.T) { db := mocks.NewDatabase() const ( name1 = "name 1" name2 = "name 2" disambig1 = "disambiguation 1" disambig2 = "disambiguation 2" newName = "new name" newDisambig = "new disambiguation" ) osUnset := models.OptionalString{} osNull := models.OptionalString{Set: true, Null: true} osName1 := models.NewOptionalString(name1) osName2 := models.NewOptionalString(name2) osDisambig1 := models.NewOptionalString(disambig1) osDisambig2 := models.NewOptionalString(disambig2) osNewName := models.NewOptionalString(newName) osNewDisambig := models.NewOptionalString(newDisambig) existing1 := models.Performer{ ID: 1, Name: name1, } existing2 := models.Performer{ ID: 2, Name: name2, Disambiguation: disambig1, } existing3 := models.Performer{ ID: 3, Name: name2, Disambiguation: disambig2, } pp := 2 findFilter := &models.FindFilterType{ PerPage: &pp, } db.Performer.On("Query", testCtx, nameFilter(name1), findFilter).Return([]*models.Performer{&existing1}, 1, nil) db.Performer.On("Query", testCtx, nameFilter(name2), findFilter).Return([]*models.Performer{&existing2, &existing3}, 2, nil) db.Performer.On("Query", testCtx, disambigFilter(name2, disambig1), findFilter).Return([]*models.Performer{&existing2}, 1, nil) db.Performer.On("Query", testCtx, disambigFilter(name2, disambig2), findFilter).Return([]*models.Performer{&existing3}, 1, nil) db.Performer.On("Query", testCtx, mock.Anything, findFilter).Return(nil, 0, nil) tests := []struct { tName string performer models.Performer name models.OptionalString disambig models.OptionalString want error }{ {"missing name", existing1, osNull, osUnset, ErrNameMissing}, {"same name", existing3, osName2, osUnset, nil}, {"same disambig", existing2, osUnset, osDisambig1, nil}, {"same name same disambig", existing2, osName2, osDisambig1, nil}, {"new name", existing1, osNewName, osUnset, nil}, {"new disambig", existing1, osUnset, osNewDisambig, nil}, {"new name new disambig", existing1, osNewName, osNewDisambig, nil}, {"remove disambig", existing3, osUnset, osNull, &NameExistsError{name2, ""}}, {"existing name keep disambig", existing3, osName1, osUnset, nil}, {"existing name remove disambig", existing3, osName1, osNull, &NameExistsError{name1, ""}}, {"existing disambig", existing2, osUnset, osDisambig2, &NameExistsError{name2, disambig2}}, {"existing name and disambig", existing1, osName2, osDisambig1, &NameExistsError{name2, disambig1}}, } for _, tt := range tests { t.Run(tt.tName, func(t *testing.T) { got := ValidateUpdateName(testCtx, tt.performer, tt.name, tt.disambig, db.Performer) assert.Equal(t, tt.want, got) }) } } func TestValidateAliases(t *testing.T) { const ( name1 = "name 1" name1U = "NAME 1" name2 = "name 2" name3 = "name 3" name4 = "name 4" ) tests := []struct { tName string name string aliases []string want error }{ {"no aliases", name1, nil, nil}, {"valid aliases", name2, []string{name3, name4}, nil}, {"duplicate alias", name1, []string{name2, name3, name2}, &DuplicateAliasError{name2}}, {"duplicate name", name4, []string{name4, name3}, &DuplicateAliasError{name4}}, {"duplicate alias caps", name2, []string{name1, name1U}, &DuplicateAliasError{name1U}}, {"duplicate name caps", name1U, []string{name1}, &DuplicateAliasError{name1}}, } for _, tt := range tests { t.Run(tt.tName, func(t *testing.T) { got := ValidateAliases(tt.name, models.NewRelatedStrings(tt.aliases)) assert.Equal(t, tt.want, got) }) } } func TestValidateUpdateAliases(t *testing.T) { const ( name1 = "name 1" name1U = "NAME 1" name2 = "name 2" name3 = "name 3" name4 = "name 4" ) existing := models.Performer{ Name: name1, Aliases: models.NewRelatedStrings([]string{name2}), } osUnset := models.OptionalString{} os1 := models.NewOptionalString(name1) os2 := models.NewOptionalString(name2) os3 := models.NewOptionalString(name3) os4 := models.NewOptionalString(name4) tests := []struct { tName string name models.OptionalString aliases []string want error }{ {"both unset", osUnset, nil, nil}, {"invalid name set", os2, nil, &DuplicateAliasError{name2}}, {"valid name set", os3, nil, nil}, {"valid aliases empty", os1, []string{}, nil}, {"invalid aliases set", osUnset, []string{name1U}, &DuplicateAliasError{name1U}}, {"valid aliases set", osUnset, []string{name3, name2}, nil}, {"invalid both set", os4, []string{name4}, &DuplicateAliasError{name4}}, {"valid both set", os2, []string{name1}, nil}, } for _, tt := range tests { t.Run(tt.tName, func(t *testing.T) { var aliases *models.UpdateStrings if tt.aliases != nil { aliases = &models.UpdateStrings{ Values: tt.aliases, Mode: models.RelationshipUpdateModeSet, } } got := ValidateUpdateAliases(existing, tt.name, aliases) assert.Equal(t, tt.want, got) }) } } func TestValidateDeathDate(t *testing.T) { date1, _ := models.ParseDate("2001-01-01") date2, _ := models.ParseDate("2002-01-01") date3, _ := models.ParseDate("2003-01-01") date4, _ := models.ParseDate("2004-01-01") tests := []struct { name string birthdate *models.Date deathdate *models.Date want error }{ {"both nil", nil, nil, nil}, {"birthdate nil", nil, &date1, nil}, {"deathdate nil", nil, &date2, nil}, {"valid", &date3, &date4, nil}, {"invalid", &date3, &date2, &DeathDateError{date3, date2}}, {"same date", &date1, &date1, nil}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := ValidateDeathDate(tt.birthdate, tt.deathdate) assert.Equal(t, tt.want, got) }) } } func TestValidateUpdateDeathDate(t *testing.T) { date1, _ := models.ParseDate("2001-01-01") date2, _ := models.ParseDate("2002-01-01") date3, _ := models.ParseDate("2003-01-01") date4, _ := models.ParseDate("2004-01-01") existing := models.Performer{ Birthdate: &date2, DeathDate: &date3, } odUnset := models.OptionalDate{} odNull := models.OptionalDate{Set: true, Null: true} od1 := models.NewOptionalDate(date1) od2 := models.NewOptionalDate(date2) od3 := models.NewOptionalDate(date3) od4 := models.NewOptionalDate(date4) tests := []struct { name string birthdate models.OptionalDate deathdate models.OptionalDate want error }{ {"both unset", odUnset, odUnset, nil}, {"invalid birthdate set", od4, odUnset, &DeathDateError{date4, date3}}, {"valid birthdate set", od1, odUnset, nil}, {"valid birthdate set null", odNull, odUnset, nil}, {"invalid deathdate set", odUnset, od1, &DeathDateError{date2, date1}}, {"valid deathdate set", odUnset, od4, nil}, {"valid deathdate set null", odUnset, odNull, nil}, {"invalid both set", od3, od2, &DeathDateError{date3, date2}}, {"valid both set", od2, od3, nil}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := ValidateUpdateDeathDate(existing, tt.birthdate, tt.deathdate) assert.Equal(t, tt.want, got) }) } }