package signinreward import "testing" func TestNormalizeSaveDays(t *testing.T) { validDays := []SignInRewardDayConfigInput{ {DayIndex: 7, RewardGroupID: mustFlexibleOptionalInt64(70)}, {DayIndex: 1, RewardGroupID: mustFlexibleOptionalInt64(10)}, {DayIndex: 3, RewardGroupID: mustFlexibleOptionalInt64(30)}, {DayIndex: 2, RewardGroupID: mustFlexibleOptionalInt64(20)}, {DayIndex: 4, RewardGroupID: mustFlexibleOptionalInt64(40)}, {DayIndex: 5, RewardGroupID: mustFlexibleOptionalInt64(50)}, {DayIndex: 6, RewardGroupID: mustFlexibleOptionalInt64(60)}, } normalized, err := normalizeSaveDays(validDays, true) if err != nil { t.Fatalf("normalizeSaveDays() error = %v", err) } for index, item := range normalized { expectedDay := index + 1 if item.DayIndex != expectedDay { t.Fatalf("normalized[%d].DayIndex = %d, want %d", index, item.DayIndex, expectedDay) } } t.Run("enabled config rejects empty reward day", func(t *testing.T) { days := append([]SignInRewardDayConfigInput(nil), validDays...) days[0].RewardGroupID = flexibleOptionalInt64{} if _, err := normalizeSaveDays(days, true); err == nil { t.Fatalf("normalizeSaveDays() error = nil, want error") } }) t.Run("disabled config allows empty reward day", func(t *testing.T) { days := append([]SignInRewardDayConfigInput(nil), validDays...) days[0].RewardGroupID = flexibleOptionalInt64{} if _, err := normalizeSaveDays(days, false); err != nil { t.Fatalf("normalizeSaveDays() error = %v, want nil", err) } }) } func TestFlexibleOptionalInt64(t *testing.T) { testCases := []struct { name string input string wantNil bool want int64 }{ {name: "null", input: "null", wantNil: true}, {name: "empty string", input: `""`, wantNil: true}, {name: "number", input: "123", want: 123}, {name: "string number", input: `"456"`, want: 456}, } for _, testCase := range testCases { var value flexibleOptionalInt64 if err := value.UnmarshalJSON([]byte(testCase.input)); err != nil { t.Fatalf("%s: UnmarshalJSON() error = %v", testCase.name, err) } if testCase.wantNil { if value.Int64Ptr() != nil { t.Fatalf("%s: Int64Ptr() = %v, want nil", testCase.name, *value.Int64Ptr()) } continue } if value.Int64Ptr() == nil || *value.Int64Ptr() != testCase.want { t.Fatalf("%s: Int64Ptr() = %v, want %d", testCase.name, value.Int64Ptr(), testCase.want) } } } func mustFlexibleOptionalInt64(value int64) flexibleOptionalInt64 { return flexibleOptionalInt64{value: &value} } func TestSignInRewardCycleHelpers(t *testing.T) { testCases := []struct { streak int nextDayIndex int cycleProgress int }{ {streak: 0, nextDayIndex: 1, cycleProgress: 0}, {streak: 1, nextDayIndex: 2, cycleProgress: 1}, {streak: 6, nextDayIndex: 7, cycleProgress: 6}, {streak: 7, nextDayIndex: 1, cycleProgress: 7}, {streak: 8, nextDayIndex: 2, cycleProgress: 1}, {streak: 14, nextDayIndex: 1, cycleProgress: 7}, } for _, testCase := range testCases { if got := nextSignInRewardDayIndex(testCase.streak); got != testCase.nextDayIndex { t.Fatalf("nextSignInRewardDayIndex(%d) = %d, want %d", testCase.streak, got, testCase.nextDayIndex) } if got := streakToCycleProgress(testCase.streak); got != testCase.cycleProgress { t.Fatalf("streakToCycleProgress(%d) = %d, want %d", testCase.streak, got, testCase.cycleProgress) } } }