package listing import ( "encoding/json" "testing" ) func TestConsumableValueOnlyCountsChargedResources(t *testing.T) { value := consumableValue(map[string]any{ "resources": []any{ map[string]any{"mode": "收费", "quantity": float64(5), "price": "0.1元/个"}, map[string]any{"mode": "赠送", "quantity": float64(3), "price": "0.6元/个"}, map[string]any{"mode": "收费", "quantity": float64(2), "price": "1元/2个"}, }, }) if value != 1.5 { t.Fatalf("expected 1.5, got %.2f", value) } } func TestCalculateAdminAdjustedPriceByRatio(t *testing.T) { base, total, ratio := calculateAdminAdjustedPrice(AdminPriceAdjustRequest{BuyerRatio: 25}, 1000, 20) if base != 40 || total != 60 || ratio != 25 { t.Fatalf("unexpected adjusted price: base=%.2f total=%.2f ratio=%.2f", base, total, ratio) } } func TestCalculateAdminAdjustedPriceByTotalPrice(t *testing.T) { base, total, ratio := calculateAdminAdjustedPrice(AdminPriceAdjustRequest{BuyerTotalPriceCent: 7000}, 1000, 20) if base != 50 || total != 70 || ratio != 20 { t.Fatalf("unexpected adjusted price: base=%.2f total=%.2f ratio=%.2f", base, total, ratio) } } func TestValidateRequestRequiresDepositAboveConsumables(t *testing.T) { req := CreateRequest{ Title: "测试账号", ServerRegion: "烽火地带", PriceCent: 10000, DepositAmountCent: 200, HafCoinAmount: 1000000, ScreenshotURLS: []string{"https://example.com/a.png"}, AssetSummary: map[string]any{ "resources": []any{ map[string]any{"mode": "收费", "quantity": float64(2), "price": "1元/个"}, }, }, } if err := validateRequest(req, publishRules{}); err != ErrDepositTooLow { t.Fatalf("expected ErrDepositTooLow, got %v", err) } req.DepositAmountCent = 300 if err := validateRequest(req, publishRules{}); err != nil { t.Fatalf("expected valid request, got %v", err) } } func TestValidateRequiredOnlineTime(t *testing.T) { req := CreateRequest{ AssetSummary: map[string]any{ "online_time": map[string]any{ "start": "09:00", "end": "23:00", }, }, } if err := validateRequiredOnlineTime(req); err != nil { t.Fatalf("expected valid online time, got %v", err) } } func TestValidateRequiredOnlineTimeRejectsMissing(t *testing.T) { req := CreateRequest{AssetSummary: map[string]any{}} if err := validateRequiredOnlineTime(req); err != ErrMissingOnlineTime { t.Fatalf("expected ErrMissingOnlineTime, got %v", err) } } func TestValidateRequiredOnlineTimeRejectsInvalidRange(t *testing.T) { req := CreateRequest{ AssetSummary: map[string]any{ "online_time": map[string]any{ "start": "23:00", "end": "09:00", }, }, } if err := validateRequiredOnlineTime(req); err != ErrInvalidOnlineTime { t.Fatalf("expected ErrInvalidOnlineTime, got %v", err) } } func TestCreateRequiresPublishAgreements(t *testing.T) { service := NewService(&Repository{}, nil) _, err := service.Create(t.Context(), 1, CreateRequest{}) if err != ErrAgreementRequired { t.Fatalf("expected ErrAgreementRequired, got %v", err) } } func TestApplySellerListingPriceUsesSellerTotalPrice(t *testing.T) { item := &ListingDTO{ PriceCent: 23800, AssetSummary: map[string]any{ "price_breakdown": map[string]any{ "seller_total_price": 200, }, }, } applySellerListingPrice(item) if item.PriceCent != 20000 { t.Fatalf("expected seller price 20000, got %d", item.PriceCent) } } func TestApplySellerListingPriceKeepsFallbackPrice(t *testing.T) { item := &ListingDTO{ PriceCent: 23800, AssetSummary: map[string]any{ "price_breakdown": map[string]any{ "seller_total_price": 0, }, }, } applySellerListingPrice(item) if item.PriceCent != 23800 { t.Fatalf("expected fallback price 23800, got %d", item.PriceCent) } } func TestParseExternalUploadItemsAcceptsSingleObject(t *testing.T) { items, err := parseExternalUploadItems(json.RawMessage(validExternalUploadDataJSON())) if err != nil { t.Fatalf("expected single upload parsed, got %v", err) } if len(items) != 1 || items[0].LoginMethod != "QQ账号密码" { t.Fatalf("unexpected items: %#v", items) } } func TestParseExternalUploadItemsReportsMissingFields(t *testing.T) { _, err := parseExternalUploadItems(json.RawMessage(`{"loginMethod":"QQ账号密码","currency":{"hafuCoin":197.1}}`)) if err == nil { t.Fatal("expected validation error") } validationErr, ok := err.(UploadValidationError) if !ok { t.Fatalf("expected UploadValidationError, got %T", err) } expected := []string{"data.rank", "data.level", "data.currency.recycleRatio", "data.dailyConsumption"} for _, field := range expected { if !containsString(validationErr.Missing, field) { t.Fatalf("expected missing %s in %#v", field, validationErr.Missing) } } } func TestExternalAccountToCreateRequestMapsUploadFields(t *testing.T) { req := externalAccountToCreateRequest("客服1", 1772526103000, ExternalAccountData{ LoginMethod: "QQ账号密码", Rank: "黑鹰", Level: 60, SafeSlots: 9, SecretKD: 1.6, DailyLossM: 7, Deposit: 400, BanRecord: "无", CommonRegion: "郑州", Currency: ExternalUploadCurrency{ HafuCoin: 197.1, RecycleRatio: 43, RecycleRent: 458, }, DailyConsumption: ExternalDailyConsumption{Stamina: 7, Weight: 7}, Inventory: ExternalUploadInventory{ AWMBullets: 45, Level6Helmets: 14, Level6Armor: 17, Skins: []string{"信条", "电锯惊魂"}, }, }) if req.ServerRegion != "QQ" { t.Fatalf("expected QQ server region, got %q", req.ServerRegion) } if req.HafCoinAmount != 197100000 { t.Fatalf("expected haf coin amount 197100000, got %d", req.HafCoinAmount) } if req.PriceCent != 45800 || req.DepositAmountCent != 40000 { t.Fatalf("unexpected price/deposit cent %d/%d", req.PriceCent, req.DepositAmountCent) } if req.AssetSummary["season_insurance"] != "3*3" { t.Fatalf("expected 3*3 insurance, got %#v", req.AssetSummary["season_insurance"]) } if req.AssetSummary["daily_loss_m"] != float64(7) { t.Fatalf("expected daily loss 7, got %#v", req.AssetSummary["daily_loss_m"]) } if req.AssetSummary["stamina_level"] != "7级" || req.AssetSummary["load_level"] != "7级" { t.Fatalf("unexpected stamina/load: %#v", req.AssetSummary) } groups := req.AssetSummary["skin_groups"].(map[string][]string) if len(groups["melee"]) != 2 { t.Fatalf("expected melee skins mapped, got %#v", groups) } if len(req.ScreenshotURLS) != 1 || req.ScreenshotURLS[0] != defaultUploadScreenshot { t.Fatalf("expected default screenshot, got %#v", req.ScreenshotURLS) } } func validExternalUploadDataJSON() string { return `{ "loginMethod":"QQ账号密码", "rank":"黑鹰", "level":60, "safeSlots":9, "secretKD":1.6, "dailyLossM":7, "deposit":400, "currency":{"hafuCoin":197.1,"recycleRatio":43,"recycleRent":458}, "dailyConsumption":{"stamina":7,"weight":7} }` } func containsString(values []string, target string) bool { for _, value := range values { if value == target { return true } } return false }