package main import ( "context" "encoding/json" "net/http" "net/http/httptest" "path/filepath" "testing" "hfb_price_tool/internal/pricing" ) func TestNormalizeServerURL(t *testing.T) { cases := []struct { raw string want string }{ {"https://hao858.com/", "https://hao858.com"}, {"hao858.com", "https://hao858.com"}, {"http://127.0.0.1:8080/", "http://127.0.0.1:8080"}, } for _, item := range cases { got, err := normalizeServerURL(item.raw) if err != nil { t.Fatalf("normalizeServerURL(%q) error: %v", item.raw, err) } if got != item.want { t.Fatalf("normalizeServerURL(%q)=%q, want %q", item.raw, got, item.want) } } if _, err := normalizeServerURL("ftp://hao858.com"); err == nil { t.Fatal("ftp url should be rejected") } } func TestFetchRemotePublishOptions(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { if request.URL.Path != publishEndpoint { t.Fatalf("unexpected path: %s", request.URL.Path) } writer.Header().Set("Content-Type", "application/json") _, _ = writer.Write([]byte(`{ "code":"ok", "message":"ok", "data":{ "ratio_config":{ "insurance_base_ratios":[{"insurance":"3*3","ratio":40}], "config_items":[{"key":"melee","label":"刀皮","kind":"skin_group","missing_penalty":1}], "coin_corrections":[{"threshold_m":130,"correction":1}] }, "quantity_items":[{"key":"awmAmmo","label":"AWM子弹","price":"0.6元/发"}] } }`)) })) defer server.Close() remote, err := fetchRemotePublishOptions(context.Background(), server.URL) if err != nil { t.Fatalf("fetchRemotePublishOptions error: %v", err) } if len(remote.RatioConfig.InsuranceBaseRatios) != 1 { t.Fatalf("insurance count = %d, want 1", len(remote.RatioConfig.InsuranceBaseRatios)) } if len(remote.QuantityItems) != 1 || remote.QuantityItems[0].Key != "awmAmmo" { t.Fatalf("unexpected quantity items: %+v", remote.QuantityItems) } } func TestFetchRemotePublishOptionsRejectsErrorEnvelope(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("Content-Type", "application/json") _, _ = writer.Write([]byte(`{"code":"internal_error","message":"数据库连接失败"}`)) })) defer server.Close() if _, err := fetchRemotePublishOptions(context.Background(), server.URL); err == nil { t.Fatal("expected error envelope to fail") } } func TestMergeRemoteQuantityItemsPreservesLocalFlags(t *testing.T) { current := []pricing.QuantityItem{ {Key: "awmAmmo", Unit: "发", Disabled: true, Placeholder: "本地提示"}, } remote := []pricing.QuantityItem{ {Key: "awmAmmo", Label: "AWM子弹", Price: "0.8元/发"}, } merged := mergeRemoteQuantityItems(current, remote) if len(merged) != 1 { t.Fatalf("merged count = %d, want 1", len(merged)) } if merged[0].Unit != "发" || !merged[0].Disabled || merged[0].Placeholder != "本地提示" { t.Fatalf("local flags were not preserved: %+v", merged[0]) } } func TestConfigFileRoundTrip(t *testing.T) { path := filepath.Join(t.TempDir(), "config.json") config := pricing.DefaultConfig() config.SyncURL = "https://example.com" if err := writeConfigFile(path, config); err != nil { t.Fatalf("writeConfigFile error: %v", err) } loaded, loadErr := loadConfigFile(path) if loadErr != "" { t.Fatalf("loadConfigFile error: %s", loadErr) } if loaded.SyncURL != "https://example.com" { t.Fatalf("sync url = %q, want https://example.com", loaded.SyncURL) } if len(loaded.InsuranceBaseRatios) != 4 { t.Fatalf("insurance count = %d, want 4", len(loaded.InsuranceBaseRatios)) } raw, err := json.Marshal(loaded) if err != nil { t.Fatalf("marshal config: %v", err) } if len(raw) == 0 { t.Fatal("marshaled config is empty") } }