2018-10-23 11:23:32 +00:00
|
|
|
//! This file will run at build time to autogenerate Rust tests based on
|
|
|
|
//! WebAssembly spec tests. It will convert the files indicated in TESTS
|
|
|
|
//! from "/spectests/{MODULE}.wast" to "/src/spectests/{MODULE}.rs".
|
2018-10-23 13:43:35 +00:00
|
|
|
use std::collections::HashMap;
|
2018-10-23 22:02:35 +00:00
|
|
|
use std::env;
|
2018-10-18 23:29:12 +00:00
|
|
|
use std::fs;
|
|
|
|
use std::io::{self, Read};
|
|
|
|
use std::path::PathBuf;
|
|
|
|
use std::time::SystemTime;
|
|
|
|
use wabt::script::{Action, Command, CommandKind, ModuleBinary, ScriptParser, Value};
|
|
|
|
use wabt::wasm2wat;
|
2018-10-23 21:54:07 +00:00
|
|
|
|
|
|
|
static ENV_VAR: &str = "WASM_GENERATE_SPECTESTS";
|
2018-10-18 23:29:12 +00:00
|
|
|
|
2018-10-19 09:31:02 +00:00
|
|
|
static BANNER: &str = "// Rust test file autogenerated with cargo build (src/build_spectests.rs).
|
|
|
|
// Please do NOT modify it by hand, as it will be reseted on next build.\n";
|
|
|
|
|
2018-10-24 00:00:59 +00:00
|
|
|
const TESTS: [&str; 23] = [
|
2018-10-23 22:02:19 +00:00
|
|
|
"spectests/block.wast",
|
2018-10-23 21:58:13 +00:00
|
|
|
"spectests/br.wast",
|
2018-10-19 10:41:53 +00:00
|
|
|
"spectests/br_if.wast",
|
2018-10-23 13:43:35 +00:00
|
|
|
"spectests/br_table.wast",
|
2018-10-23 22:22:07 +00:00
|
|
|
"spectests/break_drop.wast",
|
2018-10-19 10:41:53 +00:00
|
|
|
"spectests/call.wast",
|
2018-10-23 09:40:17 +00:00
|
|
|
"spectests/call_indirect.wast",
|
2018-10-23 22:17:36 +00:00
|
|
|
"spectests/const_.wast",
|
2018-10-23 22:27:15 +00:00
|
|
|
"spectests/data.wast",
|
2018-10-23 22:41:32 +00:00
|
|
|
"spectests/exports.wast",
|
2018-10-23 23:15:20 +00:00
|
|
|
"spectests/f32_.wast",
|
2018-10-23 23:51:52 +00:00
|
|
|
"spectests/f32_bitwise.wast",
|
2018-10-23 23:55:08 +00:00
|
|
|
"spectests/f32_cmp.wast",
|
2018-10-23 23:22:16 +00:00
|
|
|
"spectests/f64_.wast",
|
2018-10-23 23:57:37 +00:00
|
|
|
"spectests/f64_bitwise.wast",
|
2018-10-24 00:00:59 +00:00
|
|
|
"spectests/f64_cmp.wast",
|
2018-10-23 11:13:03 +00:00
|
|
|
"spectests/func_ptrs.wast",
|
2018-10-19 10:41:53 +00:00
|
|
|
"spectests/i32_.wast",
|
2018-10-23 22:04:30 +00:00
|
|
|
"spectests/i64_.wast",
|
2018-10-23 22:25:11 +00:00
|
|
|
"spectests/labels.wast",
|
2018-10-19 10:41:53 +00:00
|
|
|
"spectests/memory.wast",
|
|
|
|
"spectests/set_local.wast",
|
|
|
|
"spectests/types.wast",
|
|
|
|
];
|
|
|
|
|
2018-10-18 23:29:12 +00:00
|
|
|
fn wabt2rust_type(v: &Value) -> String {
|
|
|
|
match v {
|
|
|
|
Value::I32(v) => format!("i32"),
|
|
|
|
Value::I64(v) => format!("i64"),
|
|
|
|
Value::F32(v) => format!("f32"),
|
|
|
|
Value::F64(v) => format!("f64"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-23 23:51:52 +00:00
|
|
|
fn is_nan(v: &Value) -> bool {
|
2018-10-24 00:01:46 +00:00
|
|
|
if let Value::F32(v) = v {
|
2018-10-23 23:51:52 +00:00
|
|
|
return v.is_nan();
|
2018-10-24 00:01:46 +00:00
|
|
|
} else if let Value::F64(v) = v {
|
2018-10-23 23:51:52 +00:00
|
|
|
return v.is_nan();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-10-18 23:29:12 +00:00
|
|
|
fn wabt2rust_value(v: &Value) -> String {
|
|
|
|
match v {
|
|
|
|
Value::I32(v) => format!("{:?} as i32", v),
|
|
|
|
Value::I64(v) => format!("{:?} as i64", v),
|
2018-10-23 23:15:20 +00:00
|
|
|
Value::F32(v) => {
|
|
|
|
match *v {
|
|
|
|
std::f32::INFINITY => "std::f32::INFINITY".to_string(),
|
|
|
|
std::f32::NEG_INFINITY => "std::f32::NEG_INFINITY".to_string(),
|
2018-10-23 23:51:52 +00:00
|
|
|
// std::f32::NAN => "std::f32::NAN".to_string(),
|
|
|
|
_ => {
|
|
|
|
if v.is_nan() {
|
|
|
|
if v.is_sign_negative() {
|
|
|
|
"-std::f32::NAN".to_string()
|
2018-10-24 00:01:46 +00:00
|
|
|
} else {
|
2018-10-23 23:51:52 +00:00
|
|
|
"std::f32::NAN".to_string()
|
|
|
|
}
|
2018-10-24 00:01:46 +00:00
|
|
|
} else {
|
2018-10-23 23:51:52 +00:00
|
|
|
format!("{:?} as f32", v)
|
|
|
|
}
|
|
|
|
}
|
2018-10-23 23:15:20 +00:00
|
|
|
}
|
2018-10-24 00:01:46 +00:00
|
|
|
}
|
2018-10-23 23:22:16 +00:00
|
|
|
Value::F64(v) => {
|
|
|
|
match *v {
|
|
|
|
std::f64::INFINITY => "std::f64::INFINITY".to_string(),
|
|
|
|
std::f64::NEG_INFINITY => "std::f64::NEG_INFINITY".to_string(),
|
2018-10-23 23:51:52 +00:00
|
|
|
// std::f64::NAN => "std::f64::NAN".to_string(),
|
|
|
|
_ => {
|
|
|
|
if v.is_nan() {
|
|
|
|
if v.is_sign_negative() {
|
|
|
|
"-std::f64::NAN".to_string()
|
2018-10-24 00:01:46 +00:00
|
|
|
} else {
|
2018-10-23 23:51:52 +00:00
|
|
|
"std::f64::NAN".to_string()
|
|
|
|
}
|
2018-10-24 00:01:46 +00:00
|
|
|
} else {
|
2018-10-23 23:51:52 +00:00
|
|
|
format!("{:?} as f64", v)
|
|
|
|
}
|
|
|
|
}
|
2018-10-23 23:22:16 +00:00
|
|
|
}
|
|
|
|
}
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-23 13:43:35 +00:00
|
|
|
struct WastTestGenerator {
|
|
|
|
last_module: i32,
|
|
|
|
last_line: u64,
|
|
|
|
filename: String,
|
|
|
|
script_parser: ScriptParser,
|
|
|
|
module_calls: HashMap<i32, Vec<String>>,
|
|
|
|
buffer: String,
|
|
|
|
}
|
|
|
|
|
2018-10-18 23:29:12 +00:00
|
|
|
impl WastTestGenerator {
|
|
|
|
fn new(path: &PathBuf) -> Self {
|
|
|
|
let filename = path.file_name().unwrap().to_str().unwrap();
|
|
|
|
let source = fs::read(&path).unwrap();
|
|
|
|
let mut script: ScriptParser =
|
|
|
|
ScriptParser::from_source_and_name(&source, filename).unwrap();
|
|
|
|
let mut buffer = String::new();
|
|
|
|
WastTestGenerator {
|
|
|
|
last_module: 0,
|
|
|
|
last_line: 0,
|
|
|
|
filename: filename.to_string(),
|
|
|
|
script_parser: script,
|
|
|
|
buffer: buffer,
|
2018-10-23 13:43:35 +00:00
|
|
|
module_calls: HashMap::new(),
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn consume(&mut self) {
|
2018-10-19 09:31:02 +00:00
|
|
|
self.buffer.push_str(BANNER);
|
2018-10-18 23:29:12 +00:00
|
|
|
self.buffer.push_str(&format!(
|
2018-10-19 09:31:02 +00:00
|
|
|
"// Test based on spectests/{}
|
2018-10-23 21:54:07 +00:00
|
|
|
#![allow(
|
|
|
|
warnings,
|
|
|
|
dead_code
|
|
|
|
)]
|
2018-10-18 23:29:12 +00:00
|
|
|
use crate::webassembly::{{instantiate, compile, ImportObject, ResultObject, VmCtx, Export}};
|
2018-10-23 11:13:03 +00:00
|
|
|
use super::_common::spectest_importobject;
|
2018-10-18 23:29:12 +00:00
|
|
|
use wabt::wat2wasm;\n\n",
|
|
|
|
self.filename
|
|
|
|
));
|
|
|
|
while let Some(Command { line, kind }) = &self.script_parser.next().unwrap() {
|
|
|
|
self.last_line = line.clone();
|
|
|
|
self.buffer
|
|
|
|
.push_str(&format!("\n// Line {}\n", self.last_line));
|
|
|
|
self.visit_command(&kind);
|
|
|
|
}
|
2018-10-23 13:43:35 +00:00
|
|
|
for n in 1..self.last_module + 1 {
|
|
|
|
self.flush_module_calls(n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn flush_module_calls(&mut self, module: i32) {
|
|
|
|
let calls: Vec<String> = self
|
|
|
|
.module_calls
|
|
|
|
.entry(module)
|
|
|
|
.or_insert(Vec::new())
|
|
|
|
.iter()
|
|
|
|
.map(|call_str| format!("{}(&result_object);", call_str))
|
|
|
|
.collect();
|
|
|
|
if calls.len() > 0 {
|
|
|
|
self.buffer.push_str(
|
|
|
|
format!(
|
|
|
|
"\n#[test]
|
|
|
|
fn test_module_{}() {{
|
|
|
|
let result_object = create_module_{}();
|
|
|
|
// We group the calls together
|
|
|
|
{}
|
|
|
|
}}\n",
|
|
|
|
module,
|
|
|
|
module,
|
|
|
|
calls.join("\n ")
|
|
|
|
)
|
|
|
|
.as_str(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
self.module_calls.remove(&module);
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_module(&mut self, module: &ModuleBinary, name: &Option<String>) {
|
|
|
|
let wasm_binary: Vec<u8> = module.clone().into_vec();
|
|
|
|
let wast_string = wasm2wat(wasm_binary).expect("Can't convert back to wasm");
|
2018-10-23 13:43:35 +00:00
|
|
|
self.flush_module_calls(self.last_module);
|
2018-10-18 23:29:12 +00:00
|
|
|
self.last_module = self.last_module + 1;
|
2018-10-23 13:43:35 +00:00
|
|
|
// self.module_calls.insert(self.last_module, vec![]);
|
2018-10-18 23:29:12 +00:00
|
|
|
self.buffer.push_str(
|
|
|
|
format!(
|
|
|
|
"fn create_module_{}() -> ResultObject {{
|
|
|
|
let module_str = \"{}\";
|
|
|
|
let wasm_binary = wat2wasm(module_str.as_bytes()).expect(\"WAST not valid or malformed\");
|
2018-10-23 11:13:03 +00:00
|
|
|
instantiate(wasm_binary, spectest_importobject()).expect(\"WASM can't be instantiated\")
|
2018-10-18 23:29:12 +00:00
|
|
|
}}\n",
|
|
|
|
self.last_module,
|
2018-10-23 11:23:32 +00:00
|
|
|
// We do this to ident four spaces, so it looks aligned to the function body
|
2018-10-18 23:29:12 +00:00
|
|
|
wast_string.replace("\n", "\n ").replace("\"", "\\\""),
|
|
|
|
)
|
|
|
|
.as_str(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_assert_invalid(&mut self, module: &ModuleBinary) {
|
|
|
|
let wasm_binary: Vec<u8> = module.clone().into_vec();
|
|
|
|
// let wast_string = wasm2wat(wasm_binary).expect("Can't convert back to wasm");
|
|
|
|
self.buffer.push_str(
|
|
|
|
format!(
|
2018-10-23 11:13:03 +00:00
|
|
|
"#[test]
|
2018-10-18 23:29:12 +00:00
|
|
|
fn l{}_assert_invalid() {{
|
|
|
|
let wasm_binary = {:?};
|
|
|
|
let compilation = compile(wasm_binary.to_vec());
|
|
|
|
assert!(compilation.is_err(), \"WASM should not compile as is invalid\");
|
|
|
|
}}\n",
|
|
|
|
self.last_line,
|
|
|
|
wasm_binary,
|
|
|
|
// We do this to ident four spaces back
|
|
|
|
// String::from_utf8_lossy(&wasm_binary),
|
|
|
|
// wast_string.replace("\n", "\n "),
|
|
|
|
)
|
|
|
|
.as_str(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
fn visit_assert_malformed(&mut self, module: &ModuleBinary) {
|
|
|
|
let wasm_binary: Vec<u8> = module.clone().into_vec();
|
|
|
|
// let wast_string = wasm2wat(wasm_binary).expect("Can't convert back to wasm");
|
|
|
|
self.buffer.push_str(
|
|
|
|
format!(
|
2018-10-23 11:13:03 +00:00
|
|
|
"#[test]
|
2018-10-18 23:29:12 +00:00
|
|
|
fn l{}_assert_malformed() {{
|
|
|
|
let wasm_binary = {:?};
|
|
|
|
let compilation = compile(wasm_binary.to_vec());
|
|
|
|
assert!(compilation.is_err(), \"WASM should not compile as is malformed\");
|
|
|
|
}}\n",
|
|
|
|
self.last_line,
|
|
|
|
wasm_binary,
|
|
|
|
// We do this to ident four spaces back
|
|
|
|
// String::from_utf8_lossy(&wasm_binary),
|
|
|
|
// wast_string.replace("\n", "\n "),
|
|
|
|
)
|
|
|
|
.as_str(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_assert_return(&mut self, action: &Action, expected: &Vec<Value>) {
|
|
|
|
match action {
|
|
|
|
Action::Invoke {
|
|
|
|
module,
|
|
|
|
field,
|
|
|
|
args,
|
|
|
|
} => {
|
|
|
|
let func_return = if expected.len() > 0 {
|
|
|
|
format!(" -> {}", wabt2rust_type(&expected[0]))
|
|
|
|
} else {
|
|
|
|
"".to_string()
|
|
|
|
};
|
|
|
|
let expected_result = if expected.len() > 0 {
|
|
|
|
wabt2rust_value(&expected[0])
|
|
|
|
} else {
|
|
|
|
"()".to_string()
|
|
|
|
};
|
2018-10-23 23:51:52 +00:00
|
|
|
let assertion = if expected.len() > 0 && is_nan(&expected[0]) {
|
2018-10-24 00:01:46 +00:00
|
|
|
format!(
|
|
|
|
"assert!(result.is_nan());
|
|
|
|
assert_eq!(result.is_sign_positive(), ({}).is_sign_positive());",
|
|
|
|
expected_result
|
|
|
|
)
|
|
|
|
} else {
|
2018-10-23 23:51:52 +00:00
|
|
|
format!("assert_eq!(result, {});", expected_result)
|
|
|
|
};
|
2018-10-18 23:29:12 +00:00
|
|
|
// We map the arguments provided into the raw Arguments provided
|
|
|
|
// to libffi
|
|
|
|
let mut args_types: Vec<String> = args.iter().map(wabt2rust_type).collect();
|
|
|
|
args_types.push("&VmCtx".to_string());
|
|
|
|
let mut args_values: Vec<String> = args.iter().map(wabt2rust_value).collect();
|
|
|
|
args_values.push("&vm_context".to_string());
|
2018-10-23 13:43:35 +00:00
|
|
|
let func_name = format!("l{}_assert_return_invoke", self.last_line);
|
2018-10-18 23:29:12 +00:00
|
|
|
self.buffer.push_str(
|
|
|
|
format!(
|
2018-10-23 13:43:35 +00:00
|
|
|
"fn {}(result_object: &ResultObject) {{
|
2018-10-25 17:22:52 +00:00
|
|
|
println!(\"Executing function {{}}\", \"{}\");
|
2018-10-23 13:43:35 +00:00
|
|
|
let func_index = match result_object.module.info.exports.get({:?}) {{
|
2018-10-18 23:29:12 +00:00
|
|
|
Some(&Export::Function(index)) => index,
|
|
|
|
_ => panic!(\"Function not found\"),
|
|
|
|
}};
|
2018-10-23 13:43:35 +00:00
|
|
|
let invoke_fn: fn({}){} = get_instance_function!(result_object.instance, func_index);
|
|
|
|
let vm_context = result_object.instance.generate_context();
|
2018-10-18 23:29:12 +00:00
|
|
|
let result = invoke_fn({});
|
2018-10-23 23:51:52 +00:00
|
|
|
{}
|
2018-10-18 23:29:12 +00:00
|
|
|
}}\n",
|
2018-10-25 17:22:52 +00:00
|
|
|
func_name,
|
2018-10-23 13:43:35 +00:00
|
|
|
func_name,
|
2018-10-18 23:29:12 +00:00
|
|
|
field,
|
|
|
|
args_types.join(", "),
|
|
|
|
func_return,
|
|
|
|
args_values.join(", "),
|
2018-10-23 23:51:52 +00:00
|
|
|
assertion,
|
2018-10-18 23:29:12 +00:00
|
|
|
)
|
|
|
|
.as_str(),
|
|
|
|
);
|
2018-10-23 13:43:35 +00:00
|
|
|
self.module_calls
|
|
|
|
.entry(self.last_module)
|
|
|
|
.or_insert(Vec::new())
|
|
|
|
.push(func_name);
|
|
|
|
// let mut module_calls = self.module_calls.get(&self.last_module).unwrap();
|
|
|
|
// module_calls.push(func_name);
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_command(&mut self, cmd: &CommandKind) {
|
|
|
|
match cmd {
|
|
|
|
CommandKind::Module { module, name } => {
|
|
|
|
self.visit_module(module, name);
|
|
|
|
}
|
|
|
|
CommandKind::AssertReturn { action, expected } => {
|
|
|
|
self.visit_assert_return(action, expected);
|
|
|
|
}
|
|
|
|
CommandKind::AssertReturnCanonicalNan { action } => {
|
2018-10-23 11:23:32 +00:00
|
|
|
// Do nothing for now
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|
|
|
|
CommandKind::AssertReturnArithmeticNan { action } => {
|
2018-10-23 11:23:32 +00:00
|
|
|
// Do nothing for now
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|
|
|
|
CommandKind::AssertTrap { action, message: _ } => {
|
2018-10-23 11:23:32 +00:00
|
|
|
// Do nothing for now
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|
|
|
|
CommandKind::AssertInvalid { module, message: _ } => {
|
|
|
|
self.visit_assert_invalid(module);
|
|
|
|
}
|
|
|
|
CommandKind::AssertMalformed { module, message: _ } => {
|
|
|
|
self.visit_assert_malformed(module);
|
|
|
|
}
|
|
|
|
CommandKind::AssertUninstantiable { module, message: _ } => {
|
2018-10-23 11:23:32 +00:00
|
|
|
// Do nothing for now
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|
|
|
|
CommandKind::AssertExhaustion { action } => {
|
2018-10-23 11:23:32 +00:00
|
|
|
// Do nothing for now
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|
|
|
|
CommandKind::AssertUnlinkable { module, message: _ } => {
|
2018-10-23 11:23:32 +00:00
|
|
|
// Do nothing for now
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|
|
|
|
CommandKind::Register { name, as_name } => {
|
2018-10-23 11:23:32 +00:00
|
|
|
// Do nothing for now
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|
|
|
|
CommandKind::PerformAction(action) => {
|
2018-10-23 11:23:32 +00:00
|
|
|
// Do nothing for now
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn finalize(self) -> String {
|
|
|
|
self.buffer
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-19 00:11:27 +00:00
|
|
|
fn wast_to_rust(wast_filepath: &str) -> String {
|
2018-10-18 23:29:12 +00:00
|
|
|
let wast_filepath = format!("{}/{}", env!("CARGO_MANIFEST_DIR"), wast_filepath);
|
|
|
|
let path = PathBuf::from(&wast_filepath);
|
2018-10-19 00:11:27 +00:00
|
|
|
let script_name: String = String::from(path.file_stem().unwrap().to_str().unwrap());
|
2018-10-18 23:29:12 +00:00
|
|
|
let rust_test_filepath = format!(
|
|
|
|
concat!(env!("CARGO_MANIFEST_DIR"), "/src/spectests/{}.rs"),
|
2018-10-19 00:11:27 +00:00
|
|
|
script_name.clone().as_str()
|
2018-10-18 23:29:12 +00:00
|
|
|
);
|
2018-10-23 11:13:03 +00:00
|
|
|
if script_name == "_common" {
|
|
|
|
panic!("_common is a reserved name for the _common module. Please use other name for the spectest.");
|
|
|
|
}
|
2018-10-18 23:29:12 +00:00
|
|
|
|
|
|
|
let wast_modified = fs::metadata(&wast_filepath)
|
|
|
|
.expect("Can't get wast file metadata")
|
|
|
|
.modified()
|
|
|
|
.expect("Can't get wast file modified date");
|
|
|
|
let should_modify = match fs::metadata(&rust_test_filepath) {
|
|
|
|
Ok(m) => {
|
|
|
|
m.modified()
|
|
|
|
.expect("Can't get rust test file modified date")
|
|
|
|
< wast_modified
|
|
|
|
}
|
|
|
|
Err(_) => true,
|
|
|
|
};
|
|
|
|
|
|
|
|
// panic!("SOULD MODIFY {:?} {:?}", should_modify, rust_test_filepath);
|
|
|
|
|
2018-10-23 21:54:07 +00:00
|
|
|
if should_modify || true {
|
2018-10-18 23:29:12 +00:00
|
|
|
let mut generator = WastTestGenerator::new(&path);
|
|
|
|
generator.consume();
|
|
|
|
let generated_script = generator.finalize();
|
|
|
|
fs::write(&rust_test_filepath, generated_script.as_bytes()).unwrap();
|
|
|
|
}
|
2018-10-19 00:11:27 +00:00
|
|
|
script_name
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
2018-10-23 21:54:07 +00:00
|
|
|
if env::var(ENV_VAR).unwrap_or("0".to_string()) != "1" {
|
|
|
|
return;
|
|
|
|
}
|
2018-10-19 00:11:27 +00:00
|
|
|
let rust_test_modpath = concat!(env!("CARGO_MANIFEST_DIR"), "/src/spectests/mod.rs");
|
|
|
|
|
|
|
|
let mut modules: Vec<String> = Vec::new();
|
2018-10-19 10:41:53 +00:00
|
|
|
modules.reserve_exact(TESTS.len());
|
2018-10-19 00:11:27 +00:00
|
|
|
|
2018-10-19 10:41:53 +00:00
|
|
|
for test in TESTS.iter() {
|
2018-10-19 00:11:27 +00:00
|
|
|
let module_name = wast_to_rust(test);
|
|
|
|
modules.push(module_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut modfile_uses: Vec<String> = modules
|
|
|
|
.iter()
|
|
|
|
.map(|module| format!("mod {};", module))
|
|
|
|
.collect();
|
2018-10-19 00:18:01 +00:00
|
|
|
|
2018-10-19 09:31:02 +00:00
|
|
|
modfile_uses.insert(0, BANNER.to_string());
|
2018-10-23 11:13:03 +00:00
|
|
|
modfile_uses.insert(1, "// The _common module is not autogenerated, as it provides common functions for the spectests\nmod _common;".to_string());
|
2018-10-19 00:11:27 +00:00
|
|
|
// We add an empty line
|
|
|
|
modfile_uses.push("".to_string());
|
|
|
|
|
|
|
|
let modfile: String = modfile_uses.join("\n");
|
2018-10-19 00:15:27 +00:00
|
|
|
let source = fs::read(&rust_test_modpath).unwrap();
|
|
|
|
// We only modify the mod file if has changed
|
|
|
|
if source != modfile.as_bytes() {
|
|
|
|
fs::write(&rust_test_modpath, modfile.as_bytes()).unwrap();
|
|
|
|
}
|
2018-10-18 23:29:12 +00:00
|
|
|
}
|