File: all.rs

package info (click to toggle)
rustc 1.85.0%2Bdfsg2-3
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 893,176 kB
  • sloc: xml: 158,127; python: 35,830; javascript: 19,497; cpp: 19,002; sh: 17,245; ansic: 13,127; asm: 4,376; makefile: 1,051; lisp: 29; perl: 29; ruby: 19; sql: 11
file content (154 lines) | stat: -rw-r--r-- 4,964 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! You can run this test suite with:
//!
//!     cargo test --test all
//!
//! An argument can be passed as well to filter, based on filename, which test
//! to run
//!
//!     cargo test --test all foo.wit

use anyhow::{bail, Context, Result};
use libtest_mimic::{Arguments, Trial};
use pretty_assertions::StrComparison;
use std::env;
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::str;
use wit_parser::*;

fn main() {
    env_logger::init();
    let tests = find_tests();

    let mut trials = Vec::new();
    for test in tests {
        let trial = Trial::test(format!("{test:?}"), move || {
            Runner {}
                .run(&test)
                .context(format!("test {:?} failed", test))
                .map_err(|e| format!("{e:?}").into())
        });
        trials.push(trial);
    }

    let mut args = Arguments::from_args();
    if cfg!(target_family = "wasm") && !cfg!(target_feature = "atomics") {
        args.test_threads = Some(1);
    }
    libtest_mimic::run(&args, trials).exit();
}

/// Recursively finds all tests in a whitelisted set of directories which we
/// then load up and test in parallel.
fn find_tests() -> Vec<PathBuf> {
    let mut tests = Vec::new();
    find_tests("tests/ui".as_ref(), &mut tests);
    find_tests("tests/ui/parse-fail".as_ref(), &mut tests);
    tests.sort();
    return tests;

    fn find_tests(path: &Path, tests: &mut Vec<PathBuf>) {
        for f in path.read_dir().unwrap() {
            let f = f.unwrap();
            let path = f.path();
            if path.file_name().unwrap().to_str().unwrap() == "parse-fail" {
                continue;
            }
            if f.file_type().unwrap().is_dir() {
                tests.push(path);
                continue;
            }

            match path.extension().and_then(|s| s.to_str()) {
                Some("md") | Some("wit") | Some("wat") | Some("wasm") => {}
                _ => continue,
            }
            tests.push(path);
        }
    }
}

struct Runner {}

impl Runner {
    fn run(&mut self, test: &Path) -> Result<()> {
        let mut resolve = Resolve::new();
        resolve.features.insert("active".to_string());
        let result = resolve.push_path(test);
        let result = if test.iter().any(|s| s == "parse-fail") {
            match result {
                Ok(_) => bail!("expected test to not parse but it did"),
                Err(mut e) => {
                    if let Some(err) = e.downcast_mut::<io::Error>() {
                        *err = io::Error::new(
                            io::ErrorKind::Other,
                            "some generic platform-agnostic error message",
                        );
                    }
                    format!("{:#}", e)
                }
            }
        } else {
            result?;
            // format json string to human readable
            let json_result = serde_json::to_string_pretty(&resolve)?;
            // "foo.wit" => "foo.wit.json"
            self.read_or_write_to_file(test, &json_result, "json")?;
            return Ok(());
        };

        // "foo.wit" => "foo.wit.result"
        // "foo.wit.md" => "foo.wit.md.result"
        self.read_or_write_to_file(test, &result, "result")?;
        return Ok(());
    }

    fn read_or_write_to_file(
        &mut self,
        test: &Path,
        result: &str,
        extension: &str,
    ) -> Result<(), anyhow::Error> {
        let result_file = if test.extension() == Some(OsStr::new("md"))
            && test
                .file_stem()
                .and_then(|path| Path::new(path).extension())
                == Some(OsStr::new("wit"))
        {
            test.with_extension(format!("md.{extension}"))
        } else {
            test.with_extension(format!("wit.{extension}"))
        };
        if env::var_os("BLESS").is_some() {
            let normalized = normalize(&result, extension);
            fs::write(&result_file, normalized)?;
        } else {
            let expected = fs::read_to_string(&result_file).context(format!(
                "failed to read test expectation file {:?}\nthis can be fixed with BLESS=1",
                result_file
            ))?;
            let expected = normalize(&expected, extension);
            let result = normalize(&result, extension);
            if expected != result {
                bail!(
                    "failed test: result is not as expected:{}",
                    StrComparison::new(&expected, &result),
                );
            }
        }
        Ok(())
    }
}

fn normalize(s: &str, extension: &str) -> String {
    let s = s.trim();
    match extension {
        // .result files have error messages with paths, so normalize Windows \ separators to /
        "result" => s.replace("\\", "/").replace("\r\n", "\n"),

        // .json files escape strings with \, so leave them alone
        _ => s.replace("\r\n", "\n"),
    }
}