v2 / vlib / strings / builder_test.v
417 lines · 390 sloc · 9.54 KB · 66207866bb98f11345ce49c67014dde5b4a65cdb
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}
172
173fn test_grow_len() {
174 mut sb := strings.new_builder(10)
175 assert sb.len == 0
176 assert sb.cap == 10
177
178 sb.write_string('0123456789')
179 assert sb.len == 10
180
181 unsafe { sb.grow_len(-5) }
182 assert sb.len == 10
183 assert sb.cap == 10
184
185 unsafe { sb.grow_len(10) }
186 assert sb.len == 20
187 assert sb.cap == 20
188
189 sb.ensure_cap(35)
190 assert sb.len == 20
191 assert sb.cap >= 35
192 cap_after_ensure := sb.cap
193
194 unsafe { sb.grow_len(5) }
195 assert sb.len == 25
196 assert sb.cap == cap_after_ensure
197}
198
199fn test_write_repeated_rune() {
200 mut sb := strings.new_builder(20)
201 sb.write_repeated_rune(`h`, 5)
202 sb.write_repeated_rune(`w`, 5)
203 sb.write_repeated_rune(`√`, 5)
204 sb.write_rune(` `)
205 x := sb.str()
206 assert x == 'hhhhhwwwww√√√√√ '
207}
208
209struct IndentTest {
210 param strings.IndentParam
211 input string
212 output string
213}
214
215// vfmt off
216const indent_test_data = [
217 IndentTest{
218 input: 'User1 {
219 name: "John"
220 settings: {
221 theme: "dark"
222 language: "en"
223 }
224 }'
225 output: 'User1 {
226 name: "John"
227 settings: {
228 theme: "dark"
229 language: "en"
230 }
231}'
232 },
233 IndentTest{
234 input: 'User2{name:"John" settings:{theme:"dark" language:"en" hobbies:["reading","sports"]}}'
235 output: 'User2{
236 name:"John" settings:{
237 theme:"dark" language:"en" hobbies:["reading","sports"]
238 }
239}'
240 },
241 IndentTest{
242 input: 'message {text: "Hello {world}!" count: 5 nested: {data: "Test {inner}"}}'
243 output: 'message {
244 text: "Hello {world}!" count: 5 nested: {
245 data: "Test {inner}"
246 }
247}'
248 },
249 IndentTest{
250 input: 'if x > 0 {println("Positive") for i in 0..x {println(i) if i % 2 == 0 {println("even")}}} else {println("Not positive")}'
251 output: 'if x > 0 {
252 println("Positive") for i in 0..x {
253 println(i) if i % 2 == 0 {
254 println("even")
255 }
256 }
257} else {
258 println("Not positive")
259}'
260 },
261 IndentTest{
262 input: 'config{database:{host:"localhost" port:5432} server:{port:8080 routes:{api:"/api" static:"/static"}} log:{level:"info"}}'
263 output: 'config{
264 database:{
265 host:"localhost" port:5432
266 } server:{
267 port:8080 routes:{
268 api:"/api" static:"/static"
269 }
270 } log:{
271 level:"info"
272 }
273}'
274 },
275 IndentTest{
276 input: "MyS{
277 a: 0
278 b: 0
279 son: Son{
280 k: ''
281 m: ''
282}
283}
284"
285 output: "MyS{
286 a: 0
287 b: 0
288 son: Son{
289 k: ''
290 m: ''
291 }
292}
293"
294 },
295 IndentTest{
296 input: 'config {message: "He said: \\"Hello World!\\"" code: "if (x) { return \\"value\\"; }"}'
297 output: 'config {
298 message: "He said: \\"Hello World!\\"" code: "if (x) { return \\"value\\"; }"
299}'
300 },
301 IndentTest {
302 input : 'data {text: "String with {curly braces} and \\"quotes\\"" nested: {value: "Inner \\"quoted\\" string"}}'
303 output : 'data {
304 text: "String with {curly braces} and \\"quotes\\"" nested: {
305 value: "Inner \\"quoted\\" string"
306 }
307}'
308 },
309 IndentTest {
310 input : 'escape {backslash: "Path: C:\\\\Users\\\\Test" newline: "Line1\\nLine2" tab: "Column1\\tColumn2"}'
311 output : 'escape {
312 backslash: "Path: C:\\\\Users\\\\Test" newline: "Line1\\nLine2" tab: "Column1\\tColumn2"
313}'
314 },
315 IndentTest {
316 input : 'nested {outer: "Outer \\"quote\\" with {braces}" inner: {value: "Inner string with \\\\backslash and \\"quotes\\""}}'
317 output : 'nested {
318 outer: "Outer \\"quote\\" with {braces}" inner: {
319 value: "Inner string with \\\\backslash and \\"quotes\\""
320 }
321}'
322 },
323 IndentTest {
324 input : 'complex {str1: "\\"Escaped quotes\\"" str2: "Backslash: \\\\" str3: "Mixed: \\"quoted\\" and \\\\backslash" regex: "Pattern: \\\\d+\\\\.\\\\d+"}'
325 output : 'complex {
326 str1: "\\"Escaped quotes\\"" str2: "Backslash: \\\\" str3: "Mixed: \\"quoted\\" and \\\\backslash" regex: "Pattern: \\\\d+\\\\.\\\\d+"
327}'
328 },
329 IndentTest {
330 input : 'json {data: "{\\"name\\": \\"John\\", \\"age\\": 30, \\"city\\": \\"New York\\"}"}'
331 output : 'json {
332 data: "{\\"name\\": \\"John\\", \\"age\\": 30, \\"city\\": \\"New York\\"}"
333}'
334 },
335 IndentTest {
336 input : 'code {function: "fn test() { if (x) { return \\\"value\\\"; } }" error: "Error: \\\"File not found\\\" at line 10"}'
337 output : 'code {
338 function: "fn test() { if (x) { return \\\"value\\\"; } }" error: "Error: \\\"File not found\\\" at line 10"
339}'
340 },
341 IndentTest {
342 input : 'multiline {message: "Line 1\\nLine 2\\nLine 3 with {braces}\\nLine 4 with \\\"quotes\\\""}'
343 output : 'multiline {
344 message: "Line 1\\nLine 2\\nLine 3 with {braces}\\nLine 4 with \\\"quotes\\\""
345}'
346 },
347 IndentTest {
348 input : 'extreme {str: "\\\\\\\\\\\\\\"Quadruple escaped\\\\\\\\\\\\\\""}'
349 output : 'extreme {
350 str: "\\\\\\\\\\\\\\"Quadruple escaped\\\\\\\\\\\\\\""
351}'
352 },
353 IndentTest{
354 param: strings.IndentParam {
355 block_start: `[`
356 block_end: `]`
357 }
358 input: 'message [text: "Hello {world}!" count: 5 nested: [data: "Test {inner}"]]'
359 output: 'message [
360 text: "Hello {world}!" count: 5 nested: [
361 data: "Test {inner}"
362 ]
363]'
364 },
365 IndentTest{
366 param: strings.IndentParam {
367 block_start: `[`
368 block_end: `]`
369 indent_char: `#`
370 }
371 input: 'message [text: "Hello {world}!" count: 5 nested: [data: "Test {inner}"]]'
372 output: 'message [
373####text: "Hello {world}!" count: 5 nested: [
374########data: "Test {inner}"
375####]
376]'
377 },
378 IndentTest{
379 param: strings.IndentParam {
380 block_start: `[`
381 block_end: `]`
382 indent_char: `\t`
383 indent_count: 2
384 }
385 input: 'message [text: "Hello {world}!" count: 5 nested: [data: "Test {inner}"]]'
386 output: 'message [
387\t\ttext: "Hello {world}!" count: 5 nested: [
388\t\t\t\tdata: "Test {inner}"
389\t\t]
390]'
391 },
392 IndentTest{
393 param: strings.IndentParam {
394 block_start: `[`
395 block_end: `]`
396 indent_char: `#`
397 indent_count: 1
398 starting_level: 2
399 }
400 input: 'message [text: "Hello {world}!" count: 5 nested: [data: "Test {inner}"]]'
401 output: '##message [
402###text: "Hello {world}!" count: 5 nested: [
403####data: "Test {inner}"
404###]
405##]'
406 },
407]
408
409// vfmt on
410
411fn test_indent() {
412 for t in indent_test_data {
413 mut sb := strings.new_builder(256)
414 sb.indent(t.input, t.param)
415 assert sb.str() == t.output
416 }
417}
418