╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ undo.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
136 try std.testing.expectEqualStrings("Forbidden", session.data.undo_failure.?); 137 try std.testing.expectEqual(null, session.next_page); 138 } 139 140 test "local git has no undo and local xit can undo and refresh" { 141 inline for ([_]xit.repo.RepoKind{ .git, .xit }) |kind| { 142 var temp = std.testing.tmpDir(.{}); 143 defer temp.cleanup(); 144 var arena = std.heap.ArenaAllocator.init(allocator); 145 defer arena.deinit(); 146 const path = try temp.dir.realPathFileAlloc(io, ".", arena.allocator()); 147 { 148 var repo = try xit.repo.Repo(kind, .{}).init(io, allocator, .{ .path = path }); 149 defer repo.deinit(io, allocator); 150 try repo.addConfig(io, allocator, .{ .name = "undo.value", .value = "first" }); 151 } 152 var session = ui.Session{ .arena = &arena, .page_arena = &arena, .io = io, .local = .{ .path = path, .repo_kind = kind }, .data = .{ .host_kind = .local } }; 153 const files = ui.RoutablePage.repoFilesRoute("", null, "", "", 0).?; 154 const data = try ui.Repo.init(&arena, &session, files); 155 try std.testing.expectEqual(kind == .xit, data.undo != null); 156 if (kind == .git) { 157 try std.testing.expectError(error.NotFound, ui.Repo.init(&arena, &session, ui.RoutablePage.repoUndoRoute("", null).?)); 158 try std.testing.expectError(error.NotFound, Undo.execute(io, allocator, session.local.?, 1)); 159 } else { 160 Undo.handleRequest(allocator, &session, ui.RoutablePage.repoUndoRoute("", 999).?.repo_undo); 161 try std.testing.expectEqualStrings("InvalidHistoryIndex", session.data.undo_failure.?); 162 try std.testing.expectEqual(null, session.next_page); 163 Undo.handleRequest(allocator, &session, ui.RoutablePage.repoUndoRoute("", 1).?.repo_undo); 164 try std.testing.expectEqual(null, session.data.undo_failure); 165 const refreshed = try ui.Repo.init(&arena, &session, session.next_page.?); 166 try std.testing.expectEqualStrings("undo", refreshed.undo.?.items[0].action); 167 } 168 } 169 } 170 171 test "commit undo records use the formatted description" { 172 var temp = std.testing.tmpDir(.{}); 173 defer temp.cleanup(); 174 var arena = std.heap.ArenaAllocator.init(allocator); 175 defer arena.deinit(); 176 const path = try temp.dir.realPathFileAlloc(io, ".", arena.allocator()); 177 const opts: xit.repo.RepoOpts(.xit) = .{ .is_test = true }; 178 var repo = try xit.repo.Repo(.xit, opts).init(io, allocator, .{ .path = path }); 179 defer repo.deinit(io, allocator); 180 _ = try repo.commitAtRef(io, allocator, .{ .message = "example commit" }, null, .{ .kind = .head, .name = "master" }); 181 const data = try Undo.init(opts, &arena, &repo, null, "", null, .{ .location = .{ .repo = "" } }); 182 try std.testing.expect(std.mem.startsWith(u8, data.items[0].description, "commit -m \"example commit\"")); 183 } 184 185 test "malformed undo history is shown as an error" { 186 var temp = std.testing.tmpDir(.{}); 187 defer temp.cleanup(); 188 var arena = std.heap.ArenaAllocator.init(allocator); 189 defer arena.deinit(); 190 const path = try temp.dir.realPathFileAlloc(io, ".", arena.allocator()); 191 const Repo = xit.repo.Repo(.xit, .{}); 192 var repo = try Repo.init(io, allocator, .{ .path = path }); 193 defer repo.deinit(io, allocator); 194 195 // append an invalid undo record without damaging the repository data. 196 const Corrupt = struct { 197 pub fn run(_: @This(), cursor: *Repo.DB.Cursor(.read_write)) !void { 198 const moment = try Repo.DB.HashMap(.read_write).init(cursor.*); 199 try moment.put(xit.hash.hashInt(.sha1, "undo"), .{ .bytes = "bad" }); 200 } 201 }; 202 const history = try Repo.DB.ArrayList(.read_write).init(repo.core.db.rootCursor()); 203 try history.appendContext(.{ .slot = try history.getSlot(-1) }, Corrupt{}); 204 205 var session = ui.Session{ .arena = &arena, .page_arena = &arena, .io = io, .local = .{ .path = path, .repo_kind = .xit }, .data = .{ .host_kind = .local } }; 206 // tabs switch in-page, so every tab carries the undo data and its failure 207 const files = try ui.Repo.init(&arena, &session, ui.RoutablePage.repoFilesRoute("", null, "", "", 0).?); 208 try std.testing.expectEqual(0, files.undo.?.items.len); 209 try std.testing.expectEqualStrings("InvalidUndoRecord", files.undo.?.failure.?); 210 const undo = try ui.Repo.init(&arena, &session, ui.RoutablePage.repoUndoRoute("", null).?); 211 try std.testing.expectEqualStrings("InvalidUndoRecord", undo.undo.?.failure.?); 212 213 var root = ui.Widget{ .repo_undo = try Undo.View.init(allocator, &undo.undo.?, &session) }; 214 defer root.deinit(allocator); 215 try root.build(allocator, constraint, root.getFocus()); 216 const html = try @import("../web.zig").generateHtml(allocator, &root, &session); 217 defer allocator.free(html); 218 try std.testing.expect(std.mem.indexOf(u8, html, "InvalidUndoRecord") != null); 219 } 220