core: add tests for ghostty.h

* ensure that `ghostty.h` compiles during basic Zig tests
* ensure that non-exhaustive enums are kept synchronized between
  `ghostty.h` and their respective Zig counterpart.
* adjust some enums that varied from established conventions
This commit is contained in:
Jeffrey C. Ollie
2026-02-27 00:52:47 -06:00
parent b30db91e69
commit ea5b07d20f
11 changed files with 172 additions and 11 deletions

View File

@@ -91,3 +91,55 @@ test "abi by removing a key" {
try testing.expectEqual(2, @intFromEnum(T.d));
}
}
/// Verify that for every key in enum T, there is a matching declaration in
/// `ghostty.h` with the correct value.
pub fn checkGhosttyHEnum(comptime T: type, comptime prefix: []const u8) !void {
const info = @typeInfo(T);
try std.testing.expect(info == .@"enum");
try std.testing.expect(info.@"enum".tag_type == c_int);
@setEvalBranchQuota(1000000);
const c = @cImport({
@cInclude("ghostty.h");
});
var set: std.EnumSet(T) = .initFull();
const c_decls = @typeInfo(c).@"struct".decls;
const enum_fields = info.@"enum".fields;
inline for (enum_fields) |field| {
const upper_name = comptime u: {
var buf: [128]u8 = undefined;
break :u std.ascii.upperString(&buf, field.name);
};
inline for (c_decls) |decl| {
if (!comptime std.mem.startsWith(u8, decl.name, prefix)) continue;
const suffix = decl.name[prefix.len..];
if (!comptime std.mem.eql(u8, suffix, upper_name)) continue;
std.testing.expectEqual(field.value, @field(c, decl.name)) catch |e| {
std.log.err(@typeName(T) ++ " key " ++ field.name ++ " does not have the same backing int as " ++ decl.name, .{});
return e;
};
set.remove(@enumFromInt(field.value));
}
}
std.testing.expect(set.count() == 0) catch |e| {
var it = set.iterator();
while (it.next()) |v| {
var buf: [128]u8 = undefined;
const n = std.ascii.upperString(&buf, @tagName(v));
std.log.err("ghostty.h is missing value for {s}{s}, {t}", .{ prefix, n, v });
}
return e;
};
}