summaryrefslogtreecommitdiff
path: root/test/panes.zig
diff options
context:
space:
mode:
Diffstat (limited to 'test/panes.zig')
-rw-r--r--test/panes.zig70
1 files changed, 61 insertions, 9 deletions
diff --git a/test/panes.zig b/test/panes.zig
index 3d2821aa..c1ae1666 100644
--- a/test/panes.zig
+++ b/test/panes.zig
@@ -1622,7 +1622,8 @@ test "pane filename drafts commit and cancel without changing body or command ta
try std.testing.expectEqualStrings(tail, pardes.tagline.curTail(pane));
while (p.nextEffect()) |effect| try std.testing.expect(std.meta.activeTag(effect) != .save_file);
}
- try std.testing.expect(pane.file.?.revision != pane.file.?.saved_revision);
+ // A name alone is no edit: the pane stays clean.
+ try std.testing.expect(pane.file.?.revision == pane.file.?.saved_revision);
}
test "pane filename grapheme edits and invalid empty commits preserve the buffer" {
@@ -2500,21 +2501,48 @@ test "Save on a scratch does not watch a path the host could not create" {
const id = p.active;
while (p.nextEffect()) |_| {}
p.host = .{ .ctx = p, .vtable = &.{ .write_file = Refusing.write } };
+ const file = &p.panes[id].?.file.?;
+ const scratch_name = try std.testing.allocator.dupe(u8, file.path);
+ defer std.testing.allocator.free(scratch_name);
+ const was_dirty = file.revision != file.saved_revision;
try std.testing.expect(p.executeBuiltinLine(id, "Save /new-file.txt"));
while (p.nextEffect()) |effect| p.perform(effect);
- const file = &p.panes[id].?.file.?;
- try std.testing.expect(file.output == null);
- try std.testing.expect(file.watch_after_save);
- try std.testing.expect(file.revision != file.saved_revision);
+ // Failed, it changed nothing: still the scratch, its name and dirty
+ // flag as they were, unwatched.
+ try std.testing.expect(file.output != null);
+ try std.testing.expectEqualStrings(scratch_name, file.path);
+ try std.testing.expectEqual(was_dirty, file.revision != file.saved_revision);
try std.testing.expect(!p.fallback.watched[id]);
p.host = .{};
- try std.testing.expect(p.executeBuiltinLine(id, "Save"));
+ try std.testing.expect(p.executeBuiltinLine(id, "Save /new-file.txt"));
while (p.nextEffect()) |effect| p.perform(effect);
- try std.testing.expect(!file.watch_after_save);
+ try std.testing.expect(file.output == null);
+ try std.testing.expectEqualStrings("/new-file.txt", file.path);
try std.testing.expectEqual(file.revision, file.saved_revision);
try std.testing.expect(p.fallback.watched[id]);
}
+test "a failed Save to another name leaves a clean named file clean" {
+ const Refusing = struct {
+ fn write(ctx: ?*anyopaque, id: u8, _: []const u8, _: []const u8) void {
+ const p: *Pardes = @ptrCast(@alignCast(ctx.?));
+ p.saveFailed(id, "save", error.AccessDenied);
+ }
+ };
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 40, .rows = 12 });
+ defer p.deinit();
+ const pane = try p.setTestFile("clean\n");
+ while (p.nextEffect()) |_| {}
+ const file = &pane.file.?;
+ try std.testing.expectEqual(file.revision, file.saved_revision);
+ p.host = .{ .ctx = p, .vtable = &.{ .write_file = Refusing.write } };
+ try std.testing.expect(p.executeBuiltinLine(0, "Save /root/x.txt"));
+ while (p.nextEffect()) |effect| p.perform(effect);
+ try std.testing.expectEqual(file.revision, file.saved_revision);
+ try std.testing.expectEqualStrings("/test.txt", file.path);
+ p.host = .{};
+}
+
test "unplaced terminal panes keep their allocated grid until placement" {
const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 100, .rows = 30 });
defer p.deinit();
@@ -3438,14 +3466,14 @@ const TerminalTests = struct {
.write => return error.GreetedBeforePrompt,
else => {},
};
- p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b]133;A\x07prompt$ " } });
+ p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b]133;A;aid=pardes\x07prompt$ " } });
try std.testing.expect(!promptInputReady(pane));
while (p.nextEffect()) |effect| switch (effect) {
.write => return error.GreetedDuringPrompt,
else => {},
};
- p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b]133;B\x07" } });
+ p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b]133;B;aid=pardes\x07" } });
try std.testing.expect(promptInputReady(pane));
var greeted = false;
while (p.nextEffect()) |effect| switch (effect) {
@@ -3456,6 +3484,30 @@ const TerminalTests = struct {
try std.testing.expect(!pane.greet);
}
+ test "the greeting is dropped, never typed later, once something ran or was typed first" {
+ if (pardes.platform == .web) return;
+ for ([_][]const u8{
+ // A command ran before the first prompt was seen at rest.
+ "\x1b]133;A;aid=pardes\x07$ \x1b]133;B;aid=pardes\x07\x1b]133;C;aid=pardes\x07out\r\n\x1b]133;D;0;aid=pardes\x07\x1b]133;A;aid=pardes\x07$ \x1b]133;B;aid=pardes\x07",
+ // Someone typed at the first prompt.
+ "\x1b]133;A;aid=pardes\x07$ \x1b]133;B;aid=pardes\x07vim",
+ }) |output| {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 80, .rows = 24 });
+ defer p.deinit();
+ const pane = p.panes[0].?;
+ while (p.nextEffect()) |_| {}
+ p.update(.{ .resize = .{ .cols = 80, .rows = 24 } });
+ p.update(.{ .output = .{ .pane = 0, .bytes = output } });
+ // and a later, quiet prompt changes nothing
+ p.update(.{ .output = .{ .pane = 0, .bytes = "\r\n\x1b]133;A;aid=pardes\x07$ \x1b]133;B;aid=pardes\x07" } });
+ while (p.nextEffect()) |effect| switch (effect) {
+ .write => |write| if (std.mem.eql(u8, write.bytes.slice(), "ls\r")) return error.GreetedLate,
+ else => {},
+ };
+ try std.testing.expect(!pane.greet);
+ }
+ }
+
test "fresh-shell commands preserve order and wait for OSC 133 B" {
if (pardes.platform == .web) return;
const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true });