kernel: Add the package and test targets

4da4070b41ac80fd1a4d1ad07243ce133576a080bec1a43700f3f092972eb67f
Build kernel tests as a separate package with entry-package test
discovery. Add checked half-open ranges for memory and execution
windows.

Assisted-by: Codex:gpt-6
Alexis Sellier committed ago 1 parent 52fcce36
kernel/kernel.rad added +6 -0
1 +
//! Kernel resource management and machine execution.
2 +
3 +
use std::testing;
4 +
5 +
export mod range;
6 +
@test export mod tests;
kernel/kernel/range.rad added +22 -0
1 +
//! Checked half-open ranges for physical memory and CPU windows.
2 +
3 +
/// A nonempty half-open interval. Construct intervals with `new`.
4 +
export record Range: Copy {
5 +
    /// First included address or tick.
6 +
    start: u64,
7 +
    /// First excluded address or tick.
8 +
    end: u64,
9 +
}
10 +
11 +
/// Construct a nonempty interval. Reject addition overflow.
12 +
export fn new(start: u64, length: u64) -> ?Range {
13 +
    if length == 0 or length > 0xffffffffffffffff - start {
14 +
        return nil;
15 +
    }
16 +
    return Range { start, end: start + length };
17 +
}
18 +
19 +
/// Check that the complete nonempty interval is inside the outer interval.
20 +
export fn contains(outer: Range, inner: Range) -> bool {
21 +
    return outer.start <= inner.start and inner.start < inner.end and inner.end <= outer.end;
22 +
}
kernel/kernel/tests.rad added +3 -0
1 +
//! Kernel unit tests. Machine execution tests have separate entry points.
2 +
3 +
export mod range;
kernel/kernel/tests/range.rad added +27 -0
1 +
//! Bounds and overflow checks for kernel intervals.
2 +
3 +
use kernel::range;
4 +
use std::testing;
5 +
6 +
/// Check empty intervals and overflow at the address-space boundary.
7 +
@test fn construction() throws (testing::TestError) {
8 +
    try testing::expect(range::new(0, 0) == nil);
9 +
    try testing::expect(range::new(0xffffffffffffffff, 1) == nil);
10 +
    try testing::expect(range::new(1, 0xffffffffffffffff) == nil);
11 +
    let span = range::new(0, 0xffffffffffffffff) else {
12 +
        throw testing::TestError::Failed;
13 +
    };
14 +
    try testing::expect(span.start == 0);
15 +
    try testing::expect(span.end == 0xffffffffffffffff);
16 +
}
17 +
18 +
/// Check exact bounds, partial overlap, and the excluded upper bound.
19 +
@test fn containment() throws (testing::TestError) {
20 +
    let outer = range::Range { start: 4096, end: 8192 };
21 +
    try testing::expect(range::contains(outer, outer));
22 +
    try testing::expect(range::contains(outer, range::Range { start: 4097, end: 8191 }));
23 +
    try testing::expect(not range::contains(outer, range::Range { start: 4095, end: 4097 }));
24 +
    try testing::expect(not range::contains(outer, range::Range { start: 8191, end: 8193 }));
25 +
    try testing::expect(not range::contains(outer, range::Range { start: 8192, end: 8193 }));
26 +
    try testing::expect(not range::contains(outer, range::Range { start: 4096, end: 4096 }));
27 +
}