package dto import ( "encoding/json" "testing" "git.yeij.top/AskaEth/Scoreboard/server/internal/domain" ) // 非 admin 会话只能看到大屏渲染所需字段:admin-only 字段必须清零, // 且序列化后仍是显式的 null / 0,不能变成字段缺失。 func TestEventSettingsWithoutAdminFields(t *testing.T) { profileID := int64(3) full := EventSettings{ Event: EventSettingsEvent{Name: "运动会"}, Display: EventSettingsDisplay{Title: "大屏", RotateSecond: 15}, Standings: EventSettingsStandings{IndividualToTeamWeight: 0.5, RankingMode: "points", ShowIndividualBoard: true, ShowIndividualMedals: false}, DefaultProfileID: &profileID, RequireApproval: true, } got := full.WithoutAdminFields() if got.DefaultProfileID != nil { t.Fatalf("defaultProfileId 应置空,得到 %v", got.DefaultProfileID) } if got.RequireApproval { t.Fatalf("requireApproval 应清零") } if got.Standings.IndividualToTeamWeight != 0 { t.Fatalf("individualToTeamWeight 应清零,得到 %v", got.Standings.IndividualToTeamWeight) } if got.Event.Name != "运动会" || got.Display.Title != "大屏" || got.Display.RotateSecond != 15 { t.Fatalf("event/display 不应被裁剪: %+v", got) } if got.Standings.RankingMode != "points" || !got.Standings.ShowIndividualBoard || got.Standings.ShowIndividualMedals { t.Fatalf("榜单开关不应被裁剪: %+v", got.Standings) } raw, err := json.Marshal(got) if err != nil { t.Fatalf("序列化: %v", err) } var top map[string]json.RawMessage if err := json.Unmarshal(raw, &top); err != nil { t.Fatalf("解析: %v", err) } if string(top["defaultProfileId"]) != "null" { t.Fatalf("defaultProfileId 应显式序列化为 null: %s", raw) } if string(top["requireApproval"]) != "false" { t.Fatalf("requireApproval 应显式序列化为 false: %s", raw) } var standings map[string]json.RawMessage if err := json.Unmarshal(top["standings"], &standings); err != nil { t.Fatalf("解析 standings: %v", err) } if string(standings["individualToTeamWeight"]) != "0" { t.Fatalf("individualToTeamWeight 应显式序列化为 0: %s", raw) } } // 单位/小项的 DTO 必须把可空列写成显式 null,不能沿用 domain 的 omitempty。 func TestTeamAndEventFromDomainNullableFields(t *testing.T) { teamRaw, err := json.Marshal(TeamFromDomain(domain.Team{ID: 1, Code: "T1", Name: "第一单位"})) if err != nil { t.Fatalf("序列化单位: %v", err) } var team map[string]json.RawMessage if err := json.Unmarshal(teamRaw, &team); err != nil { t.Fatalf("解析单位: %v", err) } for _, key := range []string{"shortName", "logoPath", "color"} { if got, ok := team[key]; !ok || string(got) != "null" { t.Fatalf("单位字段 %s 应为显式 null: %s", key, teamRaw) } } eventRaw, err := json.Marshal(EventFromDomain(domain.Event{ID: 1, Code: "E1", Name: "100米"})) if err != nil { t.Fatalf("序列化小项: %v", err) } var event map[string]json.RawMessage if err := json.Unmarshal(eventRaw, &event); err != nil { t.Fatalf("解析小项: %v", err) } for _, key := range []string{"scheduledAt", "venue", "remark"} { if got, ok := event[key]; !ok || string(got) != "null" { t.Fatalf("小项字段 %s 应为显式 null: %s", key, eventRaw) } } if string(event["sortOrder"]) != "0" { t.Fatalf("sortOrder 应保留 0: %s", eventRaw) } }