package cprelation import ( "errors" "strings" "testing" ) func TestNormalizeRelationsForcesCPMaxCountAndKeepsSiblingLimits(t *testing.T) { relations, err := normalizeRelations([]relationDTO{ relationInput(relationTypeCP, 99), relationInput(relationTypeBrother, 7), relationInput(relationTypeSister, 8), }) if err != nil { t.Fatalf("normalizeRelations() error = %v", err) } got := map[string]int32{} for _, relation := range relations { got[relation.RelationType] = relation.MaxCountPerUser } if got[relationTypeCP] != 1 { t.Fatalf("CP max count = %d, want 1", got[relationTypeCP]) } if got[relationTypeBrother] != 7 { t.Fatalf("brother max count = %d, want 7", got[relationTypeBrother]) } if got[relationTypeSister] != 8 { t.Fatalf("sister max count = %d, want 8", got[relationTypeSister]) } } func TestNormalizeRelationsRequiresIncreasingLevelThresholds(t *testing.T) { input := relationInput(relationTypeBrother, 5) input.Levels[2].IntimacyThreshold = input.Levels[1].IntimacyThreshold _, err := normalizeRelations([]relationDTO{ relationInput(relationTypeCP, 1), input, relationInput(relationTypeSister, 5), }) if !errors.Is(err, ErrInvalidArgument) { t.Fatalf("normalizeRelations() error = %v, want ErrInvalidArgument", err) } } func TestNormalizeCPListOptionsBoundsPageSize(t *testing.T) { options := normalizeCPListOptions(cpListOptions{Page: -3, PageSize: 1000, Status: "ALL", RelationType: " Brother "}) if options.Page != 1 { t.Fatalf("page = %d, want 1", options.Page) } if options.PageSize != cpListMaxPageSize { t.Fatalf("page size = %d, want max %d", options.PageSize, cpListMaxPageSize) } if options.Status != "" { t.Fatalf("status = %q, want empty all filter", options.Status) } if options.RelationType != relationTypeBrother { t.Fatalf("relation type = %q, want brother", options.RelationType) } } func TestRelationshipListWhereValidatesFilters(t *testing.T) { whereSQL, args, err := relationshipListWhere("lalu", cpListOptions{RelationType: relationTypeSister, Status: "active"}) if err != nil { t.Fatalf("relationshipListWhere() error = %v", err) } if !strings.Contains(whereSQL, "r.app_code = ?") || !strings.Contains(whereSQL, "r.relation_type = ?") || !strings.Contains(whereSQL, "r.status = ?") { t.Fatalf("relationship where sql missing filters: %s", whereSQL) } wantArgs := []any{"lalu", relationTypeSister, statusActive} if len(args) != len(wantArgs) { t.Fatalf("args len = %d, want %d: %#v", len(args), len(wantArgs), args) } for index := range wantArgs { if args[index] != wantArgs[index] { t.Fatalf("args[%d] = %#v, want %#v", index, args[index], wantArgs[index]) } } if _, _, err := relationshipListWhere("lalu", cpListOptions{RelationType: "enemy"}); !errors.Is(err, ErrInvalidArgument) { t.Fatalf("invalid relation type error = %v, want ErrInvalidArgument", err) } if _, _, err := relationshipListWhere("lalu", cpListOptions{Status: "pending"}); !errors.Is(err, ErrInvalidArgument) { t.Fatalf("invalid relationship status error = %v, want ErrInvalidArgument", err) } } func TestApplicationListWhereValidatesApplicationStatuses(t *testing.T) { whereSQL, args, err := applicationListWhere("lalu", cpListOptions{RelationType: relationTypeCP, Status: "pending"}) if err != nil { t.Fatalf("applicationListWhere() error = %v", err) } if !strings.Contains(whereSQL, "a.relation_type = ?") || !strings.Contains(whereSQL, "a.status = ?") { t.Fatalf("application where sql missing filters: %s", whereSQL) } if len(args) != 3 || args[0] != "lalu" || args[1] != relationTypeCP || args[2] != "pending" { t.Fatalf("application args mismatch: %#v", args) } if _, _, err := applicationListWhere("lalu", cpListOptions{Status: "active"}); !errors.Is(err, ErrInvalidArgument) { t.Fatalf("invalid application status error = %v, want ErrInvalidArgument", err) } } func TestRelationshipDurationDaysIsInclusive(t *testing.T) { const formedAtMS int64 = 1700000000000 if got := relationshipDurationDays(formedAtMS, 0, formedAtMS); got != 1 { t.Fatalf("same moment duration = %d, want 1", got) } if got := relationshipDurationDays(formedAtMS, 0, formedAtMS+dayMS*2+1); got != 3 { t.Fatalf("third day duration = %d, want 3", got) } if got := relationshipDurationDays(formedAtMS, formedAtMS+dayMS, formedAtMS+dayMS*9); got != 2 { t.Fatalf("ended relationship duration = %d, want 2", got) } if got := relationshipDurationDays(formedAtMS, formedAtMS-1, formedAtMS+dayMS); got != 0 { t.Fatalf("invalid ended duration = %d, want 0", got) } } func TestCPGiftSnapshotEmpty(t *testing.T) { if !((&cpGiftSnapshotDTO{}).empty()) { t.Fatalf("zero gift should be empty") } gift := cpGiftSnapshotDTO{GiftValue: 100} if gift.empty() { t.Fatalf("gift with value should not be empty") } } func relationInput(relationType string, maxCount int32) relationDTO { return relationDTO{ RelationType: relationType, MaxCountPerUser: maxCount, ApplicationExpireHours: defaultExpireHours, Status: statusActive, Levels: []levelDTO{ {Level: 1, IntimacyThreshold: 0, Status: statusActive}, {Level: 2, IntimacyThreshold: 10_000, Status: statusActive}, {Level: 3, IntimacyThreshold: 30_000, Status: statusActive}, {Level: 4, IntimacyThreshold: 60_000, Status: statusActive}, {Level: 5, IntimacyThreshold: 100_000, Status: statusActive}, }, } }