package processor import ( "math/rand" "testing" "github.com/google/uuid" "github.com/stretchr/testify/assert" "apskel-pos-be/internal/constants" "apskel-pos-be/internal/repository" ) func TestSplitVoucherCost(t *testing.T) { october := uuid.New() // RFC ยง7.6: Rp10.000 voucher for 8.000 EnakPoint, 6.000 from an EnakGame reward // and 2.000 from shopping. parts := SplitVoucherCost(10_000, []repository.RedemptionPointSource{ {Points: 2_000, SourceType: constants.WalletTxTypeEarn}, {Points: 6_000, SourceType: constants.WalletTxTypeGameReward, BudgetID: &october}, }) assert.EqualValues(t, 2_500, parts[0].Cost) assert.EqualValues(t, 7_500, parts[1].Cost) // Not evenly divisible: the remainder goes to the largest part, the first of equals. parts = SplitVoucherCost(10_000, []repository.RedemptionPointSource{{Points: 3}, {Points: 3}, {Points: 3}}) assert.Equal(t, []int64{3_334, 3_333, 3_333}, []int64{parts[0].Cost, parts[1].Cost, parts[2].Cost}) parts = SplitVoucherCost(100, []repository.RedemptionPointSource{{Points: 1}, {Points: 5}, {Points: 1}}) assert.Equal(t, []int64{14, 72, 14}, []int64{parts[0].Cost, parts[1].Cost, parts[2].Cost}) // No overflow on large numbers. parts = SplitVoucherCost(9_000_000_000_000, []repository.RedemptionPointSource{{Points: 3_000_000_000_000}, {Points: 6_000_000_000_000}}) assert.Equal(t, []int64{3_000_000_000_000, 6_000_000_000_000}, []int64{parts[0].Cost, parts[1].Cost}) assert.Empty(t, SplitVoucherCost(10, nil)) // Whatever the numbers, the parts add up to the face value and none is negative. rng := rand.New(rand.NewSource(7)) for i := 0; i < 2_000; i++ { face := rng.Int63n(1_000_000) + 1 sources := make([]repository.RedemptionPointSource, rng.Intn(5)+1) for j := range sources { sources[j].Points = rng.Int63n(10_000) + 1 } var sum int64 for _, p := range SplitVoucherCost(face, sources) { assert.GreaterOrEqual(t, p.Cost, int64(0)) sum += p.Cost } assert.Equal(t, face, sum) } }