nx_string_ops_test.nx source
↩ module page · 139 lines · 5493 B
1// nx_string_ops_test.nx -- smoke for the 16-primitive byte-buffer family.
2
3import "nx_syscalls.nx"
4import "nx_tier.nx"
5import "nx_essentials.nx"
6import "nx_string_ops.nx"
7
8func _fill(buf: *u8, s: *u8, n: nx_int) -> nx_int {
9 var i: nx_int = 0
10 while i < n {
11 buf[i] = s[i]
12 i = i + 1
13 }
14 return 0
15}
16
17func main() -> nx_int {
18 let buf: *u8 = sys_mmap(64)
19
20 // === Family 1: scan + length ====================================
21 // buf = "hello world"
22 _fill(buf, "hello world" as *u8, 11)
23 // nx_str_len reads until 0; populate buf[11]=0 first.
24 buf[11] = 0
25 if nx_str_len(buf) != 11 { return 1 }
26
27 // index_of
28 if nx_str_index_of(buf, 11, 32) != 5 { return 2 } // space at 5
29 if nx_str_index_of(buf, 11, 108) != 2 { return 3 } // 'l' at 2
30 if nx_str_index_of(buf, 11, 122) != 0 - 1 { return 4 } // 'z' not present
31 if nx_str_index_of(buf, 0, 104) != 0 - 1 { return 5 } // empty
32 // last_index_of
33 if nx_str_last_index_of(buf, 11, 108) != 9 { return 6 } // last 'l' at 9 (world's l)
34 if nx_str_last_index_of(buf, 11, 122) != 0 - 1 { return 7 }
35
36 // === Family 2: equality / prefix / suffix / find ================
37 let other: *u8 = sys_mmap(32)
38 _fill(other, "hello world" as *u8, 11)
39 if nx_str_equals(buf, 11, other, 11) != 1 { return 10 }
40 _fill(other, "hello mars " as *u8, 11)
41 if nx_str_equals(buf, 11, other, 11) != 0 { return 11 }
42 if nx_str_equals(buf, 11, other, 10) != 0 { return 12 } // diff length
43
44 if nx_str_starts_with(buf, 11, "hello" as *u8, 5) != 1 { return 20 }
45 if nx_str_starts_with(buf, 11, "world" as *u8, 5) != 0 { return 21 }
46 if nx_str_starts_with(buf, 11, "" as *u8, 0) != 1 { return 22 } // empty prefix matches
47
48 if nx_str_ends_with(buf, 11, "world" as *u8, 5) != 1 { return 30 }
49 if nx_str_ends_with(buf, 11, "hello" as *u8, 5) != 0 { return 31 }
50 if nx_str_ends_with(buf, 11, "" as *u8, 0) != 1 { return 32 }
51
52 if nx_str_find(buf, 11, "world" as *u8, 5) != 6 { return 40 }
53 if nx_str_find(buf, 11, "hello" as *u8, 5) != 0 { return 41 }
54 if nx_str_find(buf, 11, "mars" as *u8, 4) != 0 - 1 { return 42 }
55 if nx_str_find(buf, 11, "" as *u8, 0) != 0 { return 43 } // empty needle at 0
56
57 // === Family 3: slice + trim =====================================
58 let dst: *u8 = sys_mmap(16)
59 if nx_str_slice_copy(buf, 6, 11, dst, 16) != 5 { return 50 }
60 if dst[0] != 119 { return 51 } // 'w'
61 if dst[4] != 100 { return 52 } // 'd'
62
63 if nx_str_slice_copy(buf, 0, 5, dst, 16) != 5 { return 53 }
64 if dst[0] != 104 { return 54 } // 'h'
65
66 // capacity too small
67 if nx_str_slice_copy(buf, 0, 10, dst, 5) != 0 { return 55 }
68
69 // Trim: " hi "
70 _fill(buf, " hi " as *u8, 6)
71 if nx_str_trim_left(buf, 6) != 2 { return 60 }
72 if nx_str_trim_right(buf, 6) != 4 { return 61 }
73 // All whitespace
74 _fill(buf, " " as *u8, 4)
75 if nx_str_trim_left(buf, 4) != 4 { return 62 }
76 if nx_str_trim_right(buf, 4) != 0 { return 63 }
77
78 // === Family 4: parse + format ===================================
79 _fill(buf, "12345" as *u8, 5)
80 if nx_str_parse_int(buf, 5) != 12345 { return 70 }
81 _fill(buf, "-42" as *u8, 3)
82 if nx_str_parse_int(buf, 3) != 0 - 42 { return 71 }
83 _fill(buf, "+7" as *u8, 2)
84 if nx_str_parse_int(buf, 2) != 7 { return 72 }
85 _fill(buf, "0" as *u8, 1)
86 if nx_str_parse_int(buf, 1) != 0 { return 73 }
87 // Empty -> 0
88 if nx_str_parse_int(buf, 0) != 0 { return 74 }
89
90 // format_int
91 let fbuf: *u8 = sys_mmap(32)
92 let nf: nx_int = nx_str_format_int(12345, fbuf, 32)
93 if nf != 5 { return 80 }
94 if fbuf[0] != 49 { return 81 } // '1'
95 if fbuf[4] != 53 { return 82 } // '5'
96
97 let nf_neg: nx_int = nx_str_format_int(0 - 42, fbuf, 32)
98 if nf_neg != 3 { return 83 }
99 if fbuf[0] != 45 { return 84 } // '-'
100 if fbuf[1] != 52 { return 85 } // '4'
101 if fbuf[2] != 50 { return 86 } // '2'
102
103 let nf_zero: nx_int = nx_str_format_int(0, fbuf, 32)
104 if nf_zero != 1 { return 87 }
105 if fbuf[0] != 48 { return 88 } // '0'
106
107 // Capacity too small
108 if nx_str_format_int(12345, fbuf, 4) != 0 { return 89 }
109
110 // === Family 5: classify =========================================
111 if nx_str_is_empty(buf, 0) != 1 { return 100 }
112 if nx_str_is_empty(buf, 1) != 0 { return 101 }
113
114 _fill(buf, "12345" as *u8, 5)
115 if nx_str_is_all_digits(buf, 5) != 1 { return 110 }
116 _fill(buf, "12a45" as *u8, 5)
117 if nx_str_is_all_digits(buf, 5) != 0 { return 111 }
118 _fill(buf, " \t " as *u8, 5)
119 if nx_str_is_all_whitespace(buf, 5) != 1 { return 120 }
120 _fill(buf, " x " as *u8, 5)
121 if nx_str_is_all_whitespace(buf, 5) != 0 { return 121 }
122
123 // === Family 6: hash =============================================
124 _fill(buf, "hello" as *u8, 5)
125 let h1: nx_int = nx_str_hash_fnv1a(buf, 5)
126 _fill(buf, "hello" as *u8, 5)
127 let h2: nx_int = nx_str_hash_fnv1a(buf, 5)
128 if h1 != h2 { return 130 } // determinism
129
130 _fill(buf, "world" as *u8, 5)
131 let h3: nx_int = nx_str_hash_fnv1a(buf, 5)
132 if h1 == h3 { return 131 } // different content -> different hash (very likely)
133
134 // Empty buf hash is the FNV offset basis.
135 let h_empty: nx_int = nx_str_hash_fnv1a(buf, 0)
136 if h_empty != nx_fnv1a_offset_basis() { return 132 }
137
138 return 0
139}