Skip to content

Commit 1e1c9b9

Browse files
authored
wasm: add vlib/v/gen/wasm/tests_decompile/must_have_test.v to allow more testing for different compilation options (#26048)
1 parent 60f7c81 commit 1e1c9b9

4 files changed

Lines changed: 147 additions & 3 deletions

File tree

‎.github/workflows/wasm_backend_ci.yml‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ on:
1818
- 'vlib/v/preludes/**.v'
1919
- 'vlib/v/gen/wasm/**.v'
2020
- 'vlib/v/gen/wasm/tests/**.v'
21+
- 'vlib/v/gen/wasm/tests/**.vv'
22+
- 'vlib/v/gen/wasm/tests_decompile/**.v'
23+
- 'vlib/v/gen/wasm/tests_decompile/**.vv'
2124
- '**/wasm_backend_ci.yml'
2225
pull_request:
2326
paths:
@@ -36,6 +39,9 @@ on:
3639
- 'vlib/v/preludes/**.v'
3740
- 'vlib/v/gen/wasm/**.v'
3841
- 'vlib/v/gen/wasm/tests/**.v'
42+
- 'vlib/v/gen/wasm/tests/**.vv'
43+
- 'vlib/v/gen/wasm/tests_decompile/**.v'
44+
- 'vlib/v/gen/wasm/tests_decompile/**.vv'
3945
- '**/wasm_backend_ci.yml'
4046

4147
concurrency:
@@ -54,15 +60,26 @@ jobs:
5460
VTEST_ONLY: wasm
5561
steps:
5662
- uses: actions/checkout@v6
63+
5764
- name: Build V
5865
if: runner.os != 'Windows'
5966
run: make -j4
6067
- name: Build V (Windows)
6168
if: runner.os == 'Windows'
6269
run: ./make.bat
63-
- name: Build examples
64-
run: ./v -silent build-examples
70+
71+
- name: Install WABT to get wasm-decompile
72+
if: runner.os != 'Windows'
73+
run: ./v retry -- sudo apt install wabt
74+
6575
- name: Setup Wasmer
6676
uses: wasmerio/setup-wasmer@v3.1
77+
78+
- name: Prebuild the WASM backend
79+
run: ./v cmd/tools/builders/wasm_builder.v
80+
6781
- name: Test the WASM backend
68-
run: ./v -silent test vlib/v/gen/wasm/tests/
82+
run: ./v test vlib/v/gen/wasm/
83+
84+
- name: Build examples
85+
run: ./v build-examples
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import os
2+
import term
3+
import benchmark
4+
5+
fn test_wasm_when_decompiled_must_have() {
6+
vexe := @VEXE
7+
vroot := os.dir(vexe).replace(os.path_separator, '/')
8+
decompiler := os.find_abs_path_of_executable('wasm-decompile') or {
9+
eprintln('> skipping test, since it needs `wasm-decompile`, which is not present')
10+
return
11+
}
12+
13+
dir := vroot + '/vlib/v/gen/wasm/tests_decompile'
14+
vv_files := os.walk_ext(dir, '.vv')
15+
assert vv_files.len > 0
16+
17+
mut bench := benchmark.new_benchmark()
18+
bench.set_total_expected_steps(vv_files.len)
19+
20+
wrkdir := os.join_path(os.vtmp_dir(), 'wasm_tests_decompile')
21+
os.mkdir_all(wrkdir)!
22+
os.chdir(wrkdir)!
23+
24+
vv_files_loop: for vv_file in vv_files {
25+
bench.step()
26+
must_have_path := vv_file.replace('.vv', '.wasm.must_have')
27+
vv_file_name := os.file_name(vv_file).replace('.vv', '')
28+
full_vv_path := os.real_path(vv_file).replace(os.path_separator, '/')
29+
relative_vv_path := full_vv_path.replace(vroot + '/', '')
30+
full_wasm_path := '${wrkdir}/${vv_file_name}.wasm'
31+
full_dcmp_path := '${wrkdir}/${vv_file_name}.dcmp'
32+
33+
file_options := get_file_options(vv_file)
34+
cmd := '${os.quoted_path(vexe)} -b wasm ${file_options.vflags} -o ${os.quoted_path(full_wasm_path)} ${os.quoted_path(full_vv_path)}'
35+
// println(cmd)
36+
res_wasm := os.execute(cmd)
37+
if res_wasm.exit_code != 0 {
38+
bench.fail()
39+
eprintln(bench.step_message_fail(cmd))
40+
eprintln(' res_wasm.exit_code: ${res_wasm.exit_code}')
41+
eprintln(' res_wasm.output : ${res_wasm.output}')
42+
continue
43+
}
44+
45+
cmd_decompile := '${os.quoted_path(decompiler)} ${os.quoted_path(full_wasm_path)} --output=${os.quoted_path(full_dcmp_path)}'
46+
// println(cmd_decompile)
47+
res_dcmp := os.execute(cmd_decompile)
48+
if res_dcmp.exit_code != 0 {
49+
bench.fail()
50+
eprintln(bench.step_message_fail(cmd_decompile))
51+
eprintln(' res_dcmp.exit_code: ${res_dcmp.exit_code}')
52+
eprintln(' res_dcmp.output : ${res_dcmp.output}')
53+
continue
54+
}
55+
56+
expected_lines := os.read_lines(must_have_path) or { [] }
57+
generated_wasm_lines := os.read_lines(full_dcmp_path) or {
58+
bench.fail()
59+
eprintln('missing ${full_dcmp_path}')
60+
continue
61+
}
62+
63+
mut failed_patterns := []string{}
64+
for idx_expected_line, eline in expected_lines {
65+
if eline == '' {
66+
continue
67+
}
68+
if !does_line_match_one_of_generated_lines(eline, generated_wasm_lines) {
69+
failed_patterns << eline
70+
eprintln('${must_have_path}:${idx_expected_line + 1}: expected match error:')
71+
eprintln('`${cmd_decompile}` did NOT produce expected line:')
72+
eprintln(term.colorize(term.red, eline))
73+
continue
74+
}
75+
}
76+
if failed_patterns.len > 0 {
77+
eprintln('> failed match patterns: ${failed_patterns.len}')
78+
bench.fail()
79+
continue
80+
}
81+
82+
bench.ok()
83+
eprintln(bench.step_message_ok(relative_vv_path))
84+
}
85+
bench.stop()
86+
eprintln(term.h_divider('-'))
87+
eprintln(bench.total_message('decompiled wasm must have'))
88+
if bench.nfail > 0 {
89+
exit(1)
90+
}
91+
os.rmdir_all(wrkdir) or {}
92+
}
93+
94+
struct FileOptions {
95+
mut:
96+
vflags string
97+
}
98+
99+
pub fn get_file_options(file string) FileOptions {
100+
mut res := FileOptions{}
101+
lines := os.read_lines(file) or { [] }
102+
for line in lines {
103+
if line.starts_with('// vtest vflags:') {
104+
res.vflags = line.all_after(':').trim_space()
105+
}
106+
}
107+
return res
108+
}
109+
110+
fn does_line_match_one_of_generated_lines(line string, generated_c_lines []string) bool {
111+
for cline in generated_c_lines {
112+
if line == cline {
113+
return true
114+
}
115+
if cline.contains(line) {
116+
return true
117+
}
118+
}
119+
return false
120+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// vtest vflags: -os wasi
2+
pub fn exported_function(x int, y int) int {
3+
return x + y
4+
}
5+
6+
println(exported_function(123, 456))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export function main_exported_function(a:int, b:int):int {

0 commit comments

Comments
 (0)