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

Configure Feed

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

Metaprogramming test cases

+193 -8
+11
Cargo.lock
··· 1945 1945 ] 1946 1946 1947 1947 [[package]] 1948 + name = "test-package-compiler" 1949 + version = "0.25.3" 1950 + dependencies = [ 1951 + "gleam-core", 1952 + "im", 1953 + "insta", 1954 + "itertools", 1955 + "toml", 1956 + ] 1957 + 1958 + [[package]] 1948 1959 name = "textwrap" 1949 1960 version = "0.15.0" 1950 1961 source = "registry+https://github.com/rust-lang/crates.io-index"
+1
Cargo.toml
··· 3 3 "compiler-cli", 4 4 "compiler-core", 5 5 "compiler-wasm", 6 + "test-package-compiler", 6 7 ]
+1 -1
compiler-core/src/build.rs
··· 69 69 70 70 #[derive(Debug)] 71 71 pub struct ErlangAppCodegenConfiguration { 72 - include_dev_deps: bool, 72 + pub include_dev_deps: bool, 73 73 } 74 74 75 75 #[derive(
+2 -1
compiler-core/src/build/package_compilation_tests.rs
··· 70 70 }; 71 71 } 72 72 73 + // TODO: move this to a test helper crate 73 74 #[derive(Debug)] 74 - struct TestCompileOutput { 75 + pub struct TestCompileOutput { 75 76 files: HashMap<PathBuf, Content>, 76 77 warnings: Vec<crate::Warning>, 77 78 }
+1 -4
compiler-core/src/build/package_compiler.rs
··· 36 36 pub root: &'a Path, 37 37 pub target: &'a TargetCodegenConfiguration, 38 38 pub config: &'a PackageConfig, 39 + // TODO: remove this. Tests can use the in memory filesystem instead 39 40 pub sources: Vec<Source>, 40 41 pub ids: UniqueIdGenerator, 41 42 pub write_metadata: bool, ··· 47 48 pub build_journal: Option<&'a mut HashSet<PathBuf>>, 48 49 } 49 50 50 - // TODO: ensure this is not a duplicate module 51 - // TODO: tests 52 - // Including cases for: 53 - // - modules that don't import anything 54 51 impl<'a, IO> PackageCompiler<'a, IO> 55 52 where 56 53 IO: FileSystemIO + CommandExecutor + Clone,
+3 -2
compiler-core/src/io/memory.rs
··· 1 + use itertools::Itertools; 2 + 1 3 use super::*; 2 4 use std::{cell::RefCell, collections::HashMap, ffi::OsStr, rc::Rc}; 3 5 ··· 34 36 .into_inner() 35 37 .into_iter() 36 38 .map(|(path, file)| (path, file.into_content())) 39 + .sorted_by(|a, b| a.0.cmp(&b.0)) 37 40 .collect() 38 41 } 39 42 } ··· 200 203 } 201 204 } 202 205 203 - // In tests the in memory file system can also be used as a command executor. 204 - #[cfg(test)] 205 206 impl CommandExecutor for InMemoryFileSystem { 206 207 fn exec( 207 208 &self,
+19
test-package-compiler/Cargo.toml
··· 1 + [package] 2 + name = "test-package-compiler" 3 + version = "0.25.3" 4 + authors = ["Louis Pilfold <louis@lpil.uk>"] 5 + edition = "2021" 6 + license-file = "LICENCE" 7 + 8 + [dependencies] 9 + gleam-core = { path = "../compiler-core" } 10 + # toml config file parsing 11 + toml = "0.5.8" 12 + # Immutable data structures 13 + im = "15.1.0" 14 + # Extra iter methods 15 + itertools = "0.10.1" 16 + 17 + [dev-dependencies] 18 + # Snapshot testing to make test maintenance easier 19 + insta = "1.8.0"
+31
test-package-compiler/build.rs
··· 1 + use std::path::PathBuf; 2 + 3 + pub fn main() { 4 + let mut module = String::new(); 5 + 6 + let cases = PathBuf::from("./cases") 7 + .canonicalize() 8 + .unwrap() 9 + .parent() 10 + .unwrap() 11 + .to_path_buf() 12 + .join("cases"); 13 + 14 + for entry in std::fs::read_dir(&cases).unwrap() { 15 + let name = entry.unwrap().file_name().into_string().unwrap(); 16 + let path = cases.join(&name); 17 + let path = path.to_str().unwrap(); 18 + module.push_str(&format!( 19 + r#"#[test] 20 + fn {name}() {{ 21 + let output = crate::prepare("{path}"); 22 + insta::assert_snapshot!(insta::internals::AutoName, output, "{path}"); 23 + }} 24 + 25 + "# 26 + )); 27 + } 28 + 29 + let out = PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("tests.rs"); 30 + std::fs::write(out, module).unwrap(); 31 + }
+2
test-package-compiler/cases/hello_joe/gleam.toml
··· 1 + name = "hello_joe" 2 + version = "0.1.0"
+3
test-package-compiler/cases/hello_joe/src/hello_joe.gleam
··· 1 + pub fn main() { 2 + "Hello, Joe!" 3 + }
+119
test-package-compiler/src/lib.rs
··· 1 + // TODO: move TestCompileOutput to a test helper crate 2 + 3 + use gleam_core::{ 4 + build::{ 5 + package_compiler::Source, ErlangAppCodegenConfiguration, Target, TargetCodegenConfiguration, 6 + }, 7 + config::PackageConfig, 8 + io::Content, 9 + }; 10 + use itertools::Itertools; 11 + use std::{ 12 + collections::{HashMap, HashSet}, 13 + fmt::Write, 14 + path::PathBuf, 15 + }; 16 + 17 + pub fn prepare(path: &str) -> String { 18 + let path = PathBuf::from(path); 19 + 20 + let toml = std::fs::read_to_string(path.join("gleam.toml")).unwrap(); 21 + let config: PackageConfig = toml::from_str(&toml).unwrap(); 22 + 23 + let sources = path 24 + .join("src") 25 + .read_dir() 26 + .unwrap() 27 + .map(|entry| { 28 + let entry = entry.unwrap(); 29 + let localpath = entry.path(); 30 + let filename = localpath.file_name().unwrap(); 31 + let path = PathBuf::from("src").join(filename); 32 + let name = localpath.file_stem().unwrap().to_string_lossy().to_string(); 33 + Source { 34 + code: std::fs::read_to_string(entry.path()).unwrap(), 35 + origin: gleam_core::build::Origin::Src, 36 + path, 37 + name, 38 + } 39 + }) 40 + .collect(); 41 + 42 + let target = match config.target { 43 + Target::Erlang => TargetCodegenConfiguration::Erlang { 44 + app_file: Some(ErlangAppCodegenConfiguration { 45 + include_dev_deps: false, 46 + }), 47 + }, 48 + Target::JavaScript => TargetCodegenConfiguration::JavaScript { 49 + emit_typescript_definitions: false, 50 + }, 51 + }; 52 + 53 + let ids = gleam_core::uid::UniqueIdGenerator::new(); 54 + let mut modules = im::HashMap::new(); 55 + let mut warnings = Vec::new(); 56 + let filesystem = gleam_core::io::memory::InMemoryFileSystem::new(); 57 + let root = PathBuf::from("/"); 58 + let out = PathBuf::from("/out/lib/the_package"); 59 + let lib = PathBuf::from("/out/lib"); 60 + let mut build_journal = HashSet::new(); 61 + let mut compiler = gleam_core::build::PackageCompiler::new( 62 + &config, 63 + &root, 64 + &out, 65 + &lib, 66 + &target, 67 + ids, 68 + filesystem.clone(), 69 + Some(&mut build_journal), 70 + ); 71 + compiler.write_entrypoint = false; 72 + compiler.write_metadata = false; 73 + compiler.compile_beam_bytecode = false; 74 + compiler.copy_native_files = false; 75 + compiler.sources = sources; 76 + compiler 77 + .compile(&mut warnings, &mut modules, &mut im::HashMap::new()) 78 + .unwrap(); 79 + let files = filesystem.into_contents(); 80 + TestCompileOutput { files, warnings }.as_overview_text() 81 + } 82 + 83 + // TODO: move this to a test helper crate 84 + #[derive(Debug)] 85 + pub struct TestCompileOutput { 86 + files: HashMap<PathBuf, Content>, 87 + warnings: Vec<gleam_core::Warning>, 88 + } 89 + 90 + impl TestCompileOutput { 91 + pub fn as_overview_text(&self) -> String { 92 + let mut buffer = String::new(); 93 + for (path, content) in self.files.iter().sorted_by(|a, b| a.0.cmp(&b.0)) { 94 + buffer.push_str("//// "); 95 + buffer.push_str(path.to_str().unwrap()); 96 + buffer.push('\n'); 97 + 98 + match content { 99 + Content::Text(text) => buffer.push_str(&text), 100 + Content::Binary(data) => write!(buffer, "{:#?}", data).unwrap(), 101 + }; 102 + buffer.push('\n'); 103 + buffer.push('\n'); 104 + } 105 + 106 + for warning in self.warnings.iter() { 107 + write!(buffer, "{:#?}", warning).unwrap(); 108 + buffer.push('\n'); 109 + buffer.push('\n'); 110 + } 111 + 112 + buffer 113 + } 114 + } 115 + 116 + #[cfg(test)] 117 + mod tests { 118 + include!(concat!(env!("OUT_DIR"), "/tests.rs")); 119 + }