Files
2026-10-25 15:02:41 +08:00

241 lines
5.8 KiB
Go

package pricing
import (
"math"
"testing"
)
func TestScreenshotExample(t *testing.T) {
config := DefaultConfig()
result := config.Calculate(Input{
CoinM: 226,
Insurance: "3*3",
States: map[string]bool{},
DailyLossM: 10,
})
if result.ReferenceRatio != 46 {
t.Fatalf("reference ratio = %v, want 46", result.ReferenceRatio)
}
if result.FinalRatio != 46 {
t.Fatalf("final ratio = %v, want 46", result.FinalRatio)
}
if result.CoinBasePrice != 491.3 {
t.Fatalf("coin base price = %v, want 491.3", result.CoinBasePrice)
}
if result.ItemPrice != 0 {
t.Fatalf("item price = %v, want 0", result.ItemPrice)
}
if result.TotalPrice != 491.3 {
t.Fatalf("total price = %v, want 491.3", result.TotalPrice)
}
}
func TestAllStatesMatched(t *testing.T) {
config := DefaultConfig()
result := config.Calculate(Input{
CoinM: 100,
Insurance: "3*3",
States: map[string]bool{
"melee": true,
"operatorRed": true,
"staminaMax": true,
"loadMax": true,
"weapon": true,
},
DailyLossM: 10,
})
if result.ReferenceRatio != 40 {
t.Fatalf("reference ratio = %v, want 40", result.ReferenceRatio)
}
if result.CoinBasePrice != 250 {
t.Fatalf("coin base price = %v, want 250", result.CoinBasePrice)
}
}
func TestMissingPenalty(t *testing.T) {
config := DefaultConfig()
result := config.Calculate(Input{
CoinM: 100,
Insurance: "3*3",
States: map[string]bool{
"melee": true,
"operatorRed": true,
"staminaMax": true,
"loadMax": true,
},
DailyLossM: 10,
})
if result.ConfigPenalty != 1 {
t.Fatalf("config penalty = %v, want 1", result.ConfigPenalty)
}
if result.ReferenceRatio != 41 {
t.Fatalf("reference ratio = %v, want 41", result.ReferenceRatio)
}
if result.CoinBasePrice != 243.9 {
t.Fatalf("coin base price = %v, want 243.9", result.CoinBasePrice)
}
}
func TestCoinCorrectionUsesHighestCrossedThreshold(t *testing.T) {
config := DefaultConfig()
cases := []struct {
coinM float64
want float64
}{
{130, 0},
{130.1, 1},
{230, 1},
{230.1, 2.5},
{380.1, 4},
{600, 5},
}
for _, item := range cases {
result := config.Calculate(Input{CoinM: item.coinM, Insurance: "3*3", DailyLossM: 10})
if result.CoinCorrection != item.want {
t.Fatalf("coinM=%v correction=%v, want %v", item.coinM, result.CoinCorrection, item.want)
}
}
}
func TestDailyLossAdjustment(t *testing.T) {
config := DefaultConfig()
cases := []struct {
loss float64
want float64
}{
{0, 0},
{10, 0},
{20, 1},
{30, 2},
{40, 3},
{50, 4},
{90, 4},
}
for _, item := range cases {
result := config.Calculate(Input{CoinM: 100, Insurance: "3*3", DailyLossM: item.loss})
if result.DailyLossAdjustment != item.want {
t.Fatalf("dailyLoss=%v adjustment=%v, want %v", item.loss, result.DailyLossAdjustment, item.want)
}
}
}
func TestAcceleratedRatioClamp(t *testing.T) {
config := DefaultConfig()
base := Input{CoinM: 226, Insurance: "3*3", DailyLossM: 10}
result := config.Calculate(withSaleRatio(base, 50))
if result.FinalRatio != 50 {
t.Fatalf("final ratio = %v, want 50", result.FinalRatio)
}
if result.MaxRatio != 56 {
t.Fatalf("max ratio = %v, want 56", result.MaxRatio)
}
result = config.Calculate(withSaleRatio(base, 100))
if result.FinalRatio != 56 {
t.Fatalf("clamped ratio = %v, want 56", result.FinalRatio)
}
result = config.Calculate(withSaleRatio(base, 30))
if result.FinalRatio != 46 {
t.Fatalf("ratio below reference = %v, want 46", result.FinalRatio)
}
}
func TestConsumablePriceParsing(t *testing.T) {
cases := []struct {
price string
want float64
}{
{"0.6元/发", 0.6},
{"6元/60发", 0.1},
{"2.5元/个", 2.5},
{"3元/张", 3},
{"2元", 2},
{"", 0},
}
for _, item := range cases {
if got := ParseUnitPrice(item.price); math.Abs(got-item.want) > 1e-9 {
t.Fatalf("ParseUnitPrice(%q)=%v, want %v", item.price, got, item.want)
}
}
}
func TestConsumablesAndFreeItems(t *testing.T) {
config := DefaultConfig()
result := config.Calculate(Input{
CoinM: 100,
Insurance: "3*3",
DailyLossM: 10,
States: map[string]bool{
"melee": true,
"operatorRed": true,
"staminaMax": true,
"loadMax": true,
"weapon": true,
},
Quantities: map[string]float64{
"awmAmmo": 10,
"helmet6": 2,
},
FreeItems: map[string]bool{
"helmet6": true,
},
})
if result.ItemPrice != 6 {
t.Fatalf("item price = %v, want 6", result.ItemPrice)
}
if result.TotalPrice != 256 {
t.Fatalf("total price = %v, want 256", result.TotalPrice)
}
}
func TestGridCardDisabledAtThreeByThree(t *testing.T) {
config := DefaultConfig()
result := config.Calculate(Input{
CoinM: 100,
Insurance: "3*3",
DailyLossM: 10,
Quantities: map[string]float64{"gridCard9": 3},
})
if result.ItemPrice != 0 {
t.Fatalf("item price = %v, want 0", result.ItemPrice)
}
for _, item := range result.Items {
if item.Key == "gridCard9" && !item.Disabled {
t.Fatal("gridCard9 should be disabled at 3*3")
}
}
result = config.Calculate(Input{
CoinM: 100,
Insurance: "2*3",
DailyLossM: 10,
Quantities: map[string]float64{"gridCard9": 3},
})
if result.ItemPrice != 9 {
t.Fatalf("item price at 2*3 = %v, want 9", result.ItemPrice)
}
}
func TestNormalizeRestoresEmptySections(t *testing.T) {
normalized := Normalize(Config{})
if len(normalized.InsuranceBaseRatios) == 0 {
t.Fatal("insurance ratios should fall back to defaults")
}
if len(normalized.RatioConfigItems) == 0 {
t.Fatal("ratio config items should fall back to defaults")
}
if len(normalized.QuantityItems) == 0 {
t.Fatal("quantity items should fall back to defaults")
}
if normalized.AcceleratedMaxRatio != 10 {
t.Fatalf("accelerated max = %v, want 10", normalized.AcceleratedMaxRatio)
}
}
func withSaleRatio(input Input, ratio float64) Input {
input.SaleRatio = ratio
return input
}