Skip to content

Commit

Permalink
add nunit
Browse files Browse the repository at this point in the history
  • Loading branch information
Nsidorenco committed Sep 29, 2024
1 parent 0d1a1f6 commit 33dc436
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 20 deletions.
32 changes: 25 additions & 7 deletions lua/neotest-dotnet/nunit/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,35 @@ local NodeTreeUtils = require("neotest-dotnet.utils.neotest-node-tree-utils")
local M = {}

---Builds a position from captured nodes, optionally parsing parameters to create sub-positions.
---@param lang string language of the treesitter parser to use
---@param base_node table The initial root node to build the positions from
---@param source any The source code to build the positions from
---@param captured_nodes any The nodes captured by the TS query
---@param match_type string The type of node that was matched by the TS query
---@return table
local build_parameterized_test_positions = function(base_node, source, captured_nodes, match_type)
local build_parameterized_test_positions = function(
lang,
base_node,
source,
captured_nodes,
match_type
)
logger.debug("neotest-dotnet(NUnit Utils): Building parameterized test positions from source")
logger.debug("neotest-dotnet(NUnit Utils): Base node: ")
logger.debug(base_node)

logger.debug("neotest-dotnet(NUnit Utils): Match Type: " .. match_type)

local query = [[
;;query
local fsharp_query = [[
(attributes
(attribute
(simple_type (long_identifier (identifier) @attribute_name (#any-of? @attribute_name "TestCase")))
(_) @arguments
)
)
]]

local csharp_query = [[
(attribute_list
(attribute
name: (identifier) @attribute_name (#any-of? @attribute_name "TestCase")
Expand All @@ -29,8 +44,10 @@ local build_parameterized_test_positions = function(base_node, source, captured_
)
]]

local param_query = vim.fn.has("nvim-0.9.0") == 1 and vim.treesitter.query.parse("c_sharp", query)
or vim.treesitter.parse_query("c_sharp", query)
local query = lang == "fsharp" and fsharp_query or csharp_query

local param_query = vim.fn.has("nvim-0.9.0") == 1 and vim.treesitter.query.parse(lang, query)
or vim.treesitter.parse_query(lang, query)

-- Set type to test (otherwise it will be test.parameterized)
local parameterized_test_node = vim.tbl_extend("force", base_node, { type = "test" })
Expand Down Expand Up @@ -75,10 +92,11 @@ local get_match_type = function(captured_nodes)
end

function M.get_treesitter_queries(lang, custom_attribute_args)
return require("neotest-dotnet.nunit.ts-queries").get_queries(custom_attribute_args)
return require("neotest-dotnet.nunit.ts-queries").get_queries(lang, custom_attribute_args)
end

M.build_position = function(file_path, source, captured_nodes)
local lang = vim.endswith(file_path, ".fs") and "fsharp" or "c_sharp"
local match_type = get_match_type(captured_nodes)

local name = vim.treesitter.get_node_text(captured_nodes[match_type .. ".name"], source)
Expand Down Expand Up @@ -107,7 +125,7 @@ M.build_position = function(file_path, source, captured_nodes)
return node
end

return build_parameterized_test_positions(node, source, captured_nodes, match_type)
return build_parameterized_test_positions(lang, node, source, captured_nodes, match_type)
end

M.position_id = function(position, parents)
Expand Down
74 changes: 69 additions & 5 deletions lua/neotest-dotnet/nunit/ts-queries.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,66 @@ local framework_discovery = require("neotest-dotnet.framework-discovery")

local M = {}

function M.get_queries(custom_attributes)
-- Don't include parameterized test attribute indicators so we don't double count them
local custom_test_attributes = custom_attributes
and framework_discovery.join_test_attributes(custom_attributes.nunit)
or ""
local function get_fsharp_queries(custom_test_attributes)
return [[
;; Matches XUnit test class (has no specific attributes on class)
(anon_type_defn
(type_name (identifier) @class.name)
) @class.definition
(named_module
name: (long_identifier) @class.name
) @class.definition
(module_defn
(identifier) @class.name
) @class.definition
;; Matches test functions
(declaration_expression
(attributes
(attribute
(simple_type (long_identifier (identifier) @attribute_name (#any-of? @attribute_name "Test" "TestCaseSource" ]] .. custom_test_attributes .. [[)))))
(function_or_value_defn
(function_declaration_left
(identifier) @test.name))
) @test.definition
;; Matches test methods
(member_defn
(attributes
(attribute
(simple_type (long_identifier (identifier) @attribute_name (#any-of? @attribute_name "Test" "TestCaseSource" ]] .. custom_test_attributes .. [[)))))
(method_or_prop_defn
(property_or_ident
(identifier) @test.name .))
) @test.definition
;; Matches test parameterized function
(declaration_expression
(attributes
(attribute
(simple_type (long_identifier (identifier) @attribute_name (#any-of? @attribute_name "^TestCase")))))
(function_or_value_defn
(function_declaration_left
(identifier) @test.name
(argument_patterns) @parameter_list))
) @test.definition
;; Matches test parameterized methods
(member_defn
(attributes
(attribute
(simple_type (long_identifier (identifier) @attribute_name (#any-of? @attribute_name "^TestCase")))))
(method_or_prop_defn
(property_or_ident
(identifier) @test.name .)
args: (_) @parameter_list)
) @test.definition
]]
end

local function get_csharp_queries(custom_test_attributes)
return [[
;; Wrap this in alternation (https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax)
;; otherwise Specflow generated classes will be picked up twice
Expand Down Expand Up @@ -69,4 +123,14 @@ function M.get_queries(custom_attributes)
]]
end

function M.get_queries(lang, custom_attributes)
-- Don't include parameterized test attribute indicators so we don't double count them
local custom_fact_attributes = custom_attributes
and framework_discovery.join_test_attributes(custom_attributes.xunit)
or ""

return lang == "fsharp" and get_fsharp_queries(custom_fact_attributes)
or get_csharp_queries(custom_fact_attributes)
end

return M
12 changes: 10 additions & 2 deletions lua/neotest-dotnet/utils/neotest-node-tree-utils.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
local M = {}

---@param identifier string the fsharp identifier to sanitize
---@return string The sanitized identifier
function M.sanitize_fsharp_identifiers(identifier)
local sanitized, _ = string.gsub(identifier, "``([^`]*)``", "%1")
return sanitized
end

--- Assuming a position_id of the form "C:\path\to\file.cs::namespace::class::method",
--- with the rule that the first :: is the separator between the file path and the rest of the position_id,
--- returns the '.' separated fully qualified name of the test, with each segment corresponding to the namespace, class, and method.
Expand All @@ -25,10 +32,11 @@ function M.get_test_nodes_data(tree)
if
node:data().framework == "xunit" --[[ or node:data().framework == "nunit" ]]
then
node:data().full_name = node:data().name
-- local full_name = string.gsub(node:data().name, "``(.*)``", "%1")
node:data().full_name = M.sanitize_fsharp_identifiers(node:data().name)
else
local full_name = M.get_qualified_test_name_from_id(node:data().id)
node:data().full_name = full_name
node:data().full_name = M.sanitize_fsharp_identifiers(full_name)
end
end

Expand Down
5 changes: 2 additions & 3 deletions lua/neotest-dotnet/xunit/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -278,11 +278,10 @@ M.generate_test_results = function(output_file_path, tree, context_id)
for _, intermediate_result in ipairs(intermediate_results) do
for _, node in ipairs(test_nodes) do
local node_data = node:data()
local full_name, _ = node_data.full_name:gsub("``(.*)``", "%1")

if
intermediate_result.test_name == full_name
or string.find(intermediate_result.test_name, full_name, 0, true)
intermediate_result.test_name == node_data.full_name
or string.find(intermediate_result.test_name, node_data.full_name, 0, true)
or intermediate_result.qualified_test_name == BuildSpecUtils.build_test_fqn(node_data.id)
then
-- For non-inlined parameterized tests, check if we already have an entry for the test.
Expand Down
4 changes: 1 addition & 3 deletions tests/xunit/discover_positions/fact_attribute_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -278,12 +278,10 @@ describe("discover_positions", function()
local spec_file_name = "fact_and_trait.fs"
local positions = plugin.discover_positions(spec_file):to_list()

vim.print(positions)

local expected_positions = {
{
id = "./tests/xunit/specs/fact_and_trait.fs",
name = "fact_and_trait.fs",
name = spec_file_name,
path = "./tests/xunit/specs/fact_and_trait.fs",
range = { 0, 0, 7, 0 },
type = "file",
Expand Down

0 comments on commit 33dc436

Please sign in to comment.