Skip to content

Commit

Permalink
feat: state consumer
Browse files Browse the repository at this point in the history
  • Loading branch information
rcarriga committed Mar 13, 2023
1 parent 95f95e3 commit 43309c0
Show file tree
Hide file tree
Showing 10 changed files with 372 additions and 6 deletions.
53 changes: 51 additions & 2 deletions doc/neotest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ neotest *neotest*
Summary Consumer...........................................|neotest.summary|
Jump Consumer.................................................|neotest.jump|
Quickfix Consumer.........................................|neotest.quickfix|
State Consumer...............................................|neotest.state|
Neotest Client..............................................|neotest.Client|
Library........................................................|neotest.lib|
Library: Files...........................................|neotest.lib.files|
Expand Down Expand Up @@ -140,6 +141,9 @@ Default values:
running = {
concurrent = true
},
state = {
enabled = true
},
status = {
enabled = true,
signs = true,
Expand Down Expand Up @@ -214,6 +218,7 @@ Fields~
{output_panel} `(neotest.Config.output_panel)`
{quickfix} `(neotest.Config.quickfix)`
{status} `(neotest.Config.status)`
{state} `(neotest.Config.state)`
{diagnostic} `(neotest.Config.diagnostic)`
{projects} `(table<string, neotest.CoreConfig>)` Project specific settings, keys
are project root directories (e.g "~/Dev/my_project")
Expand Down Expand Up @@ -284,6 +289,10 @@ Fields~
{enabled} `(boolean)`
{open_on_run} `(string|boolean)` Open nearest test result after running

*neotest.Config.state*
Fields~
{enabled} `(boolean)`

*neotest.Config.output_panel*
Fields~
{enabled} `(boolean)`
Expand Down Expand Up @@ -326,7 +335,7 @@ The client interface provides methods for interacting with tests, fetching
results as well as event listeners. To listen to an event, just assign the event
listener to a function:
>lua
client.listeners.discover_positions = function (adapter_id, path, tree)
client.listeners.discover_positions = function (adapter_id, tree)
...
end
<
Expand Down Expand Up @@ -628,6 +637,46 @@ neotest.quickfix *neotest.quickfix*
A consumer that sends results to the quickfix list.


==============================================================================
neotest.state *neotest.state*


A consumer that tracks various pieces of state in Neotest.
Most of the internals of Neotest are asynchronous so this consumer allows
tracking the state of the test suite and test results without needing to
write asynchronous code.

*neotest.state.adapter_ids()*
`adapter_ids`()

Get the list of all adapter IDs currently active
Return~
`(string[])`

*neotest.state.status_counts()*
`status_counts`({adapter_id}, {args})

Get the counts of the various states of tests for the entire suite or for a
buffer.
Parameters~
{adapter_id} `(string)`
{args?} `(neotest.state.StatusCountsArgs)`
Return~
`(neotest.state.StatusCounts)` | nil

*neotest.state.StatusCountsArgs*
Fields~
{buffer?} `(integer)` Returns statuses for this buffer

*neotest.state.StatusCounts*
Fields~
{total} `(integer)`
{passed} `(integer)`
{failed} `(integer)`
{skipped} `(integer)`
{running} `(integer)`


==============================================================================
*neotest.Client*
`Client`
Expand All @@ -644,7 +693,7 @@ start because it can slow down startup.

*neotest.ConsumerListeners*
Fields~
{discover_positions} `(fun(adapter_id: string, path: string, tree: neotest.Tree))`
{discover_positions} `(fun(adapter_id: string, tree: neotest.Tree))`
{run} `(fun(adapter_id: string, root_id: string, position_ids: string[]))`
{results} `(fun(adapter_id: string, results: table<string, neotest.Result>, partial: boolean))`
{test_file_focused} `(fun(adapter_id: string, file_path: string)>)`
Expand Down
4 changes: 2 additions & 2 deletions lua/neotest/client/events/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ local NeotestEvents = {
M.events = NeotestEvents

---@class neotest.InternalClientListeners
---@field discover_positions table<string, fun(adapter_id: integer, path: string, tree: neotest.Tree)>
---@field discover_positions table<string, fun(adapter_id: integer, tree: neotest.Tree)>
---@field run table<string, fun(adapter_id: integer, root_id: string, position_ids: string[])>
---@field results table<string, fun(adapter_id: integer, results: table<string, neotest.Result>)>
---@field results table<string, fun(adapter_id: integer, results: table<string, neotest.Result>, partial: boolean)>
---@field test_file_focused table<string,fun(file_path: string)>>
---@field test_focused table<string,fun(pos_id: string)>>

Expand Down
2 changes: 1 addition & 1 deletion lua/neotest/client/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ local neotest = {}
neotest.Client = {}

---@class neotest.ConsumerListeners
---@field discover_positions fun(adapter_id: string, path: string, tree: neotest.Tree)
---@field discover_positions fun(adapter_id: string, tree: neotest.Tree)
---@field run fun(adapter_id: string, root_id: string, position_ids: string[])
---@field results fun(adapter_id: string, results: table<string, neotest.Result>, partial: boolean)
---@field test_file_focused fun(adapter_id: string, file_path: string)>
Expand Down
1 change: 1 addition & 0 deletions lua/neotest/client/state/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ end
function NeotestClientState:update_results(adapter_id, results, partial)
logger.debug("New results for adapter", adapter_id)
logger.trace(results)
local positions = self:positions(adapter_id)
self._results[adapter_id] = vim.tbl_extend("force", self._results[adapter_id] or {}, results)
if not self._running[adapter_id] then
self._running[adapter_id] = {}
Expand Down
7 changes: 7 additions & 0 deletions lua/neotest/config/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ define_highlights()
---@field output_panel neotest.Config.output_panel
---@field quickfix neotest.Config.quickfix
---@field status neotest.Config.status
---@field state neotest.Config.state
---@field diagnostic neotest.Config.diagnostic
---@field projects table<string, neotest.CoreConfig> Project specific settings, keys
--- are project root directories (e.g "~/Dev/my_project")
Expand Down Expand Up @@ -104,6 +105,9 @@ define_highlights()
---@field enabled boolean
---@field open_on_run string|boolean Open nearest test result after running

---@class neotest.Config.state
---@field enabled boolean

---@class neotest.Config.output_panel
---@field enabled boolean
---@field open string|fun():integer A command or function to open a window for the output panel
Expand Down Expand Up @@ -252,6 +256,9 @@ local default_config = {
enabled = true,
open = true,
},
state = {
enabled = true,
},
projects = {},
}

Expand Down
3 changes: 2 additions & 1 deletion lua/neotest/consumers/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ local neotest = {}
--- results as well as event listeners. To listen to an event, just assign the event
--- listener to a function:
--- >lua
--- client.listeners.discover_positions = function (adapter_id, path, tree)
--- client.listeners.discover_positions = function (adapter_id, tree)
--- ...
--- end
--- <
Expand All @@ -37,6 +37,7 @@ neotest.consumers = {
jump = require("neotest.consumers.jump"),
benchmark = require("neotest.consumers.benchmark"),
quickfix = require("neotest.consumers.quickfix"),
state = require("neotest.consumers.state"),
}

return neotest.consumers
115 changes: 115 additions & 0 deletions lua/neotest/consumers/state/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
local async = require("neotest.async")
local logger = require("neotest.logging")
local neotest = {}
local StateTracker = require("neotest.consumers.state.tracker")

---@type neotest.state.StateTracker
---@nodoc
local tracker

---@param client neotest.Client
---@nodoc
local function init(client)
local updated_cond = async.control.Condvar.new()
local pending_update = false
tracker = StateTracker:new(client)
local function update_positions()
while true do
if not pending_update then
updated_cond:wait()
end
tracker:update_positions()
pending_update = false
async.util.sleep(50)
end
end

vim.api.nvim_create_autocmd("BufAdd", {
callback = function(args)
tracker:register_buffer(args.buf)
pending_update = true
updated_cond:notify_all()
end,
})
for _, buf in ipairs(async.api.nvim_list_bufs()) do
tracker:register_buffer(buf)
end
async.run(function()
xpcall(update_positions, function(msg)
logger.error("Error in state consumer", debug.traceback(msg, 2))
end)
end)
client.listeners.discover_positions = function(adapter_id)
if not tracker:adapter_state(adapter_id) then
tracker:register_adapter(adapter_id)
end
pending_update = true
updated_cond:notify_all()
end

client.listeners.run = function(adapter_id, _, position_ids)
tracker:update_running(adapter_id, position_ids)
end

client.listeners.results = function(adapter_id, results, partial)
if partial then
return
end
tracker:update_results(adapter_id, results)
end
end

---@param args? table
---@return neotest.state.State | nil
---@nodoc
local function state_from_args(adapter_id, args)
if args and args.buffer then
return tracker:buffer_state(adapter_id, args.buffer)
end
return tracker:adapter_state(adapter_id)
end

---@toc_entry State Consumer
---@text
--- A consumer that tracks various pieces of state in Neotest.
--- Most of the internals of Neotest are asynchronous so this consumer allows
--- tracking the state of the test suite and test results without needing to
--- write asynchronous code.
---@class neotest.consumers.state
neotest.state = {}

--- Get the list of all adapter IDs currently active
---@return string[]
function neotest.state.adapter_ids()
return tracker.adapter_ids
end

--- Get the counts of the various states of tests for the entire suite or for a
--- buffer.
---@param adapter_id string
---@param args? neotest.state.StatusCountsArgs
---@return neotest.state.StatusCounts | nil
function neotest.state.status_counts(adapter_id, args)
local state = state_from_args(adapter_id, args)

return state and state.status
end

---@class neotest.state.StatusCountsArgs
---@field buffer? integer Returns statuses for this buffer

---@class neotest.state.StatusCounts
---@field total integer
---@field passed integer
---@field failed integer
---@field skipped integer
---@field running integer

neotest.summary = setmetatable(neotest.state, {
__call = function(_, client)
init(client)
return neotest.state
end,
})

return neotest.state
Loading

0 comments on commit 43309c0

Please sign in to comment.