From 1a085f3a322a1f8d3ac8db988ba7d2323ed77559 Mon Sep 17 00:00:00 2001 From: Fredrik Averpil Date: Fri, 13 Dec 2024 08:51:25 +0100 Subject: [PATCH] docs: add design notes --- README.md | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3b223789..3291da71 100644 --- a/README.md +++ b/README.md @@ -740,9 +740,9 @@ return { ## 🙏 PRs are welcome Improvement suggestion PRs to this repo are very much welcome, and I encourage -you to begin in the -[discussions](https://github.com/fredrikaverpil/neotest-golang/discussions) in -case the change is not trivial. +you to begin by reading the below paragraph on the adapter design and engage in +the [discussions](https://github.com/fredrikaverpil/neotest-golang/discussions) +in case the change is not trivial. You can run tests, formatting and linting locally with `make all`. Install dependencies with `make install`. Have a look at the [Makefile](Makefile) for @@ -769,3 +769,74 @@ query and play around. You can paste in queries from [`query.lua`](https://github.com/fredrikaverpil/neotest-golang/blob/main/lua/neotest-golang/query.lua) in the editor, to see how the query behaves and highlights parts of your Go test file. + +## General design of the adapter + +### Treesitter queries detect tests + +Neotest leverages treesitter AST-parsing of source code to detect tests. This +adapter supplies queries so to figure out what is considered a test. + +From the result of these queries, a Neotest "position" tree is built (can be +visualized through the "Neotest summary"). Each position in the tree represents +either a `dir`, `file` or `test` type. Neotest also has a notion of a +`namespace` position type, but this is ignored by default by this adapter (but +leveraged to supply testify support). + +### Generating valid `go test` commands + +The `dir`, `file` and `test` tree position types cannot be directly translated +over to Go so to produce a valid `go test` command. Go primarily cares about a +Go package's import path, test name regexp filters and the current working +directory. + +For example, these are all valid `go test` command: + +```bash +# run all tests, recursing sub-packages, in the current working directory. +go test ./... + +# run all tests in a given package 'x', by specifying the full import path +go test github.com/fredrikaverpil/neotest-golang/x + +# run all tests in a given package 'x', recursing sub-packages +go test github.com/fredrikaverpil/neotest-golang/x/... + +# run _some_ tests in a given package, based on a regexp filter +go test github.com/fredrikaverpil/neotest-golang -run "^TestFoo$|^TestBar$" +``` + +> [!NOTE] +> +> All the above commands must be run somewhere beneath the location of the +> `go.mod` file specifying the _module_ name, which in this example is +> `github.com/fredrikaverpil/neotest-golang`. + +I figured out that by executing `go list -json ./...` in the `go.mod` root +location, the output provides valuable information about test files/folders and +their corresponding Go package's import path. This data is key to being able to +take the Neotest/treesitter position type and generate a valid `go test` command +for it. In essence, this approach is what makes neotest-golang so robust. + +### Output processing + +Neotest captures the stdout from the test execution command and writes it to +disk as a temporary file. The adapter is responsible for reading the file(s) and +reporting back status and output to the Neotest tree (and specifically the +position in the tree which was executed). It is therefore crucial for outputting +structured data, which in this case is done with `go test -json`. + +One challenge here is that Go build errors are not part of the strucutured JSON +output (although captured in the stdout) and needs to be looked for in other +ways. + +Another challenge is to properly populate statuses and errors into the +corresponding Neotest tree position. This becomes increasingly difficult when +you consider running tests in a recursive manner (e.g. `go test -json ./...`). + +Errors are recorded and populated, per position type, along with its +corresponding buffer's line number. Neotest can then show the errors inline as +diagnostics. + +I've taken an approach with this adapter where I record test outcome for each +Neotest position type and populate it onto each of them, when applicable.