lib/std/lang/module/tests.rad 12.8 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
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
}