lib/std/lang/module/tests.rad 15.3 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 owner = super::Permission {};
56
    let permission: 'permission = &mut owner in {
57
        let mut graph = super::moduleGraph(&mut storage[..], &mut arena, permission);
58
59
        let rootId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "src/root.rad") catch {
60
            throw testing::TestError::Failed;
61
        };
62
        let root = super::get(&graph, rootId) else {
63
            throw testing::TestError::Failed;
64
        };
65
        try expectPathSegments(root, &["root"]);
66
67
        // First child.
68
        let firstId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "src/root/first.rad") catch {
69
            throw testing::TestError::Failed;
70
        };
71
        let first = super::get(&graph, firstId) else {
72
            throw testing::TestError::Failed;
73
        };
74
        try expectSliceEq(first.filePath, "src/root/first.rad");
75
        try expectSliceEq(first.name, "first");
76
        try expectPathSegments(first, &["root", "first"]);
77
78
        // Second child.
79
        let secondId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "src/root/second.rad") catch {
80
            throw testing::TestError::Failed;
81
        };
82
        let second = super::get(&graph, secondId) else {
83
            throw testing::TestError::Failed;
84
        };
85
        try expectSliceEq(second.filePath, "src/root/second.rad");
86
        try expectSliceEq(second.name, "second");
87
        try expectPathSegments(second, &["root", "second"]);
88
89
        let parent = super::get(&graph, rootId) else {
90
            throw testing::TestError::Failed;
91
        };
92
        try testing::expect(super::entryCount(&graph) == 3);
93
        try testing::expect(super::childCount(&graph, parent) == 2);
94
        try testing::expect(super::childAt(&graph, parent, 0) == firstId);
95
        try testing::expect(super::childAt(&graph, parent, 1) == secondId);
96
    }
97
}
98
99
@test unsafe fn testRegisterChildReusesExisting() throws (testing::TestError) {
100
    static storage: [?*super::ModuleEntry; 4] = [nil; 4];
101
    let mut arena = ast::nodeArena(&mut TEST_ARENA[..]);
102
    let mut owner = super::Permission {};
103
    let permission: 'permission = &mut owner in {
104
        let mut graph = super::moduleGraph(&mut storage[..], &mut arena, permission);
105
106
        let rootId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "src/main.rad") catch {
107
            throw testing::TestError::Failed;
108
        };
109
        let firstId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "src/main/util.rad") catch {
110
            throw testing::TestError::Failed;
111
        };
112
        let secondId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "src/main/util.rad") catch {
113
            throw testing::TestError::Failed;
114
        };
115
        try testing::expect(firstId == secondId);
116
117
        let parent = super::get(&graph, rootId) else {
118
            throw testing::TestError::Failed;
119
        };
120
        try testing::expect(super::entryCount(&graph) == 2);
121
        try testing::expect(super::childCount(&graph, parent) == 1);
122
    }
123
}
124
125
@test fn testTrimExtensionWithRadExtension() throws (testing::TestError) {
126
    let input = "parser.rad";
127
    let result = super::trimExtension(input)
128
        else throw testing::TestError::Failed;
129
    try expectSliceEq(result, "parser");
130
}
131
132
@test fn testTrimExtensionWithoutExtension() throws (testing::TestError) {
133
    let input = "parser";
134
    let result = super::trimExtension(input);
135
    try testing::expect(result == nil);
136
}
137
138
@test fn testTrimExtensionWithWrongExtension() throws (testing::TestError) {
139
    let input = "parser.txt";
140
    let result = super::trimExtension(input);
141
    try testing::expect(result == nil);
142
}
143
144
@test fn testParsePathSingleComponent() throws (testing::TestError) {
145
    let path = "std.rad";
146
    let mut components: [*[u8]; 8] = [""; 8];
147
    let count = super::parsePath(path, &mut components[..]) else {
148
        throw testing::TestError::Failed;
149
    };
150
    try testing::expect(count == 1);
151
    try expectSliceEq(components[0], "std");
152
}
153
154
@test fn testParsePathMultipleComponents() throws (testing::TestError) {
155
    let path = "std/lang/parser.rad";
156
    let mut components: [*[u8]; 8] = [""; 8];
157
    let count = super::parsePath(path, &mut components[..]) else {
158
        throw testing::TestError::Failed;
159
    };
160
    try testing::expect(count == 3);
161
    try expectSliceEq(components[0], "std");
162
    try expectSliceEq(components[1], "lang");
163
    try expectSliceEq(components[2], "parser");
164
}
165
166
@test fn testParsePathWithoutExtension() throws (testing::TestError) {
167
    let path = "std/lang/parser";
168
    let mut components: [*[u8]; 8] = [""; 8];
169
    let result = super::parsePath(path, &mut components[..]);
170
    try testing::expect(result == nil);
171
}
172
173
@test unsafe fn testRegisterFromPathHierarchy() throws (testing::TestError) {
174
    static storage: [?*super::ModuleEntry; 8] = [nil; 8];
175
    let mut arena = ast::nodeArena(&mut TEST_ARENA[..]);
176
    let mut owner = super::Permission {};
177
    let permission: 'permission = &mut owner in {
178
        let mut graph = super::moduleGraph(&mut storage[..], &mut arena, permission);
179
180
        // Register root module.
181
        let stdId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "lib/std.rad") catch {
182
            throw testing::TestError::Failed;
183
        };
184
        let std = super::get(&graph, stdId) else {
185
            throw testing::TestError::Failed;
186
        };
187
        try expectSliceEq(std.filePath, "lib/std.rad");
188
        try expectSliceEq(super::moduleDir(std), "lib/");
189
        try expectPathSegments(std, &["std"]);
190
191
        // Register child of root.
192
        let langId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, stdId, "lib/std/lang.rad") catch {
193
            throw testing::TestError::Failed;
194
        };
195
        let lang = super::get(&graph, langId) else {
196
            throw testing::TestError::Failed;
197
        };
198
        try expectSliceEq(lang.filePath, "lib/std/lang.rad");
199
        try expectSliceEq(lang.name, "lang");
200
        try expectSliceEq(super::moduleDir(lang), "lib/std/");
201
        try expectPathSegments(lang, &["std", "lang"]);
202
203
        // Register grandchild.
204
        let parserId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, stdId, "lib/std/lang/parser.rad") catch {
205
            throw testing::TestError::Failed;
206
        };
207
        let parser = super::get(&graph, parserId) else {
208
            throw testing::TestError::Failed;
209
        };
210
        try expectSliceEq(parser.filePath, "lib/std/lang/parser.rad");
211
        try expectSliceEq(parser.name, "parser");
212
        try expectSliceEq(super::moduleDir(parser), "lib/std/lang/");
213
        try expectPathSegments(parser, &["std", "lang", "parser"]);
214
215
        // Verify parent-child relationships.
216
        try testing::expect(super::entryCount(&graph) == 3);
217
        try testing::expect(super::childCount(&graph, std) == 1);
218
        try testing::expect(super::childAt(&graph, std, 0) == langId);
219
        try testing::expect(super::childCount(&graph, lang) == 1);
220
        try testing::expect(super::childAt(&graph, lang, 0) == parserId);
221
        try testing::expect(super::childCount(&graph, parser) == 0);
222
    }
223
}
224
225
@test unsafe fn testRegisterFromPathMissingParent() throws (testing::TestError) {
226
    static storage: [?*super::ModuleEntry; 8] = [nil; 8];
227
    let mut arena = ast::nodeArena(&mut TEST_ARENA[..]);
228
    let mut owner = super::Permission {};
229
    let permission: 'permission = &mut owner in {
230
        let mut graph = super::moduleGraph(&mut storage[..], &mut arena, permission);
231
232
        let rootId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "std.rad") catch {
233
            throw testing::TestError::Failed;
234
        };
235
        let _ = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "std/lang/parser.rad") catch {
236
            // Expected to fail due to missing intermediate parent.
237
            return;
238
        };
239
        throw testing::TestError::Failed;
240
    }
241
}
242
243
@test unsafe fn testRegisterFromPathDuplicateRoot() throws (testing::TestError) {
244
    static storage: [?*super::ModuleEntry; 8] = [nil; 8];
245
    let mut arena = ast::nodeArena(&mut TEST_ARENA[..]);
246
    let mut owner = super::Permission {};
247
    let permission: 'permission = &mut owner in {
248
        let mut graph = super::moduleGraph(&mut storage[..], &mut arena, permission);
249
250
        let rootId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "std.rad") catch {
251
            throw testing::TestError::Failed;
252
        };
253
        let _ = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "parser.rad") catch {
254
            // Expected to fail due to missing intermediate parent.
255
            return;
256
        };
257
        throw testing::TestError::Failed;
258
    }
259
}
260
261
@test unsafe fn testRegisterFromPathRegistersRoot() throws (testing::TestError) {
262
    static storage: [?*super::ModuleEntry; 8] = [nil; 8];
263
    let mut arena = ast::nodeArena(&mut TEST_ARENA[..]);
264
    let mut owner = super::Permission {};
265
    let permission: 'permission = &mut owner in {
266
        let mut graph = super::moduleGraph(&mut storage[..], &mut arena, permission);
267
268
        let rootId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "lib/std.rad") catch {
269
            throw testing::TestError::Failed;
270
        };
271
        // Verify root module was registered with correct ID.
272
        try testing::expect(rootId == 0);
273
274
        let root = super::get(&graph, rootId) else {
275
            throw testing::TestError::Failed;
276
        };
277
        try expectSliceEq(root.name, "std");
278
        try expectSliceEq(root.filePath, "lib/std.rad");
279
        try expectPathSegments(root, &["std"]);
280
    }
281
}
282
283
@test unsafe fn testRegisterFromPathIgnoresLeadingDirectories() throws (testing::TestError) {
284
    static storage: [?*super::ModuleEntry; 8] = [nil; 8];
285
    let mut arena = ast::nodeArena(&mut TEST_ARENA[..]);
286
    let mut owner = super::Permission {};
287
    let permission: 'permission = &mut owner in {
288
        let mut graph = super::moduleGraph(&mut storage[..], &mut arena, permission);
289
290
        let rootId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, nil, "src/pkg/root.rad") catch {
291
            throw testing::TestError::Failed;
292
        };
293
        // Verify root module was registered with correct ID.
294
        try testing::expect(rootId == 0);
295
296
        let langId = try super::registerFromPath(&mut graph, &mut STRING_POOL, 0, rootId, "src/pkg/root/lang.rad") catch {
297
            throw testing::TestError::Failed;
298
        };
299
        let lang = super::get(&graph, langId) else {
300
            throw testing::TestError::Failed;
301
        };
302
        try expectSliceEq(lang.name, "lang");
303
        try expectPathSegments(lang, &["root", "lang"]);
304
305
        let parserId = try super::registerFromPath(
306
            &mut graph, &mut STRING_POOL, 0, rootId, "src/pkg/root/lang/parser.rad"
307
        ) catch {
308
            throw testing::TestError::Failed;
309
        };
310
        let parser = super::get(&graph, parserId) else {
311
            throw testing::TestError::Failed;
312
        };
313
        try expectSliceEq(parser.name, "parser");
314
        try expectPathSegments(parser, &["root", "lang", "parser"]);
315
    }
316
}
317
318
/// Move the graph owner while its published entries retain their identities.
319
fn relocate 'permission (
320
    graph: super::ModuleGraph 'permission
321
) -> super::ModuleGraph 'permission {
322
    return graph;
323
}
324
325
@test unsafe fn testGraphRelocation() throws (testing::TestError) {
326
    static DATA: [u8; 16384] = [0; 16384];
327
    static ENTRIES: [?*super::ModuleEntry; 2] = [nil; 2];
328
    static POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };
329
    let mut arena = ast::nodeArena(&mut DATA[..]);
330
    let mut owner = super::Permission {};
331
    let permission: 'permission = &mut owner in {
332
        let mut original = super::moduleGraph(&mut ENTRIES[..], &mut arena, permission);
333
        let rootId = try! super::registerRoot(&mut original, &mut POOL, 0, "root.rad");
334
        let root = super::get(&original, rootId) else panic;
335
        let alias = root;
336
        let mut graph = relocate(original);
337
        let child = try! super::registerChild(&mut graph, &mut POOL, rootId, "child", "root/child.rad");
338
        try testing::expect(super::childCount(&graph, root) == 1);
339
        try testing::expect(super::childAt(&graph, alias, 0) == child);
340
        let published = super::get(&graph, rootId) else panic;
341
        try testing::expect(published as u64 == root as u64);
342
        let saved = alloc::used(&arena.arena);
343
        let reused = try! super::registerChild(&mut graph, &mut POOL, rootId, "child", "root/child.rad");
344
        try testing::expect(reused == child);
345
        try testing::expect(alloc::used(&arena.arena) == saved);
346
        let mut failed = false;
347
        try super::registerChild(&mut graph, &mut POOL, rootId, "full", "root/full.rad") catch {
348
            set failed = true;
349
        };
350
        try testing::expect(failed);
351
        try testing::expect(super::entryCount(&graph) == 2);
352
        try testing::expect(super::childCount(&graph, alias) == 1);
353
        try testing::expect(alloc::used(&arena.arena) == saved);
354
        let source = "fn answer() -> u32 { return 42; }";
355
        let parsed: *ast::Node = try! parser::parse(
356
            scanner::SourceLoc::String, source, &mut arena, &mut POOL
357
        );
358
        try! super::setAst(&mut graph, rootId, parsed);
359
        try! super::setSource(&mut graph, rootId, source);
360
        let retainedAst = super::astFor(&graph, alias) else panic;
361
        try testing::expect(retainedAst as u64 == parsed as u64);
362
        let retainedSource = super::sourceFor(&graph, root) else panic;
363
        try testing::expect(mem::eq(retainedSource, source));
364
        try testing::expect(
365
            try! super::state(&graph, rootId) == super::ModuleState::Parsed
366
        );
367
    }
368
}