| use wasmparser::*; |
| |
| #[test] |
| fn name_annotations() -> anyhow::Result<()> { |
| assert_module_name("foo", r#"(module $foo)"#)?; |
| assert_module_name("foo", r#"(module (@name "foo"))"#)?; |
| assert_module_name("foo", r#"(module $bar (@name "foo"))"#)?; |
| assert_module_name("foo bar", r#"(module $bar (@name "foo bar"))"#)?; |
| Ok(()) |
| } |
| |
| fn assert_module_name(expected_name: &str, wat: &str) -> anyhow::Result<()> { |
| let wasm = wat::parse_str(wat)?; |
| let mut found = false; |
| for s in get_name_section(&wasm)? { |
| match s? { |
| Name::Module { name, .. } => { |
| assert_eq!(name, expected_name); |
| found = true; |
| } |
| _ => {} |
| } |
| } |
| assert!(found); |
| Ok(()) |
| } |
| |
| #[test] |
| fn func_annotations() -> anyhow::Result<()> { |
| assert_func_name("foo", r#"(module (func $foo))"#)?; |
| assert_func_name("foo", r#"(module (func (@name "foo")))"#)?; |
| assert_func_name("foo", r#"(module (func $bar (@name "foo")))"#)?; |
| assert_func_name("foo bar", r#"(module (func $bar (@name "foo bar")))"#)?; |
| Ok(()) |
| } |
| |
| fn assert_func_name(name: &str, wat: &str) -> anyhow::Result<()> { |
| let wasm = wat::parse_str(wat)?; |
| let mut found = false; |
| for s in get_name_section(&wasm)? { |
| match s? { |
| Name::Function(n) => { |
| let naming = n.into_iter().next().unwrap()?; |
| assert_eq!(naming.index, 0); |
| assert_eq!(naming.name, name); |
| found = true; |
| } |
| _ => {} |
| } |
| } |
| assert!(found); |
| Ok(()) |
| } |
| |
| #[test] |
| fn local_annotations() -> anyhow::Result<()> { |
| assert_local_name("foo", r#"(module (func (param $foo i32)))"#)?; |
| assert_local_name("foo", r#"(module (func (local $foo i32)))"#)?; |
| assert_local_name("foo", r#"(module (func (param (@name "foo") i32)))"#)?; |
| assert_local_name("foo", r#"(module (func (local (@name "foo") i32)))"#)?; |
| assert_local_name("foo", r#"(module (func (param $bar (@name "foo") i32)))"#)?; |
| assert_local_name("foo", r#"(module (func (local $bar (@name "foo") i32)))"#)?; |
| assert_local_name( |
| "foo bar", |
| r#"(module (func (param $bar (@name "foo bar") i32)))"#, |
| )?; |
| assert_local_name( |
| "foo bar", |
| r#"(module (func (local $bar (@name "foo bar") i32)))"#, |
| )?; |
| Ok(()) |
| } |
| |
| fn assert_local_name(name: &str, wat: &str) -> anyhow::Result<()> { |
| let wasm = wat::parse_str(wat)?; |
| let mut found = false; |
| for s in get_name_section(&wasm)? { |
| match s? { |
| Name::Local(n) => { |
| let naming = n |
| .into_iter() |
| .next() |
| .unwrap()? |
| .names |
| .into_iter() |
| .next() |
| .unwrap()?; |
| assert_eq!(naming.index, 0); |
| assert_eq!(naming.name, name); |
| found = true; |
| } |
| _ => {} |
| } |
| } |
| assert!(found); |
| Ok(()) |
| } |
| |
| fn get_name_section(wasm: &[u8]) -> anyhow::Result<NameSectionReader<'_>> { |
| for payload in Parser::new(0).parse_all(&wasm) { |
| if let Payload::CustomSection(c) = payload? { |
| if let KnownCustom::Name(s) = c.as_known() { |
| return Ok(s); |
| } |
| } |
| } |
| panic!("no name section found"); |
| } |
| |
| #[test] |
| fn custom_section_order() -> anyhow::Result<()> { |
| let bytes = wat::parse_str( |
| r#" |
| (module |
| (@custom "A" "aaa") |
| (type (func)) |
| (@custom "B" (after func) "bbb") |
| (@custom "C" (before func) "ccc") |
| (@custom "D" (after last) "ddd") |
| (table 10 funcref) |
| (func (type 0)) |
| (@custom "E" (after import) "eee") |
| (@custom "F" (before type) "fff") |
| (@custom "G" (after data) "ggg") |
| (@custom "H" (after code) "hhh") |
| (@custom "I" (after func) "iii") |
| (@custom "J" (before func) "jjj") |
| (@custom "K" (before first) "kkk") |
| ) |
| "#, |
| )?; |
| macro_rules! assert_matches { |
| ($a:expr, $b:pat $(if $cond:expr)? $(,)?) => { |
| match &$a { |
| $b $(if $cond)? => {} |
| a => panic!("`{:?}` doesn't match `{}`", a, stringify!($b)), |
| } |
| }; |
| } |
| let wasm = Parser::new(0) |
| .parse_all(&bytes) |
| .collect::<Result<Vec<_>>>()?; |
| assert_matches!(wasm[0], Payload::Version { .. }); |
| assert_matches!( |
| wasm[1], |
| Payload::CustomSection(c) if c.name() == "K" |
| ); |
| assert_matches!( |
| wasm[2], |
| Payload::CustomSection(c) if c.name() == "F" |
| ); |
| assert_matches!(wasm[3], Payload::TypeSection(_)); |
| assert_matches!( |
| wasm[4], |
| Payload::CustomSection(c) if c.name() == "E" |
| ); |
| assert_matches!( |
| wasm[5], |
| Payload::CustomSection(c) if c.name() == "C" |
| ); |
| assert_matches!( |
| wasm[6], |
| Payload::CustomSection(c) if c.name() == "J" |
| ); |
| assert_matches!(wasm[7], Payload::FunctionSection(_)); |
| assert_matches!( |
| wasm[8], |
| Payload::CustomSection(c) if c.name() == "B" |
| ); |
| assert_matches!( |
| wasm[9], |
| Payload::CustomSection(c) if c.name() == "I" |
| ); |
| assert_matches!(wasm[10], Payload::TableSection(_)); |
| assert_matches!(wasm[11], Payload::CodeSectionStart { .. }); |
| assert_matches!(wasm[12], Payload::CodeSectionEntry { .. }); |
| assert_matches!( |
| wasm[13], |
| Payload::CustomSection(c) if c.name() == "H" |
| ); |
| assert_matches!( |
| wasm[14], |
| Payload::CustomSection(c) if c.name() == "G" |
| ); |
| assert_matches!( |
| wasm[15], |
| Payload::CustomSection(c) if c.name() == "A" |
| ); |
| assert_matches!( |
| wasm[16], |
| Payload::CustomSection(c) if c.name() == "D" |
| ); |
| |
| match &wasm[17] { |
| Payload::End(x) if *x == bytes.len() => {} |
| p => panic!("`{:?}` doesn't match expected length of {}", p, bytes.len()), |
| } |
| |
| Ok(()) |
| } |