From 30729cce1ec1ab481548140cc54d4183306d03eb Mon Sep 17 00:00:00 2001 From: s1n7ax Date: Tue, 28 Nov 2023 00:30:31 +0530 Subject: [PATCH 1/7] feat: add test result parser --- lua/java-test.lua | 3 + lua/java-test/reports/junit.lua | 59 ++++++++++ lua/java-test/results/message-id.lua | 46 ++++++++ lua/java-test/results/test-parser.lua | 102 ++++++++++++++++++ lua/java-test/results/test-result.lua | 21 ++++ lua/java-test/results/test-status.lua | 8 ++ lua/plugin_name.lua | 27 ----- lua/plugin_name/module.lua | 9 -- plugin/java-test.lua | 0 plugin/plugin_name.lua | 5 - .../plugin_name_spec.lua | 0 11 files changed, 239 insertions(+), 41 deletions(-) create mode 100644 lua/java-test.lua create mode 100644 lua/java-test/reports/junit.lua create mode 100644 lua/java-test/results/message-id.lua create mode 100644 lua/java-test/results/test-parser.lua create mode 100644 lua/java-test/results/test-result.lua create mode 100644 lua/java-test/results/test-status.lua delete mode 100644 lua/plugin_name.lua delete mode 100644 lua/plugin_name/module.lua create mode 100644 plugin/java-test.lua delete mode 100644 plugin/plugin_name.lua rename tests/{plugin_name => java-test}/plugin_name_spec.lua (100%) diff --git a/lua/java-test.lua b/lua/java-test.lua new file mode 100644 index 0000000..5044d6f --- /dev/null +++ b/lua/java-test.lua @@ -0,0 +1,3 @@ +local M = {} + +return M diff --git a/lua/java-test/reports/junit.lua b/lua/java-test/reports/junit.lua new file mode 100644 index 0000000..0dc6104 --- /dev/null +++ b/lua/java-test/reports/junit.lua @@ -0,0 +1,59 @@ +local class = require('java-core.utils.class') +local log = require('java-core.utils.log') + +local TestParser = require('java-test.results.test-parser') + +---@class java_test.DapTestReport +---@field private conn uv_tcp_t +---@field private test_parser java_test.TestParser +local TestReport = class() + +function TestReport:_init() + self.conn = nil + self.test_parser = TestParser() +end + +---Returns a stream reader function +---@param conn uv_tcp_t +---@return fun(err: string, buffer: string) # callback function +function TestReport:get_stream_reader(conn) + self.conn = conn + + return vim.schedule_wrap(function(err, buffer) + if err then + self:on_error(err) + self:on_close() + self.conn:close() + return + end + + if buffer then + self:on_update(buffer) + else + self:on_close() + self.conn:close() + end + end) +end + +---Runs on connection update +---@private +---@param text string +function TestReport:on_update(text) + self.test_parser:parse(text) +end + +---Runs on connection close +---@private +function TestReport:on_close() + vim.print('closing') +end + +---Runs on connection error +---@private +---@param err string error +function TestReport:on_error(err) + log.error('Error while running test', err) +end + +return TestReport diff --git a/lua/java-test/results/message-id.lua b/lua/java-test/results/message-id.lua new file mode 100644 index 0000000..a2b6acb --- /dev/null +++ b/lua/java-test/results/message-id.lua @@ -0,0 +1,46 @@ +---@enum MessageId +local MessageId = { + -- Notification about a test inside the test suite. + -- TEST_TREE + testId + "," + testName + "," + isSuite + "," + testCount + "," + isDynamicTest + + -- "," + parentId + "," + displayName + "," + parameterTypes + "," + uniqueId + + -- isSuite = "true" or "false" + -- isDynamicTest = "true" or "false" + -- parentId = the unique id of its parent if it is a dynamic test, otherwise can be "-1" + -- displayName = the display name of the test + -- parameterTypes = comma-separated list of method parameter types if applicable, otherwise an + -- empty string + -- uniqueId = the unique ID of the test provided by JUnit launcher, otherwise an empty string + + TestTree = '%TSTTREE', + TestStart = '%TESTS', + TestEnd = '%TESTE', + TestFailed = '%FAILED', + TestError = '%ERROR', + ExpectStart = '%EXPECTS', + ExpectEnd = '%EXPECTE', + ActualStart = '%ACTUALS', + ActualEnd = '%ACTUALE', + TraceStart = '%TRACES', + TraceEnd = '%TRACEE', + IGNORE_TEST_PREFIX = '@Ignore: ', + ASSUMPTION_FAILED_TEST_PREFIX = '@AssumptionFailure: ', +} + +--[[ +************* +%TESTC 2 v2 +%TSTTREE2,com.example.demo.DemoApplicationTests,true,2,false,1,DemoApplicationTests,,[engine:junit-jupiter]/[class:com.example.demo.DemoApplicationTests] +%TSTTREE3,anotherTest(com.example.demo.DemoApplicationTests),false,1,false,2,anotherTest(),,[engine:junit-jupiter]/[class:com.example.demo.DemoApplicationTests]/[method:anotherTest()] +%TSTTREE4,contextLoads(com.example.demo.DemoApplicationTests),false,1,false,2,contextLoads(),,[engine:junit-jupiter]/[class:com.example.demo.DemoApplicationTests]/[method:contextLoads()] +%TESTS 3,anotherTest(com.example.demo.DemoApplicationTests) +************* +%TESTE 3,anotherTest(com.example.demo.DemoApplicationTests) +************* +%TESTS 4,contextLoads(com.example.demo.DemoApplicationTests) +************* +%TESTE 4,contextLoads(com.example.demo.DemoApplicationTests) +%RUNTIME2281 +--]] + +return MessageId diff --git a/lua/java-test/results/test-parser.lua b/lua/java-test/results/test-parser.lua new file mode 100644 index 0000000..8b3376b --- /dev/null +++ b/lua/java-test/results/test-parser.lua @@ -0,0 +1,102 @@ +local class = require('java-core.utils.class') +local MessageId = require('java-test.results.message-id') +local TestStatus = require('java-test.results.test-status') + +---@class java_test.TestParser +local TestParser = class() + +function TestParser:_init() + self.test_details = {} +end + +function TestParser:parse(text) + local lines = vim.split(text, '\n', { + plain = true, + trimempty = true, + }) + + for _, line in ipairs(lines) do + self:parse_line(line) + end +end + +function TestParser:parse_line(line) + local message_id = line:sub(1, 8):gsub('%s+', '') + local content = line:sub(9) + + local node_parser = TestParser.node_parsers[message_id] + + if node_parser then + local data = vim.split(content, ',', { plain = true, trimempty = true }) + if self[TestParser.node_parsers[message_id]] then + self[TestParser.node_parsers[message_id]](self, data) + end + end +end + +function TestParser:parse_test_tree(data) + local node = { + test_id = tonumber(data[1]), + test_name = data[2], + is_suite = data[3], + test_count = tonumber(data[4]), + is_dynamic_test = data[5], + parent_id = tonumber(data[6]), + display_name = data[7], + parameter_types = data[8], + unique_id = data[9], + } + + local parent = self:find_result_node(node.parent_id) + + if not parent then + table.insert(self.test_details, node) + else + parent.children = parent.children or {} + table.insert(parent.children, node) + end +end + +function TestParser:find_result_node(id) + local function find_node(nodes) + if not nodes or #nodes == 0 then + return + end + + for _, node in ipairs(nodes) do + if node.test_id == id then + return node + end + + local _node = find_node(node.children) + + if _node then + return _node + end + end + end + + return find_node(self.test_details) +end + +function TestParser:parse_test_start(data) + local test_id = tonumber(data[1]) + local node = self:find_result_node(test_id) + assert(node) + node.status = TestStatus.Started +end + +function TestParser:parse_test_end(data) + local test_id = tonumber(data[1]) + local node = self:find_result_node(test_id) + assert(node) + node.status = TestStatus.Ended +end + +TestParser.node_parsers = { + [MessageId.TestTree] = 'parse_test_tree', + [MessageId.TestStart] = 'parse_test_start', + [MessageId.TestEnd] = 'parse_test_end', +} + +return TestParser diff --git a/lua/java-test/results/test-result.lua b/lua/java-test/results/test-result.lua new file mode 100644 index 0000000..81d0d7e --- /dev/null +++ b/lua/java-test/results/test-result.lua @@ -0,0 +1,21 @@ +---@class java_test.TestResult +---@field +--- +---@class java_test.TestSuite + +return { + suite = { + id = '', + name = '', + test_count = 10, + is_dynamic_test = true, + parent_id = 1, + display_name = '', + parameter_types = '', + unique_id = '', + }, + + tests = { + {}, + }, +} diff --git a/lua/java-test/results/test-status.lua b/lua/java-test/results/test-status.lua new file mode 100644 index 0000000..8511b57 --- /dev/null +++ b/lua/java-test/results/test-status.lua @@ -0,0 +1,8 @@ +---@enum java_test.TestStatus +local TestStatus = { + Started = 'started', + Ended = 'ended', + Failed = 'failed', +} + +return TestStatus diff --git a/lua/plugin_name.lua b/lua/plugin_name.lua deleted file mode 100644 index f1eb022..0000000 --- a/lua/plugin_name.lua +++ /dev/null @@ -1,27 +0,0 @@ --- main module file -local module = require('plugin_name.module') - ----@class Config ----@field opt string Your config option -local config = { - opt = 'Hello!', -} - ----@class MyModule -local M = {} - ----@type Config -M.config = config - ----@param args Config? --- you can define your setup function here. Usually configurations can be merged, accepting outside params and --- you can also put some validation here for those. -M.setup = function(args) - M.config = vim.tbl_deep_extend('force', M.config, args or {}) -end - -M.hello = function() - print(module.my_first_function()) -end - -return M diff --git a/lua/plugin_name/module.lua b/lua/plugin_name/module.lua deleted file mode 100644 index 5665f79..0000000 --- a/lua/plugin_name/module.lua +++ /dev/null @@ -1,9 +0,0 @@ ----@class CustomModule -local M = {} - ----@return string -M.my_first_function = function() - return 'hello world!' -end - -return M diff --git a/plugin/java-test.lua b/plugin/java-test.lua new file mode 100644 index 0000000..e69de29 diff --git a/plugin/plugin_name.lua b/plugin/plugin_name.lua deleted file mode 100644 index 9f8c5b3..0000000 --- a/plugin/plugin_name.lua +++ /dev/null @@ -1,5 +0,0 @@ -vim.api.nvim_create_user_command( - 'MyFirstFunction', - require('plugin_name').hello, - {} -) diff --git a/tests/plugin_name/plugin_name_spec.lua b/tests/java-test/plugin_name_spec.lua similarity index 100% rename from tests/plugin_name/plugin_name_spec.lua rename to tests/java-test/plugin_name_spec.lua From 0a61874100fa9f2da2e1feaa0d984c442f498347 Mon Sep 17 00:00:00 2001 From: s1n7ax Date: Wed, 29 Nov 2023 02:00:49 +0530 Subject: [PATCH 2/7] feat: handle report parsing when the test is failed --- lua/java-test/reports/junit.lua | 7 +- .../results/test-execution-status.lua | 7 + lua/java-test/results/test-parser.lua | 144 +++++++++++++----- lua/java-test/results/test-result.lua | 21 --- lua/java-test/results/test-status.lua | 3 +- lua/java-test/utils/str.lua | 7 + 6 files changed, 129 insertions(+), 60 deletions(-) create mode 100644 lua/java-test/results/test-execution-status.lua delete mode 100644 lua/java-test/results/test-result.lua create mode 100644 lua/java-test/utils/str.lua diff --git a/lua/java-test/reports/junit.lua b/lua/java-test/reports/junit.lua index 0dc6104..50342a4 100644 --- a/lua/java-test/reports/junit.lua +++ b/lua/java-test/reports/junit.lua @@ -3,11 +3,13 @@ local log = require('java-core.utils.log') local TestParser = require('java-test.results.test-parser') ----@class java_test.DapTestReport +---@class java_test.JUnitTestReport ---@field private conn uv_tcp_t ---@field private test_parser java_test.TestParser local TestReport = class() +---Init +---@private function TestReport:_init() self.conn = nil self.test_parser = TestParser() @@ -46,6 +48,9 @@ end ---Runs on connection close ---@private function TestReport:on_close() + local results = self.test_parser:get_test_details() + vim.print(results) + -- vim.print(vim.lsp.get_active_clients({ name = 'jdtls' })[1]) vim.print('closing') end diff --git a/lua/java-test/results/test-execution-status.lua b/lua/java-test/results/test-execution-status.lua new file mode 100644 index 0000000..846c65e --- /dev/null +++ b/lua/java-test/results/test-execution-status.lua @@ -0,0 +1,7 @@ +---@enum java_test.TestExecutionStatus +local TestStatus = { + Started = 'started', + Ended = 'ended', +} + +return TestStatus diff --git a/lua/java-test/results/test-parser.lua b/lua/java-test/results/test-parser.lua index 8b3376b..fc71bc1 100644 --- a/lua/java-test/results/test-parser.lua +++ b/lua/java-test/results/test-parser.lua @@ -1,39 +1,64 @@ local class = require('java-core.utils.class') +local str_util = require('java-test.utils.str') + local MessageId = require('java-test.results.message-id') local TestStatus = require('java-test.results.test-status') +local TestExecStatus = require('java-test.results.test-execution-status') ---@class java_test.TestParser +---@field private test_details java_test.TestDetails local TestParser = class() +---Init +---@private function TestParser:_init() self.test_details = {} end -function TestParser:parse(text) - local lines = vim.split(text, '\n', { - plain = true, - trimempty = true, - }) +---@private +TestParser.node_parsers = { + [MessageId.TestTree] = 'parse_test_tree', + [MessageId.TestStart] = 'parse_test_start', + [MessageId.TestEnd] = 'parse_test_end', + [MessageId.TestFailed] = 'parse_test_failed', +} - for _, line in ipairs(lines) do - self:parse_line(line) - end +---Returns the parsed test details +---@return java_test.TestDetails # parsed test details +function TestParser:get_test_details() + return self.test_details end -function TestParser:parse_line(line) - local message_id = line:sub(1, 8):gsub('%s+', '') - local content = line:sub(9) +---Parse a given text into test details +---@param text string test result buffer +function TestParser:parse(text) + if text:sub(-1) ~= '\n' then + text = text .. '\n' + end + + local line_iter = text:gmatch('(.-)\n') + + local line = line_iter() + + while line ~= nil do + local message_id = line:sub(1, 8):gsub('%s+', '') + local content = line:sub(9) - local node_parser = TestParser.node_parsers[message_id] + local node_parser = TestParser.node_parsers[message_id] - if node_parser then - local data = vim.split(content, ',', { plain = true, trimempty = true }) - if self[TestParser.node_parsers[message_id]] then - self[TestParser.node_parsers[message_id]](self, data) + if node_parser then + local data = vim.split(content, ',', { plain = true, trimempty = true }) + + if self[TestParser.node_parsers[message_id]] then + self[TestParser.node_parsers[message_id]](self, data, line_iter) + end end + + line = line_iter() end end +---@private function TestParser:parse_test_tree(data) local node = { test_id = tonumber(data[1]), @@ -57,6 +82,73 @@ function TestParser:parse_test_tree(data) end end +---@private +function TestParser:parse_test_start(data) + local test_id = tonumber(data[1]) + local node = self:find_result_node(test_id) + assert(node) + node.result = {} + node.result.execution = TestExecStatus.Started +end + +---@private +function TestParser:parse_test_end(data) + local test_id = tonumber(data[1]) + local node = self:find_result_node(test_id) + assert(node) + node.result.execution = TestExecStatus.Ended +end + +---@private +function TestParser:parse_test_failed(data, line_iter) + local test_id = tonumber(data[1]) + local node = self:find_result_node(test_id) + assert(node) + + node.result.status = TestStatus.Failed + + while true do + local line = line_iter() + + if line == nil then + break + end + + -- EXPECTED + if str_util.starts_with(line, MessageId.ExpectStart) then + node.result.expected = + self:get_content_until_end_tag(MessageId.ExpectEnd, line_iter) + + -- ACTUAL + elseif str_util.starts_with(line, MessageId.ActualStart) then + node.result.actual = + self:get_content_until_end_tag(MessageId.ActualEnd, line_iter) + + -- TRACE + elseif str_util.starts_with(line, MessageId.TraceStart) then + node.result.trace = + self:get_content_until_end_tag(MessageId.TraceEnd, line_iter) + end + end +end + +function TestParser:get_content_until_end_tag(end_tag, line_iter) + local content = {} + + while true do + local line = line_iter() + + if line == nil or str_util.starts_with(line, end_tag) then + break + end + + table.insert(content, line) + end + + return content +end + +---@private function TestParser:find_result_node(id) local function find_node(nodes) if not nodes or #nodes == 0 then @@ -79,24 +171,4 @@ function TestParser:find_result_node(id) return find_node(self.test_details) end -function TestParser:parse_test_start(data) - local test_id = tonumber(data[1]) - local node = self:find_result_node(test_id) - assert(node) - node.status = TestStatus.Started -end - -function TestParser:parse_test_end(data) - local test_id = tonumber(data[1]) - local node = self:find_result_node(test_id) - assert(node) - node.status = TestStatus.Ended -end - -TestParser.node_parsers = { - [MessageId.TestTree] = 'parse_test_tree', - [MessageId.TestStart] = 'parse_test_start', - [MessageId.TestEnd] = 'parse_test_end', -} - return TestParser diff --git a/lua/java-test/results/test-result.lua b/lua/java-test/results/test-result.lua deleted file mode 100644 index 81d0d7e..0000000 --- a/lua/java-test/results/test-result.lua +++ /dev/null @@ -1,21 +0,0 @@ ----@class java_test.TestResult ----@field ---- ----@class java_test.TestSuite - -return { - suite = { - id = '', - name = '', - test_count = 10, - is_dynamic_test = true, - parent_id = 1, - display_name = '', - parameter_types = '', - unique_id = '', - }, - - tests = { - {}, - }, -} diff --git a/lua/java-test/results/test-status.lua b/lua/java-test/results/test-status.lua index 8511b57..3017aa6 100644 --- a/lua/java-test/results/test-status.lua +++ b/lua/java-test/results/test-status.lua @@ -1,8 +1,7 @@ ---@enum java_test.TestStatus local TestStatus = { - Started = 'started', - Ended = 'ended', Failed = 'failed', + Skipped = 'skipped', } return TestStatus diff --git a/lua/java-test/utils/str.lua b/lua/java-test/utils/str.lua new file mode 100644 index 0000000..f46b9a9 --- /dev/null +++ b/lua/java-test/utils/str.lua @@ -0,0 +1,7 @@ +local M = {} + +function M.starts_with(str, start) + return str:sub(1, #start) == start +end + +return M From 3ba7beae558f0083d6d4fdf9d5b2b567fe716201 Mon Sep 17 00:00:00 2001 From: s1n7ax Date: Thu, 30 Nov 2023 01:01:43 +0530 Subject: [PATCH 3/7] feat: add report viewer --- lua/java-test/reports/junit.lua | 28 +++--- lua/java-test/results/test-parser-factory.lua | 14 +++ lua/java-test/results/test-parser.lua | 52 ++++++++--- lua/java-test/ui/floating-report-viewer.lua | 93 +++++++++++++++++++ lua/java-test/utils/str.lua | 7 -- lua/java-test/utils/string-builder.lua | 30 ++++++ 6 files changed, 191 insertions(+), 33 deletions(-) create mode 100644 lua/java-test/results/test-parser-factory.lua create mode 100644 lua/java-test/ui/floating-report-viewer.lua delete mode 100644 lua/java-test/utils/str.lua create mode 100644 lua/java-test/utils/string-builder.lua diff --git a/lua/java-test/reports/junit.lua b/lua/java-test/reports/junit.lua index 50342a4..915f6e0 100644 --- a/lua/java-test/reports/junit.lua +++ b/lua/java-test/reports/junit.lua @@ -1,25 +1,28 @@ local class = require('java-core.utils.class') local log = require('java-core.utils.log') -local TestParser = require('java-test.results.test-parser') +local ReportViewer = require('java-test.ui.floating-report-viewer') ---@class java_test.JUnitTestReport ---@field private conn uv_tcp_t ---@field private test_parser java_test.TestParser -local TestReport = class() +---@field private test_parser_fac java_test.TestParserFactory +---@overload fun(test_parser_factory: java_test.TestParserFactory) +local JUnitReport = class() ---Init ----@private -function TestReport:_init() +---@param test_parser_factory java_test.TestParserFactory +function JUnitReport:_init(test_parser_factory) self.conn = nil - self.test_parser = TestParser() + self.test_parser_fac = test_parser_factory end ---Returns a stream reader function ---@param conn uv_tcp_t ---@return fun(err: string, buffer: string) # callback function -function TestReport:get_stream_reader(conn) +function JUnitReport:get_stream_reader(conn) self.conn = conn + self.test_parser = self.test_parser_fac:get_parser() return vim.schedule_wrap(function(err, buffer) if err then @@ -41,24 +44,23 @@ end ---Runs on connection update ---@private ---@param text string -function TestReport:on_update(text) +function JUnitReport:on_update(text) self.test_parser:parse(text) end ---Runs on connection close ---@private -function TestReport:on_close() +function JUnitReport:on_close() local results = self.test_parser:get_test_details() - vim.print(results) - -- vim.print(vim.lsp.get_active_clients({ name = 'jdtls' })[1]) - vim.print('closing') + local rv = ReportViewer() + rv:show(results) end ---Runs on connection error ---@private ---@param err string error -function TestReport:on_error(err) +function JUnitReport:on_error(err) log.error('Error while running test', err) end -return TestReport +return JUnitReport diff --git a/lua/java-test/results/test-parser-factory.lua b/lua/java-test/results/test-parser-factory.lua new file mode 100644 index 0000000..550e18d --- /dev/null +++ b/lua/java-test/results/test-parser-factory.lua @@ -0,0 +1,14 @@ +local class = require('java-core.utils.class') +local TestParser = require('java-test.results.test-parser') + +---@class java_test.TestParserFactory +local TestParserFactory = class() + +---Returns a test parser of given type +---@param args any +---@return java_test.TestParser +function TestParserFactory.get_parser(args) + return TestParser() +end + +return TestParserFactory diff --git a/lua/java-test/results/test-parser.lua b/lua/java-test/results/test-parser.lua index fc71bc1..01ba47d 100644 --- a/lua/java-test/results/test-parser.lua +++ b/lua/java-test/results/test-parser.lua @@ -1,12 +1,11 @@ local class = require('java-core.utils.class') -local str_util = require('java-test.utils.str') local MessageId = require('java-test.results.message-id') local TestStatus = require('java-test.results.test-status') local TestExecStatus = require('java-test.results.test-execution-status') ---@class java_test.TestParser ----@field private test_details java_test.TestDetails +---@field private test_details java_test.TestResults[] local TestParser = class() ---Init @@ -23,11 +22,11 @@ TestParser.node_parsers = { [MessageId.TestFailed] = 'parse_test_failed', } ----Returns the parsed test details ----@return java_test.TestDetails # parsed test details -function TestParser:get_test_details() - return self.test_details -end +---@private +TestParser.strtobool = { + ['true'] = true, + ['false'] = false, +} ---Parse a given text into test details ---@param text string test result buffer @@ -58,14 +57,20 @@ function TestParser:parse(text) end end +---Returns the parsed test details +---@return java_test.TestResults # parsed test details +function TestParser:get_test_details() + return self.test_details +end + ---@private function TestParser:parse_test_tree(data) local node = { test_id = tonumber(data[1]), test_name = data[2], - is_suite = data[3], + is_suite = TestParser.strtobool[data[3]], test_count = tonumber(data[4]), - is_dynamic_test = data[5], + is_dynamic_test = TestParser.strtobool[data[5]], parent_id = tonumber(data[6]), display_name = data[7], parameter_types = data[8], @@ -115,30 +120,31 @@ function TestParser:parse_test_failed(data, line_iter) end -- EXPECTED - if str_util.starts_with(line, MessageId.ExpectStart) then + if vim.startswith(line, MessageId.ExpectStart) then node.result.expected = self:get_content_until_end_tag(MessageId.ExpectEnd, line_iter) -- ACTUAL - elseif str_util.starts_with(line, MessageId.ActualStart) then + elseif vim.startswith(line, MessageId.ActualStart) then node.result.actual = self:get_content_until_end_tag(MessageId.ActualEnd, line_iter) -- TRACE - elseif str_util.starts_with(line, MessageId.TraceStart) then + elseif vim.startswith(line, MessageId.TraceStart) then node.result.trace = self:get_content_until_end_tag(MessageId.TraceEnd, line_iter) end end end +---@private function TestParser:get_content_until_end_tag(end_tag, line_iter) local content = {} while true do local line = line_iter() - if line == nil or str_util.starts_with(line, end_tag) then + if line == nil or vim.startswith(line, end_tag) then break end @@ -172,3 +178,23 @@ function TestParser:find_result_node(id) end return TestParser + +---@class java_test.TestResultExecutionDetails +---@field actual string[] lines +---@field expected string[] lines +---@field status java_test.TestStatus +---@field execution java_test.TestExecutionStatus +---@field trace string[] lines + +---@class java_test.TestResults +---@field display_name string +---@field is_dynamic_test boolean +---@field is_suite boolean +---@field parameter_types string +---@field parent_id integer +---@field test_count integer +---@field test_id integer +---@field test_name string +---@field unique_id string +---@field result java_test.TestResultExecutionDetails +---@field children java_test.TestResults[] diff --git a/lua/java-test/ui/floating-report-viewer.lua b/lua/java-test/ui/floating-report-viewer.lua new file mode 100644 index 0000000..24d79ff --- /dev/null +++ b/lua/java-test/ui/floating-report-viewer.lua @@ -0,0 +1,93 @@ +local class = require('java-core.utils.class') +local StringBuilder = require('java-test.utils.string-builder') +local TestExecutionStatus = require('java-test.results.test-execution-status') +local TestStatus = require('java-test.results.test-status') + +---@class java_test.FloatingReportViewer +---@field window number|nil +---@field buffer number|nil +---@overload fun(): java_test.FloatingReportViewer +local FloatingReportViewer = class() + +---Shows the test results in a floating window +---@param test_results java_test.TestResults[] +function FloatingReportViewer:show(test_results) + ---@param results java_test.TestResults[] + local function build_result(results, indentation, prefix) + local ts = StringBuilder() + + for _, result in ipairs(results) do + local tc = StringBuilder() + + tc.append(prefix .. indentation) + + if result.is_suite then + tc.append('📁 ' .. result.test_name).lbreak() + else + if result.result.status == TestStatus.Failed then + tc.append('❌' .. result.test_name) + .lbreak() + .append(indentation) + .append(result.result.trace, indentation) + elseif result.result.status == TestStatus.Skipped then + tc.append('⚠ ' .. result.test_name).lbreak() + else + tc.append('✅' .. result.test_name).lbreak() + end + end + + if result.children then + tc.append(build_result(result.children, indentation .. '\t', '')) + end + + ts.append(tc.build()) + end + + return ts.build() + end + + local res = build_result(test_results, '', '') + + self:show_in_window(vim.split(res, '\n')) +end + +function FloatingReportViewer:show_in_window(content) + local Popup = require('nui.popup') + local event = require('nui.utils.autocmd').event + + local popup = Popup({ + enter = true, + focusable = true, + border = { + style = 'rounded', + }, + position = '50%', + relative = 'editor', + size = { + width = '80%', + height = '60%', + }, + buf_options = { + modifiable = true, + readonly = true, + }, + win_options = { + foldmethod = 'indent', + foldlevel = 1, + }, + }) + + -- mount/open the component + popup:mount() + + -- unmount component when cursor leaves buffer + popup:on(event.BufLeave, function() + popup:unmount() + end) + + -- set content + vim.api.nvim_buf_set_lines(popup.bufnr, 0, 1, false, content) + vim.api.nvim_buf_set_option(popup.bufnr, 'modifiable', false) +end + +return FloatingReportViewer diff --git a/lua/java-test/utils/str.lua b/lua/java-test/utils/str.lua deleted file mode 100644 index f46b9a9..0000000 --- a/lua/java-test/utils/str.lua +++ /dev/null @@ -1,7 +0,0 @@ -local M = {} - -function M.starts_with(str, start) - return str:sub(1, #start) == start -end - -return M diff --git a/lua/java-test/utils/string-builder.lua b/lua/java-test/utils/string-builder.lua new file mode 100644 index 0000000..91ce178 --- /dev/null +++ b/lua/java-test/utils/string-builder.lua @@ -0,0 +1,30 @@ +local StringBuilder = function() + local str = '' + + local M = {} + M.append = function(text, prefix) + prefix = prefix or '' + if type(text) == 'table' then + for _, line in ipairs(text) do + str = str .. prefix .. line .. '\n' + end + else + assert(type(text) == 'string') + str = str .. prefix .. text + end + return M + end + + M.lbreak = function() + str = str .. '\n' + return M + end + + M.build = function() + return str + end + + return M +end + +return StringBuilder From 1fe9865d7054efc275a9714d90d4f6703309e887 Mon Sep 17 00:00:00 2001 From: s1n7ax Date: Thu, 30 Nov 2023 22:28:55 +0530 Subject: [PATCH 4/7] feat: store the last test report --- lua/java-test/reports/junit.lua | 37 +++++++++++-------- ...cution-status.lua => execution-status.lua} | 0 ...-factory.lua => result-parser-factory.lua} | 2 +- .../{test-parser.lua => result-parser.lua} | 4 +- .../{test-status.lua => result-status.lua} | 0 lua/java-test/ui/floating-report-viewer.lua | 14 +++---- lua/java-test/ui/report-viewer.lua | 12 ++++++ 7 files changed, 43 insertions(+), 26 deletions(-) rename lua/java-test/results/{test-execution-status.lua => execution-status.lua} (100%) rename lua/java-test/results/{test-parser-factory.lua => result-parser-factory.lua} (83%) rename lua/java-test/results/{test-parser.lua => result-parser.lua} (97%) rename lua/java-test/results/{test-status.lua => result-status.lua} (100%) create mode 100644 lua/java-test/ui/report-viewer.lua diff --git a/lua/java-test/reports/junit.lua b/lua/java-test/reports/junit.lua index 915f6e0..befeb88 100644 --- a/lua/java-test/reports/junit.lua +++ b/lua/java-test/reports/junit.lua @@ -1,20 +1,31 @@ local class = require('java-core.utils.class') local log = require('java-core.utils.log') -local ReportViewer = require('java-test.ui.floating-report-viewer') - ---@class java_test.JUnitTestReport ---@field private conn uv_tcp_t ----@field private test_parser java_test.TestParser ----@field private test_parser_fac java_test.TestParserFactory ----@overload fun(test_parser_factory: java_test.TestParserFactory) +---@field private result_parser java_test.TestParser +---@field private result_parser_fac java_test.TestParserFactory +---@field private report_viewer java_test.ReportViewer +---@overload fun(result_parser_factory: java_test.TestParserFactory, test_viewer: java_test.ReportViewer) local JUnitReport = class() ---Init ----@param test_parser_factory java_test.TestParserFactory -function JUnitReport:_init(test_parser_factory) +---@param result_parser_factory java_test.TestParserFactory +function JUnitReport:_init(result_parser_factory, report_viewer) self.conn = nil - self.test_parser_fac = test_parser_factory + self.result_parser_fac = result_parser_factory + self.report_viewer = report_viewer +end + +---Returns the test results +---@return java_test.TestResults[] +function JUnitReport:get_results() + return self.result_parser:get_test_details() +end + +---Shows the test report +function JUnitReport:show_report() + self.report_viewer:show(self:get_results()) end ---Returns a stream reader function @@ -22,7 +33,7 @@ end ---@return fun(err: string, buffer: string) # callback function function JUnitReport:get_stream_reader(conn) self.conn = conn - self.test_parser = self.test_parser_fac:get_parser() + self.result_parser = self.result_parser_fac:get_parser() return vim.schedule_wrap(function(err, buffer) if err then @@ -45,16 +56,12 @@ end ---@private ---@param text string function JUnitReport:on_update(text) - self.test_parser:parse(text) + self.result_parser:parse(text) end ---Runs on connection close ---@private -function JUnitReport:on_close() - local results = self.test_parser:get_test_details() - local rv = ReportViewer() - rv:show(results) -end +function JUnitReport:on_close() end ---Runs on connection error ---@private diff --git a/lua/java-test/results/test-execution-status.lua b/lua/java-test/results/execution-status.lua similarity index 100% rename from lua/java-test/results/test-execution-status.lua rename to lua/java-test/results/execution-status.lua diff --git a/lua/java-test/results/test-parser-factory.lua b/lua/java-test/results/result-parser-factory.lua similarity index 83% rename from lua/java-test/results/test-parser-factory.lua rename to lua/java-test/results/result-parser-factory.lua index 550e18d..001b109 100644 --- a/lua/java-test/results/test-parser-factory.lua +++ b/lua/java-test/results/result-parser-factory.lua @@ -1,5 +1,5 @@ local class = require('java-core.utils.class') -local TestParser = require('java-test.results.test-parser') +local TestParser = require('java-test.results.result-parser') ---@class java_test.TestParserFactory local TestParserFactory = class() diff --git a/lua/java-test/results/test-parser.lua b/lua/java-test/results/result-parser.lua similarity index 97% rename from lua/java-test/results/test-parser.lua rename to lua/java-test/results/result-parser.lua index 01ba47d..44ef84d 100644 --- a/lua/java-test/results/test-parser.lua +++ b/lua/java-test/results/result-parser.lua @@ -1,8 +1,8 @@ local class = require('java-core.utils.class') local MessageId = require('java-test.results.message-id') -local TestStatus = require('java-test.results.test-status') -local TestExecStatus = require('java-test.results.test-execution-status') +local TestStatus = require('java-test.results.result-status') +local TestExecStatus = require('java-test.results.execution-status') ---@class java_test.TestParser ---@field private test_details java_test.TestResults[] diff --git a/lua/java-test/results/test-status.lua b/lua/java-test/results/result-status.lua similarity index 100% rename from lua/java-test/results/test-status.lua rename to lua/java-test/results/result-status.lua diff --git a/lua/java-test/ui/floating-report-viewer.lua b/lua/java-test/ui/floating-report-viewer.lua index 24d79ff..a638992 100644 --- a/lua/java-test/ui/floating-report-viewer.lua +++ b/lua/java-test/ui/floating-report-viewer.lua @@ -1,13 +1,13 @@ local class = require('java-core.utils.class') local StringBuilder = require('java-test.utils.string-builder') -local TestExecutionStatus = require('java-test.results.test-execution-status') -local TestStatus = require('java-test.results.test-status') +local TestStatus = require('java-test.results.result-status') +local ReportViewer = require('java-test.ui.report-viewer') ---@class java_test.FloatingReportViewer ---@field window number|nil ---@field buffer number|nil ---@overload fun(): java_test.FloatingReportViewer -local FloatingReportViewer = class() +local FloatingReportViewer = class(ReportViewer) ---Shows the test results in a floating window ---@param test_results java_test.TestResults[] @@ -67,10 +67,6 @@ function FloatingReportViewer:show_in_window(content) width = '80%', height = '60%', }, - buf_options = { - modifiable = true, - readonly = true, - }, win_options = { foldmethod = 'indent', foldlevel = 1, @@ -87,7 +83,9 @@ function FloatingReportViewer:show_in_window(content) -- set content vim.api.nvim_buf_set_lines(popup.bufnr, 0, 1, false, content) - vim.api.nvim_buf_set_option(popup.bufnr, 'modifiable', false) + + vim.bo[popup.bufnr].modifiable = false + vim.bo[popup.bufnr].readonly = true end return FloatingReportViewer diff --git a/lua/java-test/ui/report-viewer.lua b/lua/java-test/ui/report-viewer.lua new file mode 100644 index 0000000..b49b1cd --- /dev/null +++ b/lua/java-test/ui/report-viewer.lua @@ -0,0 +1,12 @@ +local class = require('java-core.utils.class') + +---@class java_test.ReportViewer +local ReportViewer = class() + +---Shows the test results in a floating window +---@param _ java_test.TestResults[] +function ReportViewer:show(_) + error('not implemented') +end + +return ReportViewer From 125106c822e02febfbad7be8a526a28780d5bc86 Mon Sep 17 00:00:00 2001 From: s1n7ax Date: Thu, 30 Nov 2023 23:18:03 +0530 Subject: [PATCH 5/7] fix(test): test failures --- .test_plugins/lazy-lock.json | 3 +++ .test_plugins/plenary.nvim | 1 + tests/java-test/java_test_spec.lua | 7 +++++++ tests/java-test/plugin_name_spec.lua | 12 ------------ 4 files changed, 11 insertions(+), 12 deletions(-) create mode 100644 .test_plugins/lazy-lock.json create mode 160000 .test_plugins/plenary.nvim create mode 100644 tests/java-test/java_test_spec.lua delete mode 100644 tests/java-test/plugin_name_spec.lua diff --git a/.test_plugins/lazy-lock.json b/.test_plugins/lazy-lock.json new file mode 100644 index 0000000..2a4ac3b --- /dev/null +++ b/.test_plugins/lazy-lock.json @@ -0,0 +1,3 @@ +{ + "plenary.nvim": { "branch": "master", "commit": "55d9fe89e33efd26f532ef20223e5f9430c8b0c0" } +} \ No newline at end of file diff --git a/.test_plugins/plenary.nvim b/.test_plugins/plenary.nvim new file mode 160000 index 0000000..55d9fe8 --- /dev/null +++ b/.test_plugins/plenary.nvim @@ -0,0 +1 @@ +Subproject commit 55d9fe89e33efd26f532ef20223e5f9430c8b0c0 diff --git a/tests/java-test/java_test_spec.lua b/tests/java-test/java_test_spec.lua new file mode 100644 index 0000000..d1e8634 --- /dev/null +++ b/tests/java-test/java_test_spec.lua @@ -0,0 +1,7 @@ +local plugin = require('java-test') + +describe('java-test', function() + it('java-test module is available', function() + assert('module available', plugin) + end) +end) diff --git a/tests/java-test/plugin_name_spec.lua b/tests/java-test/plugin_name_spec.lua deleted file mode 100644 index c643145..0000000 --- a/tests/java-test/plugin_name_spec.lua +++ /dev/null @@ -1,12 +0,0 @@ -local plugin = require('plugin_name') - -describe('setup', function() - it('works with default', function() - assert('my first function with param = Hello!', plugin.hello()) - end) - - it('works with custom var', function() - plugin.setup({ opt = 'custom' }) - assert('my first function with param = custom', plugin.hello()) - end) -end) From bd5756e8fbe630bc9e7d3ec83974fef2ba40c056 Mon Sep 17 00:00:00 2001 From: s1n7ax Date: Fri, 1 Dec 2023 11:24:01 +0530 Subject: [PATCH 6/7] fix(test): tests are hanging due to command loading error --- .gitignore | 1 + Makefile | 8 ++++---- tests/before-test.lua | 16 ++++++++++++++++ tests/java-test/java_test_spec.lua | 4 +--- tests/minimal_init.lua | 16 ---------------- tests/{prepare-config.lua => setup-test.lua} | 20 ++++++++++++++++++++ tests/test-config.lua | 5 ----- 7 files changed, 42 insertions(+), 28 deletions(-) create mode 100644 tests/before-test.lua delete mode 100644 tests/minimal_init.lua rename tests/{prepare-config.lua => setup-test.lua} (56%) delete mode 100644 tests/test-config.lua diff --git a/.gitignore b/.gitignore index 238d11c..b6d36ab 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ vendor/plenary.nvim +.test_plugins diff --git a/Makefile b/Makefile index d5bb4c0..bce7579 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -PREPARE_CONFIG=tests/prepare-config.lua -TEST_CONFIG=tests/test-config.lua +SETUP_TEST=tests/setup-test.lua +BEFORE_TEST=tests/before-test.lua TESTS_DIR=tests/ .PHONY: test @@ -7,5 +7,5 @@ TESTS_DIR=tests/ test: @nvim \ --headless \ - -u ${PREPARE_CONFIG} \ - "+PlenaryBustedDirectory ${TESTS_DIR} { minimal_init = '${TEST_CONFIG}' }" + -u ${SETUP_TEST} \ + "+PlenaryBustedDirectory ${TESTS_DIR} { minimal_init = '${BEFORE_TEST}' }" diff --git a/tests/before-test.lua b/tests/before-test.lua new file mode 100644 index 0000000..3ed8521 --- /dev/null +++ b/tests/before-test.lua @@ -0,0 +1,16 @@ +---@diagnostic disable: assign-type-mismatch +---@param dev_path string +---@param plug_path string +---@return string|nil +local function local_plug(dev_path, plug_path) + return (vim.fn.isdirectory(dev_path) == 1) and dev_path or plug_path +end + +local plug_path = './.test_plugins' + +vim.opt.rtp:append(plug_path .. '/plenary.nvim') +vim.opt.rtp:append(plug_path .. '/nvim-lspconfig') +vim.opt.rtp:append(plug_path .. '/mason.nvim') +vim.opt.rtp:append( + local_plug('~/Workspace/nvim-java-core', plug_path .. '/nvim-java-core') +) diff --git a/tests/java-test/java_test_spec.lua b/tests/java-test/java_test_spec.lua index d1e8634..c9060b6 100644 --- a/tests/java-test/java_test_spec.lua +++ b/tests/java-test/java_test_spec.lua @@ -1,7 +1,5 @@ -local plugin = require('java-test') - describe('java-test', function() it('java-test module is available', function() - assert('module available', plugin) + assert('module available', require('java-test')) end) end) diff --git a/tests/minimal_init.lua b/tests/minimal_init.lua deleted file mode 100644 index caf9c54..0000000 --- a/tests/minimal_init.lua +++ /dev/null @@ -1,16 +0,0 @@ -local plenary_dir = os.getenv('PLENARY_DIR') or '/tmp/plenary.nvim' -local is_not_a_directory = vim.fn.isdirectory(plenary_dir) == 0 -if is_not_a_directory then - vim.fn.system({ - 'git', - 'clone', - 'https://github.com/nvim-lua/plenary.nvim', - plenary_dir, - }) -end - -vim.opt.rtp:append('.') -vim.opt.rtp:append(plenary_dir) - -vim.cmd('runtime plugin/plenary.vim') -require('plenary.busted') diff --git a/tests/prepare-config.lua b/tests/setup-test.lua similarity index 56% rename from tests/prepare-config.lua rename to tests/setup-test.lua index 50c1503..5852551 100644 --- a/tests/prepare-config.lua +++ b/tests/setup-test.lua @@ -1,3 +1,10 @@ +---@diagnostic disable: assign-type-mismatch +---@param path string +---@return string|nil +local function local_plug(path) + return vim.fn.isdirectory(path) == 1 and path or nil +end + local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim' if not vim.loop.fs_stat(lazypath) then @@ -20,6 +27,19 @@ require('lazy').setup({ 'nvim-lua/plenary.nvim', lazy = false, }, + { + 'nvim-java/nvim-java-core', + dir = local_plug('~/Workspace/nvim-java-core'), + lazy = false, + }, + { + 'neovim/nvim-lspconfig', + lazy = false, + }, + { + 'williamboman/mason.nvim', + lazy = false, + }, }, { root = temp_path, lockfile = temp_path .. '/lazy-lock.json', diff --git a/tests/test-config.lua b/tests/test-config.lua deleted file mode 100644 index aaf76f2..0000000 --- a/tests/test-config.lua +++ /dev/null @@ -1,5 +0,0 @@ -local temp_path = './.test_plugins' - -vim.opt.rtp:append(temp_path .. '/plenary.nvim') --- vim.opt.rtp:append(temp_path .. '/nvim-lspconfig') --- vim.opt.rtp:append(temp_path .. '/mason.nvim') From cd25727520fba46755b7c7c482f6ca170e95da2a Mon Sep 17 00:00:00 2001 From: s1n7ax Date: Fri, 1 Dec 2023 11:26:50 +0530 Subject: [PATCH 7/7] refactor: remove test_plugins dir --- .test_plugins/lazy-lock.json | 3 --- .test_plugins/plenary.nvim | 1 - 2 files changed, 4 deletions(-) delete mode 100644 .test_plugins/lazy-lock.json delete mode 160000 .test_plugins/plenary.nvim diff --git a/.test_plugins/lazy-lock.json b/.test_plugins/lazy-lock.json deleted file mode 100644 index 2a4ac3b..0000000 --- a/.test_plugins/lazy-lock.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "plenary.nvim": { "branch": "master", "commit": "55d9fe89e33efd26f532ef20223e5f9430c8b0c0" } -} \ No newline at end of file diff --git a/.test_plugins/plenary.nvim b/.test_plugins/plenary.nvim deleted file mode 160000 index 55d9fe8..0000000 --- a/.test_plugins/plenary.nvim +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 55d9fe89e33efd26f532ef20223e5f9430c8b0c0