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

Debug test support #9

Open
4 of 8 tasks
lawrence-laz opened this issue Apr 3, 2024 · 7 comments
Open
4 of 8 tasks

Debug test support #9

lawrence-laz opened this issue Apr 3, 2024 · 7 comments
Labels
enhancement New feature or request

Comments

@lawrence-laz
Copy link
Owner

lawrence-laz commented Apr 3, 2024

Neotest supports DAP debugging for tests.

Checklist:

  • Filter exact tests when starting the debug session
  • Run build before debug session starts (preferably async)
  • In case of build errors, report errors to user and don't start debugging session
  • Works with build.zig and without build.zig
  • Support multiple outputs and in case of multiple prompt user to choose which to debug
  • By default all addTests artifacts from build.zig are named test. If there are multiple, we should warn user to add explicit name to their addTests.
  • Allow overriding DAP configuration (ex. explicitly providing a debugger)
  • Autodetect available debugger if one is not provided in config (gdb, lldb, codelldb)
@lawrence-laz lawrence-laz added the enhancement New feature or request label Apr 3, 2024
@lawrence-laz
Copy link
Owner Author

Partially implemented in de0bd23
Need to handle scenarios when build.zig is missing.

@fnzr
Copy link
Contributor

fnzr commented May 30, 2024

I'm working on something related to this, particularly being able to debug individual tests.
We can implement filtering tests without issues:

on your project build.zig, add the filter option to the test exe:

    const exe_unit_tests = b.addTest(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
        .filters = b.option([]const []const u8, "test-filter", "Skip tests that do not match any filter") orelse &[0][]const u8{},
    });

and then just add the parameter in the zig build command: https://github.com/fnzr/neotest-zig/blob/1a1800a95d534d9acdc5055dfeab8c8a84b7bdea/lua/neotest-zig/init.lua#L213

Both running and debugging individual tests is working on my machine, but the debug configuration is kinda iffy. I dont know what to put on the run_spec command, since both the build and run must be ran by the debugger (otherwise we'd be debugging an old exe), and I dont know how to capture compilation errors when running under dap.

But if the compilation works, we get step debugging on individual tests, whether they fail or not, which is really nice.

@lawrence-laz
Copy link
Owner Author

lawrence-laz commented May 31, 2024

I was aware of the test-filter option, but for the following reasons chose to go with a custom test input file and filtering:

  • test-filter requires editing build.zig file, not a big deal, but creates additional friction, for example you cannot just zig init and debug the created tests immediatelly.
  • test-filter is not very good at filtering exact matches (last time I checked), it only does pattern matching, which triggers more tests than needed when their names overlap (ex. having two tests "My test" and "My test 2" and filtering for "My test" runs both of them). It also doesn't take into account that different files might have tests with the same name.

Instead I'd like debugging to use the same test runner that running tests uses now, where filtering is done via --neotest-input-path parameter and the contents of the input look something like this:

[
  {
    "source_path": "/Users/llaz/git/zig-enumerable/src/enumerable.zig",
    "test_name": "decltest.first",
    "output_path": "/var/folders/c2/yvzkyl496hn0bsc37tbc0fqc0000gn/T/nvim.llaz/QGJRcT/0"
  }
]

I had this mostly working in main as far as I remember, but didn't finish it yet.

Also, a few days ago I've become a father, so might be slow to respond, sorry about that!

@fnzr
Copy link
Contributor

fnzr commented Jun 1, 2024

Ah, so that's what the input file does! I see, you're absolutely right that's the better approach. I think it's working as intended, I had no issues with it.

About debugging, I believe we need a better approach. Currently, the build step is made on the program function of the dap configuration:

program = function()
                vim.fn.system(
                    "zig build neotest-build --build-file neotest_build.zig -Dneotest-runner=\"/Users/llaz/git/neotest-zig/zig/neotest_runner.zig\"")
                return program_path
            end,

This almost works, but there are two issues:

  1. program_path logic requires the user to have manually ran the build step before. This doesnt works for the first run, or after cleaning up cache/out dirs

  2. if the build command fails, at best the dap execution will fail with "launch program not found" and at worst the dap will launch attached to an old version of the binary and you'll be debugging a program that is slightly off the code you're looking at.

I've tried searching, moving around the spec command, passing different dap configurations to the strategy, but nothing quite works reliably on error cases (but as I said, if the program builds fine everything just works).

There's the overseer plugin that allows executing a task before running tests, but adding a plugin dependency is obviously not ideal.

Congratulations on becoming a father, and don't worry about it, focus on your family!

@lawrence-laz
Copy link
Owner Author

You're right. I tried to summarize all that is left to do in regards to debugging at the top of this issue. Let me know if I missed anything.

It's not immediately obvious to me how to solve all of these either. We might have to look into how other neotest adapters for other languages have solved these issues.

@fnzr
Copy link
Contributor

fnzr commented Jun 3, 2024

A bit of an update. I looked into reporting build errors and not launching debug session, but I dont think that's possible as is. Both golang and rust adapters suffer the same problem and launch the debugger even if the build fails. I opened an issue on neotest expanding on it. I think handling this situation requires either implementing a custom strategy or a upstream patch on neotest.

In the meantime, I completed a few tasks from this issue: async building, multiple output support (maybe), notification on build error (not ideal, but better) and user configurable debug adapter.

Can I make a pr with these or is it better to wait neotest response?

@lawrence-laz
Copy link
Owner Author

Please do! We don't have to resolve everything in a single go

@fnzr fnzr mentioned this issue Jun 4, 2024
lawrence-laz pushed a commit that referenced this issue Jun 4, 2024
This implements the following features related to
#9:

* Adds a configuration to customize the debugger adapter in the setup
function

* Running the DAP strategy asynchronously builds the project using
`nio.control.future` and native lua api (based on [rustacean
implementation](https://github.com/mrcjkb/rustaceanvim/blob/2fa45427c01ded4d3ecca72e357f8a60fd8e46d4/lua/rustaceanvim/neotest/init.lua#L277)
of the same feature)

* Displays  an error message on build errors with the `vim.notify` api.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants