use std::{fs, ops::Deref};
use crate::WASM;
const WASM_CUSTOM_SECTION_ID: u8 = 0;
const WASM_SOURCEMAPPINGURL_SECTION_NAME: &[u8] = b"sourceMappingURL";
#[test]
fn can_create_sourcemap() {
testutils::run_test(|out| {
if let Ok(mapper) = WASM::load(&out) {
let sourcemap = mapper.map_v3();
assert!(sourcemap.starts_with(r#"{"version":3,"names":[],"sources":["#));
assert!(sourcemap.ends_with(r#""}"#));
} else {
unreachable!()
}
});
}
#[test]
fn can_add_and_update_sourcemap() {
testutils::run_test(|out| {
const URL: &'static str = "http://localhost:8080";
let content = [
&[WASM_SOURCEMAPPINGURL_SECTION_NAME.len() as u8],
WASM_SOURCEMAPPINGURL_SECTION_NAME,
&[URL.len() as u8],
URL.as_bytes(),
]
.concat();
let section = [
&[WASM_CUSTOM_SECTION_ID] as &[u8],
&[content.len() as u8],
content.as_ref(),
]
.concat();
const URL2: &'static str = "http://127.0.0.1:8080";
let content2 = [
&[WASM_SOURCEMAPPINGURL_SECTION_NAME.len() as u8],
WASM_SOURCEMAPPINGURL_SECTION_NAME,
&[URL2.len() as u8] as &[u8],
URL2.as_bytes(),
]
.concat();
let section2 = [
&[WASM_CUSTOM_SECTION_ID] as &[u8],
&[content2.len() as u8],
content2.as_ref(),
]
.concat();
let mapper = WASM::load(&out);
if let Ok(mut mapper) = mapper {
if let Err(error) = mapper.patch(URL) {
panic!("Failed to patch the WASM file the first time: {}", error);
}
{
let test = testutils::peek_wasm_file_end(out.clone(), section.len());
assert_eq!(test, section);
}
if let Err(error) = mapper.patch(URL2) {
panic!("Failed to patch the WASM file the first time: {}", error);
}
{
let test =
testutils::peek_wasm_file_end(out.clone(), section.len() + section2.len());
assert_ne!(
test,
[section.as_ref() as &[u8], section2.as_ref()].concat()
);
assert_eq!(test[test.len() - section2.len()..], section2);
}
if let Err(error) = mapper.patch(URL2) {
panic!("Failed to patch the WASM file the first time: {}", error);
}
{
let raw = fs::read(&out).expect("Cannot open the WASM file");
let obj = object::File::parse(raw.deref());
assert!(obj.is_ok());
}
} else {
panic!("Error loading WASM: {}", mapper.err().unwrap());
}
let mapper = WASM::load(&out);
if let Ok(mut mapper) = mapper {
if let Err(error) = mapper.patch(URL2) {
panic!("Failed to patch the WASM file the first time: {}", error);
}
{
let raw = fs::read(&out).expect("Cannot open the WASM file");
let obj = object::File::parse(raw.deref());
assert!(obj.is_ok());
}
} else {
panic!("Error loading WASM: {}", mapper.err().unwrap());
}
})
}
#[test]
fn test_error_types() {
fn errors() -> Result<(), Box<dyn std::error::Error>> {
let _error: crate::Error =
std::io::Error::new(std::io::ErrorKind::AddrInUse, "This is a test").into();
let dumbarray = Vec::<u8>::new();
let _error: crate::Error = match object::File::parse(dumbarray.as_slice()) {
Ok(_) => unreachable!(),
Err(err) => err.into(),
};
let _error: crate::Error = gimli::Error::Io.into();
let _error: crate::Error = "This is a test".into();
let _error: crate::Error = "This is a test".to_owned().into();
let num: Result<i32, std::num::TryFromIntError> = u32::MAX.try_into();
let _error: crate::Error = match num {
Ok(_) => unreachable!(),
Err(err) => err.into(),
};
Err(Box::from(_error))
}
let errors = errors();
assert!(errors.is_err());
let error: crate::Error = "This is a test".into();
assert_eq!(format!("{}", error), "This is a test");
}
mod testutils {
use std::{
fs,
io::Write,
panic,
path::PathBuf,
process::{Command, Stdio},
};
pub fn get_target_dir() -> PathBuf {
let mut out = PathBuf::new();
let raw = Command::new("cargo")
.args(["locate-project", "--workspace"])
.output()
.expect("Failed to locate cargo project")
.stdout;
let locate_project = &String::from_utf8_lossy(&raw);
out.push(&locate_project[9..locate_project.len() - 14]);
out
}
pub fn build_with_rustc(source: &'_ str, output: &'_ str) {
let mut rustc = Command::new("rustc")
.args(["--target", "wasm32-unknown-unknown", "-o", output, "-"])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.expect("Test WASM compile unsuccessful");
let stdin = rustc.stdin.as_mut().unwrap();
stdin
.write_all(source.as_bytes())
.expect("Failed to write test WASM to rustc input");
drop(stdin);
rustc
.wait()
.expect("Could not compile test WASM successfully");
}
pub fn setup() -> String {
let mut out = get_target_dir();
out.push("target");
out.push("test.wasm");
build_with_rustc("fn main() {}", out.display().to_string().as_str());
out.to_string_lossy().to_string()
}
pub fn teardown() {
let mut out = get_target_dir();
out.push("target");
out.push("test.wasm");
fs::remove_file(out.as_path()).ok();
}
pub fn peek_wasm_file_end(path: String, lookback: usize) -> Vec<u8> {
let binary = fs::read(path).expect("Can't open the test WASM file for reading");
binary[binary.len() - lookback..].to_owned()
}
pub fn run_test<T>(test: T) -> ()
where
T: FnOnce(String) -> () + panic::UnwindSafe,
{
let out = setup();
let result = panic::catch_unwind(|| test(out));
teardown();
assert!(result.is_ok())
}
}