|
1 | 1 | local lib = require("neotest.lib")
|
| 2 | +local position_parser = require("src.position-parser") |
| 3 | +local package_query = require("src.treesitter.package-query") |
| 4 | +local class_query = require("src.treesitter.class-query") |
2 | 5 | local async = require("neotest.async")
|
3 |
| - |
| 6 | +local command = require("src.command") |
| 7 | +local filter = require("src.filter") |
4 | 8 | local treesitter_query = require("kotest-treesitter-query")
|
| 9 | +local output_parser = require("src.output-parser") |
5 | 10 |
|
6 | 11 | local adapter = { name = "neotest-kotest" }
|
7 | 12 |
|
8 |
| ----Find the project root directory given a current directory to work from. |
9 |
| ----Should no root be found, the adapter can still be used in a non-project context if a test file matches. |
10 |
| ----@async |
11 |
| ----@param dir string @Directory to treat as cwd |
12 |
| ----@return string | nil @Absolute root dir of test suite |
13 | 13 | function adapter.root(dir)
|
14 |
| - return lib.files.match_root_pattern("build.gradle.kts")(dir) |
| 14 | + return lib.files.match_root_pattern("build.gradle.kts")(dir) |
15 | 15 | end
|
16 | 16 |
|
17 |
| -local ignored_directories = |
18 |
| - { "docs", "build", "out", "generated", ".gradle", "main", ".idea", "buildSrc", "kapt", "taret" } |
19 |
| - |
20 |
| ----Filter directories when searching for test files |
21 |
| ----@async |
22 |
| ----@param name string Name of directory |
23 |
| ----@param rel_path string Path to directory, relative to root |
24 |
| ----@param root string Root directory of project |
25 |
| ----@return boolean |
26 | 17 | function adapter.filter_dir(name, rel_path, root)
|
27 |
| - for _, v in ipairs(ignored_directories) do |
28 |
| - if v == name then |
29 |
| - return false |
30 |
| - end |
31 |
| - end |
32 |
| - return true |
| 18 | + return filter.test_directory(name) |
33 | 19 | end
|
34 | 20 |
|
35 |
| ----@async |
36 |
| ----@param file_path string |
37 |
| ----@return boolean |
38 | 21 | function adapter.is_test_file(file_path)
|
39 |
| - if file_path == nil then |
40 |
| - return false |
41 |
| - end |
42 |
| - |
43 |
| - if not vim.endswith(file_path, ".kt") then |
44 |
| - return false |
45 |
| - end |
46 |
| - |
47 |
| - if string.find(file_path, "src/main") then |
48 |
| - return false |
49 |
| - end |
50 |
| - |
51 |
| - return true |
| 22 | + return filter.is_test_file(file_path) |
52 | 23 | end
|
53 | 24 |
|
54 | 25 | local function get_match_type(captured_nodes)
|
55 |
| - if captured_nodes["namespace.name"] then |
56 |
| - return "namespace" |
57 |
| - end |
58 |
| - if captured_nodes["test.name"] then |
59 |
| - return "test" |
60 |
| - end |
| 26 | + if captured_nodes["namespace.name"] then |
| 27 | + return "namespace" |
| 28 | + end |
| 29 | + if captured_nodes["test.name"] then |
| 30 | + return "test" |
| 31 | + end |
61 | 32 | end
|
62 | 33 |
|
63 | 34 | function adapter.build_position(file_path, source, captured_nodes)
|
64 |
| - local match_type = get_match_type(captured_nodes) |
65 |
| - local definition = captured_nodes[match_type .. ".definition"] |
| 35 | + local match_type = get_match_type(captured_nodes) |
| 36 | + local definition = captured_nodes[match_type .. ".definition"] |
66 | 37 |
|
67 |
| - local build_position = { |
68 |
| - type = match_type, |
69 |
| - path = file_path, |
70 |
| - range = { definition:range() }, |
71 |
| - } |
| 38 | + local build_position = { |
| 39 | + type = match_type, |
| 40 | + path = file_path, |
| 41 | + range = { definition:range() }, |
| 42 | + } |
72 | 43 |
|
73 |
| - return build_position |
| 44 | + return build_position |
74 | 45 | end
|
75 | 46 |
|
76 |
| ----Given a file path, parse all the tests within it. |
| 47 | +--- a file path, parse all the tests within it. |
77 | 48 | ---@async
|
78 | 49 | ---@param file_path string Absolute file path
|
79 | 50 | ---@return neotest.Tree | nil
|
80 | 51 | function adapter.discover_positions(path)
|
81 |
| - local positions = lib.treesitter.parse_positions(path, treesitter_query.value, { |
82 |
| - nested_namespaces = true, |
83 |
| - nested_tests = false, |
84 |
| - -- build_position = 'require("neotest-kotest").build_position', |
85 |
| - }) |
86 |
| - |
87 |
| - return positions |
88 |
| -end |
89 |
| - |
90 |
| -function get_package_name(file_path) |
91 |
| - local package_name_query = "(package_header (identifier) @package.name)" |
92 |
| - |
93 |
| - local file = io.open(file_path) |
94 |
| - |
95 |
| - if file == nil then |
96 |
| - return "*" |
97 |
| - end |
98 |
| - |
99 |
| - local code = file:read("*all") |
100 |
| - |
101 |
| - local new_buffer_number = vim.api.nvim_create_buf(false, true) |
102 |
| - vim.api.nvim_buf_set_lines(new_buffer_number, 0, -1, false, vim.split(code, "\n")) |
103 |
| - |
104 |
| - file:close() |
105 |
| - |
106 |
| - local language = "kotlin" |
107 |
| - |
108 |
| - local parser = vim.treesitter.get_string_parser(code, language) |
109 |
| - local tree = parser:parse() |
110 |
| - local root = tree[1]:root() |
111 |
| - |
112 |
| - local query = vim.treesitter.query.parse(language, package_name_query) |
113 |
| - |
114 |
| - for _, match, _ in query:iter_matches(root, new_buffer_number, root:start(), root:end_()) do |
115 |
| - for _, node in pairs(match) do |
116 |
| - local start_row, start_col = node:start() |
117 |
| - local end_row, end_col = node:end_() |
118 |
| - |
119 |
| - -- string:sub is 1 indexed, but the nodes apis return 0 indexed jawns... |
120 |
| - -- effectively making this a river of brain melting sadness |
121 |
| - local text = code:sub(start_row + 2, end_row - 1):sub(start_col, end_col - 1) |
122 |
| - |
123 |
| - return text |
124 |
| - end |
125 |
| - end |
126 |
| - |
127 |
| - -- local package_name = matches[0].captures["package.name"][1] |
128 |
| - |
129 |
| - -- vim.inspect(package_name) |
130 |
| - |
131 |
| - return nil |
| 52 | + local positions = lib.treesitter.parse_positions(path, treesitter_query.value, { |
| 53 | + nested_namespaces = true, |
| 54 | + nested_tests = false, |
| 55 | + }) |
| 56 | + return positions |
132 | 57 | end
|
133 | 58 |
|
134 | 59 | ---@param args neotest.run.RunArgs
|
135 | 60 | ---@return nil | neotest.RunSpec | neotest.RunSpec[]
|
136 | 61 | function adapter.build_spec(args)
|
137 |
| - local results_path = async.fn.tempname() .. ".json" |
138 |
| - |
139 |
| - -- Write something so there is a place to stream to... |
140 |
| - lib.files.write(results_path, "") |
141 |
| - |
142 |
| - local tree = args.tree |
143 |
| - |
144 |
| - if not tree then |
145 |
| - return |
146 |
| - end |
147 |
| - |
148 |
| - local pos = tree:data() |
149 |
| - |
150 |
| - local root = adapter.root(pos.path) |
151 |
| - local spec = get_package_name(pos.path) |
152 |
| - local test = "*" |
153 |
| - |
154 |
| - local command_three = "export kotest_filter_tests='" |
155 |
| - .. test |
156 |
| - .. "'; export kotest_filter_specs='" |
157 |
| - .. spec |
158 |
| - .. "'; ./gradlew clean test --info >> " |
159 |
| - .. results_path |
160 |
| - |
161 |
| - local stream_data, stop_stream = lib.files.stream(results_path) |
162 |
| - |
163 |
| - return { |
164 |
| - command = command_three, |
165 |
| - cwd = root, |
166 |
| - context = { |
167 |
| - results_path = results_path, |
168 |
| - file = pos.path, |
169 |
| - stop_stream = stop_stream, |
170 |
| - }, |
171 |
| - stream = function() |
172 |
| - return function() |
173 |
| - print("streaming...") |
174 |
| - local new_results = stream_data() |
175 |
| - |
176 |
| - local tests = {} |
177 |
| - |
178 |
| - tests["foo"] = { |
179 |
| - status = "skipped", |
180 |
| - short = "something goofy", |
181 |
| - output = "comnsole out", |
182 |
| - location = "test", |
183 |
| - } |
184 |
| - |
185 |
| - return tests |
186 |
| - end |
187 |
| - end, |
188 |
| - } |
| 62 | + local results_path = async.fn.tempname() .. ".json" |
| 63 | + |
| 64 | + -- Write something so there is a place to stream to... |
| 65 | + lib.files.write(results_path, "") |
| 66 | + |
| 67 | + local tree = args.tree |
| 68 | + |
| 69 | + if not tree then |
| 70 | + return |
| 71 | + end |
| 72 | + |
| 73 | + local pos = tree:data() |
| 74 | + |
| 75 | + local root = adapter.root(pos.path) |
| 76 | + local pkg = position_parser.get_first_match_string(pos.path, package_query) |
| 77 | + print("pkg!!!: " .. vim.inspect(pkg)) |
| 78 | + local className = position_parser.get_first_match_string(pos.path, class_query) |
| 79 | + print("class name!!!: " .. vim.inspect(className)) |
| 80 | + local specPackage = pkg .. "." .. className |
| 81 | + print("specPackage: " .. specPackage) |
| 82 | + local tests = "*" |
| 83 | + |
| 84 | + local gradle_command = command.parse(tests, specPackage, results_path) |
| 85 | + |
| 86 | + local stream_data, stop_stream = lib.files.stream_lines(results_path) |
| 87 | + |
| 88 | + print("command: " .. gradle_command) |
| 89 | + |
| 90 | + local all_results = {} |
| 91 | + |
| 92 | + return { |
| 93 | + command = gradle_command, |
| 94 | + cwd = root, |
| 95 | + context = { |
| 96 | + all_results = all_results, |
| 97 | + results_path = results_path, |
| 98 | + file = pos.path, |
| 99 | + stop_stream = stop_stream, |
| 100 | + }, |
| 101 | + stream = function() |
| 102 | + return function() |
| 103 | + local new_results = stream_data() |
| 104 | + local success, parsed_result = pcall(output_parser.lines_to_results, new_results, pos.path, specPackage) |
| 105 | + if not success then |
| 106 | + print("An error ocurred while attempting to stream data to result: " .. |
| 107 | + vim.inspect(err) .. " new_results: " .. vim.inspect(new_results)) |
| 108 | + return nil |
| 109 | + else |
| 110 | + for k, v in pairs(parsed_result) do all_results[k] = v end |
| 111 | + return parsed_result |
| 112 | + end |
| 113 | + end |
| 114 | + end, |
| 115 | + } |
189 | 116 | end
|
190 | 117 |
|
| 118 | +---@class neotest.Result |
| 119 | +---@field status neotest.ResultStatus |
| 120 | +---@field output? string Path to file containing full output data |
| 121 | +---@field short? string Shortened output string |
| 122 | +---@field errors? neotest.Error[] |
| 123 | + |
191 | 124 | ---@async
|
192 | 125 | ---@param spec neotest.RunSpec
|
193 | 126 | ---@param result neotest.StrategyResult
|
194 | 127 | ---@param tree neotest.Tree
|
195 | 128 | ---@return table<string, neotest.Result>
|
196 | 129 | function adapter.results(spec, result, tree)
|
197 |
| - print("In results") |
198 |
| - |
199 |
| - print(result) |
200 |
| - |
201 |
| - spec.context.stop_stream() |
202 |
| - return { "test", {} } |
| 130 | + spec.context.stop_stream() |
| 131 | + return spec.context.all_results |
203 | 132 | end
|
204 | 133 |
|
205 | 134 | return adapter
|
0 commit comments