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