lib/choir/src/backends/artifact/serialization/test.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const artifact = @import("../root.zig");
  3 const binary = @import("../../../serialization/root.zig").binary;
  4 const serialization = @import("root.zig");
  5 
  6 test {
  7     std.testing.refAllDecls(serialization);
  8 }
  9 
 10 test "artifact serialization uses stable model-owned tags" {
 11     try std.testing.expectEqual(@as(u8, 1), try binary.encodeTag(artifact.ArtifactKind.unknown));
 12     try std.testing.expectEqual(@as(u8, 8), try binary.encodeTag(artifact.ArtifactKind.container));
 13     try std.testing.expectEqual(@as(u8, 5), try binary.encodeTag(artifact.OptionValueTag.bytes));
 14     try std.testing.expectEqual(artifact.BufferFormat.object_file, try binary.decodeTag(artifact.BufferFormat, 3));
 15     try std.testing.expectError(error.InvalidTag, binary.decodeTag(artifact.BufferFormat, 0xff));
 16 }
 17 
 18 test "artifact binary serialization round-trips every owned concern" {
 19     var original = try artifact.Artifact.init(std.testing.allocator, .{
 20         .kind = .machine_code,
 21         .producer = "choir-x64",
 22         .target = .{
 23             .architecture = .x86_64,
 24             .triple = "x86_64-unknown-linux-gnu",
 25             .vendor = "unknown",
 26             .os = "linux",
 27             .environment = "gnu",
 28             .cpu = "x86-64-v3",
 29             .features = &.{ "sse2", "+avx2" },
 30         },
 31         .abi = .{
 32             .name = "sysv",
 33             .calling_convention = "c",
 34             .object_format = "elf",
 35             .pointer_width_bits = 64,
 36             .endianness = .little,
 37         },
 38     });
 39     defer original.deinit();
 40     try original.options.add(.{ .key = "checked", .value = .{ .flag = true } });
 41     try original.options.add(.{ .key = "bias", .value = .{ .signed = -17 } });
 42     try original.options.add(.{ .key = "seed", .value = .{ .unsigned = 42 } });
 43     try original.options.add(.{ .key = "mode", .value = .{ .text = "durable" } });
 44     try original.options.add(.{ .key = "opaque", .value = .{ .bytes = &.{ 0, 255, 7 } } });
 45     try original.linkage.addRequired(.{ .name = "runtime", .kind = .runtime, .binding = .weak });
 46     const lanes = artifact.ValueType{ .vector = .{ .element = .f32, .lanes = 4 } };
 47     const signature = try artifact.Signature.init(&.{ .{ .scalar = .u16 }, .memref }, &.{lanes});
 48     try original.linkage.addProvided(.{
 49         .name = "entry",
 50         .kind = .function,
 51         .binding = .external,
 52         .signature = signature,
 53     });
 54     try original.linkage.addProvided(.{ .name = "table", .kind = .data, .binding = .local });
 55     try original.linkage.addRelocation(.{ .offset = 2, .symbol = "runtime", .kind = .call, .addend = -4, .width_bits = 64 });
 56     try original.payload.addDebugRecord(.{ .name = ".debug_line", .kind = .dwarf_section, .bytes = &.{ 1, 0, 2, 0 } });
 57     try original.payload.addBuffer(.{ .name = "entry", .format = .machine_code, .bytes = &.{ 0x48, 0xb8, 0xff, 0xd0, 0xc3 }, .alignment = 32 });
 58     try original.payload.addTextDump(.{ .name = "lowered", .contents = "func @entry" });
 59     try original.verification.replace(original.allocator, .{ .state = .failed, .stage = "machine-verify", .message = "preserved" });
 60 
 61     const encoded = try serialization.serialize(std.testing.allocator, &original);
 62     defer std.testing.allocator.free(encoded);
 63     var decoded = try serialization.deserialize(std.testing.allocator, encoded);
 64     defer decoded.deinit();
 65     try std.testing.expect(original.eql(decoded));
 66     try std.testing.expect(decoded.linkage.provided_symbols.items[0].signature.?.eql(&signature));
 67     try std.testing.expect(decoded.linkage.provided_symbols.items[1].signature == null);
 68 
 69     const reencoded = try serialization.serialize(std.testing.allocator, &decoded);
 70     defer std.testing.allocator.free(reencoded);
 71     try std.testing.expectEqualSlices(u8, encoded, reencoded);
 72 }
 73 
 74 test "artifact linkage deserialization refuses malformed signatures" {
 75     const scalar = @backingInt(artifact.ValueKind.scalar);
 76     const memref = @backingInt(artifact.ValueKind.memref);
 77     const vector = @backingInt(artifact.ValueKind.vector);
 78     const f32_tag = @backingInt(artifact.ScalarType.f32);
 79     const f64_tag = @backingInt(artifact.ScalarType.f64);
 80 
 81     var linkage = try readSignedSymbol(&.{ 1, 1, memref, vector, f32_tag, 4 });
 82     defer linkage.deinit();
 83     const lanes = artifact.ValueType{ .vector = .{ .element = .f32, .lanes = 4 } };
 84     const signature = try artifact.Signature.init(&.{.memref}, &.{lanes});
 85     try std.testing.expect(linkage.provided_symbols.items[0].signature.?.eql(&signature));
 86 
 87     try expectMalformed(error.LimitExceeded, &.{ artifact.Signature.max_parameters + 1, 0 });
 88     try expectMalformed(error.LimitExceeded, &.{ 0, artifact.Signature.max_results + 1 });
 89     try expectMalformed(error.InvalidTag, &.{ 1, 0, vector + 1 });
 90     try expectMalformed(error.InvalidTag, &.{ 1, 0, scalar, f64_tag + 1 });
 91     try expectMalformed(error.InvalidValue, &.{ 0, 1, vector, f32_tag, 0 });
 92     try expectMalformed(error.InvalidValue, &.{ 0, 1, vector, f32_tag, 17 });
 93 }
 94 
 95 fn expectMalformed(expected: anyerror, signature: []const u8) !void {
 96     try std.testing.expectError(expected, readSignedSymbol(signature));
 97 }
 98 
 99 fn readSignedSymbol(signature: []const u8) !artifact.Linkage {
100     var writer = serialization.format.Writer.init(std.testing.allocator);
101     defer writer.deinit();
102     try writer.writeCount(0);
103     try writer.writeCount(1);
104     try writer.writeString("entry");
105     try writer.writeTag(artifact.SymbolKind.function);
106     try writer.writeTag(artifact.SymbolBinding.external);
107     try writer.writeBool(true);
108     try writer.writeRaw(signature);
109     try writer.writeCount(0);
110 
111     var reader = try serialization.format.Reader.init(writer.bytes.items);
112     var linkage = artifact.Linkage.init(std.testing.allocator);
113     errdefer linkage.deinit();
114     try serialization.linkage.readInto(&reader, &linkage);
115     try std.testing.expect(reader.atEnd());
116     return linkage;
117 }