diff options
Diffstat (limited to 'test/panes.zig')
| -rw-r--r-- | test/panes.zig | 70 |
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 }); |
