diff --git a/lua/cp/init.lua b/lua/cp/init.lua index 5928ecf..0a820b7 100644 --- a/lua/cp/init.lua +++ b/lua/cp/init.lua @@ -206,11 +206,24 @@ local function toggle_test_panel() return end + if state.platform == "codeforces" then + logger.log("test panel not yet supported for codeforces", vim.log.levels.ERROR) + return + end + local problem_id = get_current_problem() if not problem_id then return end + local ctx = problem.create_context(state.platform, state.contest_id, state.problem_id, config) + local test_module = require("cp.test") + + if not test_module.load_test_cases(ctx, state) then + logger.log("no test cases found", vim.log.levels.WARN) + return + end + state.saved_session = vim.fn.tempname() vim.cmd(("mksession! %s"):format(state.saved_session)) @@ -221,24 +234,59 @@ local function toggle_test_panel() vim.bo.filetype = "cptest" vim.bo.bufhidden = "wipe" - local test_lines = { - " 1 ✓ PASS 12ms", - " 2 ✗ FAIL 45ms", - "> 3 ✓ PASS 8ms", - " 4 ? PENDING", - "", - "── Test 3 ──", - "Input: │ Expected: │ Actual:", - "5 3 │ 8 │ 8", - "", - "j/k: navigate : toggle : run q: quit", - } + local test_state = test_module.get_test_panel_state() + local test_lines = {} + + for i, test_case in ipairs(test_state.test_cases) do + local status_icon = "?" + local status_text = "PENDING" + + if test_case.status == "pass" then + status_icon = "✓" + status_text = "PASS" + elseif test_case.status == "fail" then + status_icon = "✗" + status_text = "FAIL" + end + + local time_text = test_case.time_ms and string.format("%.0fms", test_case.time_ms) or "" + local prefix = i == test_state.current_index and "> " or " " + + table.insert(test_lines, string.format("%s%d %s %s %s", + prefix, i, status_icon, status_text, time_text)) + end + + table.insert(test_lines, "") + + local current_test = test_state.test_cases[test_state.current_index] + if current_test then + table.insert(test_lines, string.format("── Test %d ──", test_state.current_index)) + table.insert(test_lines, "Input:") + for line in current_test.input:gmatch("[^\n]*") do + table.insert(test_lines, " " .. line) + end + + table.insert(test_lines, "Expected:") + for line in current_test.expected:gmatch("[^\n]*") do + table.insert(test_lines, " " .. line) + end + + if current_test.actual then + table.insert(test_lines, "Actual:") + for line in current_test.actual:gmatch("[^\n]*") do + table.insert(test_lines, " " .. line) + end + end + end + + table.insert(test_lines, "") + table.insert(test_lines, "j/k: navigate : toggle : run q: quit") vim.api.nvim_buf_set_lines(test_buf, 0, -1, false, test_lines) vim.bo.modifiable = false state.test_panel_active = true - logger.log("test panel opened") + logger.log(string.format("test panel opened (%d test cases)", #test_state.test_cases)) end ---@param delta number 1 for next, -1 for prev diff --git a/lua/cp/scrape.lua b/lua/cp/scrape.lua index b76b3af..291a64d 100644 --- a/lua/cp/scrape.lua +++ b/lua/cp/scrape.lua @@ -225,7 +225,13 @@ function M.scrape_problem(ctx) return data end - if data.test_cases and #data.test_cases > 0 then + if data.combined then + local combined_input = data.combined.input:gsub("\r", "") + local combined_output = data.combined.output:gsub("\r", "") + + vim.fn.writefile(vim.split(combined_input, "\n", true), ctx.input_file) + vim.fn.writefile(vim.split(combined_output, "\n", true), ctx.expected_file) + elseif data.test_cases and #data.test_cases > 0 then local combined_input = data.test_cases[1].input:gsub("\r", "") local combined_output = data.test_cases[1].output:gsub("\r", "") diff --git a/lua/cp/test.lua b/lua/cp/test.lua index 96e8d1a..9c77408 100644 --- a/lua/cp/test.lua +++ b/lua/cp/test.lua @@ -1,7 +1,24 @@ +---@class TestCase +---@field index number +---@field input string +---@field expected string +---@field status "pending"|"pass"|"fail"|"running" +---@field actual string? +---@field time_ms number? +---@field error string? + +---@class TestPanelState +---@field test_cases TestCase[] +---@field current_index number +---@field buffer number? +---@field namespace number? +---@field is_active boolean +---@field saved_layout table? + local M = {} local logger = require("cp.log") -local execute = require("cp.execute") +---@type TestPanelState local test_panel_state = { test_cases = {}, current_index = 1, @@ -33,8 +50,10 @@ local function parse_test_cases_from_cache(platform, contest_id, problem_id) end local test_cases = {} + for i, test_case in ipairs(cached_test_cases) do - table.insert(test_cases, create_test_case(i, test_case.input, test_case.output)) + local index = test_case.index or i + table.insert(test_cases, create_test_case(index, test_case.input, test_case.output)) end return test_cases diff --git a/plugin/cp.lua b/plugin/cp.lua index 0bab4b9..735ff89 100644 --- a/plugin/cp.lua +++ b/plugin/cp.lua @@ -45,10 +45,10 @@ end, { if num_args == 2 then local candidates = { "--lang" } - vim.list_extend(candidates, actions) local cp = require("cp") local context = cp.get_current_context() if context.platform and context.contest_id then + vim.list_extend(candidates, actions) local cache = require("cp.cache") cache.load() local contest_data = cache.get_contest_data(context.platform, context.contest_id) diff --git a/scrapers/atcoder.py b/scrapers/atcoder.py index 63bd3db..70bd184 100644 --- a/scrapers/atcoder.py +++ b/scrapers/atcoder.py @@ -169,24 +169,26 @@ def main() -> None: print(json.dumps(result)) sys.exit(1) - test_cases: list[dict[str, str]] = [] - for input_data, output_data in tests: - test_cases.append({"input": input_data, "output": output_data}) + individual_test_cases: list[dict[str, str]] = [] + for index, (input_data, output_data) in enumerate(tests, 1): + individual_test_cases.append({ + "index": index, + "input": input_data, + "output": output_data + }) - if test_cases: - combined_input: str = ( - str(len(test_cases)) - + "\n" - + "\n".join(tc["input"] for tc in test_cases) - ) - combined_output: str = "\n".join(tc["output"] for tc in test_cases) - test_cases = [{"input": combined_input, "output": combined_output}] + combined_input = "\n".join(tc["input"] for tc in individual_test_cases) + combined_output = "\n".join(tc["output"] for tc in individual_test_cases) result = { "success": True, "problem_id": problem_id, "url": url, - "test_cases": test_cases, + "test_cases": individual_test_cases, + "combined": { + "input": combined_input, + "output": combined_output + } } print(json.dumps(result))