lib/std/graph/tests.rad 7.2 KiB raw
1
//! Graph ownership, publication, and failure recovery tests.
2
3
use std::testing;
4
use std::lang::alloc;
5
6
/// Non-copy module state retained when graph construction is abandoned.
7
record ModuleState {
8
    /// Test value returned to the caller.
9
    value: u32,
10
}
11
12
/// Fallible construction state that owns module and graph state.
13
record Construction: 'g {
14
    /// Module state retained after graph abandonment.
15
    module: ModuleState,
16
    /// Graph authority consumed during abandonment.
17
    graph: super::Builder 'g,
18
}
19
20
/// Abandon graph construction and return the independent module state.
21
fn recoverModule 'g (state: Construction 'g) -> ModuleState {
22
    let case Construction 'g { module, graph } = state else panic;
23
    super::abandon(graph);
24
    return module;
25
}
26
27
/// Empty graphs can be published without node allocations.
28
@test fn testEmptyGraph() throws (testing::TestError) {
29
    static DATA: [u8; 64] = [0; 64];
30
    let mut arena = alloc::new(&mut DATA[..]);
31
    use arena as storage in {
32
        let builder = try! super::new(&storage);
33
        assert super::pending(&builder) == 0;
34
        let frozen = try! super::freeze(builder);
35
        assert super::len(&frozen) == 0;
36
    }
37
}
38
39
/// Node identities and completion counts survive repeated completion and freeze.
40
@test fn testNodeCompletion() throws (testing::TestError) {
41
    for count in [1 as u32, 2, 8, 64] {
42
        static DATA: [u8; 1024] = [0; 1024];
43
        let mut arena = alloc::new(&mut DATA[..]);
44
        use arena as storage in {
45
            let mut builder = try! super::new(&storage);
46
            let first = try! super::reserve(&mut builder, &storage);
47
            let mut nodes: [super::Node 'storage; 64] = [first; 64];
48
            for i in 1..count {
49
                set nodes[i] = try! super::reserve(&mut builder, &storage);
50
                for j in 0..i {
51
                    assert nodes[i] <> nodes[j];
52
                }
53
            }
54
            assert super::pending(&builder) == count;
55
            for i in 0..count {
56
                try! super::check(&builder, nodes[i]);
57
                try! super::complete(&mut builder, nodes[i]);
58
                assert super::pending(&builder) == count - i - 1;
59
                try! super::complete(&mut builder, nodes[i]);
60
                assert super::pending(&builder) == count - i - 1;
61
            }
62
            let frozen = try! super::freeze(builder);
63
            assert super::len(&frozen) == count;
64
            assert nodes[0] == first;
65
            for i in 0..count {
66
                try! super::checkFrozen(&frozen, nodes[i]);
67
            }
68
        }
69
    }
70
}
71
72
/// Builders in one session have separate ownership and completion authority.
73
@test fn testForeignNode() throws (testing::TestError) {
74
    static DATA: [u8; 128] = [0; 128];
75
    let mut arena = alloc::new(&mut DATA[..]);
76
    use arena as storage in {
77
        let mut first = try! super::new(&storage);
78
        let mut second = try! super::new(&storage);
79
        let a = try! super::reserve(&mut first, &storage);
80
        let b = try! super::reserve(&mut second, &storage);
81
        let mut rejected = false;
82
        try super::complete(&mut first, b) catch error {
83
            assert error == super::Error::ForeignNode;
84
            set rejected = true;
85
        };
86
        assert rejected;
87
        assert super::pending(&first) == 1;
88
        assert super::pending(&second) == 1;
89
        try! super::complete(&mut first, a);
90
        let frozen = try! super::freeze(first);
91
        set rejected = false;
92
        try super::checkFrozen(&frozen, b) catch error {
93
            assert error == super::Error::ForeignNode;
94
            set rejected = true;
95
        };
96
        assert rejected;
97
        try! super::complete(&mut second, b);
98
        let other = try! super::freeze(second);
99
        try! super::checkFrozen(&other, b);
100
    }
101
}
102
103
/// An incomplete freeze returns the sole builder for completion and retry.
104
@test fn testIncompleteFreezeRecovery() throws (testing::TestError) {
105
    static DATA: [u8; 128] = [0; 128];
106
    let mut arena = alloc::new(&mut DATA[..]);
107
    use arena as storage in {
108
        let mut builder = try! super::new(&storage);
109
        let first = try! super::reserve(&mut builder, &storage);
110
        let second = try! super::reserve(&mut builder, &storage);
111
        try! super::complete(&mut builder, first);
112
        try super::freeze(builder) catch error {
113
            let case super::FreezeError 'storage::Incomplete(recovered) = error else panic;
114
            let mut retry = recovered;
115
            assert super::pending(&retry) == 1;
116
            try! super::complete(&mut retry, second);
117
            let frozen = try! super::freeze(retry);
118
            assert super::len(&frozen) == 2;
119
            try! super::checkFrozen(&frozen, first);
120
            try! super::checkFrozen(&frozen, second);
121
            return;
122
        };
123
        throw testing::TestError::Failed;
124
    }
125
}
126
127
/// Abandoning any construction state leaves its allocation session usable.
128
@test fn testAbandon() throws (testing::TestError) {
129
    static DATA: [u8; 128] = [0; 128];
130
    let mut arena = alloc::new(&mut DATA[..]);
131
    use arena as storage in {
132
        let empty = try! super::new(&storage);
133
        super::abandon(empty);
134
135
        let mut incomplete = try! super::new(&storage);
136
        let abandonedNode = try! super::reserve(&mut incomplete, &storage);
137
        assert super::pending(&incomplete) == 1;
138
        super::abandon(incomplete);
139
140
        let fresh = try! super::new(&storage);
141
        let mut rejected = false;
142
        try super::check(&fresh, abandonedNode) catch error {
143
            assert error == super::Error::ForeignNode;
144
            set rejected = true;
145
        };
146
        assert rejected;
147
        super::abandon(fresh);
148
149
        let mut complete = try! super::new(&storage);
150
        let node = try! super::reserve(&mut complete, &storage);
151
        try! super::complete(&mut complete, node);
152
        assert super::pending(&complete) == 0;
153
        super::abandon(complete);
154
155
        let reusable = try! super::new(&storage);
156
        let frozen = try! super::freeze(reusable);
157
        assert super::len(&frozen) == 0;
158
159
        let graph = try! super::new(&storage);
160
        let module = recoverModule(Construction 'storage {
161
            module: ModuleState { value: 7 }, graph,
162
        });
163
        assert module.value == 7;
164
    }
165
}
166
167
/// Exhausted identity storage does not add incomplete nodes to the builder.
168
@test fn testAllocationFailure() throws (testing::TestError) {
169
    for capacity in 0..9 {
170
        static DATA: [u8; 16] = [0; 16];
171
        let mut arena = alloc::new(&mut DATA[..capacity]);
172
        use arena as storage in {
173
            if let created = try? super::new(&storage) {
174
                let mut builder = created;
175
                let mut count: u32 = 0;
176
                while let node = try? super::reserve(&mut builder, &storage) {
177
                    try! super::complete(&mut builder, node);
178
                    set count += 1;
179
                }
180
                assert super::pending(&builder) == 0;
181
                let frozen = try! super::freeze(builder);
182
                assert super::len(&frozen) == count;
183
                assert count == capacity - 1;
184
            } else {
185
                assert capacity == 0;
186
            }
187
        }
188
        assert alloc::used(&arena) == capacity;
189
    }
190
}