nx_test_driver_e2e.nx source
↩ module page · 136 lines · 5649 B
1// nx_test_driver_e2e.nx -- end-to-end smoke for the bits-up test driver.
2// Composes all 5 primitives (nx_dom_query + nx_dom_click + nx_url_params
3// + nx_test_harness + nx_game_harness) against an inline "fake game" that
4// emits the same HTML shape as nx_tictactoe_render.nx.
5//
6// Why a fake game instead of importing nx_tictactoe.nx directly: the real
7// game's render imports nx_syscalls.nx (RV64); the harness imports
8// nx_syscalls_x86_64.nx; combining them creates duplicate-symbol errors.
9// Cross-arch cleanup of the substrate's syscall layer is the queued
10// follow-up; this smoke validates the *primitives* end-to-end and
11// produces the same test-output format the .mjs harnesses do, proving the
12// architecture works.
13//
14// The fake game models a 3x3 grid like tic-tac-toe. State is 9 cells +
15// last-move indicator. Render emits buttons with class="cell" and
16// data-cell-idx="N". Action 1 with arg0=N places an X at cell N.
17
18import "nx_test_harness.nx"
19import "nx_game_harness.nx"
20import "nx_dom_query.nx"
21import "nx_dom_click.nx"
22import "nx_url_params.nx"
23const K_MAGIC_65536: i64 = 65536
24
25const _FAKE_RENDER_FD: i64 = 99
26
27static FAKE_CELLS: i64 // bitmask of cells where X was played (real impl
28 // would be a 9-i64 array; bitmask suffices)
29
30func _fake_w(s: *u8) -> i64 {
31 var n: i64 = 0
32 while s[n] != 0 { n = n + 1 }
33 return sys_write(_FAKE_RENDER_FD, s, n)
34}
35
36func _fake_wi(n: i64) -> i64 {
37 if n == 0 { return _fake_w("0" as *u8) }
38 if n == 1 { return _fake_w("1" as *u8) }
39 if n == 2 { return _fake_w("2" as *u8) }
40 if n == 3 { return _fake_w("3" as *u8) }
41 if n == 4 { return _fake_w("4" as *u8) }
42 if n == 5 { return _fake_w("5" as *u8) }
43 if n == 6 { return _fake_w("6" as *u8) }
44 if n == 7 { return _fake_w("7" as *u8) }
45 if n == 8 { return _fake_w("8" as *u8) }
46 return _fake_w("?" as *u8)
47}
48
49func fake_render() -> i64 {
50 _fake_w("<div class=\"board\">" as *u8)
51 var i: i64 = 0
52 while i < 9 {
53 _fake_w("<button class=\"cell\" data-cell-idx=\"" as *u8)
54 _fake_wi(i)
55 _fake_w("\" data-action=\"1\" data-arg0=\"" as *u8)
56 _fake_wi(i)
57 _fake_w("\">" as *u8)
58 // Check the bit for cell i.
59 let mask: i64 = 1
60 var bit: i64 = 0
61 if i == 0 { bit = FAKE_CELLS - (FAKE_CELLS / 2) * 2 }
62 if i == 1 { bit = (FAKE_CELLS / 2) - (FAKE_CELLS / 4) * 2 }
63 if i == 2 { bit = (FAKE_CELLS / 4) - (FAKE_CELLS / 8) * 2 }
64 if i == 3 { bit = (FAKE_CELLS / 8) - (FAKE_CELLS / 16) * 2 }
65 if i == 4 { bit = (FAKE_CELLS / 16) - (FAKE_CELLS / 32) * 2 }
66 if i == 5 { bit = (FAKE_CELLS / 32) - (FAKE_CELLS / 64) * 2 }
67 if i == 6 { bit = (FAKE_CELLS / 64) - (FAKE_CELLS / 128) * 2 }
68 if i == 7 { bit = (FAKE_CELLS / 128) - (FAKE_CELLS / 256) * 2 }
69 if i == 8 { bit = (FAKE_CELLS / 256) - (FAKE_CELLS / 512) * 2 }
70 if bit == 1 { _fake_w("X" as *u8) }
71 _fake_w("</button>" as *u8)
72 i = i + 1
73 }
74 _fake_w("</div>" as *u8)
75 return 0
76}
77
78func fake_action(action: i64, arg0: i64) -> i64 {
79 if action != 1 { return 0 }
80 if arg0 < 0 { return 0 }
81 if arg0 > 8 { return 0 }
82 var bit: i64 = 1
83 var k: i64 = 0
84 while k < arg0 { bit = bit * 2; k = k + 1 }
85 FAKE_CELLS = FAKE_CELLS + bit
86 return 1
87}
88
89func main() -> i64 {
90 nx_test_init()
91 FAKE_CELLS = 0
92
93 // === Cycle 1: initial render ===
94 let buf: *u8 = sys_mmap(K_MAGIC_65536)
95 let cap1: *NxGameCapture = nx_capture_start()
96 fake_render()
97 let n1: i64 = nx_capture_end(cap1, buf, K_MAGIC_65536 as i64)
98 nx_test_expect_eq("cycle 1: bytes captured > 0" as *u8,
99 n1 > 0, 1 as i64)
100 nx_test_expect_class_count("cycle 1: cell count = 9" as *u8,
101 buf, n1, "cell" as *u8, 9 as i64)
102 nx_test_expect_tag_count("cycle 1: button tag count = 9" as *u8,
103 buf, n1, "button" as *u8, 9 as i64)
104 nx_test_expect_not_contains("cycle 1: no X yet" as *u8,
105 buf, n1, ">X<" as *u8)
106
107 // === Click cell 4 via the click-intent extractor ===
108 let intent: *NxClickIntent = nx_dom_click_intent(buf, n1,
109 "data-cell-idx" as *u8,
110 "4" as *u8)
111 nx_test_expect_click("click intent for cell 4 (action=1, arg0=4)" as *u8,
112 intent, 1 as i64, 4 as i64)
113 fake_action(intent.action, intent.arg0)
114
115 // === Cycle 2: render after click, X should be at cell 4 ===
116 let cap2: *NxGameCapture = nx_capture_start()
117 fake_render()
118 let n2: i64 = nx_capture_end(cap2, buf, K_MAGIC_65536 as i64)
119 nx_test_expect_contains("cycle 2: X now visible somewhere" as *u8,
120 buf, n2, ">X<" as *u8)
121 nx_test_expect_contains("cycle 2: cell 4 button contains X" as *u8,
122 buf, n2, "data-cell-idx=\"4\" data-action=\"1\" data-arg0=\"4\">X" as *u8)
123
124 // === URL params primitive integration ===
125 let url: *u8 = "/tictactoe/?v=2&debug=1" as *u8
126 var url_len: i64 = 0
127 while url[url_len] != 0 { url_len = url_len + 1 }
128 let v: i64 = nx_url_param_int(url, url_len, "v" as *u8)
129 nx_test_expect_eq("?v=2 parses to 2" as *u8, v, 2 as i64)
130 let d: i64 = nx_url_param_int(url, url_len, "debug" as *u8)
131 nx_test_expect_eq("?debug=1 parses to 1" as *u8, d, 1 as i64)
132 let m: i64 = nx_url_param_int(url, url_len, "missing" as *u8)
133 nx_test_expect_eq("?missing absent returns -1" as *u8, m, -1 as i64)
134
135 return nx_test_summary()
136}