1 module tagion.testbench.tvm.wasm_testsuite;
2 // Default import list for bdd
3 import std.array;
4 import std.file : exists, fread = read, readText, fwrite = write;
5 import std.format;
6 import std.path;
7 import std.process;
8 import std.stdio;
9 import std.typecons : Tuple;
10 import tagion.basic.Types : FileExtension;
11 import tagion.behaviour;
12 import tagion.behaviour : check;
13 import tagion.hibon.Document;
14 import tagion.testbench.tools.Environment;
15 import tagion.wasm.WasmBetterC;
16 import tagion.wasm.WasmReader;
17 import tagion.wasm.WasmWriter;
18 import tagion.wasm.WastParser;
19 import tagion.wasm.WastTokenizer;
20 
21 enum feature = Feature(
22             "Test of the wasm to betterc execution",
23             [
24             "This feature test of transpiler from wasm to betterC parses of the testsuite.",
25             "Specified in [WebAssembly testsuite](https://github.com/WebAssembly/testsuite)"
26             ]);
27 
28 alias FeatureContext = Tuple!(
29         ShouldConvertswastfileTestsuiteToWasmFileFormat, "ShouldConvertswastfileTestsuiteToWasmFileFormat",
30         ShouldLoadAwasmfileAndConvertItIntoBetterC, "ShouldLoadAwasmfileAndConvertItIntoBetterC",
31         ShouldTranspileTheWasmFileToBetterCFileAndExecutionIt, "ShouldTranspileTheWasmFileToBetterCFileAndExecutionIt",
32         FeatureGroup*, "result"
33 );
34 
35 static string testsuite;
36 @safe @Scenario("should converts #wast-file testsuite to wasm file format",
37         [])
38 class ShouldConvertswastfileTestsuiteToWasmFileFormat {
39 
40     string wast_file;
41     string wasm_file;
42     WastTokenizer tokenizer;
43     WasmWriter writer;
44     this(const string wast_file) {
45         this.wast_file = buildPath(testsuite, wast_file);
46         wasm_file = buildPath(env.bdd_results, wast_file.baseName.setExtension("wasm"));
47     }
48 
49     @Given("a wast testsuite file")
50     Document file() {
51         writefln("%s", __FUNCTION__);
52         immutable wast_text = wast_file.readText;
53         tokenizer = WastTokenizer(wast_text);
54         return result_ok;
55     }
56 
57     @When("the wast file has successfully been converted to WebAssembly")
58     Document webAssembly() {
59         writer = new WasmWriter;
60         auto wast_parser = WastParser(writer);
61         wast_parser.parse(tokenizer);
62         return result_ok;
63     }
64 
65     @Then("write the wasm-binary data of to a #wasm-file")
66     Document wasmfile() {
67         wasm_file = buildPath(env.bdd_results, wast_file.baseName.setExtension("wasm"));
68         writefln("wasm file %s", wasm_file);
69         wasm_file.fwrite(writer.serialize);
70         return result_ok;
71     }
72 
73 }
74 
75 @safe @Scenario("should load a #wasm-file and convert it into betterC",
76         [])
77 class ShouldLoadAwasmfileAndConvertItIntoBetterC {
78     string wasm_file;
79     string betterc_file;
80     WasmReader reader;
81     this(ShouldConvertswastfileTestsuiteToWasmFileFormat load_wasm) {
82         wasm_file = load_wasm.wasm_file;
83         betterc_file = wasm_file.setExtension("d");
84     }
85 
86     @Given("the testsuite file in #wasm-file format")
87     Document wasmfileFormat() @trusted {
88         writefln("%s", __FUNCTION__);
89         immutable data = cast(immutable(ubyte)[]) wasm_file.fread;
90         reader = WasmReader(data);
91         return result_ok;
92     }
93 
94     @Then("convert the #wasm-file into betteC #dlang-file format")
95     Document dlangfileFormat() {
96         writefln("betterc_file=%s", betterc_file);
97         auto fout = File(betterc_file, "w");
98         scope (exit) {
99             fout.close;
100         }
101         auto src_out = wasmBetterC(reader, fout);
102         src_out.module_name = betterc_file.baseName(FileExtension.dsrc);
103         src_out.imports = environment.get("imports", null).split.array;
104         src_out.attributes = environment.get("attributes", null).split.array;
105         src_out.serialize;
106         return result_ok;
107     }
108 
109 }
110 
111 @safe @Scenario("should transpile the wasm file to betterC file and execution it.",
112         [])
113 class ShouldTranspileTheWasmFileToBetterCFileAndExecutionIt {
114     string betterc_file;
115     string test_file;
116     this(ShouldLoadAwasmfileAndConvertItIntoBetterC transpiled) {
117         betterc_file = transpiled.betterc_file;
118         test_file = betterc_file.stripExtension;
119     }
120 
121     @Given("the testsuite #dlang-file in betterC/D format.")
122     Document betterc_format() {
123         check(betterc_file.exists, format("%s not found", betterc_file));
124         return result_ok;
125     }
126 
127     @When("the #dlang-file has been compile in unittest mode.")
128     Document compile() {
129         auto cmd = environment["DCOMPILE"];
130 
131         cmd = [cmd, betterc_file, format("-of=%s", test_file)].join(" ");
132         auto pid = spawnShell(cmd);
133         writefln("%s", cmd);
134         const ret = wait(pid);
135         check(ret == 0, format("Compilation of %s faild", betterc_file));
136         return result_ok;
137     }
138 
139     @Then("execute the unittest file and check that all unittests parses.")
140     Document run_test() @trusted {
141         writefln("test_file %s", test_file);
142         auto pid = spawnShell(test_file);
143         const ret = wait(pid);
144         check(ret == 0, format("Test %s failed (see logfile)", test_file));
145         return result_ok;
146     }
147 
148 }