1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
namespace LivingVillage.Desktop.Tests
open Microsoft.VisualStudio.TestTools.UnitTesting
open LivingVillage.Kernel
open LivingVillage.Kernel.Sim
open LivingVillage.Desktop
/// P38 界面升级切片:顶部常驻 HUD 图标化(时段/时间/倍速/体力/钱币)的布局与确定性回归。
[<TestClass>]
type P38HudIconTests () =
let world = Sim.initialWorldN 42UL 4
let control = SimulationControl.initial
let segments = HudLayout.segments world control
[<TestMethod>]
member _.EveryHudSegmentCarriesAWellFormedDistinctIcon () =
let expected =
[ "时段", HudLayout.PeriodIcon
"时间", HudLayout.ClockIcon
"倍速", HudLayout.SpeedIcon
"体力", HudLayout.EnergyIcon
"钱币", HudLayout.MoneyIcon ]
Assert.AreEqual<string list>(expected |> List.map fst, segments |> List.map (fun segment -> segment.Label))
Assert.AreEqual<HudLayout.HudIcon list>(expected |> List.map snd, segments |> List.map (fun segment -> segment.Icon))
for segment in segments do
let rows = HudLayout.iconRows segment.Icon
Assert.IsTrue(rows.Length = HudLayout.iconGrid, sprintf "%s 图标行数" segment.Label)
for row in rows do
Assert.IsTrue(row.Length = HudLayout.iconGrid, sprintf "%s 图标行宽" segment.Label)
Assert.IsTrue(rows |> List.exists (fun row -> row.Contains "1"), sprintf "%s 图标必须有实心像素" segment.Label)
let distinct = segments |> List.map (fun segment -> segment.Icon) |> List.distinct |> List.length
Assert.IsTrue(segments.Length = distinct, "每个常驻段图标应互不相同")
[<TestMethod>]
member _.HudLayoutReservesIconThenTextAndFitsTheStrip () =
let placed = HudLayout.layout segments
Assert.AreEqual<int>(segments.Length, placed.Length)
let (firstX, _, _) = List.head placed
Assert.AreEqual<int>(HudLayout.paddingX, firstX)
for (x, width, segment) in placed do
let textWidth = FloatingPrompt.measureWidth (HudLayout.segmentText segment) HudLayout.textScale
Assert.AreEqual<int>(HudLayout.iconWidth + HudLayout.iconGap + textWidth, width)
// 图标与文本都必须落在段宽内。
Assert.IsTrue(x + HudLayout.iconWidth <= x + width, "图标越出段宽")
Assert.IsTrue(HudLayout.textOrigin x + textWidth <= x + width, "文本越出段宽")
Assert.IsTrue(HudLayout.iconHeight <= HudLayout.barHeight, "图标必须放进窄条")
placed
|> List.pairwise
|> List.iter (fun ((x1, w1, _), (x2, _, _)) ->
Assert.IsTrue(x2 >= x1 + w1, sprintf "段重叠:%d+%d vs %d" x1 w1 x2))
let (lastX, lastWidth, _) = List.last placed
Assert.IsTrue(lastX + lastWidth <= 1280, "最后一段必须留在 1280 视口内")
[<TestMethod>]
member _.HudSegmentsAndLayoutAreDeterministic () =
Assert.AreEqual<HudLayout.Segment list>(segments, HudLayout.segments world control)
Assert.AreEqual<(int * int * HudLayout.Segment) list>(HudLayout.layout segments, HudLayout.layout segments)
for segment in segments do
Assert.AreEqual<string list>(HudLayout.iconRows segment.Icon, HudLayout.iconRows segment.Icon)
[<TestMethod>]
member _.HudBackdropCoversIconAndTextInBothPeriods () =
for mode in [ Day; Night ] do
let palette = HudLayout.palette mode
Assert.IsTrue(palette.SegmentBackdrop.A > 0uy && palette.SegmentBackdrop.A < 255uy, "底色必须半透明")
for (x, width, _) in HudLayout.layout segments do
let rect = HudLayout.segmentBackdrop x width
Assert.IsTrue(rect.X <= x, "底色未覆盖图标左沿")
Assert.IsTrue(rect.X + rect.Width >= HudLayout.textOrigin x, "底色未覆盖文本区")
Assert.IsTrue(rect.Y >= 0 && rect.Y + rect.Height <= HudLayout.barHeight, "底色必须留在窄条内")
|