local log = require('java-core.utils.log2') local notify = require('java-core.utils.notify') local test_adapters = require('java-test.adapters') local dap_adapters = require('java-dap.data-adapters') local buf_util = require('java-core.utils.buffer') local win_util = require('java.utils.window') local DebugClient = require('java-core.ls.clients.java-debug-client') local TestClient = require('java-core.ls.clients.java-test-client') ---@class java_test.TestApi ---@field private client java-core.JdtlsClient ---@field private debug_client java-core.DebugClient ---@field private test_client java-core.TestClient ---@field private runner java-dap.DapRunner local M = {} ---Returns a new test helper client ---@param args { client: vim.lsp.Client, runner: java-dap.DapRunner } ---@return java_test.TestApi function M:new(args) local o = { client = args.client, } o.debug_client = DebugClient(args.client) o.test_client = TestClient(args.client) o.runner = args.runner setmetatable(o, self) self.__index = self return o end ---Returns a list of test methods ---@param file_uri string uri of the class ---@return java-core.TestDetailsWithRange[] # list of test methods function M:get_test_methods(file_uri) log.debug('finding test methods for uri: ' .. file_uri) local classes = self.test_client:find_test_types_and_methods(file_uri) local methods = {} for _, class in ipairs(classes) do for _, method in ipairs(class.children) do ---@diagnostic disable-next-line: inject-field method.class = class table.insert(methods, method) end end log.debug('found ' .. #methods .. ' test methods') return methods end ---comment ---@param buffer number ---@param report java-test.JUnitTestReport ---@param config? java-dap.DapLauncherConfigOverridable config to override the default values in test launcher config function M:run_class_by_buffer(buffer, report, config) log.debug('running test class from buffer: ' .. buffer) local tests = self:get_test_class_by_buffer(buffer) if #tests < 1 then notify.warn('No tests found in the current buffer') return end log.debug('found ' .. #tests .. ' test classes') self:run_test(tests, report, config) end ---Returns test classes in the given buffer ---@private ---@param buffer integer ---@return java-core.TestDetailsWithChildrenAndRange # get test class details function M:get_test_class_by_buffer(buffer) log.debug('finding test class by buffer') local uri = vim.uri_from_bufnr(buffer) return self.test_client:find_test_types_and_methods(uri) end ---Run the given test ---@param tests java-core.TestDetails[] ---@param report java-test.JUnitTestReport ---@param config? java-dap.DapLauncherConfigOverridable config to override the default values in test launcher config function M:run_test(tests, report, config) log.debug('running ' .. #tests .. ' tests') local launch_args = self.test_client:resolve_junit_launch_arguments(test_adapters.tests_to_junit_launch_params(tests)) log.debug( 'resolved launch args - mainClass: ' .. launch_args.mainClass .. ', projectName: ' .. launch_args.projectName ) local java_exec = self.debug_client:resolve_java_executable(launch_args.mainClass, launch_args.projectName) log.debug('java executable', java_exec) local dap_launcher_config = dap_adapters.junit_launch_args_to_dap_config(launch_args, java_exec, { debug = true, label = 'Launch All Java Tests', }) dap_launcher_config = vim.tbl_deep_extend('force', dap_launcher_config, config or {}) log.debug('launching tests with config', dap_launcher_config) self.runner:run_by_config(dap_launcher_config, report) end ---Run the current test class ---@param report java-test.JUnitTestReport ---@param config java-dap.DapLauncherConfigOverridable function M:execute_current_test_class(report, config) log.debug('running the current class') return self:run_class_by_buffer(buf_util.get_curr_buf(), report, config) end ---Run the current test method ---@param report java-test.JUnitTestReport ---@param config java-dap.DapLauncherConfigOverridable function M:execute_current_test_method(report, config) log.debug('running the current method') local method = self:find_current_test_method() if not method then notify.warn('cursor is not on a test method') return end self:run_test({ method }, report, config) end ---Find the test method at the current cursor position ---@return java-core.TestDetailsWithRange | nil function M:find_current_test_method() log.debug('finding the current test method') local cursor = win_util.get_cursor() local methods = self:get_test_methods(buf_util.get_curr_uri()) for _, method in ipairs(methods) do local line_start = method.range.start.line local line_end = method.range['end'].line if cursor.line >= line_start and cursor.line <= line_end then return method end end end return M