I’m working on a module for parsing PNG files.
For testing I have a set of 166 different .png files that are all setup to test a specific item. What I’m currently doing is using Io.Group with concurrent to loop over a list of filenames and add a concurrent task for each seperate file, so far so good.
This works fast but I have the following issues with it:
- All exceptions are hidden behind Io.Cancelable.Canceled
- No way of identifying the precise file that failed.
Not sure what a solution could be for the first issue when using concurrent
For the last case I do see 2 solutions.
- use std.log.err/std.debug.print on exception
- use different test “” per file
The first one is easy to do but I have a feeling this is not really the correct way of providing context to tests, the second one requires quite a bit of different test cases and loses the performance (Is not the biggest issue though). So far I have avoided using AI in this project but this might be a use case for it to just provide a general test function and have AI write all the test cases calling that function.
Here the code.
test "can parse basic png" {
const testing = std.testing;
const io = testing.io;
const gpa = testing.allocator;
const Test = struct {
pub fn testHeader(dir: Io.Dir, path: []const u8, expected_width: u32, expected_height: u32) !void {
// Not sure yet how to be able to return different error types in this case, as concurrent expects Cancelable!void
const file = dir.openFile(io, path, .{}) catch return Io.Cancelable.Canceled;
defer file.close(io);
var buff: [128]u8 = undefined;
var fr = file.reader(io, &buff);
const reader = &fr.interface;
const image: Image = parse(reader, gpa) catch return Io.Cancelable.Canceled;
testing.expectEqual(expected_width, image.width) catch return Io.Cancelable.Canceled;
testing.expectEqual(expected_height, image.height) catch return Io.Cancelable.Canceled;
}
pub fn testHeaderCorrupted(dir: Io.Dir, path: []const u8) !void {
const file = dir.openFile(io, path, .{}) catch return Io.Cancelable.Canceled;
defer file.close(io);
var buff: [128]u8 = undefined;
var fr = file.reader(io, &buff);
const reader = &fr.interface;
const image = parse(reader, gpa);
testing.expectError(ReadError.InvalidFormat, image) catch return Io.Cancelable.Canceled;
}
};
const cwd = Io.Dir.cwd();
var group: Io.Group = .init;
for (primary_pngs) |png| {
try group.concurrent(io, Test.testHeader, .{ cwd, png.path, png.width, png.height });
}
for (primary_check_pngs) |png| {
try group.concurrent(io, Test.testHeader, .{ cwd, png.path, png.width, png.height });
}
for (corrupt_pngs) |png| {
try group.concurrent(io, Test.testHeaderCorrupted, .{ cwd, png.path });
}
try group.await(io);
}
Curious to here your thoughts on how you would solve this!
Also this is my first time using concurrent with the new IO interface, if you see an issue please let me know ![]()