v4 / vlib / v3 / tests / optional_struct_lvalue_codegen_test.v
174 lines · 153 sloc · 4.27 KB · 288feee4702b35beadb4037d02b96b5c8674156b
Raw
1import os
2
3const vexe = @VEXE
4const tests_dir = os.dir(@FILE)
5const v3_dir = os.dir(tests_dir)
6const vlib_dir = os.dir(v3_dir)
7const v3_src = os.join_path(v3_dir, 'v3.v')
8
9fn test_optional_struct_selector_assignment_mutates_payload_storage() {
10 v3_bin := os.join_path(os.temp_dir(), 'v3_optional_struct_lvalue_test')
11 build :=
12 os.execute('${vexe} -gc none -path "${vlib_dir}|@vlib|@vmodules" -o ${v3_bin} ${v3_src}')
13 assert build.exit_code == 0, build.output
14
15 src := os.join_path(os.temp_dir(), 'v3_optional_struct_lvalue_input.v')
16 os.write_file(src, "struct AFoo {
17mut:
18 name string
19}
20
21struct Inner {
22mut:
23 name string
24}
25
26struct Holder {
27mut:
28 opt ?Inner
29}
30
31struct ResultHolder {
32mut:
33 res !Inner
34}
35
36struct Outer {
37mut:
38 inner Inner
39}
40
41fn (mut f AFoo) opt_string(arr ?[]int) ?string {
42 return arr?.len.str()
43}
44
45fn guarded_failure() ?AFoo {
46 mut m := ?AFoo(none)
47 m?.name = 'bad'
48 return m
49}
50
51fn fail_inner() !Inner {
52 return error('boom')
53}
54
55fn mutate_result_source(mut h ResultHolder) ! {
56 h.res!.name = 'result'
57}
58
59fn mutate_explicit_or_source(mut holder Holder) {
60 (holder.opt or {
61 assert false
62 return
63 }).name = 'ok'
64}
65
66fn mutate_explicit_or_none() {
67 mut holder := Holder{
68 opt: none
69 }
70 (holder.opt or {
71 assert err.msg() == ''
72 println('none')
73 return
74 }).name = 'bad'
75 assert false
76}
77
78fn mutate_result_explicit_or_ok(mut h ResultHolder) {
79 (h.res or {
80 assert false
81 return
82 }).name = 'explicit-result'
83}
84
85fn mutate_result_explicit_or_err(mut h ResultHolder) {
86 (h.res or {
87 assert err.msg() == 'boom'
88 println('boom')
89 return
90 }).name = 'bad'
91 assert false
92}
93
94fn main() {
95 mut m := ?AFoo(AFoo{})
96 assert m?.opt_string([1, 2, 3])? == '3'
97 m?.name = 'foo'
98 assert m?.name == 'foo'
99 mut holder := Holder{
100 opt: Inner{}
101 }
102 holder.opt?.name = 'holder'
103 assert holder.opt?.name == 'holder'
104 mut outer := ?Outer(Outer{})
105 outer?.inner.name = 'deep'
106 assert outer?.inner.name == 'deep'
107 mut result_ok := ResultHolder{
108 res: Inner{}
109 }
110 mutate_result_source(mut result_ok)!
111 assert result_ok.res!.name == 'result'
112 mutate_result_explicit_or_ok(mut result_ok)
113 assert result_ok.res!.name == 'explicit-result'
114 mut result_bad := ResultHolder{
115 res: fail_inner()
116 }
117 mut saw_result_err := false
118 mutate_result_source(mut result_bad) or {
119 assert err.msg() == 'boom'
120 saw_result_err = true
121 }
122 assert saw_result_err
123 mutate_result_explicit_or_err(mut result_bad)
124 mutate_explicit_or_source(mut holder)
125 assert holder.opt?.name == 'ok'
126 mutate_explicit_or_none()
127 guarded_failure() or {
128 assert err.msg() == ''
129 println('ok')
130 return
131 }
132 assert false
133}
134") or {
135 panic(err)
136 }
137
138 bin := os.join_path(os.temp_dir(), 'v3_optional_struct_lvalue_input')
139 compile := os.execute('${v3_bin} ${src} -b c -o ${bin}')
140 assert compile.exit_code == 0, compile.output
141 assert !compile.output.contains('C compilation failed'), compile.output
142
143 c_code := os.read_file(bin + '.c') or { panic(err) }
144 assert c_code.contains('m.value.name ='), c_code
145 assert c_code.contains('holder.opt.value.name ='), c_code
146 assert c_code.contains('outer.value.inner.name ='), c_code
147 assert c_code.contains('holder->opt.value.name =') || c_code.contains('holder.opt.value.name ='), c_code
148
149 assert c_code.contains('if (!m.ok)'), c_code
150 assert c_code.contains('if (!holder.opt.ok)'), c_code
151 assert c_code.contains('if (!outer.ok)'), c_code
152 assert c_code.contains('.err = h->res.err') || c_code.contains('.err = h.res.err'), c_code
153 assert c_code.contains('IError err = holder.opt.err')
154 || c_code.contains('IError err = holder->opt.err'), c_code
155 assert c_code.contains('IError err = h->res.err') || c_code.contains('IError err = h.res.err'), c_code
156
157 mutate_result_start := c_code.index('\nOptional mutate_result_source(ResultHolder* h) {') or {
158 -1
159 }
160 assert mutate_result_start >= 0, c_code
161 mutate_result_tail := c_code[mutate_result_start..]
162 mutate_result_guard := mutate_result_tail[..mutate_result_tail.index('h->res.value.name') or {
163 mutate_result_tail.len
164 }]
165 assert !mutate_result_guard.contains('return (Optional){.ok = false};'), mutate_result_guard
166 for line in c_code.split_into_lines() {
167 assert !(line.contains('__or_val_') && line.contains('.name =')), line
168 assert !(line.contains('__or_val_') && line.contains('.inner.name =')), line
169 }
170
171 run := os.execute(bin)
172 assert run.exit_code == 0, run.output
173 assert run.output.trim_space() == 'boom\nnone\nok'
174}
175