Add ability to write tests

This commit is contained in:
Cameron Reed 2024-08-03 16:29:43 -06:00
parent 6b7495078e
commit d30342c3f7
4 changed files with 128 additions and 6 deletions

View File

@ -88,4 +88,9 @@ pub fn build(b: *std.Build) void {
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_lib_unit_tests.step);
test_step.dependOn(&run_exe_unit_tests.step);
// Configure zls to run this step on save for better error checking with zls
const check_step = b.step("check", "Check compilation status");
check_step.dependOn(&exe.step);
check_step.dependOn(&lib.step);
}

View File

@ -106,7 +106,7 @@ pub const Pane = struct {
};
pub const WriterContext = struct { pane: *Pane, term_io: *TermIO };
pub const Writer = std.io.Writer(WriterContext, std.fs.File.WriteError, write);
pub const Writer = std.io.Writer(WriterContext, anyerror, write);
pub fn ReDraw(self: *Pane, term_io: *TermIO, parentDims: dim.CalculatedDimensions) !void {
if (!self.should_draw) {
@ -231,7 +231,7 @@ pub const Pane = struct {
};
}
pub fn write(self: WriterContext, bytes: []const u8) std.fs.File.WriteError!usize {
pub fn write(self: WriterContext, bytes: []const u8) !usize {
if (self.pane != focused_pane) {
self.pane.focus(self.term_io);
}

View File

@ -4,6 +4,7 @@ const posix = std.posix;
const borders = @import("borders.zig");
const dim = @import("dimensions.zig");
const color = @import("colors.zig");
const term_test = @import("test/term.zig");
var orig_termios: posix.termios = undefined;
@ -226,8 +227,10 @@ pub const TermFormat = packed struct {
};
pub const TermIO = struct {
stdin: fs.File.Reader,
stdout: std.io.BufferedWriter(4096, fs.File.Writer).Writer,
stdin: std.io.AnyReader,
stdout: std.io.BufferedWriter(4096, std.io.AnyWriter).Writer,
//stdin: std.fs.File.Reader,
//stdout: std.io.BufferedWriter(4096, std.fs.File.Writer).Writer,
tty_file: fs.File,
current_format: TermFormat = .{},
current_background: color.Color = color.Default,
@ -520,9 +523,9 @@ pub fn getTermSize(term_io: *const TermIO) dim.CalculatedDimensions {
}
pub fn getTermIO() !TermIO {
var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
var bw = std.io.bufferedWriter(std.io.getStdOut().writer().any());
return TermIO{
.stdin = std.io.getStdIn().reader(),
.stdin = std.io.getStdIn().reader().any(),
.stdout = bw.writer(),
.tty_file = try fs.cwd().openFile("/dev/tty", .{ .mode = .read_write }),
};
@ -540,3 +543,24 @@ fn decipherEscapeSequence(sequence: []u8) Key {
return .{ .type = KeyType.SEQUENCE, .value = @intFromEnum(SequenceKey.UNKNOWN) };
}
test "cool test" {
term_test.term_io.print("Hello {}", .{123});
try term_test.term_io.flush();
try std.testing.expectEqualStrings("Hello 123", term_test.readAllTestStdout());
}
test "stdin" {
try term_test.writeTestStdin(&[_]u8{ 'a', '\x1b', '[', 'A' });
var key = term_test.term_io.getKey(false);
try std.testing.expect(key.type == .ASCII);
try std.testing.expect(key.value == 'a');
key = term_test.term_io.getKey(false);
try std.testing.expect(key.type == .SEQUENCE);
try std.testing.expect(@as(SequenceKey, @enumFromInt(key.value)) == SequenceKey.UP);
key = term_test.term_io.getKey(false);
try std.testing.expect(key.type == .NO_KEY);
}

93
src/test/term.zig Normal file
View File

@ -0,0 +1,93 @@
const std = @import("std");
const TermIO = @import("../term.zig").TermIO;
var StdinBuf: [4096]u8 = undefined;
var StdinStart: usize = 0;
var StdinEnd: usize = 0;
var StdoutBuf: [4096]u8 = undefined;
var StdoutStart: usize = 0;
var StdoutEnd: usize = 0;
var bw = std.io.bufferedWriter(TestStdout.writer().any());
pub var term_io: TermIO = .{
.stdin = TestStdin.reader().any(),
.stdout = bw.writer(),
.tty_file = undefined,
};
const TestStdin = struct {
const ReadError = error{};
const Reader = std.io.Reader(TestStdin, ReadError, read);
fn reader() Reader {
return .{
.context = .{},
};
}
fn read(self: TestStdin, buffer: []u8) ReadError!usize {
_ = self;
const bytesAvailable = StdinEnd - StdinStart;
if (bytesAvailable == 0) {
//std.debug.print("Buffer is empty: {} to {}\n", .{ StdinStart, StdinEnd });
return 0;
} else if (buffer.len >= bytesAvailable) {
std.mem.copyForwards(u8, buffer, StdinBuf[StdinStart..StdinEnd]);
StdinStart = 0;
StdinEnd = 0;
//std.debug.print("{x}\n", .{buffer});
return bytesAvailable;
} else {
std.mem.copyForwards(u8, buffer, StdinBuf[StdinStart .. StdinStart + buffer.len]);
StdinStart += buffer.len;
//std.debug.print("{x}\n", .{buffer});
return buffer.len;
}
}
};
const TestStdout = struct {
const WriteError = error{};
const Writer = std.io.Writer(TestStdout, WriteError, write);
fn writer() Writer {
return .{
.context = .{},
};
}
fn write(self: TestStdout, buffer: []const u8) WriteError!usize {
_ = self;
const c = @min(buffer.len, StdoutBuf.len - StdoutEnd);
std.mem.copyForwards(u8, StdoutBuf[StdoutEnd .. StdoutEnd + c], buffer[0..c]);
StdoutEnd += c;
return c;
}
};
pub fn getTestTermIO() TermIO {}
pub fn writeTestStdin(input: []const u8) !void {
if (StdinEnd + input.len < StdinBuf.len) {
std.mem.copyForwards(u8, StdinBuf[StdinEnd .. StdinEnd + input.len], input);
StdinEnd += input.len;
//std.debug.print("{x}\n", .{StdinBuf[StdinStart..StdinEnd]});
} else {
return error.BufferFull;
}
}
pub fn readTestStdout(count: usize) []u8 {
const c = @min(count, StdoutEnd - StdoutStart);
const buf = StdoutBuf[StdoutStart .. StdoutStart + c];
StdoutStart += c;
return buf;
}
pub fn readAllTestStdout() []u8 {
const buf = StdoutBuf[StdoutStart..StdoutEnd];
StdoutStart = 0;
StdoutEnd = 0;
return buf;
}