Skip to content

Commit 46a999f

Browse files
committed
test(replay): replay full session reload path
1 parent e7a6d31 commit 46a999f

3 files changed

Lines changed: 104 additions & 18 deletions

File tree

tests/helpers.lua

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ function M.replay_setup()
2121
renderer._cleanup_subscriptions()
2222
renderer.reset()
2323

24+
M.mock_time_ago()
25+
2426
if not config.config then
2527
config.config = vim.deepcopy(config.defaults)
2628
end
@@ -143,6 +145,56 @@ function M.load_test_data(filename)
143145
return vim.json.decode(content)
144146
end
145147

148+
function M.load_session_from_events(events)
149+
local session_data = {}
150+
151+
for _, event in ipairs(events) do
152+
local properties = event.properties
153+
154+
if event.type == 'message.updated' and properties.info then
155+
local msg = properties.info
156+
local existing_msg = nil
157+
for _, m in ipairs(session_data) do
158+
if m.info.id == msg.id then
159+
existing_msg = m
160+
break
161+
end
162+
end
163+
164+
if existing_msg then
165+
existing_msg.info = vim.deepcopy(msg)
166+
else
167+
table.insert(session_data, {
168+
info = vim.deepcopy(msg),
169+
parts = {},
170+
})
171+
end
172+
elseif event.type == 'message.part.updated' and properties.part then
173+
local part = properties.part
174+
for _, msg in ipairs(session_data) do
175+
if msg.info.id == part.messageID then
176+
local existing_part = nil
177+
for i, p in ipairs(msg.parts) do
178+
if p.id == part.id then
179+
existing_part = i
180+
break
181+
end
182+
end
183+
184+
if existing_part then
185+
msg.parts[existing_part] = vim.deepcopy(part)
186+
else
187+
table.insert(msg.parts, vim.deepcopy(part))
188+
end
189+
break
190+
end
191+
end
192+
end
193+
end
194+
195+
return session_data
196+
end
197+
146198
function M.get_session_from_events(events)
147199
-- renderer needs a valid session id
148200
for _, event in ipairs(events) do
@@ -185,7 +237,8 @@ end
185237

186238
function M.normalize_namespace_ids(extmarks)
187239
local normalized = vim.deepcopy(extmarks)
188-
for _, mark in ipairs(normalized) do
240+
for i, mark in ipairs(normalized) do
241+
mark[1] = i
189242
if mark[4] and mark[4].ns_id then
190243
mark[4].ns_id = 3
191244
end

tests/manual/renderer_replay.lua

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
local state = require('opencode.state')
22
local renderer = require('opencode.ui.renderer')
3-
local ui = require('opencode.ui.ui')
4-
local config_file = require('opencode.config_file')
53
local helpers = require('tests.helpers')
64
local output_window = require('opencode.ui.output_window')
75

@@ -12,7 +10,6 @@ M.current_index = 0
1210
M.timer = nil
1311
M.last_loaded_file = nil
1412
M.headless_mode = false
15-
M.restore_time_ago = nil
1613

1714
function M.load_events(file_path)
1815
file_path = file_path or 'tests/data/simple-session.json'
@@ -106,6 +103,7 @@ function M.replay_all(delay_ms)
106103
delay_ms = delay_ms or 50
107104

108105
if M.timer then
106+
---@diagnostic disable-next-line: undefined-field
109107
M.timer:stop()
110108
M.timer = nil
111109
end
@@ -116,12 +114,14 @@ function M.replay_all(delay_ms)
116114
end
117115

118116
M.timer = vim.loop.new_timer()
117+
---@diagnostic disable-next-line: undefined-field
119118
M.timer:start(
120119
0,
121120
delay_ms,
122121
vim.schedule_wrap(function()
123122
if M.current_index >= #M.events then
124123
if M.timer then
124+
---@diagnostic disable-next-line: undefined-field
125125
M.timer:stop()
126126
M.timer = nil
127127
end
@@ -139,6 +139,7 @@ end
139139

140140
function M.replay_stop()
141141
if M.timer then
142+
---@diagnostic disable-next-line: undefined-field
142143
M.timer:stop()
143144
M.timer = nil
144145
vim.notify('Replay stopped at event ' .. M.current_index .. '/' .. #M.events, vim.log.levels.INFO)
@@ -210,6 +211,21 @@ function M.save_output(filename)
210211
return snapshot
211212
end
212213

214+
function M.replay_full_session()
215+
if #M.events == 0 then
216+
vim.notify('No events loaded. Use :ReplayLoad first.', vim.log.levels.WARN)
217+
return false
218+
end
219+
220+
local session_data = helpers.load_session_from_events(M.events)
221+
222+
renderer.reset()
223+
renderer._render_full_session_data(session_data)
224+
225+
vim.notify('Rendered full session from loaded events', vim.log.levels.INFO)
226+
return true
227+
end
228+
213229
function M.dump_buffer_and_quit()
214230
vim.schedule(function()
215231
if not state.windows or not state.windows.output_buf then
@@ -269,23 +285,29 @@ function M.start(opts)
269285
'Streaming Renderer Replay',
270286
'',
271287
'Use :ReplayLoad [file] to load event data',
288+
'Use :ReplayFullSession to render loaded events using full session mode',
272289
'',
273290
'Commands:',
274-
' :ReplayLoad [file] - Load events (default: tests/data/simple-session.json)',
275-
" :ReplayNext [step] - Replay next [step] event(s) (default 1) (<leader>n or '>' )",
276-
' :ReplayAll [ms] - Replay all events with delay (default 50ms) (<leader>a)',
277-
' :ReplayStop - Stop auto-replay (<leader>s)',
278-
' :ReplayReset - Reset to beginning (<leader>r)',
279-
' :ReplayClear - Clear output buffer (<leader>c)',
280-
' :ReplaySave [file] - Save snapshot (auto-derives from loaded file)',
281-
' :ReplayStatus - Show status',
291+
' :ReplayLoad [file] - Load events (default: tests/data/simple-session.json)',
292+
' :ReplayFullSession - Render loaded events using full session mode',
293+
" :ReplayNext [step] - Replay next [step] event(s) (default 1) (<leader>n or '>' )",
294+
' :ReplayAll [ms] - Replay all events with delay (default 50ms) (<leader>a)',
295+
' :ReplayStop - Stop auto-replay (<leader>s)',
296+
' :ReplayReset - Reset to beginning (<leader>r)',
297+
' :ReplayClear - Clear output buffer (<leader>c)',
298+
' :ReplaySave [file] - Save snapshot (auto-derives from loaded file)',
299+
' :ReplayStatus - Show status',
282300
})
283301

284302
vim.api.nvim_create_user_command('ReplayLoad', function(cmd_opts)
285303
local file = cmd_opts.args ~= '' and cmd_opts.args or nil
286304
M.load_events(file)
287305
end, { nargs = '?', desc = 'Load event data file', complete = 'file' })
288306

307+
vim.api.nvim_create_user_command('ReplayFullSession', function()
308+
M.replay_full_session()
309+
end, { desc = 'Render loaded events using full session mode' })
310+
289311
vim.api.nvim_create_user_command('ReplayNext', function(cmd_opts)
290312
local steps = cmd_opts.args ~= '' and cmd_opts.args or nil
291313
M.replay_next(steps)

tests/unit/renderer_spec.lua

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,12 @@ describe('renderer', function()
88

99
before_each(function()
1010
helpers.replay_setup()
11-
restore_time_ago = helpers.mock_time_ago()
1211
end)
1312

1413
after_each(function()
1514
if state.windows then
1615
ui.close_windows(state.windows)
1716
end
18-
19-
if restore_time_ago then
20-
restore_time_ago()
21-
end
2217
end)
2318

2419
local json_files = vim.fn.glob('tests/data/*.json', false, true)
@@ -30,7 +25,7 @@ describe('renderer', function()
3025
local expected_path = 'tests/data/' .. name .. '.expected.json'
3126

3227
if vim.fn.filereadable(expected_path) == 1 then
33-
it('replays ' .. name .. ' correctly', function()
28+
it('replays ' .. name .. ' correctly (event-by-event)', function()
3429
local events = helpers.load_test_data(filepath)
3530
state.active_session = helpers.get_session_from_events(events)
3631
local expected = helpers.load_test_data(expected_path)
@@ -43,6 +38,22 @@ describe('renderer', function()
4338
assert.are.same(expected.lines, actual.lines)
4439
assert.are.same(expected.extmarks, helpers.normalize_namespace_ids(actual.extmarks))
4540
end)
41+
42+
it('replays ' .. name .. ' correctly (full session load)', function()
43+
local renderer = require('opencode.ui.renderer')
44+
local events = helpers.load_test_data(filepath)
45+
state.active_session = helpers.get_session_from_events(events)
46+
local expected = helpers.load_test_data(expected_path)
47+
48+
local session_data = helpers.load_session_from_events(events)
49+
renderer._render_full_session_data(session_data)
50+
vim.wait(200)
51+
52+
local actual = helpers.capture_output(state.windows.output_buf, output_window.namespace)
53+
54+
assert.are.same(expected.lines, actual.lines)
55+
assert.are.same(expected.extmarks, helpers.normalize_namespace_ids(actual.extmarks))
56+
end)
4657
end
4758
end
4859
end

0 commit comments

Comments
 (0)