1use serde::de::DeserializeOwned;
2use serde_derive::Deserialize;
3use std::fmt;
4use std::fs;
5use std::path::Path;
6use std::path::PathBuf;
7use wasmtime_environ::prelude::*;
8
9pub mod limits {
19 pub const MEMORY_SIZE: usize = 805 << 16;
20 pub const MEMORIES: u32 = 450;
21 pub const GC_HEAP_SIZE: usize = 10 << 16;
22 pub const TABLES: u32 = 200;
23 pub const MEMORIES_PER_MODULE: u32 = 9;
24 pub const TABLES_PER_MODULE: u32 = 5;
25 pub const COMPONENT_INSTANCES: u32 = 50;
26 pub const CORE_INSTANCES: u32 = 900;
27 pub const TABLE_ELEMENTS: usize = 1000;
28 pub const CORE_INSTANCE_SIZE: usize = 64 * 1024;
29 pub const TOTAL_STACKS: u32 = 20;
30}
31
32pub fn find_tests(root: &Path) -> Result<Vec<WastTest>> {
35 let mut tests = Vec::new();
36
37 let spec_tests = root.join("tests/spec_testsuite");
38 add_tests(
39 &mut tests,
40 &spec_tests,
41 &FindConfig::Infer(spec_test_config),
42 )
43 .context("Do you need to `git submodule update --init`?")
44 .with_context(|| format!("failed to add tests from `{}`", spec_tests.display()))?;
45
46 let misc_tests = root.join("tests/misc_testsuite");
47 add_tests(&mut tests, &misc_tests, &FindConfig::InTest)
48 .with_context(|| format!("failed to add tests from `{}`", misc_tests.display()))?;
49
50 let cm_tests = root.join("tests/component-model/test");
51 add_tests(
52 &mut tests,
53 &cm_tests,
54 &FindConfig::Infer(component_test_config),
55 )
56 .context("Do you need to `git submodule update --init`?")
57 .with_context(|| format!("failed to add tests from `{}`", cm_tests.display()))?;
58
59 {
62 let skip_list = &[
63 ];
65 tests.retain(|test| {
66 test.path
67 .file_name()
68 .and_then(|name| name.to_str())
69 .map(|name| !skip_list.contains(&name))
70 .unwrap_or(true)
71 });
72 }
73
74 Ok(tests)
75}
76
77enum FindConfig {
78 InTest,
79 Infer(fn(&Path) -> TestConfig),
80}
81
82fn add_tests(tests: &mut Vec<WastTest>, path: &Path, config: &FindConfig) -> Result<()> {
83 for entry in path.read_dir().context("failed to read directory")? {
84 let entry = entry.context("failed to read directory entry")?;
85 let path = entry.path();
86 if entry
87 .file_type()
88 .context("failed to get file type")?
89 .is_dir()
90 {
91 add_tests(tests, &path, config).context("failed to read sub-directory")?;
92 continue;
93 }
94
95 if path.extension().and_then(|s| s.to_str()) != Some("wast") {
96 continue;
97 }
98
99 if path.ends_with("spec_testsuite/custom/custom_annot.wast")
102 || path.ends_with("spec_testsuite/custom/branch_hint.wast")
103 || path.ends_with("spec_testsuite/custom/name_annot.wast")
104 {
105 continue;
106 }
107
108 let contents =
109 fs::read_to_string(&path).with_context(|| format!("failed to read test: {path:?}"))?;
110 let config = match config {
111 FindConfig::InTest => parse_test_config(&contents, ";;!")
112 .with_context(|| format!("failed to parse test configuration: {path:?}"))?,
113 FindConfig::Infer(f) => f(&path),
114 };
115 tests.push(WastTest {
116 path,
117 contents,
118 config,
119 })
120 }
121 Ok(())
122}
123
124fn spec_test_config(test: &Path) -> TestConfig {
125 let mut ret = TestConfig::default();
126 ret.spec_test = Some(true);
127 ret.bulk_memory = Some(true);
128 match spec_proposal_from_path(test) {
129 Some("wide-arithmetic") => {
130 ret.wide_arithmetic = Some(true);
131 }
132 Some("threads") => {
133 ret.threads = Some(true);
134 ret.reference_types = Some(false);
135 }
136 Some("custom-page-sizes") => {
137 ret.custom_page_sizes = Some(true);
138 ret.multi_memory = Some(true);
139 ret.memory64 = Some(true);
140 ret.reference_types = Some(true);
141
142 if test.ends_with("memory_max.wast") || test.ends_with("memory_max_i64.wast") {
145 ret.hogs_memory = Some(true);
146 }
147 }
148 Some("custom-descriptors") => {
149 ret.custom_descriptors = Some(true);
150 }
151 Some(proposal) => panic!("unsupported proposal {proposal:?}"),
152 None => {
153 ret.reference_types = Some(true);
154 ret.simd = Some(true);
155 ret.simd = Some(true);
156 ret.relaxed_simd = Some(true);
157 ret.multi_memory = Some(true);
158 ret.gc = Some(true);
159 ret.reference_types = Some(true);
160 ret.memory64 = Some(true);
161 ret.tail_call = Some(true);
162 ret.extended_const = Some(true);
163 ret.exceptions = Some(true);
164
165 if test.parent().unwrap().ends_with("legacy") {
166 ret.legacy_exceptions = Some(true);
167 }
168
169 if test.ends_with("memory.wast")
178 || test.ends_with("table.wast")
179 || test.ends_with("memory64.wast")
180 || test.ends_with("table64.wast")
181 {
182 ret.hogs_memory = Some(true);
183 }
184 }
185 }
186
187 ret
188}
189
190fn component_test_config(test: &Path) -> TestConfig {
191 let mut ret = TestConfig::default();
192 ret.spec_test = Some(true);
193 ret.reference_types = Some(true);
194 ret.multi_memory = Some(true);
195
196 if let Some(parent) = test.parent() {
197 if parent.ends_with("async")
198 || [
199 "trap-in-post-return.wast",
200 "resources.wast",
201 "multiple-resources.wast",
202 ]
203 .into_iter()
204 .any(|name| Some(name) == test.file_name().and_then(|s| s.to_str()))
205 {
206 ret.component_model_async = Some(true);
207 ret.component_model_async_stackful = Some(true);
208 ret.component_model_more_async_builtins = Some(true);
209 ret.component_model_threading = Some(true);
210 }
211 if parent.ends_with("wasm-tools") {
212 ret.memory64 = Some(true);
213 ret.threads = Some(true);
214 ret.exceptions = Some(true);
215 ret.gc = Some(true);
216 }
217 if parent.ends_with("wasmtime") {
218 ret.exceptions = Some(true);
219 ret.gc = Some(true);
220 }
221 }
222
223 ret
224}
225
226pub fn parse_test_config<T>(wat: &str, comment: &'static str) -> Result<T>
229where
230 T: DeserializeOwned,
231{
232 let config_lines: Vec<_> = wat
235 .lines()
236 .take_while(|l| l.starts_with(comment))
237 .map(|l| &l[comment.len()..])
238 .collect();
239 let config_text = config_lines.join("\n");
240
241 toml::from_str(&config_text).context("failed to parse the test configuration")
242}
243
244#[derive(Clone)]
246pub struct WastTest {
247 pub path: PathBuf,
248 pub contents: String,
249 pub config: TestConfig,
250}
251
252impl fmt::Debug for WastTest {
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 f.debug_struct("WastTest")
255 .field("path", &self.path)
256 .field("contents", &"...")
257 .field("config", &self.config)
258 .finish()
259 }
260}
261
262macro_rules! foreach_config_option {
263 ($m:ident) => {
264 $m! {
265 bulk_memory
266 memory64
267 custom_page_sizes
268 multi_memory
269 threads
270 shared_everything_threads
271 gc
272 function_references
273 relaxed_simd
274 reference_types
275 tail_call
276 extended_const
277 wide_arithmetic
278 branch_hinting
279 hogs_memory
280 nan_canonicalization
281 component_model_async
282 component_model_more_async_builtins
283 component_model_async_stackful
284 component_model_threading
285 component_model_error_context
286 component_model_gc
287 component_model_map
288 component_model_fixed_length_lists
289 component_model_implements
290 simd
291 gc_types
292 exceptions
293 legacy_exceptions
294 stack_switching
295 spec_test
296 custom_descriptors
297 }
298 };
299}
300
301macro_rules! define_test_config {
302 ($($option:ident)*) => {
303 #[derive(Debug, PartialEq, Default, Deserialize, Clone)]
306 #[serde(deny_unknown_fields)]
307 pub struct TestConfig {
308 $(pub $option: Option<bool>,)*
309 }
310
311 impl TestConfig {
312 $(
313 pub fn $option(&self) -> bool {
314 self.$option.unwrap_or(false)
315 }
316 )*
317 }
318 }
319}
320
321foreach_config_option!(define_test_config);
322
323impl TestConfig {
324 pub fn options_mut(&mut self) -> impl Iterator<Item = (&'static str, &mut Option<bool>)> {
326 macro_rules! mk {
327 ($($option:ident)*) => {
328 [
329 $((stringify!($option), &mut self.$option),)*
330 ].into_iter()
331 }
332 }
333 foreach_config_option!(mk)
334 }
335}
336
337#[derive(Debug)]
339pub struct WastConfig {
340 pub compiler: Compiler,
342 pub pooling: bool,
344 pub collector: Collector,
346}
347
348#[derive(PartialEq, Debug, Copy, Clone)]
350pub enum Compiler {
351 CraneliftNative,
358
359 Winch,
364
365 CraneliftPulley,
372}
373
374impl Compiler {
375 pub fn should_fail(&self, config: &TestConfig) -> bool {
386 match self {
387 Compiler::CraneliftNative => {
388 if config.legacy_exceptions() {
389 return true;
390 }
391
392 if config.stack_switching() && !(cfg!(target_arch = "x86_64") && cfg!(unix)) {
395 return true;
396 }
397
398 false
399 }
400
401 Compiler::Winch => {
402 if config.gc()
403 || config.tail_call()
404 || config.function_references()
405 || config.gc()
406 || config.relaxed_simd()
407 || config.gc_types()
408 || config.exceptions()
409 || config.legacy_exceptions()
410 || config.stack_switching()
411 || config.legacy_exceptions()
412 || config.component_model_async()
413 {
414 return true;
415 }
416
417 if cfg!(target_arch = "aarch64") {
418 return (config.simd() && !config.spec_test()) || config.threads();
419 }
420
421 !cfg!(target_arch = "x86_64")
422 }
423
424 Compiler::CraneliftPulley => {
425 config.threads() || config.legacy_exceptions() || config.stack_switching()
426 }
427 }
428 }
429
430 pub fn supports_host(&self) -> bool {
433 match self {
434 Compiler::CraneliftNative => {
435 cfg!(target_arch = "x86_64")
436 || cfg!(target_arch = "aarch64")
437 || cfg!(target_arch = "riscv64")
438 || cfg!(target_arch = "s390x")
439 }
440 Compiler::Winch => cfg!(target_arch = "x86_64") || cfg!(target_arch = "aarch64"),
441 Compiler::CraneliftPulley => true,
442 }
443 }
444}
445
446#[derive(PartialEq, Debug, Copy, Clone)]
447pub enum Collector {
448 Auto,
449 Null,
450 DeferredReferenceCounting,
451 Copying,
452}
453
454impl WastTest {
455 pub fn test_uses_gc_types(&self) -> bool {
458 self.config.gc() || self.config.function_references()
459 }
460
461 pub fn spec_proposal(&self) -> Option<&str> {
463 spec_proposal_from_path(&self.path)
464 }
465
466 pub fn should_fail(&self, config: &WastConfig) -> bool {
469 if !config.compiler.supports_host() {
470 return true;
471 }
472
473 let unsupported = [
474 "test/async/trap-if-block-and-sync.wast",
478 "test/wasm-tools/memory64.wast",
481 ];
482 if unsupported.iter().any(|part| self.path.ends_with(part)) {
483 return true;
484 }
485
486 if config.pooling {
488 if self.config.hogs_memory() {
490 return true;
491 }
492 let unsupported = [
493 "misc_testsuite/memory-combos.wast",
495 "misc_testsuite/threads/atomics-end-of-memory.wast",
496 "misc_testsuite/threads/LB.wast",
497 "misc_testsuite/threads/LB_atomic.wast",
498 "misc_testsuite/threads/MP.wast",
499 "misc_testsuite/threads/MP_atomic.wast",
500 "misc_testsuite/threads/MP_wait.wast",
501 "misc_testsuite/threads/SB.wast",
502 "misc_testsuite/threads/SB_atomic.wast",
503 "misc_testsuite/threads/atomics_notify.wast",
504 "misc_testsuite/threads/atomics_wait_address.wast",
505 "misc_testsuite/threads/wait_notify.wast",
506 "spec_testsuite/proposals/threads/atomic.wast",
507 "spec_testsuite/proposals/threads/exports.wast",
508 "spec_testsuite/proposals/threads/memory.wast",
509 "misc_testsuite/memory64/threads.wast",
510 "misc_testsuite/winch/rmw32_cmpxchg_u_wrap.wast",
511 ];
512
513 if unsupported.iter().any(|part| self.path.ends_with(part)) {
514 return true;
515 }
516 }
517
518 if config.compiler.should_fail(&self.config) {
519 return true;
520 }
521
522 if config.compiler == Compiler::Winch {
524 let unsupported = [
526 "extended-const/elem.wast",
527 "extended-const/global.wast",
528 "misc_testsuite/component-model/modules.wast",
529 "misc_testsuite/externref-id-function.wast",
530 "misc_testsuite/externref-segment.wast",
531 "misc_testsuite/externref-segments.wast",
532 "misc_testsuite/externref-table-dropped-segment-issue-8281.wast",
533 "misc_testsuite/linking-errors.wast",
534 "misc_testsuite/many_table_gets_lead_to_gc.wast",
535 "misc_testsuite/mutable_externref_globals.wast",
536 "misc_testsuite/no-mixup-stack-maps.wast",
537 "misc_testsuite/no-panic.wast",
538 "misc_testsuite/simple_ref_is_null.wast",
539 ];
540
541 if unsupported.iter().any(|part| self.path.ends_with(part)) {
542 return true;
543 }
544
545 #[cfg(target_arch = "aarch64")]
546 {
547 let unsupported = [
548 "misc_testsuite/int-to-float-splat.wast",
549 "misc_testsuite/issue6562.wast",
550 "misc_testsuite/memory64/simd.wast",
551 "misc_testsuite/simd/almost-extmul.wast",
552 "misc_testsuite/simd/canonicalize-nan.wast",
553 "misc_testsuite/simd/cvt-from-uint.wast",
554 "misc_testsuite/simd/edge-of-memory.wast",
555 "misc_testsuite/simd/interesting-float-splat.wast",
556 "misc_testsuite/simd/issue4807.wast",
557 "misc_testsuite/simd/issue6725-no-egraph-panic.wast",
558 "misc_testsuite/simd/issue_3173_select_v128.wast",
559 "misc_testsuite/simd/issue_3327_bnot_lowering.wast",
560 "misc_testsuite/simd/load_splat_out_of_bounds.wast",
561 "misc_testsuite/simd/replace-lane-preserve.wast",
562 "misc_testsuite/simd/spillslot-size-fuzzbug.wast",
563 "misc_testsuite/simd/sse-cannot-fold-unaligned-loads.wast",
564 "misc_testsuite/simd/unaligned-load.wast",
565 "misc_testsuite/simd/v128-select.wast",
566 "misc_testsuite/winch/issue-10331.wast",
567 "misc_testsuite/winch/issue-10357.wast",
568 "misc_testsuite/winch/issue-10460.wast",
569 "misc_testsuite/winch/replace_lane.wast",
570 "misc_testsuite/winch/simd_multivalue.wast",
571 "misc_testsuite/winch/v128_load_lane_invalid_address.wast",
572 "spec_testsuite/proposals/annotations/simd_lane.wast",
573 "spec_testsuite/proposals/multi-memory/simd_memory-multi.wast",
574 "spec_testsuite/simd_address.wast",
575 "spec_testsuite/simd_align.wast",
576 "spec_testsuite/simd_bit_shift.wast",
577 "spec_testsuite/simd_bitwise.wast",
578 "spec_testsuite/simd_boolean.wast",
579 "spec_testsuite/simd_const.wast",
580 "spec_testsuite/simd_conversions.wast",
581 "spec_testsuite/simd_f32x4.wast",
582 "spec_testsuite/simd_f32x4_arith.wast",
583 "spec_testsuite/simd_f32x4_cmp.wast",
584 "spec_testsuite/simd_f32x4_pmin_pmax.wast",
585 "spec_testsuite/simd_f32x4_rounding.wast",
586 "spec_testsuite/simd_f64x2.wast",
587 "spec_testsuite/simd_f64x2_arith.wast",
588 "spec_testsuite/simd_f64x2_cmp.wast",
589 "spec_testsuite/simd_f64x2_pmin_pmax.wast",
590 "spec_testsuite/simd_f64x2_rounding.wast",
591 "spec_testsuite/simd_i16x8_arith.wast",
592 "spec_testsuite/simd_i16x8_arith2.wast",
593 "spec_testsuite/simd_i16x8_cmp.wast",
594 "spec_testsuite/simd_i16x8_extadd_pairwise_i8x16.wast",
595 "spec_testsuite/simd_i16x8_extmul_i8x16.wast",
596 "spec_testsuite/simd_i16x8_q15mulr_sat_s.wast",
597 "spec_testsuite/simd_i16x8_sat_arith.wast",
598 "spec_testsuite/simd_i32x4_arith.wast",
599 "spec_testsuite/simd_i32x4_arith2.wast",
600 "spec_testsuite/simd_i32x4_cmp.wast",
601 "spec_testsuite/simd_i32x4_dot_i16x8.wast",
602 "spec_testsuite/simd_i32x4_extadd_pairwise_i16x8.wast",
603 "spec_testsuite/simd_i32x4_extmul_i16x8.wast",
604 "spec_testsuite/simd_i32x4_trunc_sat_f32x4.wast",
605 "spec_testsuite/simd_i32x4_trunc_sat_f64x2.wast",
606 "spec_testsuite/simd_i64x2_arith.wast",
607 "spec_testsuite/simd_i64x2_arith2.wast",
608 "spec_testsuite/simd_i64x2_cmp.wast",
609 "spec_testsuite/simd_i64x2_extmul_i32x4.wast",
610 "spec_testsuite/simd_i8x16_arith.wast",
611 "spec_testsuite/simd_i8x16_arith2.wast",
612 "spec_testsuite/simd_i8x16_cmp.wast",
613 "spec_testsuite/simd_i8x16_sat_arith.wast",
614 "spec_testsuite/simd_int_to_int_extend.wast",
615 "spec_testsuite/simd_lane.wast",
616 "spec_testsuite/simd_load.wast",
617 "spec_testsuite/simd_load16_lane.wast",
618 "spec_testsuite/simd_load32_lane.wast",
619 "spec_testsuite/simd_load64_lane.wast",
620 "spec_testsuite/simd_load8_lane.wast",
621 "spec_testsuite/simd_load_extend.wast",
622 "spec_testsuite/simd_load_splat.wast",
623 "spec_testsuite/simd_load_zero.wast",
624 "spec_testsuite/simd_select.wast",
625 "spec_testsuite/simd_splat.wast",
626 "spec_testsuite/simd_store.wast",
627 "spec_testsuite/simd_store16_lane.wast",
628 "spec_testsuite/simd_store32_lane.wast",
629 "spec_testsuite/simd_store64_lane.wast",
630 "spec_testsuite/simd_store8_lane.wast",
631 ];
632
633 if unsupported.iter().any(|part| self.path.ends_with(part)) {
634 return true;
635 }
636 }
637
638 #[cfg(target_arch = "x86_64")]
639 {
640 #[cfg(target_arch = "x86_64")]
642 if !(std::is_x86_feature_detected!("avx") && std::is_x86_feature_detected!("avx2"))
643 {
644 let unsupported = [
645 "annotations/simd_lane.wast",
646 "memory64/simd.wast",
647 "misc_testsuite/int-to-float-splat.wast",
648 "misc_testsuite/issue6562.wast",
649 "misc_testsuite/simd/almost-extmul.wast",
650 "misc_testsuite/simd/canonicalize-nan.wast",
651 "misc_testsuite/simd/cvt-from-uint.wast",
652 "misc_testsuite/simd/edge-of-memory.wast",
653 "misc_testsuite/simd/issue_3327_bnot_lowering.wast",
654 "misc_testsuite/simd/issue6725-no-egraph-panic.wast",
655 "misc_testsuite/simd/replace-lane-preserve.wast",
656 "misc_testsuite/simd/spillslot-size-fuzzbug.wast",
657 "misc_testsuite/simd/sse-cannot-fold-unaligned-loads.wast",
658 "misc_testsuite/winch/issue-10331.wast",
659 "misc_testsuite/winch/replace_lane.wast",
660 "misc_testsuite/simd/riscv64-replicated-imm5-works.wast",
661 "misc_testsuite/simd/v128-equal.wast",
662 "spec_testsuite/simd_align.wast",
663 "spec_testsuite/simd_boolean.wast",
664 "spec_testsuite/simd_conversions.wast",
665 "spec_testsuite/simd_f32x4.wast",
666 "spec_testsuite/simd_f32x4_arith.wast",
667 "spec_testsuite/simd_f32x4_cmp.wast",
668 "spec_testsuite/simd_f32x4_pmin_pmax.wast",
669 "spec_testsuite/simd_f32x4_rounding.wast",
670 "spec_testsuite/simd_f64x2.wast",
671 "spec_testsuite/simd_f64x2_arith.wast",
672 "spec_testsuite/simd_f64x2_cmp.wast",
673 "spec_testsuite/simd_f64x2_pmin_pmax.wast",
674 "spec_testsuite/simd_f64x2_rounding.wast",
675 "spec_testsuite/simd_i16x8_cmp.wast",
676 "spec_testsuite/simd_i32x4_cmp.wast",
677 "spec_testsuite/simd_i64x2_arith2.wast",
678 "spec_testsuite/simd_i64x2_cmp.wast",
679 "spec_testsuite/simd_i8x16_arith2.wast",
680 "spec_testsuite/simd_i8x16_cmp.wast",
681 "spec_testsuite/simd_int_to_int_extend.wast",
682 "spec_testsuite/simd_load.wast",
683 "spec_testsuite/simd_load_extend.wast",
684 "spec_testsuite/simd_load_splat.wast",
685 "spec_testsuite/simd_load_zero.wast",
686 "spec_testsuite/simd_splat.wast",
687 "spec_testsuite/simd_store16_lane.wast",
688 "spec_testsuite/simd_store32_lane.wast",
689 "spec_testsuite/simd_store64_lane.wast",
690 "spec_testsuite/simd_store8_lane.wast",
691 "spec_testsuite/simd_load16_lane.wast",
692 "spec_testsuite/simd_load32_lane.wast",
693 "spec_testsuite/simd_load64_lane.wast",
694 "spec_testsuite/simd_load8_lane.wast",
695 "spec_testsuite/simd_bitwise.wast",
696 "misc_testsuite/simd/load_splat_out_of_bounds.wast",
697 "misc_testsuite/simd/unaligned-load.wast",
698 "multi-memory/simd_memory-multi.wast",
699 "misc_testsuite/simd/issue4807.wast",
700 "spec_testsuite/simd_const.wast",
701 "spec_testsuite/simd_i8x16_sat_arith.wast",
702 "spec_testsuite/simd_i64x2_arith.wast",
703 "spec_testsuite/simd_i16x8_arith.wast",
704 "spec_testsuite/simd_i16x8_arith2.wast",
705 "spec_testsuite/simd_i16x8_q15mulr_sat_s.wast",
706 "spec_testsuite/simd_i16x8_sat_arith.wast",
707 "spec_testsuite/simd_i32x4_arith.wast",
708 "spec_testsuite/simd_i32x4_dot_i16x8.wast",
709 "spec_testsuite/simd_i32x4_trunc_sat_f32x4.wast",
710 "spec_testsuite/simd_i32x4_trunc_sat_f64x2.wast",
711 "spec_testsuite/simd_i8x16_arith.wast",
712 "spec_testsuite/simd_bit_shift.wast",
713 "spec_testsuite/simd_lane.wast",
714 "spec_testsuite/simd_i16x8_extmul_i8x16.wast",
715 "spec_testsuite/simd_i32x4_extmul_i16x8.wast",
716 "spec_testsuite/simd_i64x2_extmul_i32x4.wast",
717 "spec_testsuite/simd_i16x8_extadd_pairwise_i8x16.wast",
718 "spec_testsuite/simd_i32x4_extadd_pairwise_i16x8.wast",
719 "spec_testsuite/simd_i32x4_arith2.wast",
720 ];
721
722 if unsupported.iter().any(|part| self.path.ends_with(part)) {
723 return true;
724 }
725 }
726 }
727 }
728
729 if self.config.custom_descriptors() {
731 let happens_to_work =
732 ["spec_testsuite/proposals/custom-descriptors/binary-leb128.wast"];
733
734 if happens_to_work.iter().any(|part| self.path.ends_with(part)) {
735 return false;
736 }
737 return true;
738 }
739
740 false
741 }
742}
743
744fn spec_proposal_from_path(path: &Path) -> Option<&str> {
745 let mut iter = path.iter();
746 loop {
747 match iter.next()?.to_str()? {
748 "proposals" => break,
749 _ => {}
750 }
751 }
752 Some(iter.next()?.to_str()?)
753}