Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: add fsharp support #118

Closed
wants to merge 6 commits into from
Closed
Changes from 1 commit
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
Prev Previous commit
add nunit support
Nsidorenco committed Oct 1, 2024

Verified

This commit was signed with the committer’s verified signature.
Nsidorenco Nikolaj Sidorenco
commit 4538c8e3389da07d31ad1e41390ba181caa148d5
27 changes: 12 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ Neotest adapter for dotnet tests
- Covers the "majority" of use cases for the 3 major .NET test runners
- Attempts to provide support for `SpecFlow` generated tests for the various test runners
- Support for this may still be patchy, so please raise an issue if it doesn't behave as expected
- `RunNearest` or `RunInFile` functions will need to be run from the *generated* specflow tests (NOT the `.feature`)
- `RunNearest` or `RunInFile` functions will need to be run from the _generated_ specflow tests (NOT the `.feature`)

# Pre-requisites

@@ -23,7 +23,7 @@ neotest-dotnet requires makes a number of assumptions about your environment:
1. The `dotnet sdk` that is compatible with the current project is installed and the `dotnet` executable is on the users runtime path (future updates may allow customisation of the dotnet exe location)
2. The user is running tests using one of the supported test runners / frameworks (see support grid)
3. (For Debugging) `netcoredbg` is installed and `nvim-dap` plugin has been configured for `netcoredbg` (see debug config for more details)
4. Requires [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) and the parser for C#.
4. Requires [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) and the parser for C# or F#.

# Installation

@@ -93,7 +93,7 @@ require("neotest").setup({
## Additional `dotnet test` arguments

As well as the `dotnet_additional_args` option in the adapter setup above, you may also provide additional CLI arguments as a table to each `neotest` command.
By doing this, the additional args provided in the setup function will be *replaced* in their entirety by the ones provided at the command level.
By doing this, the additional args provided in the setup function will be _replaced_ in their entirety by the ones provided at the command level.

For example, to provide a `runtime` argument to the `dotnet test` command, for all the tests in the file, you can run:

@@ -150,7 +150,7 @@ To see if your use case is supported, check the grids below. If it isn't there,
### NUnit

| Framework Feature | Scope Level | Docs | Status | Notes |
| ------------------------- | ----------- | ------------------------------------------------------------------------------------------------------ | ------------------ | ------------------------------------------------------------------------------------------------------------------- |
| ---------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Test` (Attribute) | Method | [Test - Nunit](https://docs.nunit.org/articles/nunit/writing-tests/attributes/test.html) | :heavy_check_mark: | Supported when used inside a class with or without the `TestFixture` attribute decoration |
| `TestFixture` (Attribute) | Class | [TestFixture - Nunit](https://docs.nunit.org/articles/nunit/writing-tests/attributes/testfixture.html) | :heavy_check_mark: | |
| `TestCase()` (Attribute) | Method | [TestCase - Nunit](https://docs.nunit.org/articles/nunit/writing-tests/attributes/testcase.html) | :heavy_check_mark: | Support for parameterized tests with inline parameters. Supports neotest 'run nearest' and 'run file' functionality |
@@ -170,13 +170,13 @@ To see if your use case is supported, check the grids below. If it isn't there,

### MSTest

| Framework Feature | Scope Level | Docs | Status | Notes |
| ------------------------- | ----------- | ------------------------------------------------------------------------------------------------------ | ------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `TestMethod` (Attribute) | Method | [TestMethod - MSTest](https://docs.nunit.org/articles/nunit/writing-tests/attributes/test.html) | :heavy_check_mark: | |
| `TestClass` (Attribute) | Class | [TestClass - MSTest](https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.testtools.unittesting.testclassattribute?view=visualstudiosdk-2022) | :heavy_check_mark: | |
| Nested Classes | Class | | :heavy_check_mark: | Fully qualified name is corrected to include `+` when class is nested |
| `DataTestMethod` (Attribute) | Method | [DataTestMethod - MSTest](https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.testtools.unittesting.datatestmethodattribute?view=visualstudiosdk-2022) | :heavy_check_mark: | |
| `DataRow` (Attribute) | Method | [DataRow - MSTest](https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.testtools.unittesting.datarowattribute?view=visualstudiosdk-2022) | :heavy_check_mark: | Support for parameterized tests with inline parameters. Supports neotest 'run nearest' and 'run file' functionality |
| Framework Feature | Scope Level | Docs | Status | Notes |
| ---------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `TestMethod` (Attribute) | Method | [TestMethod - MSTest](https://docs.nunit.org/articles/nunit/writing-tests/attributes/test.html) | :heavy_check_mark: | |
| `TestClass` (Attribute) | Class | [TestClass - MSTest](https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.testtools.unittesting.testclassattribute?view=visualstudiosdk-2022) | :heavy_check_mark: | |
| Nested Classes | Class | | :heavy_check_mark: | Fully qualified name is corrected to include `+` when class is nested |
| `DataTestMethod` (Attribute) | Method | [DataTestMethod - MSTest](https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.testtools.unittesting.datatestmethodattribute?view=visualstudiosdk-2022) | :heavy_check_mark: | |
| `DataRow` (Attribute) | Method | [DataRow - MSTest](https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.testtools.unittesting.datarowattribute?view=visualstudiosdk-2022) | :heavy_check_mark: | Support for parameterized tests with inline parameters. Supports neotest 'run nearest' and 'run file' functionality |

# Limitations

@@ -185,10 +185,7 @@ To see if your use case is supported, check the grids below. If it isn't there,
2. Dynamically parameterized tests need to be grouped together as neotest-dotnet is unable to robustly match the full test names that the .NET test runner attaches to the tests at runtime.
- An attempt was made to use `dotnet test -t` to extract the dynamic test names, but this was too unreliable (duplicate test names were indistinguishable, and xUnit was the only runner that provided fully qualified test names)
3. See the support guidance for feature and language support

- F# is currently unsupported due to the fact there is no complete tree-sitter parser for F# available as yet (<https://github.com/baronfel/tree-sitter-fsharp>)

3. As mentioned in the **Debugging** section, there are some discrepancies in test output at the moment.
4. As mentioned in the **Debugging** section, there are some discrepancies in test output at the moment.

## NUnit Limitations

23 changes: 15 additions & 8 deletions lua/neotest-dotnet/nunit/init.lua
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@ local build_parameterized_test_positions = function(
(attribute_list
(attribute
name: (identifier) @attribute_name (#any-of? @attribute_name "TestCase")
((attribute_argument_list) @arguments)
(attribute_argument_list) @arguments
)
)
]]
@@ -61,13 +61,14 @@ local build_parameterized_test_positions = function(
local arguments_index = capture_indices["arguments"]

for _, match in param_query:iter_matches(captured_nodes[match_type .. ".definition"], source) do
local args_node = match[arguments_index]
local args_text = vim.treesitter.get_node_text(args_node, source):gsub("[()]", "")
for _, args_node in ipairs(match[arguments_index]) do
local args_text = vim.treesitter.get_node_text(args_node, source):gsub("[()]", "")

nodes[#nodes + 1] = vim.tbl_extend("force", parameterized_test_node, {
name = parameterized_test_node.name .. "(" .. args_text .. ")",
range = { args_node:range() },
})
nodes[#nodes + 1] = vim.tbl_extend("force", parameterized_test_node, {
name = parameterized_test_node.name .. "(" .. args_text .. ")",
range = { args_node:range() },
})
end
end

logger.debug("neotest-dotnet(NUnit Utils): Built parameterized test positions: ")
@@ -292,9 +293,15 @@ M.generate_test_results = function(output_file_path, tree, context_id)
result_test_name = string.gsub(result_test_name, "%(.*%)", "")
end

-- remove spacing between parameters
local full_name = node_data.full_name:gsub(", ", ",")

-- string generic type parameters from test name
result_test_name = result_test_name:gsub("<.*>(", "")

-- Use the full_name of the test, including namespace
local is_match = #result_test_name == #node_data.full_name
or string.find(result_test_name, node_data.full_name, 0, true)
or string.find(result_test_name, full_name, 0, true)

if is_match then
-- For non-inlined parameterized tests, check if we already have an entry for the test.
12 changes: 6 additions & 6 deletions lua/neotest-dotnet/nunit/ts-queries.lua
Original file line number Diff line number Diff line change
@@ -41,23 +41,23 @@ local function get_fsharp_queries(custom_test_attributes)
(declaration_expression
(attributes
(attribute
(simple_type (long_identifier (identifier) @attribute_name (#any-of? @attribute_name "^TestCase")))))
(simple_type (long_identifier (identifier) @attribute_name (#any-of? @attribute_name "TestCase"))))+)
(function_or_value_defn
(function_declaration_left
(identifier) @test.name
(identifier) @test.parameterized.name
(argument_patterns) @parameter_list))
) @test.definition
) @test.parameterized.definition

;; Matches test parameterized methods
(member_defn
(attributes
(attribute
(simple_type (long_identifier (identifier) @attribute_name (#any-of? @attribute_name "^TestCase")))))
(simple_type (long_identifier (identifier) @attribute_name (#any-of? @attribute_name "TestCase"))))+)
(method_or_prop_defn
(property_or_ident
(identifier) @test.name .)
(identifier) @test.parameterized.name .)
args: (_) @parameter_list)
) @test.definition
) @test.parameterized.definition
]]
end

3 changes: 2 additions & 1 deletion lua/neotest-dotnet/utils/build-spec-utils.lua
Original file line number Diff line number Diff line change
@@ -15,7 +15,8 @@ local BuildSpecUtils = {}
function BuildSpecUtils.build_test_fqn(position_id)
local fqn = neotest_node_tree_utils.get_qualified_test_name_from_id(position_id)
-- Remove any test parameters as these don't work well with the dotnet filter formatting.
fqn = fqn:gsub("%b()", "")
-- Also replace spaces with "&" since some test runners can't parse the test name.
fqn = fqn:gsub("%b()", ""):gsub(" ", "&")

return fqn
end
1 change: 0 additions & 1 deletion lua/neotest-dotnet/utils/neotest-node-tree-utils.lua
Original file line number Diff line number Diff line change
@@ -32,7 +32,6 @@ function M.get_test_nodes_data(tree)
if
node:data().framework == "xunit" --[[ or node:data().framework == "nunit" ]]
then
-- 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)