vxx / vlib / strings / builder_test.v
440 lines · 411 sloc · 10.27 KB · 8a793005dd8c68803b6c75dac8be00299a2caf66
Raw
1import strings
2
3type MyInt = int
4
5const maxn = 100000
6
7fn test_sb() {
8 mut sb := strings.new_builder(100)
9 sb.write_string('hi')
10 sb.write_string('!')
11 sb.write_string('hello')
12 assert sb.len == 8
13 sb_end := sb.str()
14 assert sb_end == 'hi!hello'
15 assert sb.len == 0
16 ///
17 sb = strings.new_builder(10)
18 sb.write_string('a')
19 sb.write_string('b')
20 assert sb.len == 2
21 assert sb.str() == 'ab'
22 // Test interpolation optimization
23 sb = strings.new_builder(10)
24 x := 10
25 y := MyInt(20)
26 sb.writeln('x = ${x} y = ${y}')
27 res := sb.str()
28 assert res[res.len - 1] == `\n`
29 println('"${res}"')
30 assert res.trim_space() == 'x = 10 y = 20'
31
32 sb = strings.new_builder(10)
33 sb.write_string('x = ${x} y = ${y}')
34 assert sb.str() == 'x = 10 y = 20'
35 //$if !windows {
36 sb = strings.new_builder(10)
37 sb.write_string('123456')
38 last_2 := sb.cut_last(2)
39 assert last_2 == '56'
40 final_sb := sb.str()
41 assert final_sb == '1234'
42 //}
43 sb.clear()
44 assert sb.str() == ''
45}
46
47fn test_big_sb() {
48 mut sb := strings.new_builder(100)
49 mut sb2 := strings.new_builder(10000)
50 for i in 0 .. maxn {
51 sb.writeln(i.str())
52 sb2.write_string('+')
53 }
54 s := sb.str()
55 lines := s.split_into_lines()
56 assert lines.len == maxn
57 assert lines[0] == '0'
58 assert lines[1] == '1'
59 assert lines[777] == '777'
60 assert lines[98765] == '98765'
61 println(sb2.len)
62 assert sb2.len == maxn
63}
64
65fn test_byte_write() {
66 mut sb := strings.new_builder(100)
67 temp_str := 'byte testing'
68 mut count := 0
69 for word in temp_str {
70 sb.write_u8(word)
71 count++
72 assert count == sb.len
73 }
74 sb_final := sb.str()
75 assert sb_final == temp_str
76}
77
78fn test_strings_builder_reuse() {
79 mut sb := strings.new_builder(256)
80 sb.write_string('world')
81 assert sb.str() == 'world'
82 sb.write_string('hello')
83 assert sb.str() == 'hello'
84}
85
86fn test_cut_to() {
87 mut sb := strings.new_builder(16)
88 sb.write_string('hello')
89 assert sb.cut_to(3) == 'lo'
90 assert sb.len == 3
91 assert sb.cut_to(3) == ''
92 assert sb.len == 3
93 assert sb.cut_to(0) == 'hel'
94 assert sb.cut_to(32) == ''
95 assert sb.len == 0
96}
97
98fn test_write_rune() {
99 mut sb := strings.new_builder(10)
100 sb.write_rune(`h`)
101 sb.write_rune(`e`)
102 sb.write_rune(`l`)
103 sb.write_rune(`l`)
104 sb.write_rune(`o`)
105 x := sb.str()
106 assert x == 'hello'
107}
108
109fn test_write_runes() {
110 mut sb := strings.new_builder(20)
111 sb.write_runes([`h`, `e`, `l`, `l`, `o`])
112 sb.write_rune(` `)
113 sb.write_runes([`w`, `o`, `r`, `l`, `d`])
114 x := sb.str()
115 assert x == 'hello world'
116}
117
118fn test_ensure_cap() {
119 mut sb := strings.new_builder(0)
120 assert sb.cap == 0
121 sb.ensure_cap(10)
122 assert sb.cap >= 10
123 old_cap := sb.cap
124 sb.ensure_cap(10)
125 assert sb.cap == old_cap
126 sb.ensure_cap(15)
127 assert sb.cap >= 15
128 old_cap2 := sb.cap
129 sb.ensure_cap(10)
130 assert sb.cap == old_cap2
131 sb.ensure_cap(-1)
132 assert sb.cap == old_cap2
133}
134
135fn test_drain_builder() {
136 mut sb := strings.new_builder(0)
137 mut target_sb := strings.new_builder(0)
138 assert sb.cap == 0
139 assert target_sb.cap == 0
140
141 sb.write_string('abc')
142 assert sb.len == 3
143
144 target_sb.drain_builder(mut sb, 0)
145 assert sb.len == 0
146 assert target_sb.len == 3
147 assert target_sb.str() == 'abc'
148}
149
150@[manualfree]
151fn sb_i64_str(n i64) string {
152 mut sb := strings.new_builder(24)
153 defer {
154 unsafe { sb.free() }
155 }
156 sb.write_decimal(n)
157 return sb.str()
158}
159
160fn test_write_decimal() {
161 assert sb_i64_str(0) == '0'
162 assert sb_i64_str(1) == '1'
163 assert sb_i64_str(-1) == '-1'
164 assert sb_i64_str(1001) == '1001'
165 assert sb_i64_str(-1001) == '-1001'
166 assert sb_i64_str(1234567890) == '1234567890'
167 assert sb_i64_str(-1234567890) == '-1234567890'
168 assert sb_i64_str(9223372036854775807) == '9223372036854775807'
169 assert sb_i64_str(-9223372036854775807) == '-9223372036854775807'
170 assert sb_i64_str(min_i64) == '-9223372036854775808'
171 // runtime `min_i64` (parsed, not the constant), whose negation overflows i64:
172 assert sb_i64_str('-9223372036854775808'.i64()) == '-9223372036854775808'
173}
174
175@[manualfree]
176fn sb_u64_str(n u64) string {
177 mut sb := strings.new_builder(24)
178 defer {
179 unsafe { sb.free() }
180 }
181 sb.write_u_decimal(n)
182 return sb.str()
183}
184
185fn test_write_u_decimal() {
186 assert sb_u64_str(0) == '0'
187 assert sb_u64_str(1) == '1'
188 assert sb_u64_str(1001) == '1001'
189 assert sb_u64_str(1234567890) == '1234567890'
190 assert sb_u64_str(u64(9223372036854775807)) == '9223372036854775807'
191 // values above max_i64, which write_decimal(i64) cannot represent:
192 assert sb_u64_str(u64(9223372036854775807) + 1) == '9223372036854775808'
193 assert sb_u64_str(max_u64) == '18446744073709551615'
194}
195
196fn test_grow_len() {
197 mut sb := strings.new_builder(10)
198 assert sb.len == 0
199 assert sb.cap == 10
200
201 sb.write_string('0123456789')
202 assert sb.len == 10
203
204 unsafe { sb.grow_len(-5) }
205 assert sb.len == 10
206 assert sb.cap == 10
207
208 unsafe { sb.grow_len(10) }
209 assert sb.len == 20
210 assert sb.cap == 20
211
212 sb.ensure_cap(35)
213 assert sb.len == 20
214 assert sb.cap >= 35
215 cap_after_ensure := sb.cap
216
217 unsafe { sb.grow_len(5) }
218 assert sb.len == 25
219 assert sb.cap == cap_after_ensure
220}
221
222fn test_write_repeated_rune() {
223 mut sb := strings.new_builder(20)
224 sb.write_repeated_rune(`h`, 5)
225 sb.write_repeated_rune(`w`, 5)
226 sb.write_repeated_rune(`√`, 5)
227 sb.write_rune(` `)
228 x := sb.str()
229 assert x == 'hhhhhwwwww√√√√√ '
230}
231
232struct IndentTest {
233 param strings.IndentParam
234 input string
235 output string
236}
237
238// vfmt off
239const indent_test_data = [
240 IndentTest{
241 input: 'User1 {
242 name: "John"
243 settings: {
244 theme: "dark"
245 language: "en"
246 }
247 }'
248 output: 'User1 {
249 name: "John"
250 settings: {
251 theme: "dark"
252 language: "en"
253 }
254}'
255 },
256 IndentTest{
257 input: 'User2{name:"John" settings:{theme:"dark" language:"en" hobbies:["reading","sports"]}}'
258 output: 'User2{
259 name:"John" settings:{
260 theme:"dark" language:"en" hobbies:["reading","sports"]
261 }
262}'
263 },
264 IndentTest{
265 input: 'message {text: "Hello {world}!" count: 5 nested: {data: "Test {inner}"}}'
266 output: 'message {
267 text: "Hello {world}!" count: 5 nested: {
268 data: "Test {inner}"
269 }
270}'
271 },
272 IndentTest{
273 input: 'if x > 0 {println("Positive") for i in 0..x {println(i) if i % 2 == 0 {println("even")}}} else {println("Not positive")}'
274 output: 'if x > 0 {
275 println("Positive") for i in 0..x {
276 println(i) if i % 2 == 0 {
277 println("even")
278 }
279 }
280} else {
281 println("Not positive")
282}'
283 },
284 IndentTest{
285 input: 'config{database:{host:"localhost" port:5432} server:{port:8080 routes:{api:"/api" static:"/static"}} log:{level:"info"}}'
286 output: 'config{
287 database:{
288 host:"localhost" port:5432
289 } server:{
290 port:8080 routes:{
291 api:"/api" static:"/static"
292 }
293 } log:{
294 level:"info"
295 }
296}'
297 },
298 IndentTest{
299 input: "MyS{
300 a: 0
301 b: 0
302 son: Son{
303 k: ''
304 m: ''
305}
306}
307"
308 output: "MyS{
309 a: 0
310 b: 0
311 son: Son{
312 k: ''
313 m: ''
314 }
315}
316"
317 },
318 IndentTest{
319 input: 'config {message: "He said: \\"Hello World!\\"" code: "if (x) { return \\"value\\"; }"}'
320 output: 'config {
321 message: "He said: \\"Hello World!\\"" code: "if (x) { return \\"value\\"; }"
322}'
323 },
324 IndentTest {
325 input : 'data {text: "String with {curly braces} and \\"quotes\\"" nested: {value: "Inner \\"quoted\\" string"}}'
326 output : 'data {
327 text: "String with {curly braces} and \\"quotes\\"" nested: {
328 value: "Inner \\"quoted\\" string"
329 }
330}'
331 },
332 IndentTest {
333 input : 'escape {backslash: "Path: C:\\\\Users\\\\Test" newline: "Line1\\nLine2" tab: "Column1\\tColumn2"}'
334 output : 'escape {
335 backslash: "Path: C:\\\\Users\\\\Test" newline: "Line1\\nLine2" tab: "Column1\\tColumn2"
336}'
337 },
338 IndentTest {
339 input : 'nested {outer: "Outer \\"quote\\" with {braces}" inner: {value: "Inner string with \\\\backslash and \\"quotes\\""}}'
340 output : 'nested {
341 outer: "Outer \\"quote\\" with {braces}" inner: {
342 value: "Inner string with \\\\backslash and \\"quotes\\""
343 }
344}'
345 },
346 IndentTest {
347 input : 'complex {str1: "\\"Escaped quotes\\"" str2: "Backslash: \\\\" str3: "Mixed: \\"quoted\\" and \\\\backslash" regex: "Pattern: \\\\d+\\\\.\\\\d+"}'
348 output : 'complex {
349 str1: "\\"Escaped quotes\\"" str2: "Backslash: \\\\" str3: "Mixed: \\"quoted\\" and \\\\backslash" regex: "Pattern: \\\\d+\\\\.\\\\d+"
350}'
351 },
352 IndentTest {
353 input : 'json {data: "{\\"name\\": \\"John\\", \\"age\\": 30, \\"city\\": \\"New York\\"}"}'
354 output : 'json {
355 data: "{\\"name\\": \\"John\\", \\"age\\": 30, \\"city\\": \\"New York\\"}"
356}'
357 },
358 IndentTest {
359 input : 'code {function: "fn test() { if (x) { return \\\"value\\\"; } }" error: "Error: \\\"File not found\\\" at line 10"}'
360 output : 'code {
361 function: "fn test() { if (x) { return \\\"value\\\"; } }" error: "Error: \\\"File not found\\\" at line 10"
362}'
363 },
364 IndentTest {
365 input : 'multiline {message: "Line 1\\nLine 2\\nLine 3 with {braces}\\nLine 4 with \\\"quotes\\\""}'
366 output : 'multiline {
367 message: "Line 1\\nLine 2\\nLine 3 with {braces}\\nLine 4 with \\\"quotes\\\""
368}'
369 },
370 IndentTest {
371 input : 'extreme {str: "\\\\\\\\\\\\\\"Quadruple escaped\\\\\\\\\\\\\\""}'
372 output : 'extreme {
373 str: "\\\\\\\\\\\\\\"Quadruple escaped\\\\\\\\\\\\\\""
374}'
375 },
376 IndentTest{
377 param: strings.IndentParam {
378 block_start: `[`
379 block_end: `]`
380 }
381 input: 'message [text: "Hello {world}!" count: 5 nested: [data: "Test {inner}"]]'
382 output: 'message [
383 text: "Hello {world}!" count: 5 nested: [
384 data: "Test {inner}"
385 ]
386]'
387 },
388 IndentTest{
389 param: strings.IndentParam {
390 block_start: `[`
391 block_end: `]`
392 indent_char: `#`
393 }
394 input: 'message [text: "Hello {world}!" count: 5 nested: [data: "Test {inner}"]]'
395 output: 'message [
396####text: "Hello {world}!" count: 5 nested: [
397########data: "Test {inner}"
398####]
399]'
400 },
401 IndentTest{
402 param: strings.IndentParam {
403 block_start: `[`
404 block_end: `]`
405 indent_char: `\t`
406 indent_count: 2
407 }
408 input: 'message [text: "Hello {world}!" count: 5 nested: [data: "Test {inner}"]]'
409 output: 'message [
410\t\ttext: "Hello {world}!" count: 5 nested: [
411\t\t\t\tdata: "Test {inner}"
412\t\t]
413]'
414 },
415 IndentTest{
416 param: strings.IndentParam {
417 block_start: `[`
418 block_end: `]`
419 indent_char: `#`
420 indent_count: 1
421 starting_level: 2
422 }
423 input: 'message [text: "Hello {world}!" count: 5 nested: [data: "Test {inner}"]]'
424 output: '##message [
425###text: "Hello {world}!" count: 5 nested: [
426####data: "Test {inner}"
427###]
428##]'
429 },
430]
431
432// vfmt on
433
434fn test_indent() {
435 for t in indent_test_data {
436 mut sb := strings.new_builder(256)
437 sb.indent(t.input, t.param)
438 assert sb.str() == t.output
439 }
440}
441