Fork of daniellemaywood.uk/gleam — Wasm codegen work
3.8 kB
108 lines
1use camino::{Utf8Path, Utf8PathBuf};
2use gleam_core::{
3 io::{Content, FileSystemWriter, memory::InMemoryFileSystem},
4 version::COMPILER_VERSION,
5};
6use itertools::Itertools;
7use regex::Regex;
8use std::{collections::HashMap, fmt::Write, sync::LazyLock};
9
10#[derive(Debug)]
11pub struct TestCompileOutput {
12 pub files: HashMap<Utf8PathBuf, Content>,
13 pub warnings: Vec<gleam_core::Warning>,
14}
15
16impl TestCompileOutput {
17 pub fn as_overview_text(&self) -> String {
18 let mut buffer = String::new();
19 for (path, content) in self.files.iter().sorted_by(|a, b| a.0.cmp(b.0)) {
20 let normalised_path = if path.as_str().contains("cases") {
21 path.as_str()
22 .split("cases")
23 .skip(1)
24 .collect::<String>()
25 .as_str()
26 .replace('\\', "/")
27 .split('/')
28 .skip(1)
29 .join("/")
30 } else {
31 path.as_str().replace('\\', "/")
32 };
33 buffer.push_str("//// ");
34 buffer.push_str(&normalised_path);
35 buffer.push('\n');
36
37 let extension = path.extension();
38 match content {
39 _ if extension == Some("cache") => buffer.push_str("<.cache binary>"),
40 Content::Binary(data) => write!(buffer, "<{} byte binary>", data.len()).unwrap(),
41
42 Content::Text(_) if normalised_path.ends_with("@@main.erl") => {
43 write!(buffer, "<erlang entrypoint>").unwrap()
44 }
45
46 Content::Text(text) => {
47 let text = FILE_LINE_REGEX
48 .replace_all(text, |caps: ®ex::Captures| {
49 let path = caps
50 .get(1)
51 .expect("file path")
52 .as_str()
53 .replace("\\\\", "/");
54 let line_number = caps.get(2).expect("line number").as_str();
55 format!("-file(\"{path}\", {line_number}).")
56 })
57 .replace(COMPILER_VERSION, "<gleam compiler version string>");
58 buffer.push_str(&text)
59 }
60 };
61 buffer.push('\n');
62 buffer.push('\n');
63 }
64
65 for warning in self.warnings.iter().map(|w| w.to_pretty_string()).sorted() {
66 write!(buffer, "//// Warning\n{}", normalise_diagnostic(&warning)).unwrap();
67 buffer.push('\n');
68 buffer.push('\n');
69 }
70
71 buffer
72 }
73}
74
75pub fn to_in_memory_filesystem(path: &Utf8Path) -> InMemoryFileSystem {
76 let fs = InMemoryFileSystem::new();
77
78 let files = walkdir::WalkDir::new(path)
79 .follow_links(true)
80 .into_iter()
81 .filter_map(Result::ok)
82 .filter(|entry| entry.file_type().is_file())
83 .map(|entry| entry.into_path());
84
85 for fullpath in files {
86 let content = std::fs::read(&fullpath).unwrap();
87 let path = fullpath.strip_prefix(path).unwrap();
88 fs.write_bytes(Utf8Path::from_path(path).unwrap(), &content)
89 .unwrap();
90 }
91
92 fs
93}
94
95static FILE_LINE_REGEX: LazyLock<Regex> =
96 LazyLock::new(|| Regex::new(r#"-file\("([^"]+)", (\d+)\)\."#).expect("Invalid regex"));
97
98pub fn normalise_diagnostic(text: &str) -> String {
99 // There is an extra ^ on Windows in some error messages' code
100 // snippets.
101 // I've not managed to determine why this is yet (it is especially
102 // tricky without a Windows computer) so for now we just squash them
103 // in these cross-platform tests.
104 Regex::new(r"\^+")
105 .expect("^ sequence regex")
106 .replace_all(text, "^")
107 .replace('\\', "/")
108}