Skip to content

Commit 2baef14

Browse files
move ssz int tests to ssz module (#162)
These tests aren't integration tests - they're tests isolated to public API of the `ssz` module, so should belong there, or at the very least in a `/test` directory adjacent to the implementation. With this change, we can test ssz changes easily with `zig build test:ssz`, which now is a lot more comprehensive with tree view tests, rather than `zig build test:int` (which contains other tests, which arguably, should also belong in their respective modules, and the `int` directory should arguably be deleted entirely) This PR, at a glance, is going to be messy because this essentially copypastas all the test code, without cleanup, to the `ssz` module. In a pair review with @wemeetagain we discussed possibly cleaning some of the tests and making it less verbose, but for the sake for reviewability, this PR only copypastas (take my word for it!) Let's leave further cleanup of the tests to a followup PR.
1 parent f7e1f21 commit 2baef14

34 files changed

+4189
-4319
lines changed

build.zig

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -943,14 +943,11 @@ pub fn build(b: *std.Build) void {
943943
module_bench_process_epoch.addImport("zbench", dep_zbench.module("zbench"));
944944

945945
module_int.addImport("build_options", options_module_build_options);
946-
module_int.addImport("ssz", module_ssz);
947946
module_int.addImport("state_transition", module_state_transition);
948947
module_int.addImport("config", module_config);
949948
module_int.addImport("consensus_types", module_consensus_types);
950949
module_int.addImport("preset", module_preset);
951950
module_int.addImport("constants", module_constants);
952-
module_int.addImport("hex", module_hex);
953-
module_int.addImport("persistent_merkle_tree", module_persistent_merkle_tree);
954951
module_int.addImport("blst", dep_blst.module("blst"));
955952

956953
module_int_slow.addImport("config", module_config);

src/ssz/tree_view/array_basic.zig

Lines changed: 345 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,348 @@ pub fn ArrayBasicTreeView(comptime ST: type) type {
9696
}
9797
};
9898
}
99+
100+
const UintType = @import("../type/uint.zig").UintType;
101+
const FixedVectorType = @import("../type/vector.zig").FixedVectorType;
102+
103+
test "TreeView vector element roundtrip" {
104+
const allocator = std.testing.allocator;
105+
var pool = try Node.Pool.init(allocator, 128);
106+
defer pool.deinit();
107+
108+
const Uint64 = UintType(64);
109+
const VectorType = FixedVectorType(Uint64, 4);
110+
111+
const original: VectorType.Type = [_]u64{ 11, 22, 33, 44 };
112+
113+
const root_node = try VectorType.tree.fromValue(&pool, &original);
114+
var view = try VectorType.TreeView.init(allocator, &pool, root_node);
115+
defer view.deinit();
116+
117+
try std.testing.expectEqual(@as(u64, 11), try view.get(0));
118+
try std.testing.expectEqual(@as(u64, 44), try view.get(3));
119+
120+
try view.set(1, 77);
121+
try view.set(2, 88);
122+
123+
try view.commit();
124+
125+
var expected = original;
126+
expected[1] = 77;
127+
expected[2] = 88;
128+
129+
var expected_root: [32]u8 = undefined;
130+
try VectorType.hashTreeRoot(&expected, &expected_root);
131+
132+
var actual_root: [32]u8 = undefined;
133+
try view.hashTreeRoot(&actual_root);
134+
135+
try std.testing.expectEqualSlices(u8, &expected_root, &actual_root);
136+
137+
var roundtrip: VectorType.Type = undefined;
138+
try VectorType.tree.toValue(view.base_view.data.root, &pool, &roundtrip);
139+
try std.testing.expectEqualSlices(u64, &expected, &roundtrip);
140+
}
141+
142+
test "TreeView vector getAll fills provided buffer" {
143+
const allocator = std.testing.allocator;
144+
var pool = try Node.Pool.init(allocator, 256);
145+
defer pool.deinit();
146+
147+
const Uint32 = UintType(32);
148+
const VectorType = FixedVectorType(Uint32, 8);
149+
150+
const values = [_]u32{ 9, 8, 7, 6, 5, 4, 3, 2 };
151+
const root_node = try VectorType.tree.fromValue(&pool, &values);
152+
var view = try VectorType.TreeView.init(allocator, &pool, root_node);
153+
defer view.deinit();
154+
155+
const out = try allocator.alloc(u32, values.len);
156+
defer allocator.free(out);
157+
158+
const filled = try view.getAllInto(out);
159+
try std.testing.expectEqual(out.ptr, filled.ptr);
160+
try std.testing.expectEqual(out.len, filled.len);
161+
try std.testing.expectEqualSlices(u32, values[0..], filled);
162+
163+
const wrong = try allocator.alloc(u32, values.len - 1);
164+
defer allocator.free(wrong);
165+
try std.testing.expectError(error.InvalidSize, view.getAllInto(wrong));
166+
}
167+
168+
test "TreeView vector getAllAlloc roundtrip" {
169+
const allocator = std.testing.allocator;
170+
var pool = try Node.Pool.init(allocator, 256);
171+
defer pool.deinit();
172+
173+
const Uint16 = UintType(16);
174+
const VectorType = FixedVectorType(Uint16, 5);
175+
const values = [_]u16{ 3, 1, 4, 1, 5 };
176+
177+
const root_node = try VectorType.tree.fromValue(&pool, &values);
178+
var view = try VectorType.TreeView.init(allocator, &pool, root_node);
179+
defer view.deinit();
180+
181+
const filled = try view.getAll(allocator);
182+
defer allocator.free(filled);
183+
184+
try std.testing.expectEqualSlices(u16, values[0..], filled);
185+
}
186+
187+
test "TreeView vector getAllAlloc repeat reflects updates" {
188+
const allocator = std.testing.allocator;
189+
var pool = try Node.Pool.init(allocator, 256);
190+
defer pool.deinit();
191+
192+
const Uint32 = UintType(32);
193+
const VectorType = FixedVectorType(Uint32, 6);
194+
var values = [_]u32{ 10, 20, 30, 40, 50, 60 };
195+
196+
const root_node = try VectorType.tree.fromValue(&pool, &values);
197+
var view = try VectorType.TreeView.init(allocator, &pool, root_node);
198+
defer view.deinit();
199+
200+
const first = try view.getAll(allocator);
201+
defer allocator.free(first);
202+
try std.testing.expectEqualSlices(u32, values[0..], first);
203+
204+
try view.set(3, 99);
205+
206+
const second = try view.getAll(allocator);
207+
defer allocator.free(second);
208+
values[3] = 99;
209+
try std.testing.expectEqualSlices(u32, values[0..], second);
210+
}
211+
212+
test "TreeView vector clone isolates subsequent updates" {
213+
const allocator = std.testing.allocator;
214+
var pool = try Node.Pool.init(allocator, 1024);
215+
defer pool.deinit();
216+
217+
const Uint16 = UintType(16);
218+
const Vec4 = FixedVectorType(Uint16, 4);
219+
220+
const value: Vec4.Type = [_]u16{ 0, 0, 0, 0 };
221+
const root = try Vec4.tree.fromValue(&pool, &value);
222+
223+
var v1 = try Vec4.TreeView.init(allocator, &pool, root);
224+
defer v1.deinit();
225+
226+
var v2 = try v1.clone(.{});
227+
defer v2.deinit();
228+
229+
try v2.set(1, @as(u16, 9));
230+
try v2.commit();
231+
232+
try std.testing.expectEqual(@as(u16, 0), try v1.get(1));
233+
try std.testing.expectEqual(@as(u16, 9), try v2.get(1));
234+
}
235+
236+
test "TreeView vector clone reads committed state" {
237+
const allocator = std.testing.allocator;
238+
var pool = try Node.Pool.init(allocator, 1024);
239+
defer pool.deinit();
240+
241+
const Uint16 = UintType(16);
242+
const Vec4 = FixedVectorType(Uint16, 4);
243+
244+
const value: Vec4.Type = [_]u16{ 0, 0, 0, 0 };
245+
const root = try Vec4.tree.fromValue(&pool, &value);
246+
247+
var v1 = try Vec4.TreeView.init(allocator, &pool, root);
248+
defer v1.deinit();
249+
250+
try v1.set(2, @as(u16, 7));
251+
try v1.commit();
252+
253+
var v2 = try v1.clone(.{});
254+
defer v2.deinit();
255+
256+
try std.testing.expectEqual(@as(u16, 7), try v2.get(2));
257+
}
258+
259+
test "TreeView vector clone drops uncommitted changes" {
260+
const allocator = std.testing.allocator;
261+
var pool = try Node.Pool.init(allocator, 1024);
262+
defer pool.deinit();
263+
264+
const Uint16 = UintType(16);
265+
const Vec4 = FixedVectorType(Uint16, 4);
266+
267+
const value: Vec4.Type = [_]u16{ 1, 2, 3, 4 };
268+
const root = try Vec4.tree.fromValue(&pool, &value);
269+
270+
var v = try Vec4.TreeView.init(allocator, &pool, root);
271+
defer v.deinit();
272+
273+
try v.set(0, @as(u16, 9));
274+
try std.testing.expectEqual(@as(u16, 9), try v.get(0));
275+
276+
var dropped = try v.clone(.{});
277+
defer dropped.deinit();
278+
279+
try std.testing.expectEqual(@as(u16, 1), try v.get(0));
280+
try std.testing.expectEqual(@as(u16, 1), try dropped.get(0));
281+
}
282+
283+
test "TreeView vector clone(true) does not transfer cache" {
284+
const allocator = std.testing.allocator;
285+
var pool = try Node.Pool.init(allocator, 1024);
286+
defer pool.deinit();
287+
288+
const Uint16 = UintType(16);
289+
const Vec4 = FixedVectorType(Uint16, 4);
290+
291+
const value: Vec4.Type = [_]u16{ 1, 2, 3, 4 };
292+
const root = try Vec4.tree.fromValue(&pool, &value);
293+
294+
var v = try Vec4.TreeView.init(allocator, &pool, root);
295+
defer v.deinit();
296+
297+
_ = try v.get(0);
298+
try std.testing.expect(v.base_view.data.children_nodes.count() > 0);
299+
300+
var cloned_no_cache = try v.clone(.{ .transfer_cache = false });
301+
defer cloned_no_cache.deinit();
302+
303+
try std.testing.expect(v.base_view.data.children_nodes.count() > 0);
304+
try std.testing.expectEqual(@as(usize, 0), cloned_no_cache.base_view.data.children_nodes.count());
305+
}
306+
307+
test "TreeView vector clone(false) transfers cache and clears source" {
308+
const allocator = std.testing.allocator;
309+
var pool = try Node.Pool.init(allocator, 1024);
310+
defer pool.deinit();
311+
312+
const Uint16 = UintType(16);
313+
const Vec4 = FixedVectorType(Uint16, 4);
314+
315+
const value: Vec4.Type = [_]u16{ 1, 2, 3, 4 };
316+
const root = try Vec4.tree.fromValue(&pool, &value);
317+
318+
var v = try Vec4.TreeView.init(allocator, &pool, root);
319+
defer v.deinit();
320+
321+
_ = try v.get(0);
322+
try std.testing.expect(v.base_view.data.children_nodes.count() > 0);
323+
324+
var cloned = try v.clone(.{});
325+
defer cloned.deinit();
326+
327+
try std.testing.expectEqual(@as(usize, 0), v.base_view.data.children_nodes.count());
328+
try std.testing.expect(cloned.base_view.data.children_nodes.count() > 0);
329+
}
330+
331+
// Tests ported from TypeScript ssz packages/ssz/test/unit/byType/vector/tree.test.ts
332+
test "ArrayBasicTreeView - serialize (uint64 vector)" {
333+
const allocator = std.testing.allocator;
334+
335+
const Uint64 = UintType(64);
336+
const VecU64Type = FixedVectorType(Uint64, 4);
337+
338+
var pool = try Node.Pool.init(allocator, 1024);
339+
defer pool.deinit();
340+
341+
const TestCase = struct {
342+
id: []const u8,
343+
values: [4]u64,
344+
expected_serialized: []const u8,
345+
expected_root: [32]u8,
346+
};
347+
348+
const test_cases = [_]TestCase{
349+
.{
350+
.id = "4 values",
351+
.values = [4]u64{ 100000, 200000, 300000, 400000 },
352+
// 0xa086010000000000400d030000000000e093040000000000801a060000000000
353+
.expected_serialized = &[_]u8{ 0xa0, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1a, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
354+
// For VectorBasic, the root is the same as the serialized bytes (fits in one chunk)
355+
.expected_root = [_]u8{ 0xa0, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1a, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
356+
},
357+
};
358+
359+
for (test_cases) |tc| {
360+
const value = tc.values;
361+
362+
var value_serialized: [VecU64Type.fixed_size]u8 = undefined;
363+
_ = VecU64Type.serializeIntoBytes(&value, &value_serialized);
364+
365+
const tree_node = try VecU64Type.tree.fromValue(&pool, &value);
366+
var view = try VecU64Type.TreeView.init(allocator, &pool, tree_node);
367+
defer view.deinit();
368+
369+
var view_serialized: [VecU64Type.fixed_size]u8 = undefined;
370+
const written = try view.serializeIntoBytes(&view_serialized);
371+
try std.testing.expectEqual(view_serialized.len, written);
372+
373+
try std.testing.expectEqualSlices(u8, tc.expected_serialized, &view_serialized);
374+
try std.testing.expectEqualSlices(u8, &value_serialized, &view_serialized);
375+
376+
const view_size = view.serializedSize();
377+
try std.testing.expectEqual(tc.expected_serialized.len, view_size);
378+
379+
var hash_root: [32]u8 = undefined;
380+
try view.hashTreeRoot(&hash_root);
381+
try std.testing.expectEqualSlices(u8, &tc.expected_root, &hash_root);
382+
}
383+
}
384+
385+
test "ArrayBasicTreeView - serialize (uint8 vector)" {
386+
const allocator = std.testing.allocator;
387+
388+
const Uint8 = UintType(8);
389+
const VecU8Type = FixedVectorType(Uint8, 8);
390+
391+
var pool = try Node.Pool.init(allocator, 1024);
392+
defer pool.deinit();
393+
394+
const value = [8]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
395+
396+
var value_serialized: [VecU8Type.fixed_size]u8 = undefined;
397+
_ = VecU8Type.serializeIntoBytes(&value, &value_serialized);
398+
399+
const tree_node = try VecU8Type.tree.fromValue(&pool, &value);
400+
var view = try VecU8Type.TreeView.init(allocator, &pool, tree_node);
401+
defer view.deinit();
402+
403+
var view_serialized: [VecU8Type.fixed_size]u8 = undefined;
404+
const written = try view.serializeIntoBytes(&view_serialized);
405+
try std.testing.expectEqual(view_serialized.len, written);
406+
407+
try std.testing.expectEqualSlices(u8, &value, &view_serialized);
408+
409+
const view_size = view.serializedSize();
410+
try std.testing.expectEqual(@as(usize, 8), view_size);
411+
}
412+
413+
test "ArrayBasicTreeView - get and set" {
414+
const allocator = std.testing.allocator;
415+
416+
const Uint64 = UintType(64);
417+
const VecU64Type = FixedVectorType(Uint64, 4);
418+
419+
var pool = try Node.Pool.init(allocator, 1024);
420+
defer pool.deinit();
421+
422+
const value = [4]u64{ 100, 200, 300, 400 };
423+
const tree_node = try VecU64Type.tree.fromValue(&pool, &value);
424+
var view = try VecU64Type.TreeView.init(allocator, &pool, tree_node);
425+
defer view.deinit();
426+
427+
try std.testing.expectEqual(@as(u64, 100), try view.get(0));
428+
try std.testing.expectEqual(@as(u64, 200), try view.get(1));
429+
try std.testing.expectEqual(@as(u64, 300), try view.get(2));
430+
try std.testing.expectEqual(@as(u64, 400), try view.get(3));
431+
432+
try view.set(1, 999);
433+
try std.testing.expectEqual(@as(u64, 999), try view.get(1));
434+
435+
var serialized: [VecU64Type.fixed_size]u8 = undefined;
436+
const written = try view.serializeIntoBytes(&serialized);
437+
try std.testing.expectEqual(serialized.len, written);
438+
439+
const expected = [4]u64{ 100, 999, 300, 400 };
440+
var expected_serialized: [VecU64Type.fixed_size]u8 = undefined;
441+
_ = VecU64Type.serializeIntoBytes(&expected, &expected_serialized);
442+
try std.testing.expectEqualSlices(u8, &expected_serialized, &serialized);
443+
}

0 commit comments

Comments
 (0)