Files
ttstd-infinite-canvas/backend/internal/kernel/token_billing_test.go

91 lines
3.2 KiB
Go

package kernel
import (
"errors"
"math"
"testing"
)
func TestTokenBillingAmount(t *testing.T) {
for _, test := range []struct {
name string
multiplier int64
terms []TokenBillingTerm
want int64
}{
{
name: "maximum configured price", multiplier: 10_000,
terms: []TokenBillingTerm{{Tokens: 10_000_000, PriceMicrocredits: 1_000_000_000_000}},
want: 10_000_000_000_000,
},
{
name: "maximum configured price with multiplier", multiplier: 12_500,
terms: []TokenBillingTerm{{Tokens: 10_000_000, PriceMicrocredits: 1_000_000_000_000}},
want: 12_500_000_000_000,
},
{
name: "round once after combining terms", multiplier: 10_000,
terms: []TokenBillingTerm{{Tokens: 1, PriceMicrocredits: 400_000}, {Tokens: 1, PriceMicrocredits: 400_000}, {Tokens: 1, PriceMicrocredits: 100_000}},
want: 1,
},
{
name: "apply multiplier before rounding", multiplier: 12_500,
terms: []TokenBillingTerm{{Tokens: 1, PriceMicrocredits: 400_000}, {Tokens: 1, PriceMicrocredits: 400_000}},
want: 1,
},
{
name: "fractional microcredit rounds up", multiplier: 1,
terms: []TokenBillingTerm{{Tokens: 1, PriceMicrocredits: 1}},
want: 1,
},
{
name: "maximum int64 result after overflowing intermediate sum", multiplier: 10_000,
terms: []TokenBillingTerm{{Tokens: math.MaxInt64, PriceMicrocredits: 500_000}, {Tokens: math.MaxInt64, PriceMicrocredits: 500_000}},
want: math.MaxInt64,
},
{
name: "free usage", multiplier: math.MaxInt64,
terms: []TokenBillingTerm{{Tokens: math.MaxInt64, PriceMicrocredits: 0}},
want: 0,
},
} {
t.Run(test.name, func(t *testing.T) {
amount, err := TokenBillingAmount(test.multiplier, test.terms...)
if err != nil || amount != test.want {
t.Fatalf("TokenBillingAmount() = %d, %v; want %d", amount, err, test.want)
}
})
}
}
func TestTokenBillingAmountRejectsInvalidParametersAndFinalOverflow(t *testing.T) {
for _, test := range []struct {
name string
multiplier int64
terms []TokenBillingTerm
wantErr error
}{
{name: "zero multiplier", terms: []TokenBillingTerm{{Tokens: 1, PriceMicrocredits: 1}}, wantErr: ErrInvalidTokenBilling},
{name: "negative multiplier", multiplier: -1, wantErr: ErrInvalidTokenBilling},
{name: "negative tokens", multiplier: 10_000, terms: []TokenBillingTerm{{Tokens: -1}}, wantErr: ErrInvalidTokenBilling},
{name: "negative price even with zero tokens", multiplier: 10_000, terms: []TokenBillingTerm{{PriceMicrocredits: -1}}, wantErr: ErrInvalidTokenBilling},
{
name: "final amount overflow", multiplier: 10_001,
terms: []TokenBillingTerm{{Tokens: math.MaxInt64, PriceMicrocredits: 1_000_000}},
wantErr: ErrTokenBillingOverflow,
},
{
name: "rounding causes final overflow", multiplier: 10_000,
terms: []TokenBillingTerm{{Tokens: math.MaxInt64, PriceMicrocredits: 1_000_000}, {Tokens: 1, PriceMicrocredits: 1}},
wantErr: ErrTokenBillingOverflow,
},
} {
t.Run(test.name, func(t *testing.T) {
amount, err := TokenBillingAmount(test.multiplier, test.terms...)
if amount != 0 || !errors.Is(err, test.wantErr) {
t.Fatalf("TokenBillingAmount() = %d, %v; want 0, %v", amount, err, test.wantErr)
}
})
}
}