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

Configure Feed

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

1use ecow::{EcoString, eco_format}; 2use hexpm::version::Version; 3 4use super::*; 5use crate::{ 6 Warning, 7 build::SourceFingerprint, 8 io::{FileSystemWriter, memory::InMemoryFileSystem}, 9 line_numbers, 10 parse::extra::ModuleExtra, 11 warning::NullWarningEmitterIO, 12}; 13 14use std::time::Duration; 15 16#[derive(Debug)] 17struct LoaderTestOutput { 18 to_compile: Vec<EcoString>, 19 cached: Vec<EcoString>, 20 warnings: Vec<Warning>, 21} 22 23const TEST_SOURCE_1: &'static str = "const x = 1"; 24const TEST_SOURCE_2: &'static str = "const x = 2"; 25 26fn write_src(fs: &InMemoryFileSystem, path: &str, seconds: u64, src: &str) { 27 let path = Utf8Path::new(path); 28 fs.write(&path, src).unwrap(); 29 fs.set_modification_time(&path, SystemTime::UNIX_EPOCH + Duration::from_secs(seconds)); 30} 31 32fn write_cache( 33 fs: &InMemoryFileSystem, 34 name: &str, 35 seconds: u64, 36 deps: Vec<(EcoString, SrcSpan)>, 37 src: &str, 38) { 39 let line_numbers = line_numbers::LineNumbers::new(src); 40 let mtime = SystemTime::UNIX_EPOCH + Duration::from_secs(seconds); 41 let cache_metadata = CacheMetadata { 42 mtime, 43 codegen_performed: true, 44 dependencies: deps, 45 fingerprint: SourceFingerprint::new(src), 46 line_numbers: line_numbers.clone(), 47 }; 48 let path = Utf8Path::new("/artefact").join(format!("{name}.cache_meta")); 49 fs.write_bytes(&path, &cache_metadata.to_binary()).unwrap(); 50 51 let cache = crate::type_::ModuleInterface { 52 name: name.into(), 53 origin: Origin::Src, 54 package: "my_package".into(), 55 types: Default::default(), 56 types_value_constructors: Default::default(), 57 values: Default::default(), 58 accessors: Default::default(), 59 line_numbers: line_numbers.clone(), 60 is_internal: false, 61 src_path: Utf8PathBuf::from(format!("/src/{}.gleam", name)), 62 warnings: vec![], 63 minimum_required_version: Version::new(0, 1, 0), 64 type_aliases: Default::default(), 65 documentation: Default::default(), 66 }; 67 let path = Utf8Path::new("/artefact").join(format!("{name}.cache")); 68 fs.write_bytes( 69 &path, 70 &metadata::ModuleEncoder::new(&cache).encode().unwrap(), 71 ) 72 .unwrap(); 73} 74 75fn run_loader(fs: InMemoryFileSystem, root: &Utf8Path, artefact: &Utf8Path) -> LoaderTestOutput { 76 let mut defined = im::HashMap::new(); 77 let ids = UniqueIdGenerator::new(); 78 let (emitter, warnings) = WarningEmitter::vector(); 79 80 let loader = PackageLoader { 81 io: fs.clone(), 82 ids, 83 mode: Mode::Dev, 84 root: &root, 85 warnings: &emitter, 86 codegen: CodegenRequired::Yes, 87 artefact_directory: &artefact, 88 package_name: &"my_package".into(), 89 target: Target::JavaScript, 90 stale_modules: &mut StaleTracker::default(), 91 already_defined_modules: &mut defined, 92 incomplete_modules: &mut HashSet::new(), 93 cached_warnings: CachedWarnings::Ignore, 94 }; 95 let loaded = loader.run().unwrap(); 96 97 LoaderTestOutput { 98 to_compile: loaded.to_compile.into_iter().map(|m| m.name).collect(), 99 cached: loaded.cached.into_iter().map(|m| m.name).collect(), 100 warnings: warnings.take(), 101 } 102} 103 104#[test] 105fn no_modules() { 106 let fs = InMemoryFileSystem::new(); 107 let root = Utf8Path::new("/"); 108 let artefact = Utf8Path::new("/artefact"); 109 110 let loaded = run_loader(fs, root, artefact); 111 assert!(loaded.to_compile.is_empty()); 112 assert!(loaded.cached.is_empty()); 113} 114 115#[test] 116fn one_src_module() { 117 let fs = InMemoryFileSystem::new(); 118 let root = Utf8Path::new("/"); 119 let artefact = Utf8Path::new("/artefact"); 120 121 write_src(&fs, "/src/main.gleam", 0, "const x = 1"); 122 123 let loaded = run_loader(fs, root, artefact); 124 assert_eq!(loaded.to_compile, vec![EcoString::from("main")]); 125 assert!(loaded.cached.is_empty()); 126} 127 128#[test] 129fn one_test_module() { 130 let fs = InMemoryFileSystem::new(); 131 let root = Utf8Path::new("/"); 132 let artefact = Utf8Path::new("/artefact"); 133 134 write_src(&fs, "/test/main.gleam", 0, "const x = 1"); 135 136 let loaded = run_loader(fs, root, artefact); 137 assert_eq!(loaded.to_compile, vec![EcoString::from("main")]); 138 assert!(loaded.cached.is_empty()); 139} 140 141#[test] 142fn importing() { 143 let fs = InMemoryFileSystem::new(); 144 let root = Utf8Path::new("/"); 145 let artefact = Utf8Path::new("/artefact"); 146 147 write_src(&fs, "/src/three.gleam", 0, "import two"); 148 write_src(&fs, "/src/one.gleam", 0, ""); 149 write_src(&fs, "/src/two.gleam", 0, "import one"); 150 151 let loaded = run_loader(fs, root, artefact); 152 assert_eq!( 153 loaded.to_compile, 154 vec![ 155 EcoString::from("one"), 156 EcoString::from("two"), 157 EcoString::from("three") 158 ] 159 ); 160 assert!(loaded.cached.is_empty()); 161} 162 163#[test] 164fn reading_cache() { 165 let fs = InMemoryFileSystem::new(); 166 let root = Utf8Path::new("/"); 167 let artefact = Utf8Path::new("/artefact"); 168 169 write_src(&fs, "/src/one.gleam", 0, TEST_SOURCE_1); 170 write_cache(&fs, "one", 0, vec![], TEST_SOURCE_1); 171 172 let loaded = run_loader(fs, root, artefact); 173 assert!(loaded.to_compile.is_empty()); 174 assert_eq!(loaded.cached, vec![EcoString::from("one")]); 175} 176 177#[test] 178fn module_is_stale_if_cache_older() { 179 let fs = InMemoryFileSystem::new(); 180 let root = Utf8Path::new("/"); 181 let artefact = Utf8Path::new("/artefact"); 182 183 write_src(&fs, "/src/one.gleam", 1, TEST_SOURCE_2); 184 write_cache(&fs, "one", 0, vec![], TEST_SOURCE_1); 185 186 let loaded = run_loader(fs, root, artefact); 187 assert_eq!(loaded.to_compile, vec![EcoString::from("one")]); 188 assert!(loaded.cached.is_empty()); 189} 190 191#[test] 192fn module_is_stale_if_deps_are_stale() { 193 let fs = InMemoryFileSystem::new(); 194 let root = Utf8Path::new("/"); 195 let artefact = Utf8Path::new("/artefact"); 196 197 // Cache is stale 198 write_src(&fs, "/src/one.gleam", 1, TEST_SOURCE_2); 199 write_cache(&fs, "one", 0, vec![], TEST_SOURCE_1); 200 201 // Cache is fresh but dep is stale 202 write_src(&fs, "/src/two.gleam", 1, "import one"); 203 write_cache( 204 &fs, 205 "two", 206 2, 207 vec![(EcoString::from("one"), SrcSpan { start: 0, end: 0 })], 208 "import one", 209 ); 210 211 // Cache is fresh 212 write_src(&fs, "/src/three.gleam", 1, TEST_SOURCE_1); 213 write_cache(&fs, "three", 2, vec![], TEST_SOURCE_1); 214 215 let loaded = run_loader(fs, root, artefact); 216 assert_eq!( 217 loaded.to_compile, 218 vec![EcoString::from("one"), EcoString::from("two")] 219 ); 220 assert_eq!(loaded.cached, vec![EcoString::from("three")]); 221} 222 223#[test] 224fn module_is_stale_if_deps_removed() { 225 let fs = InMemoryFileSystem::new(); 226 let root = Utf8Path::new("/"); 227 let artefact = Utf8Path::new("/artefact"); 228 229 // Source is removed, cache is present 230 write_cache(&fs, "one", 0, vec![], TEST_SOURCE_1); 231 232 // Cache is fresh but dep is removed 233 write_src(&fs, "/src/two.gleam", 1, "import one"); 234 write_cache( 235 &fs, 236 "two", 237 2, 238 vec![(EcoString::from("one"), SrcSpan { start: 0, end: 0 })], 239 "import one", 240 ); 241 242 let loaded = run_loader(fs, root, artefact); 243 assert_eq!(loaded.to_compile, vec![EcoString::from("two")]); 244} 245 246#[test] 247fn module_continues_to_be_stale_if_deps_get_updated() { 248 let fs = InMemoryFileSystem::new(); 249 let root = Utf8Path::new("/"); 250 let artefact = Utf8Path::new("/artefact"); 251 252 // Cache is stale 253 write_src(&fs, "/src/one.gleam", 1, TEST_SOURCE_2); 254 write_cache(&fs, "one", 0, vec![], TEST_SOURCE_1); 255 256 // Cache is fresh but dep is stale 257 write_src(&fs, "/src/two.gleam", 1, "import one"); 258 write_cache( 259 &fs, 260 "two", 261 2, 262 vec![(EcoString::from("one"), SrcSpan { start: 0, end: 0 })], 263 "import one", 264 ); 265 266 // Cache is fresh 267 write_src(&fs, "/src/three.gleam", 1, TEST_SOURCE_1); 268 write_cache(&fs, "three", 2, vec![], TEST_SOURCE_1); 269 270 let _loaded1 = run_loader(fs.clone(), root, artefact); 271 272 // update the dependency 273 write_cache(&fs, "one", 3, vec![], TEST_SOURCE_2); 274 let loaded2 = run_loader(fs, root, artefact); 275 276 assert_eq!(loaded2.to_compile, vec![EcoString::from("two")]); 277 assert_eq!( 278 loaded2.cached, 279 vec![EcoString::from("one"), EcoString::from("three")] 280 ); 281} 282 283#[test] 284fn invalid_module_name() { 285 let fs = InMemoryFileSystem::new(); 286 let root = Utf8Path::new("/"); 287 let artefact = Utf8Path::new("/artefact"); 288 289 // Cache is stale 290 write_src(&fs, "/src/One.gleam", 1, TEST_SOURCE_2); 291 292 let loaded = run_loader(fs, root, artefact); 293 assert!(loaded.to_compile.is_empty()); 294 assert!(loaded.cached.is_empty()); 295 assert_eq!( 296 loaded.warnings, 297 vec![Warning::InvalidSource { 298 path: Utf8PathBuf::from("/src/One.gleam"), 299 }], 300 ); 301} 302 303#[test] 304fn invalid_nested_module_name() { 305 let fs = InMemoryFileSystem::new(); 306 let root = Utf8Path::new("/"); 307 let artefact = Utf8Path::new("/artefact"); 308 309 // Cache is stale 310 write_src(&fs, "/src/1/one.gleam", 1, TEST_SOURCE_2); 311 312 let loaded = run_loader(fs, root, artefact); 313 assert!(loaded.to_compile.is_empty()); 314 assert!(loaded.cached.is_empty()); 315 assert_eq!( 316 loaded.warnings, 317 vec![Warning::InvalidSource { 318 path: Utf8PathBuf::from("/src/1/one.gleam"), 319 }], 320 ); 321} 322 323#[test] 324fn invalid_module_name_in_test() { 325 let fs = InMemoryFileSystem::new(); 326 let root = Utf8Path::new("/"); 327 let artefact = Utf8Path::new("/artefact"); 328 329 // Cache is stale 330 write_src(&fs, "/test/One.gleam", 1, TEST_SOURCE_2); 331 332 let loaded = run_loader(fs, root, artefact); 333 assert!(loaded.to_compile.is_empty()); 334 assert!(loaded.cached.is_empty()); 335 assert_eq!( 336 loaded.warnings, 337 vec![Warning::InvalidSource { 338 path: Utf8PathBuf::from("/test/One.gleam"), 339 }], 340 ); 341} 342 343#[test] 344fn invalid_nested_module_name_in_test() { 345 let fs = InMemoryFileSystem::new(); 346 let root = Utf8Path::new("/"); 347 let artefact = Utf8Path::new("/artefact"); 348 349 // Cache is stale 350 write_src(&fs, "/test/1/one.gleam", 1, TEST_SOURCE_2); 351 352 let loaded = run_loader(fs, root, artefact); 353 assert!(loaded.to_compile.is_empty()); 354 assert!(loaded.cached.is_empty()); 355 assert_eq!( 356 loaded.warnings, 357 vec![Warning::InvalidSource { 358 path: Utf8PathBuf::from("/test/1/one.gleam"), 359 }], 360 ); 361}