summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wasmparser-0.48.2/src/tests.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/wasmparser-0.48.2/src/tests.rs')
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/tests.rs529
1 files changed, 529 insertions, 0 deletions
diff --git a/third_party/rust/wasmparser-0.48.2/src/tests.rs b/third_party/rust/wasmparser-0.48.2/src/tests.rs
new file mode 100644
index 0000000000..527ace1993
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/tests.rs
@@ -0,0 +1,529 @@
+/* Copyright 2017 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#[cfg(test)]
+mod simple_tests {
+ use crate::operators_validator::OperatorValidatorConfig;
+ use crate::parser::{Parser, ParserInput, ParserState, WasmDecoder};
+ use crate::primitives::{Operator, SectionCode};
+ use crate::validator::{ValidatingParser, ValidatingParserConfig};
+ use std::fs::{read_dir, File};
+ use std::io::prelude::*;
+ use std::path::PathBuf;
+
+ const VALIDATOR_CONFIG: Option<ValidatingParserConfig> = Some(ValidatingParserConfig {
+ operator_config: OperatorValidatorConfig {
+ enable_threads: true,
+ enable_reference_types: true,
+ enable_simd: true,
+ enable_bulk_memory: true,
+ enable_multi_value: true,
+
+ #[cfg(feature = "deterministic")]
+ deterministic_only: true,
+ },
+ });
+
+ fn read_file_data(path: &PathBuf) -> Vec<u8> {
+ println!("Parsing {:?}", path);
+ let mut data = Vec::new();
+ let mut f = File::open(path).ok().unwrap();
+ f.read_to_end(&mut data).unwrap();
+ data
+ }
+
+ #[allow(dead_code)]
+ fn scan_tests_files(prefix: &str) -> Vec<PathBuf> {
+ let mut files = Vec::new();
+
+ for entry in read_dir("tests/").unwrap() {
+ let dir = entry.unwrap();
+ if !dir.file_type().unwrap().is_file() {
+ continue;
+ }
+
+ let path = dir.path();
+ let file = path.to_str().unwrap();
+
+ if file.starts_with(prefix) {
+ files.push(path);
+ }
+ }
+
+ return files;
+ }
+
+ #[test]
+ fn it_works() {
+ for entry in read_dir("tests").unwrap() {
+ let dir = entry.unwrap();
+ if !dir.file_type().unwrap().is_file() {
+ continue;
+ }
+ let data = read_file_data(&dir.path());
+ let mut parser = Parser::new(data.as_slice());
+ let mut max_iteration = 100000000;
+ loop {
+ let state = parser.read();
+ match *state {
+ ParserState::EndWasm => break,
+ ParserState::Error(err) => panic!("Error: {:?}", err),
+ _ => (),
+ }
+ max_iteration -= 1;
+ if max_iteration == 0 {
+ panic!("Max iterations exceeded");
+ }
+ }
+ }
+ }
+
+ #[test]
+ fn validator_not_fails() {
+ for entry in read_dir("tests").unwrap() {
+ let dir = entry.unwrap();
+ if !dir.file_type().unwrap().is_file() {
+ continue;
+ }
+ let data = read_file_data(&dir.path());
+ let mut parser = ValidatingParser::new(data.as_slice(), VALIDATOR_CONFIG);
+ let mut max_iteration = 100000000;
+ loop {
+ let state = parser.read();
+ match *state {
+ ParserState::EndWasm => break,
+ ParserState::Error(err) => panic!("Error: {:?}", err),
+ _ => (),
+ }
+ max_iteration -= 1;
+ if max_iteration == 0 {
+ panic!("Max iterations exceeded");
+ }
+ }
+ }
+ }
+
+ #[test]
+ fn validator_fails() {
+ for entry in read_dir("tests/invalid").unwrap() {
+ let dir = entry.unwrap();
+ if !dir.file_type().unwrap().is_file() {
+ continue;
+ }
+ let data = read_file_data(&dir.path());
+ let mut parser = ValidatingParser::new(data.as_slice(), VALIDATOR_CONFIG);
+ let mut max_iteration = 100000000;
+ let mut error = false;
+ loop {
+ let state = parser.read();
+ if let ParserState::Error(_) = *state {
+ error = true;
+ break;
+ }
+ if let ParserState::EndWasm = *state {
+ break;
+ }
+ max_iteration -= 1;
+ if max_iteration == 0 {
+ panic!("Max iterations exceeded");
+ }
+ }
+ if !error {
+ panic!("fail is expected");
+ }
+ }
+ }
+
+ macro_rules! expect_state {
+ ($state:expr, $expected:pat) => {{
+ {
+ let state: &ParserState = $state;
+ match *state {
+ $expected => (),
+ _ => panic!("Unexpected state during testing: {:?}", state),
+ }
+ }
+ }};
+ }
+
+ #[test]
+ fn default_read() {
+ let data = read_file_data(&PathBuf::from("tests/simple.wasm"));
+ let mut parser = Parser::new(data.as_slice());
+
+ expect_state!(parser.read(), ParserState::BeginWasm { .. });
+ expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Type, .. });
+ expect_state!(parser.read(), ParserState::TypeSectionEntry(_));
+ expect_state!(parser.read(), ParserState::EndSection);
+ expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Function, .. });
+ expect_state!(parser.read(), ParserState::FunctionSectionEntry(_));
+ expect_state!(parser.read(), ParserState::EndSection);
+ expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Code, .. });
+ expect_state!(parser.read(), ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read(), ParserState::FunctionBodyLocals { .. });
+ expect_state!(parser.read(), ParserState::CodeOperator(_));
+ expect_state!(parser.read(), ParserState::CodeOperator(Operator::End));
+ expect_state!(parser.read(), ParserState::EndFunctionBody);
+ expect_state!(parser.read(), ParserState::EndSection);
+ expect_state!(parser.read(), ParserState::EndWasm);
+ }
+
+ #[test]
+ fn default_read_with_input() {
+ let data = read_file_data(&PathBuf::from("tests/simple.wasm"));
+ let mut parser = Parser::new(data.as_slice());
+
+ expect_state!(parser.read(), ParserState::BeginWasm { .. });
+ expect_state!(parser.read_with_input(ParserInput::Default),
+ ParserState::BeginSection { code: SectionCode::Type, .. });
+ expect_state!(parser.read(), ParserState::TypeSectionEntry(_));
+ expect_state!(parser.read(), ParserState::EndSection);
+ expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Function, ..});
+ expect_state!(
+ parser.read_with_input(ParserInput::ReadSectionRawData),
+ ParserState::SectionRawData(_)
+ );
+ expect_state!(parser.read(), ParserState::EndSection);
+ expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Code, .. });
+ expect_state!(parser.read(), ParserState::BeginFunctionBody { .. });
+ expect_state!(
+ parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::EndSection
+ );
+ expect_state!(parser.read(), ParserState::EndWasm);
+ }
+
+ #[test]
+ fn skipping() {
+ let data = read_file_data(&PathBuf::from("tests/naming.wasm"));
+ let mut parser = Parser::new(data.as_slice());
+
+ expect_state!(parser.read(),
+ ParserState::BeginWasm { .. });
+ expect_state!(parser.read_with_input(ParserInput::Default),
+ ParserState::BeginSection { code: SectionCode::Type, .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Import, ..});
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Function, ..});
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Global, ..});
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Export, ..});
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Element, ..});
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Code, .. });
+ expect_state!(parser.read(),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(
+ parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::EndSection
+ );
+ expect_state!(parser.read(),
+ ParserState::BeginSection { code: SectionCode::Custom { .. }, ..});
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Custom { .. }, .. });
+ expect_state!(
+ parser.read_with_input(ParserInput::SkipSection),
+ ParserState::EndWasm
+ );
+ }
+
+ #[cfg(feature = "deterministic")]
+ fn run_deterministic_enabled_test(path: &PathBuf) {
+ let data = read_file_data(path);
+
+ let config = Some(ValidatingParserConfig {
+ operator_config: OperatorValidatorConfig {
+ deterministic_only: false,
+ enable_threads: true,
+ enable_reference_types: true,
+ enable_simd: true,
+ enable_bulk_memory: true,
+ enable_multi_value: true,
+ },
+ });
+
+ let mut parser = ValidatingParser::new(data.as_slice(), config);
+ let mut error = false;
+
+ loop {
+ let state = parser.read();
+ if let ParserState::Error(_) = *state {
+ error = true;
+ break;
+ }
+ if let ParserState::EndWasm = *state {
+ break;
+ }
+ }
+
+ assert!(error);
+ }
+
+ #[cfg(feature = "deterministic")]
+ #[test]
+ fn deterministic_enabled() {
+ // `float_exprs.*.wasm`
+ let mut tests_count = 0;
+ for path in scan_tests_files("tests/float_exprs.") {
+ run_deterministic_enabled_test(&path);
+ tests_count += 1;
+ }
+ assert_eq!(96, tests_count);
+
+ // `float_memory.*.wasm`
+ let mut tests_count = 0;
+ for path in scan_tests_files("tests/float_memory.") {
+ run_deterministic_enabled_test(&path);
+ tests_count += 1;
+ }
+ assert_eq!(6, tests_count);
+
+ // `float_misc.*.wasm`
+ let mut tests_count = 0;
+ for path in scan_tests_files("tests/float_misc.") {
+ run_deterministic_enabled_test(&path);
+ tests_count += 1;
+ }
+ assert_eq!(1, tests_count);
+ }
+}
+
+#[cfg(test)]
+mod wast_tests {
+ use crate::operators_validator::OperatorValidatorConfig;
+ use crate::parser::{ParserState, WasmDecoder};
+ use crate::validator::{ValidatingParser, ValidatingParserConfig};
+ use crate::BinaryReaderError;
+ use std::fs::{read, read_dir};
+ use std::str;
+
+ const SPEC_TESTS_PATH: &str = "testsuite";
+
+ fn default_config() -> ValidatingParserConfig {
+ ValidatingParserConfig {
+ operator_config: OperatorValidatorConfig {
+ enable_threads: false,
+ enable_reference_types: false,
+ enable_simd: false,
+ enable_bulk_memory: false,
+ enable_multi_value: false,
+
+ #[cfg(feature = "deterministic")]
+ deterministic_only: true,
+ },
+ }
+ }
+
+ fn validate_module(
+ mut module: wast::Module,
+ config: ValidatingParserConfig,
+ ) -> Result<(), BinaryReaderError> {
+ let data = module.encode().unwrap();
+ let mut parser = ValidatingParser::new(data.as_slice(), Some(config));
+ let mut max_iteration = 100000000;
+ loop {
+ let state = parser.read();
+ match *state {
+ ParserState::EndWasm => break,
+ ParserState::Error(err) => return Err(err),
+ _ => (),
+ }
+ max_iteration -= 1;
+ if max_iteration == 0 {
+ panic!("Max iterations exceeded");
+ }
+ }
+ Ok(())
+ }
+
+ fn run_wabt_scripts<F>(
+ filename: &str,
+ wast: &[u8],
+ config: ValidatingParserConfig,
+ skip_test: F,
+ ) where
+ F: Fn(&str, u64) -> bool,
+ {
+ println!("Parsing {:?}", filename);
+ // Check if we need to skip entire wast file test/parsing.
+ if skip_test(filename, /* line = */ 0) {
+ println!("{}: skipping", filename);
+ return;
+ }
+
+ let contents = str::from_utf8(wast).unwrap();
+ let buf = wast::parser::ParseBuffer::new(&contents)
+ .map_err(|mut e| {
+ e.set_path(filename.as_ref());
+ e
+ })
+ .unwrap();
+ let wast = wast::parser::parse::<wast::Wast>(&buf)
+ .map_err(|mut e| {
+ e.set_path(filename.as_ref());
+ e
+ })
+ .unwrap();
+
+ for directive in wast.directives {
+ use wast::WastDirective::*;
+ let (line, _col) = directive.span().linecol_in(&contents);
+ let line = line + 1;
+ if skip_test(filename, line as u64) {
+ println!("{}:{}: skipping", filename, line);
+ continue;
+ }
+ match directive {
+ Module(module) | AssertUnlinkable { module, .. } => {
+ if let Err(err) = validate_module(module, config.clone()) {
+ panic!("{}:{}: invalid module: {}", filename, line, err.message);
+ }
+ }
+ AssertInvalid { module, .. }
+ | AssertMalformed {
+ module: wast::QuoteModule::Module(module),
+ ..
+ } => {
+ // TODO diffentiate between assert_invalid and assert_malformed
+ if let Ok(_) = validate_module(module, config.clone()) {
+ panic!(
+ "{}:{}: invalid module was successfully parsed",
+ filename, line
+ );
+ }
+ // TODO: Check the assert_invalid or assert_malformed message
+ }
+
+ AssertMalformed {
+ module: wast::QuoteModule::Quote(_),
+ ..
+ }
+ | Register { .. }
+ | Invoke { .. }
+ | AssertTrap { .. }
+ | AssertReturn { .. }
+ | AssertReturnFunc { .. }
+ | AssertExhaustion { .. } => {}
+ }
+ }
+ }
+
+ fn run_proposal_tests<F>(name: &str, config: ValidatingParserConfig, skip_test: F)
+ where
+ F: Fn(&str, u64) -> bool,
+ {
+ let proposal_dir = format!("{}/proposals/{}", SPEC_TESTS_PATH, name);
+ for entry in read_dir(&proposal_dir).unwrap() {
+ let dir = entry.unwrap();
+ if !dir.file_type().unwrap().is_file()
+ || dir.path().extension().map(|s| s.to_str().unwrap()) != Some("wast")
+ {
+ continue;
+ }
+
+ let data = read(&dir.path()).expect("wast data");
+ run_wabt_scripts(
+ dir.file_name().to_str().expect("name"),
+ &data,
+ config,
+ |name, line| skip_test(name, line),
+ );
+ }
+ }
+
+ #[test]
+ fn run_proposals_tests() {
+ run_proposal_tests(
+ "simd",
+ {
+ let mut config: ValidatingParserConfig = default_config();
+ config.operator_config.enable_simd = true;
+ config
+ },
+ |name, line| match (name, line) {
+ // FIXME(WebAssembly/simd#140) needs a few updates to the
+ // `*.wast` file to successfully parse it (or so I think)
+ ("simd_lane.wast", _) => true,
+ ("simd_load_extend.wast", _) => true,
+ ("simd_f32x4_arith.wast", _) => true,
+ ("simd_f64x2_arith.wast", _) => true,
+ ("simd_f32x4.wast", _) => true,
+ ("simd_f64x2.wast", _) => true,
+ ("simd_const.wast", _) => true,
+ ("simd_load_splat.wast", _) => true,
+ _ => false,
+ },
+ );
+
+ run_proposal_tests(
+ "multi-value",
+ {
+ let mut config: ValidatingParserConfig = default_config();
+ config.operator_config.enable_multi_value = true;
+ config
+ },
+ |_name, _line| false,
+ );
+
+ run_proposal_tests(
+ "reference-types",
+ {
+ let mut config: ValidatingParserConfig = default_config();
+ config.operator_config.enable_reference_types = true;
+ config.operator_config.enable_bulk_memory = true;
+ config
+ },
+ |name, line| match (name, line) {
+ ("br_table.wast", _) | ("select.wast", _) => true,
+ _ => false,
+ },
+ );
+ }
+
+ #[test]
+ fn run_spec_tests() {
+ for entry in read_dir(SPEC_TESTS_PATH).unwrap() {
+ let dir = entry.unwrap();
+ if !dir.file_type().unwrap().is_file()
+ || dir.path().extension().map(|s| s.to_str().unwrap()) != Some("wast")
+ {
+ continue;
+ }
+
+ let data = read(&dir.path()).expect("wast data");
+ run_wabt_scripts(
+ dir.file_name().to_str().expect("name"),
+ &data,
+ default_config(),
+ |_, _| false,
+ );
+ }
+ }
+}