nx_dom_query_test.nx source
↩ module page · 164 lines · 7624 B
1// nx_dom_query_test.nx -- smoke test for nx_dom_query.nx.
2//
3// Tests against a representative bits-up game-emitted HTML buffer (the
4// kind nx_checkers_render.nx writes to fd 99). Covers all four queries
5// plus the underlying attribute scanner.
6
7// Syscalls come transitively via nx_dom_query.nx -> nx_html_tokenizer.nx ->
8// nx_syscalls_x86_64.nx. This file builds + runs natively on x86_64 Linux.
9import "nx_dom_query.nx"
10
11func _dqt_strlen(s: *u8) -> i64 {
12 var n: i64 = 0
13 while s[n] != 0 { n = n + 1 }
14 return n
15}
16
17func _dqt_w(s: *u8) -> i64 {
18 return sys_write(1 as i64, s, _dqt_strlen(s))
19}
20
21func _dqt_wln(s: *u8) -> i64 {
22 _dqt_w(s)
23 let nl: *u8 = sys_mmap(2) as *u8
24 nl[0] = 10 as u8
25 return sys_write(1 as i64, nl, 1 as i64)
26}
27
28func _dqt_assert_int(label: *u8, got: i64, want: i64,
29 passes: *i64, fails: *i64) -> i64 {
30 if got == want {
31 _dqt_w(" [PASS] " as *u8)
32 _dqt_wln(label)
33 passes[0] = passes[0] + 1
34 return 1
35 }
36 _dqt_w(" [FAIL] " as *u8)
37 _dqt_w(label)
38 _dqt_wln(" (int mismatch)" as *u8)
39 fails[0] = fails[0] + 1
40 return 0
41}
42
43func nx_dom_query_test() -> i64 {
44 let passes: *i64 = sys_mmap(8) as *i64
45 let fails: *i64 = sys_mmap(8) as *i64
46 passes[0] = 0
47 fails[0] = 0
48
49 _dqt_wln("nx_dom_query_test:" as *u8)
50
51 // A representative slice of a /checkers bits-up render. Mixes:
52 // - status div with class
53 // - 32 dark sqs (button.sq.dark) -- only show 4 here
54 // - light sqs (div.sq.light)
55 // - selected square (button with class "sq dark sel")
56 // - controls (button[data-action="2"] for reset)
57 // - select[data-action="3"] for opponent
58 let html: *u8 = "<div class=\"chk-shell\"><div class=\"chk-status\">Your move (Red).</div><div class=\"chk-board\"><button type=\"button\" class=\"sq dark\" data-sq=\"1\" data-action=\"1\" data-arg0=\"1\"></button><div class=\"sq light\"></div><button type=\"button\" class=\"sq dark sel\" data-sq=\"40\" data-action=\"1\" data-arg0=\"40\"><div class=\"piece red\"></div></button><div class=\"sq light\"></div></div><div class=\"controls\"><button type=\"button\" data-action=\"2\">New game</button><select data-action=\"3\"><option value=\"-1\">Another human</option><option value=\"0\" selected>AI - easy (random)</option></select></div></div>" as *u8
59 let n: i64 = _dqt_strlen(html)
60
61 // Test 1: count all dark squares -> 2 (we have 2 in the fixture).
62 let n_dark: i64 = nx_dom_count_class(html, n, "dark" as *u8)
63 _dqt_assert_int("count dark class = 2" as *u8, n_dark, 2 as i64, passes, fails)
64
65 // Test 2: count all light squares -> 2.
66 let n_light: i64 = nx_dom_count_class(html, n, "light" as *u8)
67 _dqt_assert_int("count light class = 2" as *u8, n_light, 2 as i64, passes, fails)
68
69 // Test 3: count "sel" class -> 1 (one selected).
70 let n_sel: i64 = nx_dom_count_class(html, n, "sel" as *u8)
71 _dqt_assert_int("count sel class = 1" as *u8, n_sel, 1 as i64, passes, fails)
72
73 // Test 4: count all <button> tags -> 3 (2 squares + reset).
74 let n_btn: i64 = nx_dom_count_tag(html, n, "button" as *u8)
75 _dqt_assert_int("count button tags = 3" as *u8, n_btn, 3 as i64, passes, fails)
76
77 // Test 5: count all <div> tags -> 6 (chk-shell + chk-status + chk-board +
78 // 2 light squares + piece red + controls = actually 7). Recount fixture:
79 // <div class="chk-shell"> 1
80 // <div class="chk-status"> 2
81 // <div class="chk-board"> 3
82 // <div class="sq light"> 4
83 // <div class="sq light"> 5
84 // <div class="piece red"> 6
85 // <div class="controls"> 7
86 let n_div: i64 = nx_dom_count_tag(html, n, "div" as *u8)
87 _dqt_assert_int("count div tags = 7" as *u8, n_div, 7 as i64, passes, fails)
88
89 // Test 6: find class "chk-shell" -> found, name should be "div".
90 let r1: *NxDomQueryResult = nx_dom_find_class(html, n, "chk-shell" as *u8)
91 _dqt_assert_int("find chk-shell.found = 1" as *u8, r1.found, 1 as i64, passes, fails)
92 _dqt_assert_int("find chk-shell.name_len = 3 (div)" as *u8, r1.name_len, 3 as i64, passes, fails)
93
94 // Test 7: find class "sel" -> found (the selected square).
95 let r2: *NxDomQueryResult = nx_dom_find_class(html, n, "sel" as *u8)
96 _dqt_assert_int("find sel.found = 1" as *u8, r2.found, 1 as i64, passes, fails)
97 _dqt_assert_int("find sel.name_len = 6 (button)" as *u8, r2.name_len, 6 as i64, passes, fails)
98
99 // Test 8: find data-sq="40" exact value -> the selected square.
100 let r3: *NxDomQueryResult = nx_dom_find_attr_eq(html, n, "data-sq" as *u8, "40" as *u8)
101 _dqt_assert_int("find data-sq=40.found = 1" as *u8, r3.found, 1 as i64, passes, fails)
102
103 // Test 9: find data-action="2" -> the reset button.
104 let r4: *NxDomQueryResult = nx_dom_find_attr_eq(html, n, "data-action" as *u8, "2" as *u8)
105 _dqt_assert_int("find data-action=2.found = 1" as *u8, r4.found, 1 as i64, passes, fails)
106 _dqt_assert_int("find data-action=2.name_len = 6 (button)" as *u8, r4.name_len, 6 as i64, passes, fails)
107
108 // Test 10: find class "ghost" -> NOT found.
109 let r5: *NxDomQueryResult = nx_dom_find_class(html, n, "ghost" as *u8)
110 _dqt_assert_int("find ghost.found = 0" as *u8, r5.found, 0 as i64, passes, fails)
111
112 // Test 11: find data-action="999" -> NOT found.
113 let r6: *NxDomQueryResult = nx_dom_find_attr_eq(html, n, "data-action" as *u8, "999" as *u8)
114 _dqt_assert_int("find data-action=999.found = 0" as *u8, r6.found, 0 as i64, passes, fails)
115
116 // Test 12: word-boundary correctness -- "dark" should NOT match "darkness".
117 // No "darkness" class in our fixture, but verify the matcher is strict.
118 let html2: *u8 = "<div class=\"darkness\"></div>" as *u8
119 let n2: i64 = _dqt_strlen(html2)
120 let r7: i64 = nx_dom_count_class(html2, n2, "dark" as *u8)
121 _dqt_assert_int("dark must not match darkness" as *u8, r7, 0 as i64, passes, fails)
122
123 // Test 13: substring-attr-name correctness -- query "action" should
124 // NOT spuriously match "data-action".
125 let r8: *NxDomQueryResult = nx_dom_find_attr_eq(html, n, "action" as *u8, "2" as *u8)
126 _dqt_assert_int("action != data-action (no false match)" as *u8, r8.found, 0 as i64, passes, fails)
127
128 _dqt_w("nx_dom_query_test: " as *u8)
129 // Print "X pass, Y fail" via two simple counts (just write digit chars).
130 let buf: *u8 = sys_mmap(64) as *u8
131 var off: i64 = 0
132 let p: i64 = passes[0]
133 let f: i64 = fails[0]
134 // Tens + ones for both counts (we have <100 tests).
135 let pt: i64 = p / 10
136 let po: i64 = p - pt * 10
137 if pt > 0 { buf[off] = (48 + pt) as u8; off = off + 1 }
138 buf[off] = (48 + po) as u8; off = off + 1
139 buf[off] = 32 as u8; off = off + 1
140 buf[off] = 112 as u8; off = off + 1 // p
141 buf[off] = 97 as u8; off = off + 1 // a
142 buf[off] = 115 as u8; off = off + 1 // s
143 buf[off] = 115 as u8; off = off + 1 // s
144 buf[off] = 44 as u8; off = off + 1 // ,
145 buf[off] = 32 as u8; off = off + 1 // space
146 let ft: i64 = f / 10
147 let fo: i64 = f - ft * 10
148 if ft > 0 { buf[off] = (48 + ft) as u8; off = off + 1 }
149 buf[off] = (48 + fo) as u8; off = off + 1
150 buf[off] = 32 as u8; off = off + 1
151 buf[off] = 102 as u8; off = off + 1 // f
152 buf[off] = 97 as u8; off = off + 1 // a
153 buf[off] = 105 as u8; off = off + 1 // i
154 buf[off] = 108 as u8; off = off + 1 // l
155 buf[off] = 10 as u8; off = off + 1 // \n
156 sys_write(1 as i64, buf, off)
157
158 if fails[0] > 0 { return 1 }
159 return 0
160}
161
162func main() -> i64 {
163 return nx_dom_query_test()
164}