fix(systemconfig): 首页入口展示开关与发布选项编码修复
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
package systemconfig
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDecodeCP1252Mojibake(t *testing.T) {
|
||||
original := `{"label":"6级子弹","price":"0.26元/发","punct":"(:,)"}`
|
||||
mojibake := encodeCP1252Mojibake(original)
|
||||
|
||||
decoded, ok := decodeCP1252Mojibake(mojibake)
|
||||
if !ok {
|
||||
t.Fatal("期望识别出 CP1252 乱码")
|
||||
}
|
||||
if decoded != original {
|
||||
t.Fatalf("还原结果 = %q, want %q", decoded, original)
|
||||
}
|
||||
if _, ok := decodeCP1252Mojibake(original); ok {
|
||||
t.Fatal("正常中文不应被误判为乱码")
|
||||
}
|
||||
if _, ok := decodeCP1252Mojibake("plain ascii"); ok {
|
||||
t.Fatal("纯 ASCII 不应被误判为乱码")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepairMojibakeJSONRepairsIndividualFields(t *testing.T) {
|
||||
raw := `{"normal":"正常字段","broken":"` + encodeCP1252Mojibake("6级子弹") + `"}`
|
||||
repaired := repairMojibakeJSON(raw)
|
||||
|
||||
var payload map[string]string
|
||||
if err := json.Unmarshal([]byte(repaired), &payload); err != nil {
|
||||
t.Fatalf("还原后的 JSON 无法解析: %v", err)
|
||||
}
|
||||
if payload["normal"] != "正常字段" {
|
||||
t.Fatalf("正常字段被破坏: %q", payload["normal"])
|
||||
}
|
||||
if payload["broken"] != "6级子弹" {
|
||||
t.Fatalf("乱码字段未还原: %q", payload["broken"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizePublishOptionsValueMigratesLegacyQuantityItems(t *testing.T) {
|
||||
legacy := `{
|
||||
"server_options": ["QQ"],
|
||||
"quantity_items": [
|
||||
{"key": "kit5", "label": "5级全装套数量", "price": "5元/个"},
|
||||
{"key": "level6Ammo", "label": "6级子弹", "price": "0.26元/发"}
|
||||
]
|
||||
}`
|
||||
|
||||
normalized, err := normalizePublishOptionsValue(legacy)
|
||||
if err != nil {
|
||||
t.Fatalf("规范化失败: %v", err)
|
||||
}
|
||||
var options PublishOptionsDTO
|
||||
if err := json.Unmarshal([]byte(normalized), &options); err != nil {
|
||||
t.Fatalf("解析规范化结果失败: %v", err)
|
||||
}
|
||||
if options.SchemaVersion != publishOptionsSchemaVersion {
|
||||
t.Fatalf("schema_version = %d, want %d", options.SchemaVersion, publishOptionsSchemaVersion)
|
||||
}
|
||||
for _, item := range options.QuantityItems {
|
||||
if item.Key == "kit5" {
|
||||
t.Fatal("旧版 kit5 选项应被迁移掉")
|
||||
}
|
||||
}
|
||||
if !hasQuantityItemKey(options.QuantityItems, "level6Ammo") {
|
||||
t.Fatal("迁移后的默认选项缺少 level6Ammo")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizePublishOptionsValuePreservesCurrentSchema(t *testing.T) {
|
||||
options := DefaultPublishOptions()
|
||||
for index := range options.ScreenshotSlots {
|
||||
if options.ScreenshotSlots[index].Key == "tencentSecurity" {
|
||||
options.ScreenshotSlots[index].Required = true
|
||||
}
|
||||
}
|
||||
options.QuantityItems = append(options.QuantityItems, PublishQuantityItem{
|
||||
Key: "kit5",
|
||||
Label: "自定义旧选项",
|
||||
Price: "9元/个",
|
||||
})
|
||||
raw, err := json.Marshal(options)
|
||||
if err != nil {
|
||||
t.Fatalf("构造当前版本配置失败: %v", err)
|
||||
}
|
||||
|
||||
normalized, err := normalizePublishOptionsValue(string(raw))
|
||||
if err != nil {
|
||||
t.Fatalf("规范化失败: %v", err)
|
||||
}
|
||||
var got PublishOptionsDTO
|
||||
if err := json.Unmarshal([]byte(normalized), &got); err != nil {
|
||||
t.Fatalf("解析规范化结果失败: %v", err)
|
||||
}
|
||||
if !hasQuantityItemKey(got.QuantityItems, "kit5") {
|
||||
t.Fatal("当前版本配置中的自定义项不应被旧版迁移清掉")
|
||||
}
|
||||
for _, slot := range got.ScreenshotSlots {
|
||||
if slot.Key == "tencentSecurity" && !slot.Required {
|
||||
t.Fatal("当前版本配置中 tencentSecurity.required=true 不应被覆盖")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizePublishOptionsValueRepairsMojibake(t *testing.T) {
|
||||
options := DefaultPublishOptions()
|
||||
raw, err := json.Marshal(options)
|
||||
if err != nil {
|
||||
t.Fatalf("构造配置失败: %v", err)
|
||||
}
|
||||
mojibake := encodeCP1252Mojibake(string(raw))
|
||||
|
||||
normalized, err := normalizePublishOptionsValue(mojibake)
|
||||
if err != nil {
|
||||
t.Fatalf("规范化乱码配置失败: %v", err)
|
||||
}
|
||||
var got PublishOptionsDTO
|
||||
if err := json.Unmarshal([]byte(normalized), &got); err != nil {
|
||||
t.Fatalf("解析规范化结果失败: %v", err)
|
||||
}
|
||||
if !containsString(got.ServerOptions, "微信") {
|
||||
t.Fatalf("乱码未恢复,server_options = %#v", got.ServerOptions)
|
||||
}
|
||||
if got.SchemaVersion != publishOptionsSchemaVersion {
|
||||
t.Fatalf("schema_version = %d, want %d", got.SchemaVersion, publishOptionsSchemaVersion)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeCP1252Mojibake(value string) string {
|
||||
var builder strings.Builder
|
||||
for _, item := range []byte(value) {
|
||||
if item >= 0x80 && item <= 0x9F {
|
||||
builder.WriteRune(cp1252HighRunes[item-0x80])
|
||||
continue
|
||||
}
|
||||
builder.WriteRune(rune(item))
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func hasQuantityItemKey(items []PublishQuantityItem, key string) bool {
|
||||
for _, item := range items {
|
||||
if item.Key == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func containsString(items []string, target string) bool {
|
||||
for _, item := range items {
|
||||
if item == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user