compiler/
kernel/
lib/
examples/
std/
arch/
char/
collections/
lang/
alloc/
ast/
gen/
il/
module/
printer.rad
2.8 KiB
tests.rad
12.8 KiB
parser/
resolver/
scanner/
alloc.rad
7.1 KiB
ast.rad
26.7 KiB
gen.rad
513 B
il.rad
19.5 KiB
lower.rad
308.1 KiB
module.rad
14.9 KiB
package.rad
1.3 KiB
parser.rad
89.5 KiB
resolver.rad
439.6 KiB
scanner.rad
18.0 KiB
sexpr.rad
6.4 KiB
strings.rad
2.2 KiB
types.rad
1.6 KiB
sys/
arch.rad
68 B
char.rad
855 B
collections.rad
39 B
fmt.rad
8.3 KiB
intrinsics.rad
467 B
io.rad
1.7 KiB
lang.rad
276 B
mem.rad
2.3 KiB
sys.rad
179 B
testing.rad
2.4 KiB
tests.rad
15.7 KiB
vec.rad
3.2 KiB
std.rad
281 B
scripts/
seed/
sublime/
test/
vim/
.gitignore
336 B
.gitsigners
112 B
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
9.2 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
662 B
lib/std/lang/module/tests.rad
raw
| 1 | //! Tests for the module loader. |
| 2 | |
| 3 | use std::mem; |
| 4 | use std::testing; |
| 5 | use std::lang::ast; |
| 6 | use std::lang::alloc; |
| 7 | use std::lang::parser; |
| 8 | use std::lang::scanner; |
| 9 | use std::lang::strings; |
| 10 | |
| 11 | /// Test arena backing storage. |
| 12 | static TEST_ARENA: [u8; 16384] = [0; 16384]; |
| 13 | /// Interned string pool. |
| 14 | unsafe static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
| 15 | |
| 16 | fn expectSliceEq(actual: *[u8], expected: *[u8]) |
| 17 | throws (testing::TestError) |
| 18 | { |
| 19 | if not mem::eq(actual, expected) { |
| 20 | throw testing::TestError::Failed; |
| 21 | } |
| 22 | } |
| 23 | |
| 24 | fn expectPathSegments(entry: *super::ModuleEntry, expected: *[*[u8]]) |
| 25 | throws (testing::TestError) |
| 26 | { |
| 27 | let actual = super::moduleQualifiedPath(entry); |
| 28 | try testing::expect(actual.len == expected.len); |
| 29 | for i in 0..expected.len { |
| 30 | try expectSliceEq(actual[i], expected[i]); |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | @test unsafe fn testRegisterChildren() throws (testing::TestError) { |
| 35 | static storage: [?*super::ModuleEntry; 4] = [nil; 4]; |
| 36 | let mut arena = ast::nodeArena(&mut TEST_ARENA[..]); |
| 37 | let mut graph = super::moduleGraph(&mut storage[..], &mut arena); |
| 38 | |
| 39 | let rootId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "src/root.rad") catch { |
| 40 | throw testing::TestError::Failed; |
| 41 | }; |
| 42 | let root = super::get(&graph, rootId) else { |
| 43 | throw testing::TestError::Failed; |
| 44 | }; |
| 45 | try expectPathSegments(root, &["root"]); |
| 46 | |
| 47 | // First child. |
| 48 | let firstId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "src/root/first.rad") catch { |
| 49 | throw testing::TestError::Failed; |
| 50 | }; |
| 51 | let first = super::get(&graph, firstId) else { |
| 52 | throw testing::TestError::Failed; |
| 53 | }; |
| 54 | try expectSliceEq(first.filePath, "src/root/first.rad"); |
| 55 | try expectSliceEq(first.name, "first"); |
| 56 | try expectPathSegments(first, &["root", "first"]); |
| 57 | |
| 58 | // Second child. |
| 59 | let secondId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "src/root/second.rad") catch { |
| 60 | throw testing::TestError::Failed; |
| 61 | }; |
| 62 | let second = super::get(&graph, secondId) else { |
| 63 | throw testing::TestError::Failed; |
| 64 | }; |
| 65 | try expectSliceEq(second.filePath, "src/root/second.rad"); |
| 66 | try expectSliceEq(second.name, "second"); |
| 67 | try expectPathSegments(second, &["root", "second"]); |
| 68 | |
| 69 | let parent = super::get(&graph, rootId) else { |
| 70 | throw testing::TestError::Failed; |
| 71 | }; |
| 72 | try testing::expect(graph.entriesLen == 3); |
| 73 | try testing::expect(super::childCount(parent) == 2); |
| 74 | try testing::expect(super::childAt(parent, 0) == firstId); |
| 75 | try testing::expect(super::childAt(parent, 1) == secondId); |
| 76 | } |
| 77 | |
| 78 | @test unsafe fn testRegisterChildReusesExisting() throws (testing::TestError) { |
| 79 | static storage: [?*super::ModuleEntry; 4] = [nil; 4]; |
| 80 | let mut arena = ast::nodeArena(&mut TEST_ARENA[..]); |
| 81 | let mut graph = super::moduleGraph(&mut storage[..], &mut arena); |
| 82 | |
| 83 | let rootId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "src/main.rad") catch { |
| 84 | throw testing::TestError::Failed; |
| 85 | }; |
| 86 | let firstId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "src/main/util.rad") catch { |
| 87 | throw testing::TestError::Failed; |
| 88 | }; |
| 89 | let secondId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "src/main/util.rad") catch { |
| 90 | throw testing::TestError::Failed; |
| 91 | }; |
| 92 | try testing::expect(firstId == secondId); |
| 93 | |
| 94 | let parent = super::get(&graph, rootId) else { |
| 95 | throw testing::TestError::Failed; |
| 96 | }; |
| 97 | try testing::expect(graph.entriesLen == 2); |
| 98 | try testing::expect(super::childCount(parent) == 1); |
| 99 | } |
| 100 | |
| 101 | @test fn testTrimExtensionWithRadExtension() throws (testing::TestError) { |
| 102 | let input = "parser.rad"; |
| 103 | let result = super::trimExtension(input) |
| 104 | else throw testing::TestError::Failed; |
| 105 | try expectSliceEq(result, "parser"); |
| 106 | } |
| 107 | |
| 108 | @test fn testTrimExtensionWithoutExtension() throws (testing::TestError) { |
| 109 | let input = "parser"; |
| 110 | let result = super::trimExtension(input); |
| 111 | try testing::expect(result == nil); |
| 112 | } |
| 113 | |
| 114 | @test fn testTrimExtensionWithWrongExtension() throws (testing::TestError) { |
| 115 | let input = "parser.txt"; |
| 116 | let result = super::trimExtension(input); |
| 117 | try testing::expect(result == nil); |
| 118 | } |
| 119 | |
| 120 | @test fn testParsePathSingleComponent() throws (testing::TestError) { |
| 121 | let path = "std.rad"; |
| 122 | let mut components: [*[u8]; 8] = [""; 8]; |
| 123 | let count = super::parsePath(path, &mut components[..]) else { |
| 124 | throw testing::TestError::Failed; |
| 125 | }; |
| 126 | try testing::expect(count == 1); |
| 127 | try expectSliceEq(components[0], "std"); |
| 128 | } |
| 129 | |
| 130 | @test fn testParsePathMultipleComponents() throws (testing::TestError) { |
| 131 | let path = "std/lang/parser.rad"; |
| 132 | let mut components: [*[u8]; 8] = [""; 8]; |
| 133 | let count = super::parsePath(path, &mut components[..]) else { |
| 134 | throw testing::TestError::Failed; |
| 135 | }; |
| 136 | try testing::expect(count == 3); |
| 137 | try expectSliceEq(components[0], "std"); |
| 138 | try expectSliceEq(components[1], "lang"); |
| 139 | try expectSliceEq(components[2], "parser"); |
| 140 | } |
| 141 | |
| 142 | @test fn testParsePathWithoutExtension() throws (testing::TestError) { |
| 143 | let path = "std/lang/parser"; |
| 144 | let mut components: [*[u8]; 8] = [""; 8]; |
| 145 | let result = super::parsePath(path, &mut components[..]); |
| 146 | try testing::expect(result == nil); |
| 147 | } |
| 148 | |
| 149 | @test unsafe fn testRegisterFromPathHierarchy() throws (testing::TestError) { |
| 150 | static storage: [?*super::ModuleEntry; 8] = [nil; 8]; |
| 151 | let mut arena = ast::nodeArena(&mut TEST_ARENA[..]); |
| 152 | let mut graph = super::moduleGraph(&mut storage[..], &mut arena); |
| 153 | |
| 154 | // Register root module. |
| 155 | let stdId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "lib/std.rad") catch { |
| 156 | throw testing::TestError::Failed; |
| 157 | }; |
| 158 | let std = super::get(&graph, stdId) else { |
| 159 | throw testing::TestError::Failed; |
| 160 | }; |
| 161 | try expectSliceEq(std.filePath, "lib/std.rad"); |
| 162 | try expectSliceEq(super::moduleDir(std), "lib/"); |
| 163 | try expectPathSegments(std, &["std"]); |
| 164 | |
| 165 | // Register child of root. |
| 166 | let langId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, stdId, "lib/std/lang.rad") catch { |
| 167 | throw testing::TestError::Failed; |
| 168 | }; |
| 169 | let lang = super::get(&graph, langId) else { |
| 170 | throw testing::TestError::Failed; |
| 171 | }; |
| 172 | try expectSliceEq(lang.filePath, "lib/std/lang.rad"); |
| 173 | try expectSliceEq(lang.name, "lang"); |
| 174 | try expectSliceEq(super::moduleDir(lang), "lib/std/"); |
| 175 | try expectPathSegments(lang, &["std", "lang"]); |
| 176 | |
| 177 | // Register grandchild. |
| 178 | let parserId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, stdId, "lib/std/lang/parser.rad") catch { |
| 179 | throw testing::TestError::Failed; |
| 180 | }; |
| 181 | let parser = super::get(&graph, parserId) else { |
| 182 | throw testing::TestError::Failed; |
| 183 | }; |
| 184 | try expectSliceEq(parser.filePath, "lib/std/lang/parser.rad"); |
| 185 | try expectSliceEq(parser.name, "parser"); |
| 186 | try expectSliceEq(super::moduleDir(parser), "lib/std/lang/"); |
| 187 | try expectPathSegments(parser, &["std", "lang", "parser"]); |
| 188 | |
| 189 | // Verify parent-child relationships. |
| 190 | try testing::expect(graph.entriesLen == 3); |
| 191 | try testing::expect(super::childCount(std) == 1); |
| 192 | try testing::expect(super::childAt(std, 0) == langId); |
| 193 | try testing::expect(super::childCount(lang) == 1); |
| 194 | try testing::expect(super::childAt(lang, 0) == parserId); |
| 195 | try testing::expect(super::childCount(parser) == 0); |
| 196 | } |
| 197 | |
| 198 | @test unsafe fn testRegisterFromPathMissingParent() throws (testing::TestError) { |
| 199 | static storage: [?*super::ModuleEntry; 8] = [nil; 8]; |
| 200 | let mut arena = ast::nodeArena(&mut TEST_ARENA[..]); |
| 201 | let mut graph = super::moduleGraph(&mut storage[..], &mut arena); |
| 202 | |
| 203 | let rootId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "std.rad") catch { |
| 204 | throw testing::TestError::Failed; |
| 205 | }; |
| 206 | let _ = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "std/lang/parser.rad") catch { |
| 207 | // Expected to fail due to missing intermediate parent. |
| 208 | return; |
| 209 | }; |
| 210 | throw testing::TestError::Failed; |
| 211 | } |
| 212 | |
| 213 | @test unsafe fn testRegisterFromPathDuplicateRoot() throws (testing::TestError) { |
| 214 | static storage: [?*super::ModuleEntry; 8] = [nil; 8]; |
| 215 | let mut arena = ast::nodeArena(&mut TEST_ARENA[..]); |
| 216 | let mut graph = super::moduleGraph(&mut storage[..], &mut arena); |
| 217 | |
| 218 | let rootId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "std.rad") catch { |
| 219 | throw testing::TestError::Failed; |
| 220 | }; |
| 221 | let _ = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "parser.rad") catch { |
| 222 | // Expected to fail due to missing intermediate parent. |
| 223 | return; |
| 224 | }; |
| 225 | throw testing::TestError::Failed; |
| 226 | } |
| 227 | |
| 228 | @test unsafe fn testRegisterFromPathRegistersRoot() throws (testing::TestError) { |
| 229 | static storage: [?*super::ModuleEntry; 8] = [nil; 8]; |
| 230 | let mut arena = ast::nodeArena(&mut TEST_ARENA[..]); |
| 231 | let mut graph = super::moduleGraph(&mut storage[..], &mut arena); |
| 232 | |
| 233 | let rootId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "lib/std.rad") catch { |
| 234 | throw testing::TestError::Failed; |
| 235 | }; |
| 236 | // Verify root module was registered with correct ID. |
| 237 | try testing::expect(rootId == 0); |
| 238 | |
| 239 | let root = super::get(&graph, rootId) else { |
| 240 | throw testing::TestError::Failed; |
| 241 | }; |
| 242 | try expectSliceEq(root.name, "std"); |
| 243 | try expectSliceEq(root.filePath, "lib/std.rad"); |
| 244 | try expectPathSegments(root, &["std"]); |
| 245 | } |
| 246 | |
| 247 | @test unsafe fn testRegisterFromPathIgnoresLeadingDirectories() throws (testing::TestError) { |
| 248 | static storage: [?*super::ModuleEntry; 8] = [nil; 8]; |
| 249 | let mut arena = ast::nodeArena(&mut TEST_ARENA[..]); |
| 250 | let mut graph = super::moduleGraph(&mut storage[..], &mut arena); |
| 251 | |
| 252 | let rootId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "src/pkg/root.rad") catch { |
| 253 | throw testing::TestError::Failed; |
| 254 | }; |
| 255 | // Verify root module was registered with correct ID. |
| 256 | try testing::expect(rootId == 0); |
| 257 | |
| 258 | let langId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "src/pkg/root/lang.rad") catch { |
| 259 | throw testing::TestError::Failed; |
| 260 | }; |
| 261 | let lang = super::get(&graph, langId) else { |
| 262 | throw testing::TestError::Failed; |
| 263 | }; |
| 264 | try expectSliceEq(lang.name, "lang"); |
| 265 | try expectPathSegments(lang, &["root", "lang"]); |
| 266 | |
| 267 | let parserId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "src/pkg/root/lang/parser.rad") catch { |
| 268 | throw testing::TestError::Failed; |
| 269 | }; |
| 270 | let parser = super::get(&graph, parserId) else { |
| 271 | throw testing::TestError::Failed; |
| 272 | }; |
| 273 | try expectSliceEq(parser.name, "parser"); |
| 274 | try expectPathSegments(parser, &["root", "lang", "parser"]); |
| 275 | } |
| 276 | /// Move the graph owner while its published entries retain their identities. |
| 277 | fn relocate(graph: super::ModuleGraph) -> super::ModuleGraph { |
| 278 | return graph; |
| 279 | } |
| 280 | @test unsafe fn testGraphRelocation() throws (testing::TestError) { |
| 281 | static DATA: [u8; 16384] = [0; 16384]; |
| 282 | static ENTRIES: [?*super::ModuleEntry; 2] = [nil; 2]; |
| 283 | static POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
| 284 | let mut arena = ast::nodeArena(&mut DATA[..]); |
| 285 | let mut original = super::moduleGraph(&mut ENTRIES[..], &mut arena); |
| 286 | let rootId = try! super::registerRoot(&mut original, &mut POOL, 0, "root.rad"); |
| 287 | let root = super::get(&original, rootId) else panic; |
| 288 | let alias = root; |
| 289 | let mut graph = relocate(original); |
| 290 | let child = try! super::registerChild(&mut graph, &mut POOL, rootId, "child", "root/child.rad"); |
| 291 | try testing::expect(super::childCount(root) == 1); |
| 292 | try testing::expect(super::childAt(alias, 0) == child); |
| 293 | let published = super::get(&graph, rootId) else panic; |
| 294 | try testing::expect(published as u64 == root as u64); |
| 295 | let saved = alloc::used(&arena.arena); |
| 296 | let reused = try! super::registerChild(&mut graph, &mut POOL, rootId, "child", "root/child.rad"); |
| 297 | try testing::expect(reused == child); |
| 298 | try testing::expect(alloc::used(&arena.arena) == saved); |
| 299 | let mut failed = false; |
| 300 | try super::registerChild(&mut graph, &mut POOL, rootId, "full", "root/full.rad") catch { |
| 301 | set failed = true; |
| 302 | }; |
| 303 | try testing::expect(failed); |
| 304 | try testing::expect(graph.entriesLen == 2); |
| 305 | try testing::expect(super::childCount(alias) == 1); |
| 306 | try testing::expect(alloc::used(&arena.arena) == saved); |
| 307 | let source = "fn answer() -> u32 { return 42; }"; |
| 308 | let parsed: *ast::Node = try! parser::parse(scanner::SourceLoc::String, source, &mut arena, &mut POOL); |
| 309 | try! super::setAst(&mut graph, rootId, parsed); |
| 310 | try! super::setSource(&mut graph, rootId, source); |
| 311 | let retainedAst = super::astFor(alias) else panic; |
| 312 | try testing::expect(retainedAst as u64 == parsed as u64); |
| 313 | let retainedSource = super::sourceFor(root) else panic; |
| 314 | try testing::expect(mem::eq(retainedSource, source)); |
| 315 | try testing::expect(try! super::state(&graph, rootId) == super::ModuleState::Parsed); |
| 316 | |
| 317 | } |