v4 / vlib / v3 / markused / custom_str_test.v
392 lines · 342 sloc · 12.52 KB · 351709f1031b64c6175612e9e459d8216eeca7f5
Raw
1module markused
2
3import os
4import v3.flat
5import v3.gen.c as cgen
6import v3.parser
7import v3.pref
8import v3.transform
9import v3.types
10
11const custom_str_tests_dir = os.dir(@FILE)
12const custom_str_v3_dir = os.dir(custom_str_tests_dir)
13const custom_str_v3_src = os.join_path(custom_str_v3_dir, 'v3.v')
14const custom_str_vexe = @VEXE
15
16// parse_checked_two_file_source reads parse checked two file source input for v3 tests.
17fn parse_checked_two_file_source(name string, main_source string, module_rel string, module_source string) (&flat.FlatAst, &types.TypeChecker) {
18 root := os.join_path(os.temp_dir(), 'v3_markused_${name}_project')
19 if os.exists(root) {
20 os.rmdir_all(root) or { panic(err) }
21 }
22 os.mkdir_all(root) or { panic(err) }
23 main_src := os.join_path(root, 'main.v')
24 module_src := os.join_path(root, module_rel)
25 os.mkdir_all(os.dir(module_src)) or { panic(err) }
26 os.write_file(main_src, main_source) or { panic(err) }
27 os.write_file(module_src, module_source) or { panic(err) }
28 prefs := pref.new_preferences()
29 mut p := parser.Parser.new(prefs)
30 mut a := p.parse_files([main_src, module_src])
31 mut tc := types.TypeChecker.new(a)
32 tc.collect(a)
33 tc.diagnose_unknown_calls = true
34 tc.diagnostic_files[main_src] = true
35 tc.diagnostic_files[module_src] = true
36 tc.check_semantics()
37 assert tc.errors.len == 0, tc.errors.str()
38 return a, &tc
39}
40
41// build_v3_bin builds v3 bin data for v3 tests.
42fn build_v3_bin(name string) string {
43 v3_bin := os.join_path(os.temp_dir(), 'v3_markused_${name}')
44 build := os.execute('${custom_str_vexe} -o ${v3_bin} ${custom_str_v3_src}')
45 assert build.exit_code == 0, build.output
46 return v3_bin
47}
48
49// imported_enum_main_source supports imported enum main source handling for v3 tests.
50fn imported_enum_main_source(expr string) string {
51 return '
52module main
53
54import colors
55
56fn main() {
57 c := colors.Color.red
58 ${expr}
59}
60'
61}
62
63// imported_optional_enum_main_source
64// supports helper handling in v3 tests.
65fn imported_optional_enum_main_source(expr string) string {
66 return '
67module main
68
69import colors
70
71fn maybe_color() ?colors.Color {
72 return colors.Color.red
73}
74
75fn main() {
76 ${expr}
77}
78'
79}
80
81// imported_enum_module_source supports imported enum module source handling for v3 tests.
82fn imported_enum_module_source() string {
83 return '
84module colors
85
86pub enum Color {
87 red
88 blue
89}
90
91pub fn (c Color) str() string {
92 return "red"
93}
94'
95}
96
97// imported_operator_main_source supports imported operator main source handling for v3 tests.
98fn imported_operator_main_source(expr string) string {
99 return '
100module main
101
102import vectors
103
104fn main() {
105 a := vectors.new_vec(1)
106 b := vectors.new_vec(2)
107 ${expr}
108}
109'
110}
111
112// imported_operator_module_source supports imported operator module source handling for v3 tests.
113fn imported_operator_module_source() string {
114 return '
115module vectors
116
117pub struct Vec {
118 x int
119}
120
121pub fn new_vec(x int) Vec {
122 return Vec{
123 x: x
124 }
125}
126
127pub fn (a Vec) + (b Vec) Vec {
128 return Vec{
129 x: a.x + b.x
130 }
131}
132
133pub fn (a Vec) < (b Vec) bool {
134 return a.x < b.x
135}
136'
137}
138
139// imported_operator_usage_source supports imported operator usage source handling for v3 tests.
140fn imported_operator_usage_source() string {
141 return 'sum := a + b
142 gt := b > a
143 if gt {
144 _ := sum
145 }'
146}
147
148// imported_struct_default_main_source supports imported_struct_default_main_source handling.
149fn imported_struct_default_main_source(expr string) string {
150 return '
151module main
152
153import defaults
154
155fn main() {
156 ${expr}
157}
158'
159}
160
161// imported_struct_default_module_source supports imported_struct_default_module_source handling.
162fn imported_struct_default_module_source() string {
163 return '
164module defaults
165
166pub struct Box {
167 value int = default_value()
168}
169
170pub fn default_value() int {
171 return 7
172}
173
174pub fn maybe_box() ?Box {
175 return none
176}
177'
178}
179
180// test_string_interpolation_seeds_imported_enum_str_method validates this v3 regression case.
181fn test_string_interpolation_seeds_imported_enum_str_method() {
182 a, tc := parse_checked_two_file_source('imported_enum_interp_str',
183 imported_enum_main_source('_ := "\${c}"'), 'colors/colors.v', imported_enum_module_source())
184 mut used := mark_used(a, tc)
185 assert used['colors.Color.str']
186}
187
188// test_optional_string_interpolation_seeds_imported_enum_str_method
189// validates this v3 regression case.
190fn test_optional_string_interpolation_seeds_imported_enum_str_method() {
191 a, tc := parse_checked_two_file_source('imported_optional_enum_interp_str',
192 imported_optional_enum_main_source('_ := "\${maybe_color()}"'), 'colors/colors.v',
193 imported_enum_module_source())
194 mut used := mark_used(a, tc)
195 assert used['colors.Color.str']
196}
197
198// test_imported_operator_infix_seeds_operator_methods validates this v3 regression case.
199fn test_imported_operator_infix_seeds_operator_methods() {
200 a, tc := parse_checked_two_file_source('imported_operator_infix',
201 imported_operator_main_source(imported_operator_usage_source()), 'vectors/vectors.v',
202 imported_operator_module_source())
203 mut used := mark_used(a, tc)
204 assert used['vectors.Vec.+']
205 assert used['vectors.Vec.<']
206}
207
208// test_flag_enum_seeds_string_plus_helper validates this v3 regression case: a `[flag]`
209// enum's synthesized `<Enum>__autostr` builds its string with `string__plus`, but that
210// generated body is invisible to markused, so the helper must be seeded from the flag-enum
211// declaration or it could be pruned and leave the autostr calling an undefined helper.
212fn test_flag_enum_seeds_string_plus_helper() {
213 main_src := '
214module main
215
216import colors
217
218@[flag]
219enum Perm {
220 read
221 write
222}
223
224fn main() {
225 p := Perm.read | Perm.write
226 _ := p
227 _ := colors.Color.red
228}
229'
230 a, tc := parse_checked_two_file_source('flag_enum_string_plus', main_src, 'colors/colors.v',
231 imported_enum_module_source())
232 mut used := mark_used(a, tc)
233 assert used['string__plus']
234}
235
236// test_optional_struct_zero_seeds_imported_default_helper validates this v3 regression case.
237fn test_optional_struct_zero_seeds_imported_default_helper() {
238 a, tc := parse_checked_two_file_source('imported_struct_default_or',
239 imported_struct_default_main_source('box := defaults.maybe_box() or { return }\n\t_ := box'),
240 'defaults/defaults.v', imported_struct_default_module_source())
241 mut used := mark_used(a, tc)
242 assert used['defaults.default_value']
243}
244
245// test_string_interpolation_lowers_to_imported_enum_str_after_used_filter_transform
246// validates this v3 regression case.
247fn test_string_interpolation_lowers_to_imported_enum_str_after_used_filter_transform() {
248 mut a, mut tc := parse_checked_two_file_source('imported_enum_interp_str_cgen',
249 imported_enum_main_source('_ := "\${c}"'), 'colors/colors.v', imported_enum_module_source())
250 mut used := mark_used(a, tc)
251 assert used['colors.Color.str']
252 used = transform.transform_with_used(mut a, tc, used)
253 tc.diagnose_unknown_calls = false
254 tc.reject_unlowered_map_mutation = true
255 tc.annotate_types()
256 mut g := cgen.FlatGen.new()
257 c_code := g.gen_with_used_options(a, used, tc, true)
258 assert c_code.contains('colors__Color__str(')
259}
260
261// test_imported_operator_infix_lowers_after_used_filter_transform
262// validates this v3 regression case.
263fn test_imported_operator_infix_lowers_after_used_filter_transform() {
264 mut a, mut tc := parse_checked_two_file_source('imported_operator_infix_cgen',
265 imported_operator_main_source(imported_operator_usage_source()), 'vectors/vectors.v',
266 imported_operator_module_source())
267 mut used := mark_used(a, tc)
268 assert used['vectors.Vec.+']
269 assert used['vectors.Vec.<']
270 used = transform.transform_with_used(mut a, tc, used)
271 tc.diagnose_unknown_calls = false
272 tc.reject_unlowered_map_mutation = true
273 tc.annotate_types()
274 mut g := cgen.FlatGen.new()
275 c_code := g.gen_with_used_options(a, used, tc, true)
276 assert c_code.contains('vectors__Vec__plus(')
277 assert c_code.contains('vectors__Vec__lt(')
278}
279
280// test_optional_struct_zero_lowers_to_imported_default_after_used_filter_transform
281// validates this v3 regression case.
282fn test_optional_struct_zero_lowers_to_imported_default_after_used_filter_transform() {
283 mut a, mut tc := parse_checked_two_file_source('imported_struct_default_or_cgen',
284 imported_struct_default_main_source('box := defaults.maybe_box() or { return }\n\t_ := box'),
285 'defaults/defaults.v', imported_struct_default_module_source())
286 mut used := mark_used(a, tc)
287 assert used['defaults.default_value']
288 used = transform.transform_with_used(mut a, tc, used)
289 tc.diagnose_unknown_calls = false
290 tc.reject_unlowered_map_mutation = true
291 tc.annotate_types()
292 mut g := cgen.FlatGen.new()
293 c_code := g.gen_with_used_options(a, used, tc, true)
294 assert c_code.contains('defaults__default_value(')
295}
296
297// test_optional_string_interpolation_lowers_to_imported_enum_str_after_used_filter_transform
298// validates this v3 regression case.
299fn test_optional_string_interpolation_lowers_to_imported_enum_str_after_used_filter_transform() {
300 mut a, mut tc := parse_checked_two_file_source('imported_optional_enum_interp_str_cgen',
301 imported_optional_enum_main_source('_ := "\${maybe_color()}"'), 'colors/colors.v',
302 imported_enum_module_source())
303 mut used := mark_used(a, tc)
304 assert used['colors.Color.str']
305 used = transform.transform_with_used(mut a, tc, used)
306 tc.diagnose_unknown_calls = false
307 tc.reject_unlowered_map_mutation = true
308 tc.annotate_types()
309 mut g := cgen.FlatGen.new()
310 c_code := g.gen_with_used_options(a, used, tc, true)
311 assert c_code.contains('colors__Color__str(')
312}
313
314// test_imported_enum_print_compile_keeps_str_method validates this v3 regression case.
315fn test_imported_enum_print_compile_keeps_str_method() {
316 v3_bin := build_v3_bin('imported_enum_print_str_test')
317
318 root := os.join_path(os.temp_dir(), 'v3_markused_imported_enum_print_input')
319 if os.exists(root) {
320 os.rmdir_all(root) or { panic(err) }
321 }
322 os.mkdir_all(os.join_path(root, 'colors')) or { panic(err) }
323 os.write_file(os.join_path(root, 'main.v'), imported_enum_main_source('println(c)')) or {
324 panic(err)
325 }
326 os.write_file(os.join_path(root, 'colors/colors.v'), imported_enum_module_source()) or {
327 panic(err)
328 }
329 bin := os.join_path(os.temp_dir(), 'v3_markused_imported_enum_print_input_bin')
330 compile := os.execute('${v3_bin} -o ${bin} ${root}')
331 assert compile.exit_code == 0, compile.output
332}
333
334// test_imported_operator_compile_keeps_operator_methods validates this v3 regression case.
335fn test_imported_operator_compile_keeps_operator_methods() {
336 v3_bin := build_v3_bin('imported_operator_test')
337
338 root := os.join_path(os.temp_dir(), 'v3_markused_imported_operator_input')
339 if os.exists(root) {
340 os.rmdir_all(root) or { panic(err) }
341 }
342 os.mkdir_all(os.join_path(root, 'vectors')) or { panic(err) }
343 os.write_file(os.join_path(root, 'main.v'),
344 imported_operator_main_source(imported_operator_usage_source())) or { panic(err) }
345 os.write_file(os.join_path(root, 'vectors/vectors.v'), imported_operator_module_source()) or {
346 panic(err)
347 }
348 bin := os.join_path(os.temp_dir(), 'v3_markused_imported_operator_input_bin')
349 compile := os.execute('${v3_bin} -o ${bin} ${root}')
350 assert compile.exit_code == 0, compile.output
351}
352
353// test_optional_struct_zero_compile_keeps_imported_default_helper
354// validates this v3 regression case.
355fn test_optional_struct_zero_compile_keeps_imported_default_helper() {
356 v3_bin := build_v3_bin('imported_struct_default_or_test')
357
358 root := os.join_path(os.temp_dir(), 'v3_markused_imported_struct_default_or_input')
359 if os.exists(root) {
360 os.rmdir_all(root) or { panic(err) }
361 }
362 os.mkdir_all(os.join_path(root, 'defaults')) or { panic(err) }
363 os.write_file(os.join_path(root, 'main.v'),
364 imported_struct_default_main_source('box := defaults.maybe_box() or { return }\n\t_ := box')) or {
365 panic(err)
366 }
367 os.write_file(os.join_path(root, 'defaults/defaults.v'),
368 imported_struct_default_module_source()) or { panic(err) }
369 bin := os.join_path(os.temp_dir(), 'v3_markused_imported_struct_default_or_input_bin')
370 compile := os.execute('${v3_bin} -o ${bin} ${root}')
371 assert compile.exit_code == 0, compile.output
372}
373
374// test_imported_optional_enum_interpolation_compile_keeps_str_method
375// validates this v3 regression case.
376fn test_imported_optional_enum_interpolation_compile_keeps_str_method() {
377 v3_bin := build_v3_bin('imported_optional_enum_interp_str_test')
378
379 root := os.join_path(os.temp_dir(), 'v3_markused_imported_optional_enum_interp_input')
380 if os.exists(root) {
381 os.rmdir_all(root) or { panic(err) }
382 }
383 os.mkdir_all(os.join_path(root, 'colors')) or { panic(err) }
384 os.write_file(os.join_path(root, 'main.v'),
385 imported_optional_enum_main_source('_ := "\${maybe_color()}"')) or { panic(err) }
386 os.write_file(os.join_path(root, 'colors/colors.v'), imported_enum_module_source()) or {
387 panic(err)
388 }
389 bin := os.join_path(os.temp_dir(), 'v3_markused_imported_optional_enum_interp_input_bin')
390 compile := os.execute('${v3_bin} -o ${bin} ${root}')
391 assert compile.exit_code == 0, compile.output
392}
393