Closed boonkerz closed 2 years ago
I considered doing this after I completed the work on the RSpec
adapter. Big challenge will be that PHPUnit outputs in xml only (never understood why they removed the JSON option in previous versions). Guessing you'd need to add a luarocks dependency to be able to process it.
Funny enough I actually embedded https://github.com/manoelcampos/xml2lua inside the neotest libs with the idea of using it for code coverage but never got around to it. Can always use that :sweat_smile: Just call require("neotest.lib").xml.parse(<xml string>)
currently i working on this but is my first try in lua :)
the message says no tests found but the logfile is showing somthing:
DEBUG | 2022-06-14T15:08:44Z+0200 | .../packer/start/neotest/lua/neotest/client/events/init.lua:48 | Calling listener diagnostic for event discover_positions
DEBUG | 2022-06-14T15:08:44Z+0200 | ...k/packer/start/neotest/lua/neotest/client/state/init.lua:54 | New positions at ID /home/thomas/projekte/calc/tests/PreCalc/ParseTest.php
INFO | 2022-06-14T15:08:44Z+0200 | .../packer/start/neotest/lua/neotest/client/events/init.lua:46 | Emitting discover_positions event
DEBUG | 2022-06-14T15:08:44Z+0200 | .../packer/start/neotest/lua/neotest/client/events/init.lua:48 | Calling listener status for event discover_positions
DEBUG | 2022-06-14T15:08:44Z+0200 | .../packer/start/neotest/lua/neotest/client/events/init.lua:48 | Calling listener summary for event discover_positions
DEBUG | 2022-06-14T15:08:44Z+0200 | .../packer/start/neotest/lua/neotest/client/events/init.lua:48 | Calling listener diagnostic for event discover_positions
DEBUG | 2022-06-14T15:08:44Z+0200 | ...k/packer/start/neotest/lua/neotest/client/state/init.lua:54 | New positions at ID /home/thomas/projekte/calc/tests/PreCalc/ParseVariantTest.php
my query:
(method_declaration
name: (name) @test.name)
@test.definition
(namespace_definition
name: (namespace_name) @namespace.name)
@namespace.definition
query is tested with https://tree-sitter.github.io/tree-sitter/playground
Can you provide the adapter code as well? I can't really tell much from the logs
very minimal
---@diagnostic disable: undefined-field
local lib = require('neotest.lib')
local logger = require('neotest.logging')
---@type neotest.Adapter
local adapter = { name = 'neotest-phpunit' }
adapter.root = lib.files.match_root_pattern('composer.json')
function adapter.is_test_file(file_path)
return vim.endswith(file_path, "Test.php")
end
function adapter.build_spec(args)
local results_path = vim.fn.tempname() .. '.json'
local tree = args.tree
if not tree then
return
end
local pos = args.tree:data()
local testNamePattern = '.*'
if pos.type == 'test' then
testNamePattern = pos.name
end
local binary = 'phpunit'
if vim.fn.filereadable('vendor/bin/phpunit') then
binary = 'vendor/bin/phpunit'
end
local command = vim.tbl_flatten({
binary,
pos.path,
})
return {
command = command,
context = {
results_path = results_path,
file = pos.path,
},
}
end
function adapter.discover_positions(path)
local query = [[
(method_declaration
name: (name) @test.name)
@test.definition
(namespace_definition
name: (namespace_name) @namespace.name)
@namespace.definition
]]
return lib.treesitter.parse_positions(path, query, { nested_namespace = true })
end
setmetatable(adapter, {
__call = function()
return adapter
end,
})
Current Status
Ah so it's working :+1: I see you haven't parsed the class as Neotest's "namespace" type. The namespace in PHP is not really what Neotest means by namespace so the class would be more suitable
@boonkerz Does your code detect tests which use the @test
annotation, as well as methods named test*
?
From the PHPUnit documentation:
Alternatively, you can use the
@test
annotation in a method’s docblock to mark it as a test method.
@boonkerz Does your code detect tests which use the
@test
annotation, as well as methods namedtest*
?From the PHPUnit documentation:
Alternatively, you can use the
@test
annotation in a method’s docblock to mark it as a test method.
currently not but i work on this :)
Ah so it's working +1 I see you haven't parsed the class as Neotest's "namespace" type. The namespace in PHP is not really what Neotest means by namespace so the class would be more suitable
yea currently happy does it do anything :)
my goal for the gui structure is the phpstorm version.
but the xml is stupid because the failure is only 1 blob of text with \n
<testcase name="testNotO" class="PSC\Library\Calc\Tests\Complex\firstTest" classname="PSC.Library.Calc.Tests.Complex.firstTest" file="/home/thomas/projekte/phpunit_test/tests/Complex/firstTest.php" line="13" assertions="1" time="0.003164">
<failure type="PHPUnit\Framework\ExpectationFailedException">PSC\Library\Calc\Tests\Complex\firstTest::testNotO
Failed asserting that true is false.
/home/thomas/projekte/phpunit_test/tests/Complex/firstTest.php:15</failure>
</testcase>
so usable for me :D a little bit slow.
@boonkerz care to share your work so far?
---@diagnostic disable: undefined-field
local lib = require('neotest.lib')
local logger = require('neotest.logging')
local async = require('neotest.async')
local adapter = { name = 'neotest-phpunit' }
adapter.root = lib.files.match_root_pattern('composer.json')
function adapter.is_test_file(file_path)
if string.match(file_path, "vendor") then
return false
end
return vim.endswith(file_path, "Test.php")
end
function adapter.build_spec(args)
local results_path = vim.fn.tempname() .. '.xml'
local tree = args.tree
if not tree then
return
end
local pos = args.tree:data()
local testNamePattern = '.*'
if pos.type == 'test' then
testNamePattern = pos.name
end
local binary = 'phpunit'
if vim.fn.filereadable('vendor/bin/phpunit') then
binary = 'vendor/bin/phpunit'
end
local command = vim.tbl_flatten({
binary,
pos.path,
'--log-junit='..results_path
})
logger.error('phpunit_command', command)
return {
command = command,
context = {
results_path = results_path,
file = pos.path,
},
}
end
function adapter.results(spec, result)
local results = {}
local success, data = pcall(lib.files.read, spec.context.results_path)
if not success then
results = "{}"
end
local parsedXml = lib.xml.parse(data)
for _, containerSuite in pairs(parsedXml.testsuites) do
for __, testsuite in pairs(containerSuite.testsuite) do
for ___,testcase in pairs(testsuite.testcase) do
local error = { message = "Error", line = 15 }
local alias_id = ""
if testcase['_attr'] then
alias_id = testcase._attr.file .. '::' .. testcase._attr.name
elseif testcase["name"] then
alias_id = testcase.file .. '::' .. testcase.name
end
if not testcase["failure"] then
results[alias_id] = { status = "passed", short = "", output = ""}
else
local fname = async.fn.tempname()
vim.fn.writefile({testcase.failure[1]}, fname)
results[alias_id] = { status = "failed", short = testcase.failure[1], output = fname, errors = {error} }
end
end
end
end
return results
end
local function generate_position_id(position, namespaces)
local id = table.concat(
vim.tbl_flatten({
position.path,
position.name,
}),
"::"
)
logger.error("generate_position_id", id)
return id
end
function adapter.discover_positions(path)
local query = [[
(method_declaration
name: (name) @test.name
(#match? @test.name "test"))
@test.definition
(namespace_definition
name: (namespace_name) @namespace.name)
@namespace.definition
]]
return lib.treesitter.parse_positions(path, query, { nested_namespace = true, position_id = generate_position_id })
end
setmetatable(adapter, {
__call = function()
return adapter
end,
})
return adapter
currently i not know what errors in results array does. dap integration and i love to see not the filenames in gui run this file does also not work :)
@test works currently not because i not know how to make the query.
Any plans to put it in a repo? I'd like to work on the @test
treesitter query.
I'm not sure if this will be helpful, but I post in the hope that it will be.
I notice that it's possible to pass the PHPUnit command a --list-tests-xml
argument.
This identifies test methods with:
test*
method name prefix@test
annotation.It also identifies different test runs with @dataProvider
data-sets (see documentation).
It does not include line numbers, though.
--list-tests-xml
seems to need an output file, and you don't seem to be able to filter it by a particular file.
In contrast --list-tests
outputs plain text to STDOUT, and you can limit it to a particular file.
link to repo https://github.com/boonkerz/neotest-phpunit
@Geraint thanks
I haven't heard anything more from @boonkerz on the development of this adapter so I've advanced it quite a bit, here. Would really appreciate people using it in anger and for any bugs they find, raising an issue with an example test I can work against
Since we now have a documented adapter, going to close this out.
Anyone work on this Adapter?