tests(Clip): added explicit interface checking
- change ID
- tutkzxlsvtqvkxwytnsyxyvkzyvkvzqz
- git commit
- ecdcf0c0b89e478e8bf65cbd76655411c341c156
- author
- Grace Yoder <grace_yoder@outlook.com> - 2026-06-24T17:48:16-06:00
- committer
- Grace Yoder <grace_yoder@outlook.com> - 2026-06-25T16:42:38-06:00
- parents
- uqttuptknuzk
- refs
- signature
- Present (not validated)
tests(Clip): added explicit interface checking
tree
| type | name | size |
|---|---|---|
| file | .crow/build.yml | 2096 bytes |
| file | .crow/release.yml | 566 bytes |
| file | .gitignore | 354 bytes |
| file | LICENSE | 1073 bytes |
| file | README.md | 632 bytes |
| file | build.zig | 1056 bytes |
| file | build.zig.zon | 247 bytes |
| file | src/Clip/OSC52.zig | 4611 bytes |
| file | src/Clip.zig | 1236 bytes |
| file | src/main.zig | 1370 bytes |
diff
build.zig
modified (file → file)
b.installArtifact(exe);
+ const tests = b.addTest(.{
+ .name = "tpb",
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("src/main.zig"),
+ .target = target,
+ .optimize = optimize,
+ }),
+ });
+
+ const test_step = b.step("test", "Run tests");
+ const run_tests = b.addRunArtifact(tests);
+ test_step.dependOn(&run_tests.step);
+
const run_step = b.step("run", "Run the app");
const run_cmd = b.addRunArtifact(exe);
src/Clip.zig
modified (file → file)
pub const OSC52 = @import("Clip/OSC52.zig");
+
+// I am not sure if this is super idiomatic Zig or if this is bad practice, but
+// by ensuring that all Clip backends implement the same methods, we are able
+// to use the `anytype` type and we are able to have an interface that is able
+// to dispatch statically
+
+/// Check if a function with the given name and type exists.
+/// `@compileError` if not
+fn assertFn(comptime T: type, comptime name: []const u8, comptime Sig: type) void {
+ if (!@import("std").meta.hasFn(T, name))
+ @compileError(@typeName(T) ++ " missing fn " ++ name);
+ if (@TypeOf(@field(T, name)) != Sig)
+ @compileError(@typeName(T) ++ "." ++ name ++ " must be " ++ @typeName(Sig));
+}
+
+test {
+ inline for (@typeInfo(@This()).@"struct".decls) |decl| {
+ // Only grab types of structs
+ const T = @field(@This(), decl.name);
+ if (@TypeOf(T) != type) continue;
+ if (@typeInfo(T) != .@"struct") continue;
+
+ // ==============================
+ // === Interface Requirements ===
+ // ==============================
+ assertFn(T, "writeCopyBuffer", fn (*T, []const u8) anyerror!void);
+ assertFn(T, "writePasteboard", fn (*T) anyerror!void);
+ }
+}