|
1 | 1 | use anyhow::{bail, Context, Error, Result}; |
| 2 | +use libtest_mimic::{Arguments, Trial}; |
2 | 3 | use pretty_assertions::assert_eq; |
3 | 4 | use std::{borrow::Cow, fs, path::Path}; |
4 | 5 | use wasm_encoder::{Encode, Section}; |
@@ -50,137 +51,145 @@ use wit_parser::{PackageId, Resolve, UnresolvedPackage}; |
50 | 51 | /// |
51 | 52 | /// Run the test with the environment variable `BLESS` set to update |
52 | 53 | /// either `component.wat` or `error.txt` depending on the outcome of the encoding. |
53 | | -#[test] |
54 | | -fn component_encoding_via_flags() -> Result<()> { |
| 54 | +fn main() -> Result<()> { |
55 | 55 | drop(env_logger::try_init()); |
56 | 56 |
|
| 57 | + let mut trials = Vec::new(); |
57 | 58 | for entry in fs::read_dir("tests/components")? { |
58 | 59 | let path = entry?.path(); |
59 | 60 | if !path.is_dir() { |
60 | 61 | continue; |
61 | 62 | } |
62 | 63 |
|
63 | | - let test_case = path.file_stem().unwrap().to_str().unwrap(); |
64 | | - println!("testing {test_case}"); |
| 64 | + trials.push(Trial::test(path.to_str().unwrap().to_string(), move || { |
| 65 | + run_test(&path).map_err(|e| format!("{e:?}").into()) |
| 66 | + })); |
| 67 | + } |
65 | 68 |
|
66 | | - let mut resolve = Resolve::default(); |
67 | | - let (pkg, _) = resolve.push_dir(&path)?; |
| 69 | + let mut args = Arguments::from_args(); |
| 70 | + if cfg!(target_family = "wasm") && !cfg!(target_feature = "atomics") { |
| 71 | + args.test_threads = Some(1); |
| 72 | + } |
| 73 | + libtest_mimic::run(&args, trials).exit(); |
| 74 | +} |
68 | 75 |
|
69 | | - let module_path = path.join("module.wat"); |
70 | | - let mut adapters = glob::glob(path.join("adapt-*.wat").to_str().unwrap())?; |
71 | | - let result = if module_path.is_file() { |
72 | | - let module = read_core_module(&module_path, &resolve, pkg)?; |
73 | | - adapters |
74 | | - .try_fold( |
75 | | - ComponentEncoder::default().module(&module)?.validate(true), |
76 | | - |encoder, path| { |
77 | | - let (name, wasm) = read_name_and_module("adapt-", &path?, &resolve, pkg)?; |
78 | | - Ok::<_, Error>(encoder.adapter(&name, &wasm)?) |
79 | | - }, |
80 | | - )? |
81 | | - .encode() |
82 | | - } else { |
83 | | - let mut libs = glob::glob(path.join("lib-*.wat").to_str().unwrap())? |
84 | | - .map(|path| Ok(("lib-", path?, false))) |
85 | | - .chain( |
86 | | - glob::glob(path.join("dlopen-lib-*.wat").to_str().unwrap())? |
87 | | - .map(|path| Ok(("dlopen-lib-", path?, true))), |
88 | | - ) |
89 | | - .collect::<Result<Vec<_>>>()?; |
| 76 | +fn run_test(path: &Path) -> Result<()> { |
| 77 | + let test_case = path.file_stem().unwrap().to_str().unwrap(); |
90 | 78 |
|
91 | | - // Sort list to ensure deterministic order, which determines priority in cases of duplicate symbols: |
92 | | - libs.sort_by(|(_, a, _), (_, b, _)| a.cmp(b)); |
| 79 | + let mut resolve = Resolve::default(); |
| 80 | + let (pkg, _) = resolve.push_dir(&path)?; |
93 | 81 |
|
94 | | - let mut linker = Linker::default().validate(true); |
| 82 | + let module_path = path.join("module.wat"); |
| 83 | + let mut adapters = glob::glob(path.join("adapt-*.wat").to_str().unwrap())?; |
| 84 | + let result = if module_path.is_file() { |
| 85 | + let module = read_core_module(&module_path, &resolve, pkg)?; |
| 86 | + adapters |
| 87 | + .try_fold( |
| 88 | + ComponentEncoder::default().module(&module)?.validate(true), |
| 89 | + |encoder, path| { |
| 90 | + let (name, wasm) = read_name_and_module("adapt-", &path?, &resolve, pkg)?; |
| 91 | + Ok::<_, Error>(encoder.adapter(&name, &wasm)?) |
| 92 | + }, |
| 93 | + )? |
| 94 | + .encode() |
| 95 | + } else { |
| 96 | + let mut libs = glob::glob(path.join("lib-*.wat").to_str().unwrap())? |
| 97 | + .map(|path| Ok(("lib-", path?, false))) |
| 98 | + .chain( |
| 99 | + glob::glob(path.join("dlopen-lib-*.wat").to_str().unwrap())? |
| 100 | + .map(|path| Ok(("dlopen-lib-", path?, true))), |
| 101 | + ) |
| 102 | + .collect::<Result<Vec<_>>>()?; |
95 | 103 |
|
96 | | - if path.join("stub-missing-functions").is_file() { |
97 | | - linker = linker.stub_missing_functions(true); |
98 | | - } |
| 104 | + // Sort list to ensure deterministic order, which determines priority in cases of duplicate symbols: |
| 105 | + libs.sort_by(|(_, a, _), (_, b, _)| a.cmp(b)); |
99 | 106 |
|
100 | | - if path.join("use-built-in-libdl").is_file() { |
101 | | - linker = linker.use_built_in_libdl(true); |
102 | | - } |
| 107 | + let mut linker = Linker::default().validate(true); |
103 | 108 |
|
104 | | - let linker = |
105 | | - libs.into_iter() |
106 | | - .try_fold(linker, |linker, (prefix, path, dl_openable)| { |
107 | | - let (name, wasm) = read_name_and_module(prefix, &path, &resolve, pkg)?; |
108 | | - Ok::<_, Error>(linker.library(&name, &wasm, dl_openable)?) |
109 | | - })?; |
| 109 | + if path.join("stub-missing-functions").is_file() { |
| 110 | + linker = linker.stub_missing_functions(true); |
| 111 | + } |
110 | 112 |
|
111 | | - adapters |
112 | | - .try_fold(linker, |linker, path| { |
113 | | - let (name, wasm) = read_name_and_module("adapt-", &path?, &resolve, pkg)?; |
114 | | - Ok::<_, Error>(linker.adapter(&name, &wasm)?) |
115 | | - })? |
116 | | - .encode() |
117 | | - }; |
118 | | - let component_path = path.join("component.wat"); |
119 | | - let component_wit_path = path.join("component.wit.print"); |
120 | | - let error_path = path.join("error.txt"); |
| 113 | + if path.join("use-built-in-libdl").is_file() { |
| 114 | + linker = linker.use_built_in_libdl(true); |
| 115 | + } |
121 | 116 |
|
122 | | - let bytes = match result { |
123 | | - Ok(bytes) => { |
124 | | - if test_case.starts_with("error-") { |
125 | | - bail!("expected an error but got success"); |
126 | | - } |
127 | | - bytes |
| 117 | + let linker = libs |
| 118 | + .into_iter() |
| 119 | + .try_fold(linker, |linker, (prefix, path, dl_openable)| { |
| 120 | + let (name, wasm) = read_name_and_module(prefix, &path, &resolve, pkg)?; |
| 121 | + Ok::<_, Error>(linker.library(&name, &wasm, dl_openable)?) |
| 122 | + })?; |
| 123 | + |
| 124 | + adapters |
| 125 | + .try_fold(linker, |linker, path| { |
| 126 | + let (name, wasm) = read_name_and_module("adapt-", &path?, &resolve, pkg)?; |
| 127 | + Ok::<_, Error>(linker.adapter(&name, &wasm)?) |
| 128 | + })? |
| 129 | + .encode() |
| 130 | + }; |
| 131 | + let component_path = path.join("component.wat"); |
| 132 | + let component_wit_path = path.join("component.wit.print"); |
| 133 | + let error_path = path.join("error.txt"); |
| 134 | + |
| 135 | + let bytes = match result { |
| 136 | + Ok(bytes) => { |
| 137 | + if test_case.starts_with("error-") { |
| 138 | + bail!("expected an error but got success"); |
128 | 139 | } |
129 | | - Err(err) => { |
130 | | - if !test_case.starts_with("error-") { |
131 | | - return Err(err); |
132 | | - } |
133 | | - assert_output(&format!("{err:?}"), &error_path)?; |
134 | | - continue; |
| 140 | + bytes |
| 141 | + } |
| 142 | + Err(err) => { |
| 143 | + if !test_case.starts_with("error-") { |
| 144 | + return Err(err); |
135 | 145 | } |
136 | | - }; |
| 146 | + assert_output(&format!("{err:?}"), &error_path)?; |
| 147 | + return Ok(()); |
| 148 | + } |
| 149 | + }; |
137 | 150 |
|
138 | | - let wat = wasmprinter::print_bytes(&bytes)?; |
139 | | - assert_output(&wat, &component_path)?; |
140 | | - let (pkg, resolve) = match wit_component::decode(&bytes)? { |
141 | | - DecodedWasm::WitPackage(..) => unreachable!(), |
142 | | - DecodedWasm::Component(resolve, world) => { |
143 | | - (resolve.worlds[world].package.unwrap(), resolve) |
144 | | - } |
145 | | - }; |
146 | | - let wit = WitPrinter::default().print(&resolve, pkg)?; |
147 | | - assert_output(&wit, &component_wit_path)?; |
| 151 | + let wat = wasmprinter::print_bytes(&bytes)?; |
| 152 | + assert_output(&wat, &component_path)?; |
| 153 | + let (pkg, resolve) = match wit_component::decode(&bytes)? { |
| 154 | + DecodedWasm::WitPackage(..) => unreachable!(), |
| 155 | + DecodedWasm::Component(resolve, world) => (resolve.worlds[world].package.unwrap(), resolve), |
| 156 | + }; |
| 157 | + let wit = WitPrinter::default().print(&resolve, pkg)?; |
| 158 | + assert_output(&wit, &component_wit_path)?; |
148 | 159 |
|
149 | | - UnresolvedPackage::parse(&component_wit_path, &wit) |
150 | | - .context("failed to parse printed WIT")?; |
| 160 | + UnresolvedPackage::parse(&component_wit_path, &wit).context("failed to parse printed WIT")?; |
151 | 161 |
|
152 | | - // Check that the producer data got piped through properly |
153 | | - let metadata = wasm_metadata::Metadata::from_binary(&bytes)?; |
154 | | - match metadata { |
155 | | - // Depends on the ComponentEncoder always putting the first module as the 0th child: |
156 | | - wasm_metadata::Metadata::Component { children, .. } => match children[0].as_ref() { |
157 | | - wasm_metadata::Metadata::Module { producers, .. } => { |
158 | | - let producers = producers.as_ref().expect("child module has producers"); |
159 | | - let processed_by = producers |
160 | | - .get("processed-by") |
161 | | - .expect("child has processed-by section"); |
| 162 | + // Check that the producer data got piped through properly |
| 163 | + let metadata = wasm_metadata::Metadata::from_binary(&bytes)?; |
| 164 | + match metadata { |
| 165 | + // Depends on the ComponentEncoder always putting the first module as the 0th child: |
| 166 | + wasm_metadata::Metadata::Component { children, .. } => match children[0].as_ref() { |
| 167 | + wasm_metadata::Metadata::Module { producers, .. } => { |
| 168 | + let producers = producers.as_ref().expect("child module has producers"); |
| 169 | + let processed_by = producers |
| 170 | + .get("processed-by") |
| 171 | + .expect("child has processed-by section"); |
| 172 | + assert_eq!( |
| 173 | + processed_by |
| 174 | + .get("wit-component") |
| 175 | + .expect("wit-component producer present"), |
| 176 | + env!("CARGO_PKG_VERSION") |
| 177 | + ); |
| 178 | + if module_path.is_file() { |
162 | 179 | assert_eq!( |
163 | 180 | processed_by |
164 | | - .get("wit-component") |
165 | | - .expect("wit-component producer present"), |
166 | | - env!("CARGO_PKG_VERSION") |
| 181 | + .get("my-fake-bindgen") |
| 182 | + .expect("added bindgen field present"), |
| 183 | + "123.45" |
167 | 184 | ); |
168 | | - if module_path.is_file() { |
169 | | - assert_eq!( |
170 | | - processed_by |
171 | | - .get("my-fake-bindgen") |
172 | | - .expect("added bindgen field present"), |
173 | | - "123.45" |
174 | | - ); |
175 | | - } else { |
176 | | - // Otherwise, we used `Linker`, which synthesizes the |
177 | | - // "main" module and thus won't have `my-fake-bindgen` |
178 | | - } |
| 185 | + } else { |
| 186 | + // Otherwise, we used `Linker`, which synthesizes the |
| 187 | + // "main" module and thus won't have `my-fake-bindgen` |
179 | 188 | } |
180 | | - _ => panic!("expected child to be a module"), |
181 | | - }, |
182 | | - _ => panic!("expected top level metadata of component"), |
183 | | - } |
| 189 | + } |
| 190 | + _ => panic!("expected child to be a module"), |
| 191 | + }, |
| 192 | + _ => panic!("expected top level metadata of component"), |
184 | 193 | } |
185 | 194 |
|
186 | 195 | Ok(()) |
|
0 commit comments