terminal: test for match in second slice of circ buf

This commit is contained in:
Mitchell Hashimoto
2024-12-04 10:58:22 -08:00
parent af1ee4d95f
commit 852e04fa00

View File

@ -118,12 +118,16 @@ const SlidingWindow = struct {
/// the invariant that the window is always big enough to contain /// the invariant that the window is always big enough to contain
/// the needle. /// the needle.
pub fn next(self: *SlidingWindow, needle: []const u8) ?Selection { pub fn next(self: *SlidingWindow, needle: []const u8) ?Selection {
const slices = slices: {
// If we have less data then the needle then we can't possibly match
const data_len = self.data.len(); const data_len = self.data.len();
if (data_len == 0) return null; if (data_len < needle.len) return null;
const slices = self.data.getPtrSlice(
break :slices self.data.getPtrSlice(
self.data_offset, self.data_offset,
data_len - self.data_offset, data_len - self.data_offset,
); );
};
// Search the first slice for the needle. // Search the first slice for the needle.
if (std.mem.indexOf(u8, slices[0], needle)) |idx| { if (std.mem.indexOf(u8, slices[0], needle)) |idx| {
@ -134,7 +138,6 @@ const SlidingWindow = struct {
// Search the last slice for the needle. // Search the last slice for the needle.
if (std.mem.indexOf(u8, slices[1], needle)) |idx| { if (std.mem.indexOf(u8, slices[1], needle)) |idx| {
if (true) @panic("TODO: test");
return self.selection(slices[0].len + idx, needle.len); return self.selection(slices[0].len + idx, needle.len);
} }
@ -182,6 +185,10 @@ const SlidingWindow = struct {
self.data.deleteOldest(prune_data_len); self.data.deleteOldest(prune_data_len);
} }
// Our data offset now moves to needle.len - 1 from the end so
// that we can handle the overlap case.
self.data_offset = self.data.len() - needle.len + 1;
self.assertIntegrity(); self.assertIntegrity();
return null; return null;
} }
@ -615,3 +622,55 @@ test "SlidingWindow two pages no match keeps both pages" {
// No pruning because both pages are needed to fit needle. // No pruning because both pages are needed to fit needle.
try testing.expectEqual(2, w.meta.len()); try testing.expectEqual(2, w.meta.len());
} }
test "SlidingWindow single append across circular buffer boundary" {
const testing = std.testing;
const alloc = testing.allocator;
var w = try SlidingWindow.initEmpty(alloc);
defer w.deinit(alloc);
var s = try Screen.init(alloc, 80, 24, 0);
defer s.deinit();
try s.testWriteString("XXXXXXXXXXXXXXXXXXXboo!XXXXX");
// We are trying to break a circular buffer boundary so the way we
// do this is to duplicate the data then do a failing search. This
// will cause the first page to be pruned. The next time we append we'll
// put it in the middle of the circ buffer. We assert this so that if
// our implementation changes our test will fail.
try testing.expect(s.pages.pages.first == s.pages.pages.last);
const node: *PageList.List.Node = s.pages.pages.first.?;
try w.append(alloc, node);
try w.append(alloc, node);
{
// No wrap around yet
const slices = w.data.getPtrSlice(0, w.data.len());
try testing.expect(slices[0].len > 0);
try testing.expect(slices[1].len == 0);
}
// Search non-match, prunes page
try testing.expect(w.next("abc") == null);
try testing.expectEqual(1, w.meta.len());
// Add new page, now wraps
try w.append(alloc, node);
{
const slices = w.data.getPtrSlice(0, w.data.len());
try testing.expect(slices[0].len > 0);
try testing.expect(slices[1].len > 0);
}
{
const sel = w.next("boo!").?;
try testing.expectEqual(point.Point{ .active = .{
.x = 19,
.y = 0,
} }, s.pages.pointFromPin(.active, sel.start()).?);
try testing.expectEqual(point.Point{ .active = .{
.x = 22,
.y = 0,
} }, s.pages.pointFromPin(.active, sel.end()).?);
}
try testing.expect(w.next("boo!") == null);
}