From 47f2491ae0688637d82900dfe8d92b8b4e774e8e Mon Sep 17 00:00:00 2001 From: Grace Yoder Date: Wed, 24 Jun 2026 17:48:16 -0600 Subject: [PATCH] tests(OSC52): Added base64 encoding test cases --- src/Clip/OSC52.zig | 89 +++++++++++++++++++++++++++++++++++----------- src/main.zig | 4 +++ 2 files changed, 72 insertions(+), 21 deletions(-) diff --git a/src/Clip/OSC52.zig b/src/Clip/OSC52.zig index 44d92bf..d95fca1 100644 --- a/src/Clip/OSC52.zig +++ b/src/Clip/OSC52.zig @@ -13,7 +13,7 @@ base64buffer: std.ArrayList(u8), leftover_bytes: [3]u8, leftover_count: u8, -const base64encoder = std.base64.Base64Encoder.init(std.base64.standard_alphabet_chars, null); +const base64encoder = std.base64.Base64Encoder.init(std.base64.standard_alphabet_chars, '='); pub fn init(alloc: std.mem.Allocator, io: Io, buf_size: usize) !OSC52 { return .{ @@ -25,31 +25,34 @@ pub fn init(alloc: std.mem.Allocator, io: Io, buf_size: usize) !OSC52 { }; } -pub fn writeCopyBuffer(self: *OSC52, buf: []u8) !void { +pub fn free(self: *OSC52) void { + self.base64buffer.clearAndFree(self.alloc); +} + +pub fn writeCopyBuffer(self: *OSC52, buf: []const u8) anyerror!void { if (buf.len == 0) return; // Start of buffer after dealing with leftover bytes const buf_idx = 3 - self.leftover_count; - if (buf.len + self.leftover_count < 3) { - const len = buf.len + self.leftover_count; - @memcpy(self.leftover_bytes[self.leftover_count..len], buf[0..buf.len]); - self.leftover_count = @intCast(len); + // When we dont fill the leftover buffer, just copy data + if (buf_idx > buf.len) { + const end = self.leftover_count + buf.len; + @memcpy(self.leftover_bytes[self.leftover_count..end], buf[0..buf.len]); + self.leftover_count = @intCast(end); return; } - if (self.leftover_count != 0) { - @memcpy(self.leftover_bytes[self.leftover_count..3], buf[0..buf_idx]); - var temp: [5]u8 = undefined; - const s = OSC52.base64encoder.encode(&temp, &self.leftover_bytes); - try self.base64buffer.appendSlice(self.alloc, s); - } + @memcpy(self.leftover_bytes[self.leftover_count..3], buf[0..buf_idx]); + var temp: [5]u8 = undefined; + var s = OSC52.base64encoder.encode(&temp, &self.leftover_bytes); + try self.base64buffer.appendSlice(self.alloc, s); const chunkable_length = buf.len - ((buf.len - buf_idx) % 3); - var chunker = std.mem.window(u8, buf[0..chunkable_length], 3, 3); + var chunker = std.mem.window(u8, buf[buf_idx..chunkable_length], 3, 3); while (chunker.next()) |chunk| { - var temp: [5]u8 = undefined; - const s = OSC52.base64encoder.encode(&temp, chunk); + // var temp: [5]u8 = undefined; + s = OSC52.base64encoder.encode(&temp, chunk); try self.base64buffer.appendSlice(self.alloc, s); } @@ -59,7 +62,14 @@ pub fn writeCopyBuffer(self: *OSC52, buf: []u8) !void { } } -pub fn writePasteboard(self: *OSC52) !void { +pub fn encodeRemaining(self: *OSC52) anyerror!void { + var temp: [5]u8 = undefined; + const s = OSC52.base64encoder.encode(&temp, self.leftover_bytes[0..self.leftover_count]); + try self.base64buffer.appendSlice(self.alloc, s); +} + +pub fn writePasteboard(self: *OSC52) anyerror!void { + try self.encodeRemaining(); // https://ghostty.org/docs/vt/osc/52 const osc_header = &[_]u8{ @@ -76,14 +86,51 @@ pub fn writePasteboard(self: *OSC52) !void { 0x5c, // '\' }; - // Write leftover bytes - var temp: [5]u8 = undefined; - const s = OSC52.base64encoder.encode(&temp, self.leftover_bytes[0..self.leftover_count]); - try self.base64buffer.appendSlice(self.alloc, s); - // Write data to stdout const stdout = Io.File.stdout(); try stdout.writeStreamingAll(self.io, osc_header); try stdout.writeStreamingAll(self.io, self.base64buffer.items); try stdout.writeStreamingAll(self.io, osc_footer); } + +test "basic base64 encode" { + var osc = try OSC52.init(std.testing.allocator, std.testing.io, 1024); + defer osc.free(); + try osc.writeCopyBuffer("part1"); + try osc.encodeRemaining(); + try std.testing.expectEqualSlices(u8, "cGFydDE=", osc.base64buffer.items); +} + +test "multi part base64 encode" { + var osc = try OSC52.init(std.testing.allocator, std.testing.io, 1024); + defer osc.free(); + try osc.writeCopyBuffer("part1"); + try osc.writeCopyBuffer("part2"); + try osc.encodeRemaining(); + try std.testing.expectEqualSlices(u8, "cGFydDFwYXJ0Mg==", osc.base64buffer.items); +} + +test "tiny buffers base64 encode" { + var osc = try OSC52.init(std.testing.allocator, std.testing.io, 1024); + defer osc.free(); + try osc.writeCopyBuffer("part1"); + try osc.writeCopyBuffer("part2"); + try osc.writeCopyBuffer("1"); + try osc.writeCopyBuffer("2"); + try osc.writeCopyBuffer("3"); + try osc.writeCopyBuffer("45"); + try osc.writeCopyBuffer("6"); + try osc.writeCopyBuffer("78"); + try osc.writeCopyBuffer("90fin"); + try osc.encodeRemaining(); + try std.testing.expectEqualSlices(u8, "cGFydDFwYXJ0MjEyMzQ1Njc4OTBmaW4=", osc.base64buffer.items); +} + +test "big buffers base64 encode" { + var osc = try OSC52.init(std.testing.allocator, std.testing.io, 1024); + defer osc.free(); + try osc.writeCopyBuffer("part1part1part1part1part1part1part1part1part1|"); + try osc.writeCopyBuffer("part2part2part2part2part2part2part2part2part2"); + try osc.encodeRemaining(); + try std.testing.expectEqualSlices(u8, "cGFydDFwYXJ0MXBhcnQxcGFydDFwYXJ0MXBhcnQxcGFydDFwYXJ0MXBhcnQxfHBhcnQycGFydDJwYXJ0MnBhcnQycGFydDJwYXJ0MnBhcnQycGFydDJwYXJ0Mg==", osc.base64buffer.items); +} diff --git a/src/main.zig b/src/main.zig index 5c1a339..2d5bc56 100644 --- a/src/main.zig +++ b/src/main.zig @@ -38,3 +38,7 @@ pub fn main(init: std.process.Init) !void { std.debug.print("\x1b[0;32mCopied To Pasteboard!\x1b[0m\n", .{}); } + +test { + _ = @import("Clip.zig"); +}