Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

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