1
- local neotest = require (" neotest" )
2
1
local lib = require (" neotest.lib" )
3
2
local async = require (" neotest.async" )
4
3
4
+ local treesitter_query = require (" kotest-treesitter-query" )
5
+
5
6
local adapter = { name = " neotest-kotest" }
6
7
7
8
--- Find the project root directory given a current directory to work from.
@@ -10,7 +11,7 @@ local adapter = { name = "neotest-kotest" }
10
11
--- @param dir string @Directory to treat as cwd
11
12
--- @return string | nil @Absolute root dir of test suite
12
13
function adapter .root (dir )
13
- return lib .files .match_root_pattern (" build.gradle?( .kts) " )(dir )
14
+ return lib .files .match_root_pattern (" build.gradle.kts" )(dir )
14
15
end
15
16
16
17
local ignored_directories =
@@ -39,87 +40,128 @@ function adapter.is_test_file(file_path)
39
40
return false
40
41
end
41
42
42
- -- todo(mikol): see if this has a kotest import...
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
+
43
51
return true
44
52
end
45
53
54
+ 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
61
+ end
62
+
63
+ 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" ]
66
+
67
+ local build_position = {
68
+ type = match_type ,
69
+ path = file_path ,
70
+ range = { definition :range () },
71
+ }
72
+
73
+ return build_position
74
+ end
75
+
76
+ --- Given a file path, parse all the tests within it.
46
77
--- @async
78
+ --- @param file_path string Absolute file path
79
+ --- @return neotest.Tree | nil
47
80
function adapter .discover_positions (path )
48
- local query = [[
49
-
50
- ;; --- DESCRIBE SPEC ---
51
-
52
- ; Matches describe("context") { /** body **/ }
53
-
54
- (call_expression
55
- (call_expression
56
- (simple_identifier) @func_name (#eq? @func_name "describe")
57
- (call_suffix
58
- (value_arguments
59
- (value_argument
60
- (string_literal) @namespace.name
61
- )
62
- )
63
- )
64
- )
65
- ) @namespace.definition
66
-
67
- ; Matches it("context") { /** body **/ }
68
-
69
- (call_expression
70
- (call_expression
71
- (simple_identifier) @func_name (#eq? @func_name "it")
72
- (call_suffix
73
- (value_arguments
74
- (value_argument
75
- (string_literal) @namespace.name
76
- )
77
- )
78
- )
79
- )
80
- ) @namespace.definition
81
-
82
- ;; -- todo FUN SPEC --
83
- ;; -- todo SHOULD SPEC --
84
- ;; -- todo STRING SPEC --
85
- ;; -- todo BEHAVIOR SPEC --
86
- ;; -- todo FREE SPEC --
87
- ;; -- todo WORD SPEC --
88
- ;; -- todo FEATURE SPEC --
89
- ;; -- todo EXPECT SPEC --
90
- ;; -- todo ANNOTATION SPEC --
91
- ]]
92
-
93
- return lib .treesitter .parse_positions (path , query , { nested_namespaces = true })
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
94
132
end
95
133
96
- --- @param args neotest.RunArgs
134
+ --- @param args neotest.run. RunArgs
97
135
--- @return nil | neotest.RunSpec | neotest.RunSpec[]
98
136
function adapter .build_spec (args )
99
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
+
100
142
local tree = args .tree
101
143
102
144
if not tree then
103
145
return
104
146
end
105
147
106
- local pos = args . tree :data ()
148
+ local pos = tree :data ()
107
149
108
150
local root = adapter .root (pos .path )
151
+ local spec = get_package_name (pos .path )
152
+ local test = " *"
109
153
110
- local package = get_test_package (args )
111
- local test_name = string.sub ()
112
-
113
- local command = " /.gradlew test -Dkotest.filter.specs='"
114
- .. package
115
- .. " ' -Dkotest.filter.tests='"
116
- .. test_name
117
- .. " '"
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
118
160
119
161
local stream_data , stop_stream = lib .files .stream (results_path )
120
162
121
163
return {
122
- command = command ,
164
+ command = command_three ,
123
165
cwd = root ,
124
166
context = {
125
167
results_path = results_path ,
@@ -128,14 +170,19 @@ function adapter.build_spec(args)
128
170
},
129
171
stream = function ()
130
172
return function ()
173
+ print (" streaming..." )
131
174
local new_results = stream_data ()
132
- local ok , parsed = pcall (vim .json .decode , new_results , { luanil = { object = true } })
133
175
134
- if not ok or not parsed .testResults then
135
- return {}
136
- end
176
+ local tests = {}
177
+
178
+ tests [" foo" ] = {
179
+ status = " skipped" ,
180
+ short = " something goofy" ,
181
+ output = " comnsole out" ,
182
+ location = " test" ,
183
+ }
137
184
138
- return {}
185
+ return tests
139
186
end
140
187
end ,
141
188
}
147
194
--- @param tree neotest.Tree
148
195
--- @return table<string , neotest.Result>
149
196
function adapter .results (spec , result , tree )
197
+ print (" In results" )
198
+
199
+ print (result )
200
+
150
201
spec .context .stop_stream ()
151
- return " something "
202
+ return { " test " , {} }
152
203
end
153
204
154
205
return adapter
0 commit comments