Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions lua/java-core/adapters/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
local List = require('java-core.utils.list')
local Set = require('java-core.utils.set')
local JavaTestClient = require('java-core.ls.clients.java-test-client')

local M = {}

---Returns the launcher config
---@param launch_args JavaCoreTestJunitLaunchArguments
---@param java_exec string
---@param config { debug: boolean, label: string }
---@return JavaCoreDapLauncherConfig
function M.get_dap_launcher_config(launch_args, java_exec, config)
return {
name = config.label,
type = 'java',
request = 'launch',
mainClass = launch_args.mainClass,
projectName = launch_args.projectName,
noDebug = not config.debug,
javaExec = java_exec,
cwd = launch_args.workingDirectory,
classPaths = Set:new(launch_args.classpath),
modulePaths = Set:new(launch_args.modulepath),
vmArgs = List:new(launch_args.vmArguments):join(' '),
args = List:new(launch_args.programArguments):join(' '),
-- env: config?.env,
-- envFile: config?.envFile,
-- sourcePaths: config?.sourcePaths,
-- preLaunchTask: config?.preLaunchTask,
-- postDebugTask: config?.postDebugTask,
}

-- if test_details.testKind == TestKind.TestNG then
-- path.join(extensionContext.extensionPath, 'server', 'com.microsoft.java.test.runner-jar-with-dependencies.jar'),
-- end
end

---Ruterns the launch argument parameters for given test or tests
---@param tests JavaCoreTestDetails | JavaCoreTestDetails[]
---@return JavaCoreTestResolveJUnitLaunchArgumentsParams
function M.get_junit_launch_argument_params(tests)
if not vim.tbl_islist(tests) then
return {
projectName = tests.projectName,
testLevel = tests.testLevel,
testKind = tests.testKind,
testNames = M.get_test_names({ tests }),
}
end

local first_test = tests[1]

return {
projectName = first_test.projectName,
testLevel = first_test.testLevel,
testKind = first_test.testKind,
testNames = M.get_test_names(tests),
}
end

---Returns a list of test names to be passed to test launch arguments resolver
---@param tests JavaCoreTestDetails[]
---@return List
function M.get_test_names(tests)
return List:new(tests):map(function(test)
if
test.testKind == JavaTestClient.TestKind.TestNG
or test.testLevel == JavaTestClient.TestLevel.Class
then
return test.fullName
end

return test.jdtHandler
end)
end

return M
116 changes: 116 additions & 0 deletions lua/java-core/api/test.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
local log = require('java-core.utils.log')
local data_adapters = require('java-core.adapters')

local Promise = require('java-core.utils.promise')
local TestReport = require('java-core.dap.test-report')
local JavaDapRunner = require('java-core.dap.runner')
local JavaDebug = require('java-core.ls.clients.java-debug-client')
local JavaTest = require('java-core.ls.clients.java-test-client')

---@class JavaCoreTestApi
---@field private client JavaCoreJdtlsClient
---@field private debug_client JavaCoreDebugClient
---@field private test_client JavaCoreTestClient
---@field private runner JavaCoreDapRunner
local M = {}

---Returns a new test helper client
---@param args { client: LspClient }
---@return JavaCoreTestApi
function M:new(args)
local o = {
client = args.client,
}

o.debug_client = JavaDebug:new({
client = args.client,
})

o.test_client = JavaTest:new({
client = args.client,
})

o.runner = JavaDapRunner:new({
reporter = TestReport:new(),
})

setmetatable(o, self)
self.__index = self

return o
end

---Runs the test class in the given buffer
---@param buffer integer
---@param config JavaCoreDapLauncherConfigOverridable
---@return Promise
function M:run_class_by_buffer(buffer, config)
return self:get_test_class_by_buffer(buffer):thenCall(function(tests)
return self:run_test(tests, config)
end)
end

---Returns test classes in the given buffer
---@priate
---@param buffer integer
---@return Promise # Promise<JavaCoreTestDetailsWithChildrenAndRange>
function M:get_test_class_by_buffer(buffer)
log.debug('finding test class by buffer')

return Promise.resolve():thenCall(function()
if not vim.api.nvim_buf_is_valid(buffer) then
local msg = 'passed buffer' .. tostring(buffer) .. ' is not valid'
log.error(msg)
error(msg)
end

local uri = vim.uri_from_bufnr(buffer)
return self.test_client:find_test_types_and_methods(uri)
end)
end

---Run the given test
---@private
---@param tests JavaCoreTestDetails[]
---@param config? JavaCoreDapLauncherConfigOverridable config to override the default values in test launcher config
---@return Promise #
function M:run_test(tests, config)
---@type JavaCoreTestJunitLaunchArguments
local launch_args

return self.test_client
:resolve_junit_launch_arguments(
data_adapters.get_junit_launch_argument_params(tests)
)
:thenCall(
---@param _launch_args JavaCoreTestJunitLaunchArguments
function(_launch_args)
launch_args = _launch_args

return self.debug_client:resolve_java_executable(
launch_args.mainClass,
launch_args.projectName
)
end
)
:thenCall(
---@param java_exec string
function(java_exec)
local dap_launcher_config =
--@TODO I don't know why the hell debug is hard coded here
data_adapters.get_dap_launcher_config(launch_args, java_exec, {
debug = true,
label = 'Launch All Java Tests',
})

log.debug('dap launcher config is: ', dap_launcher_config)

dap_launcher_config =
vim.tbl_deep_extend('force', dap_launcher_config, config or {})

return self.runner:run_by_config(dap_launcher_config)
end
)
end

return M
26 changes: 26 additions & 0 deletions lua/java-core/dap/adapters.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
local M = {}

---Returns the dap config record
---@param main JavaDebugResolveMainClassRecord
---@param classpath string[][]
---@param java_exec string
---@return JavaCoreDapLauncherConfig
function M.get_dap_config(main, classpath, java_exec)
local project_name = main.projectName
local main_class = main.mainClass
local module_paths = classpath[1]
local class_paths = classpath[2]

return {
request = 'launch',
type = 'java',
name = string.format('%s -> %s', project_name, main_class),
projectName = project_name,
mainClass = main_class,
javaExec = java_exec,
modulePaths = module_paths,
classPaths = class_paths,
}
end

return M
113 changes: 49 additions & 64 deletions lua/java-core/dap.lua → lua/java-core/dap/init.lua
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
local log = require('java-core.utils.log')
local adapters = require('java-core.ls.adapters.test-adapter')
local adapters = require('java-core.dap.adapters')
local List = require('java-core.utils.list')
local JavaDebug = require('java-core.ls.clients.java-debug-client')
local Promise = require('java-core.utils.promise')

---@class JavaCoreDap
---@field client LSPClient
---@field client LspClient
---@field java_debug JavaCoreDebugClient
local M = {}

---Returns a new dap instance
---@param args { client: LSPClient }
---@param args { client: LspClient }
---@return JavaCoreDap
function M:new(args)
local o = {
Expand All @@ -26,18 +26,18 @@ function M:new(args)
return o
end

---@class JavaDapAdapter
---@class JavaCoreDapAdapter
---@field type string
---@field host string
---@field port integer

---Returns the dap adapter config
---@return Promise
---@return Promise # Promise<JavaCoreDapAdapter>
function M:get_dap_adapter()
log.info('creating dap adapter for java')

return self.java_debug:start_debug_session():thenCall(
---@param port JavaDebugStartDebugSessionResponse
---@param port integer
function(port)
return {
type = 'server',
Expand All @@ -48,15 +48,13 @@ function M:get_dap_adapter()
)
end

---@alias JavaDapConfigurationList JavaDapConfiguration[]

---Returns the dap configuration for the current project
---@return Promise
---@return Promise # Promise<JavaDapConfiguration[]>
function M:get_dap_config()
log.info('creating dap configuration for java')

return self.java_debug:resolve_main_class():thenCall(
---@param mains JavaDebugResolveMainClassResponse
---@param mains JavaDebugResolveMainClassRecord[]
function(mains)
local config_promises = List:new(mains):map(function(main)
return self:get_dap_config_record(main)
Expand All @@ -69,71 +67,58 @@ end

---Returns the dap config for the given main class
---@param main JavaDebugResolveMainClassRecord
---@return Promise
---@return Promise # Promise<JavaCoreDapLauncherConfig>
function M:get_dap_config_record(main)
return Promise.all({
self.java_debug:resolve_classpath(main.mainClass, main.projectName),
self.java_debug:resolve_java_executable(main.mainClass, main.projectName),
}):thenCall(function(res)
---@type JavaDebugResolveClasspathResponse
---@type string[][]
local classpaths = res[1]

---@type JavaDebugResolveJavaExecutableResponse
---@type string
local java_exec = res[2]

return adapters.get_dap_config(main, classpaths, java_exec)
end)
end

---Dap run with given config
---@param config JavaDapConfiguration
function M.dap_run(config)
log.info('running dap with config: ', config)

local function get_stream_reader(conn)
return vim.schedule_wrap(function(err, buffer)
assert(not err, err)

if buffer then
vim.print(buffer)
else
conn:close()
end
end)
end

---@type uv_tcp_t
local server

require('dap').run(config --[[@as Configuration]], {
before = function(conf)
log.debug('running before dap callback')

server = assert(vim.loop.new_tcp(), 'uv.new_tcp() must return handle')
server:bind('127.0.0.1', 0)
server:listen(128, function(err)
assert(not err, err)

local sock = assert(vim.loop.new_tcp(), 'uv.new_tcp must return handle')
server:accept(sock)
sock:read_start(get_stream_reader(sock))
end)

conf.args =
conf.args:gsub('-port ([0-9]+)', '-port ' .. server:getsockname().port)

return conf
end,

after = function()
vim.debug('running after dap callback')

if server then
server:shutdown()
server:close()
end
end,
})
end

return M

---@class JavaCoreDapLauncherConfigOverridable
---@field name? string
---@field type? string
---@field request? string
---@field mainClass? string
---@field projectName? string
---@field cwd? string
---@field classPaths? string[]
---@field modulePaths? string[]
---@field vmArgs? string
---@field noDebug? boolean
---@field javaExec? string
---@field args? string
---@field env? { [string]: string; }
---@field envFile? string
---@field sourcePaths? string[]
---@field preLaunchTask? string
---@field postDebugTask? string

---@class JavaCoreDapLauncherConfig
---@field name string
---@field type string
---@field request string
---@field mainClass string
---@field projectName string
---@field cwd string
---@field classPaths string[]
---@field modulePaths string[]
---@field vmArgs string
---@field noDebug boolean
---@field javaExec string
---@field args string
---@field env? { [string]: string; }
---@field envFile? string
---@field sourcePaths string[]
---@field preLaunchTask? string
---@field postDebugTask? string
Loading