v2 / vlib / v / tests / builtin_strings_and_interpolation / string_interpolation_test.v
298 lines · 265 sloc · 7.71 KB · 046d870cb46a2a276fbe02a1d4f43b3af0c00a23
Raw
1fn test_simple_string_interpolation() {
2 a := 'Hello'
3 b := 'World'
4 res := '${a} ${b}'
5 assert res == 'Hello World'
6}
7
8fn test_mixed_string_interpolation() {
9 num := 7
10 str := 'abc'
11 s1 := 'number=${num}'
12 assert s1 == 'number=7'
13 s2 := 'string=${str}'
14 assert s2 == 'string=abc'
15 s3 := 'a: ${num} | b: ${str}'
16 assert s3 == 'a: 7 | b: abc'
17}
18
19fn test_formatted_string_interpolation() {
20 x := 'abc'
21 axb := 'a:${x}:b'
22 assert axb == 'a:abc:b'
23 x_10 := 'a:${x:10s}:b'
24 x10_ := 'a:${x:-10s}:b'
25 assert x_10 == 'a: abc:b'
26 assert x10_ == 'a:abc :b'
27 i := 23
28 si_right := '${i:10d}'
29 si__left := '${i:-10d}'
30 assert si_right == ' 23'
31 assert si__left == '23 '
32}
33
34fn test_dynamic_format_widths() {
35 width := 10
36 left_width := -10
37 zero_width := 5
38 sign_width := 6
39 name := 'abc'
40 num := 42
41 assert '>${name:(width)}<' == '> abc<'
42 assert '>${name:(left_width)}<' == '>abc <'
43 assert '>${name:(-width)}<' == '>abc <'
44 assert '${num:0(zero_width)d}' == '00042'
45 assert '${num:+(sign_width)d}' == ' +42'
46}
47
48fn test_dynamic_format_precision() {
49 width := 8
50 precision := 3
51 value := 12.34567
52 assert '>${value:(width).(precision)f}<' == '> 12.346<'
53}
54
55fn test_escape_dollar_in_string() {
56 i := 42
57 assert '(${i})' == '(42)'
58 assert '(\$i)'.contains('i') && !'(\$i)'.contains('42')
59 assert !'(\\${i})'.contains('i') && '(\\${i})'.contains('42') && '(\\${i})'.contains('\\')
60 assert '(\\\$i)'.contains('i') && !'(\\\$i)'.contains('42') && '(\\${i})'.contains('\\')
61 assert !'(\\\\${i})'.contains('i') && '(\\\\${i})'.contains('42')
62 && '(\\\\${i})'.contains('\\\\')
63 assert '(${i})' == '(42)'
64 assert '(\${i})'.contains('i') && !'(\${i})'.contains('42')
65 assert !'(\\${i})'.contains('i') && '(\\${i})'.contains('42') && '(\\${i})'.contains('\\')
66 assert '(\\\${i})'.contains('i') && !'(\\\${i})'.contains('42') && '(\\${i})'.contains('\\')
67 assert !'(\\\\${i})'.contains('i') && '(\\\\${i})'.contains('42')
68 && '(\\\\${i})'.contains('\\\\')
69 assert i == 42
70}
71
72fn test_dollar_sign_is_literal_without_braces() {
73 b := 10
74 text := 'a$b'
75 assert text == 'a$b'
76 assert b == 10
77}
78
79fn test_implicit_str() {
80 i := 42
81 assert 'int ${i}' == 'int 42'
82 assert '${i}' == '42'
83 check := '${i}' == '42'
84 assert check
85 text := '${i}' + '42'
86 assert text == '4242'
87}
88
89fn test_string_interpolation_percent_escaping() {
90 test := 'hello'
91 hello := 'world'
92 x := '%.*s${hello}${test} |${hello:-30s}|'
93 assert x == '%.*sworldhello |world |'
94}
95
96fn test_string_interpolation_string_prefix() {
97 // `r`, `c` and `js` are also used as a string prefix.
98 r := 'r'
99 rr := '${r}${r}'
100 assert rr == 'rr'
101 c := 'c'
102 cc := '${c}${c}'
103 assert cc == 'cc'
104 js := 'js'
105 jsjs := '${js}${js}'
106 assert jsjs == 'jsjs'
107}
108
109fn test_interpolation_string_prefix_expr() {
110 r := 1
111 c := 2
112 js := 1
113 assert '>${3 + r}<' == '>4<'
114 assert '${r == js} ${js}' == 'true 1'
115 assert '>${js + c} ${js + r == c}<' == '>3 true<'
116}
117
118fn test_inttypes_string_interpolation() {
119 c := i8(-103) // -0x67
120 uc := u8(217) // 0xD9
121 uc2 := u8(13) // 0x0D
122 s := i16(-23456) // -0x5BA0
123 us := u16(54321) // 0xD431
124 i := -1622999040 // -0x60BD 0000
125 ui := u32(3421958087) // 0xCBF6 EFC7
126 vp := voidptr(ui)
127 mut bp := &u8(unsafe { nil })
128 unsafe {
129 $if x64 {
130 bp = &u8(15541149836) // 0x3 9E53 208C
131 } $else {
132 bp = &u8(3541149836) // 0xD311 A88C
133 }
134 }
135 l := i64(-7694555558525237396)
136 ul := u64(17234006112912956370)
137 assert '${s} ${us}' == '-23456 54321'
138 assert '${ui} ${i}' == '3421958087 -1622999040'
139 assert '${l} ${ul}' == '-7694555558525237396 17234006112912956370'
140 assert '>${s:11}:${us:-13}<' == '> -23456:54321 <'
141 assert '0x${ul:-19x}:${l:22d}' == '0xef2b7d4001165bd2 : -7694555558525237396'
142 assert '${c:5}${uc:-7}x' == ' -103217 x'
143 assert '${c:x}:${uc:x}:${uc2:02X}' == '-67:d9:0D'
144 assert '${s:X}:${us:x}:${u16(uc):04x}' == '-5BA0:d431:00d9'
145 assert '${i:x}:${ui:X}:${int(s):x}' == '-60bd0000:CBF6EFC7:-5ba0'
146 assert '${l:x}:${ul:X}' == '-6ac88d8352677894:EF2B7D4001165BD2'
147 // default pointer format is platform dependent, so try a few
148 eprintln("platform pointer format: '${vp:p}:${bp}'")
149 $if x64 {
150 assert '${vp:p}:${bp}' == '0xcbf6efc7:0x39e53208c'
151 || '${vp:p}:${bp}' == 'CBF6EFC7:39E53208C' || '${vp:p}:${bp}' == 'cbf6efc7:39e53208c'
152 || '${vp:p}:${bp}' == '00000000CBF6EFC7:000000039E53208C'
153 } $else {
154 assert '${vp:p}:${bp}' == 'CBF6EFC7:D311A88C' || '${vp:p}:${bp}' == 'cbf6efc7:d311a88c'
155 || '${vp:p}:${bp}' == '0xcbf6efc7:0xd311a88c'
156 }
157}
158
159fn int_ref_mut_string(mut n &int) string {
160 return '${n}'
161}
162
163fn int_ref_string(n &int) string {
164 return '${n}'
165}
166
167fn test_int_ref_string_interpolation() {
168 mut count := 10
169 count_ref := &count
170 assert int_ref_mut_string(mut &count) == '10'
171 assert int_ref_string(&count) == '10'
172 assert '${count_ref}' == '10'
173 assert '${&count}' == '10'
174 assert '${count_ref:x}' == 'a'
175}
176
177fn test_utf8_string_interpolation() {
178 a := 'à-côté'
179 st := 'Sträßle'
180 m := '10€'
181 assert '${a} ${st} ${m}' == 'à-côté Sträßle 10€'
182 zz := '>${a:10}< >${st:-8}< >${m:5}<-'
183 zz_expected := '> à-côté< >Sträßle < > 10€<-'
184 eprintln(' zz: ${zz}')
185 eprintln('zz_expected: ${zz_expected}')
186 assert zz == zz_expected
187 // e := '\u20AC' // Eurosign doesn' work with MSVC and tcc
188 e := '€'
189 assert '100.00 ${e}' == '100.00 €'
190 m2 := 'Москва́' // cyrillic а́: combination of U+0430 and U+0301, UTF-8: d0 b0 cc 81
191 d := 'Antonín Dvořák' // latin á: U+00E1, UTF-8: c3 a1
192 assert ':${m2:7}:${d:-15}:' == ': Москва́:Antonín Dvořák :'
193 g := 'Πελοπόννησος'
194 assert '>${g:-13}<' == '>Πελοπόννησος <'
195}
196
197fn test_utf8_string_interpolation_uses_grapheme_clusters() {
198 assert '>${'\u006E\u0303':10}<' == '> ñ<'
199 assert '>${'\U0001F3F3\uFE0F\u200D\U0001F308':10}<' == '> 🏳️‍🌈<'
200 assert '>${'ห์':10}<' == '> ห์<'
201 assert '>${'ปีเตอร์':10}<' == '> ปีเตอร์<'
202 assert '>${'👩🏽‍💻':10}<' == '> 👩🏽‍💻<'
203}
204
205struct Sss {
206 v1 int
207 v2 f64
208}
209
210fn (s Sss) str() string {
211 return '[${s.v1}, ${s.v2:.3f}]'
212}
213
214fn test_string_interpolation_str_evaluation() {
215 mut x := Sss{17, 13.455893}
216 assert '${x}' == '[17, 13.456]'
217}
218
219fn test_string_interpolation_with_negative_format_width_should_compile_and_run_without_segfaulting() {
220 // discovered during debugging VLS
221 i := 3
222 input := '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'
223 eprintln('---------------------------------------------------------------------------------------------')
224 eprintln('+60 ${i:10} | input.len: ${input.len:10} | ${input.hex():60} | ${input}')
225 eprintln('-60 ${i:10} | input.len: ${input.len:10} | ${input.hex():-60} | ${input}')
226 eprintln('---------------------------------------------------------------------------------------------')
227 assert true
228}
229
230struct Aa {
231 a int
232}
233
234struct Bb {
235 b Aa
236}
237
238fn (x Bb) f() Aa {
239 return x.b
240}
241
242fn test_method_interpolation() {
243 y := Bb{
244 b: Aa{
245 a: 2
246 }
247 }
248 assert '>${y.f().a}<' == '>2<'
249 assert '>${y.f().a}<' == '>2<'
250}
251
252fn f(i int) int {
253 return i
254}
255
256fn test_call() {
257 s := '${f(4)}'
258 assert s == '4'
259}
260
261// for issue: 19048
262struct Foo {
263}
264
265fn (mut f Foo) intp_pointer() string {
266 return '${f:p}'
267}
268
269fn test_intp_pointer_specifier_p() {
270 mut foo := Foo{}
271 str1 := foo.intp_pointer()
272
273 str2 := '${&foo:p}'
274 assert str1 == str2
275}
276
277// for issue: 20199
278// string contains the zero character: `\0`
279fn test_contains_zero_characters() {
280 mut str := 'abc'
281 str = '${str}\x00${str}'
282 assert str.len == 7
283 assert str == 'abc\0abc'
284}
285
286// for issue: 20432
287// non-ascii escape was lost
288fn test_interpo_non_ascii_characters() {
289 hello := '你好'
290 assert '${hello},世界!' == '你好,世界!'
291}
292
293fn test_float_exponent_sign() {
294 a := 1234567.0123456e03
295 assert '${a:6.1e}' == '1.2e+09'
296 assert '${a:6.2e}' == '1.23e+09'
297 assert '${a:6.5e}' == '1.23457e+09'
298}
299