test_launcher 1.5.0 → 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +18 -0
- data/bin/test_launcher +2 -5
- data/lib/test_launcher/cli/input_parser.rb +37 -12
- data/lib/test_launcher/cli/query.rb +30 -0
- data/lib/test_launcher/cli/request.rb +61 -0
- data/lib/test_launcher/cli.rb +44 -0
- data/lib/test_launcher/frameworks/base.rb +26 -7
- data/lib/test_launcher/frameworks/elixir.rb +84 -0
- data/lib/test_launcher/frameworks/implementation/test_case.rb +4 -7
- data/lib/test_launcher/frameworks/minitest.rb +80 -23
- data/lib/test_launcher/frameworks/rspec.rb +38 -13
- data/lib/test_launcher/queries.rb +346 -0
- data/lib/test_launcher/rubymine/launcher.rb +1 -12
- data/lib/test_launcher/rubymine/request.rb +15 -0
- data/lib/test_launcher/rubymine.rb +20 -13
- data/lib/test_launcher/search/ag.rb +96 -0
- data/lib/test_launcher/search/git.rb +6 -2
- data/lib/test_launcher/search.rb +18 -0
- data/lib/test_launcher/shell/runner.rb +2 -1
- data/lib/test_launcher/version.rb +1 -1
- data/lib/test_launcher.rb +0 -26
- data/test/test_helper.rb +2 -1
- data/test/test_helpers/integration_helper.rb +40 -0
- data/test/test_helpers/mock.rb +59 -0
- data/test/test_helpers/mock_searcher.rb +1 -0
- data/test/test_helpers/mocks/searcher_mock.rb +82 -0
- data/test/test_helpers/mocks.rb +76 -0
- data/test/test_launcher/cli/input_parser_test.rb +72 -0
- data/test/test_launcher/frameworks/minitest/runner_test.rb +72 -0
- data/test/test_launcher/frameworks/minitest/searcher_test.rb +109 -0
- data/test/test_launcher/frameworks/rspec/runner_test.rb +76 -0
- data/test/test_launcher/frameworks/rspec/searcher_test.rb +54 -0
- data/test/test_launcher/minitest_integration_test.rb +31 -40
- data/test/test_launcher/queries/example_name_query_test.rb +217 -0
- data/test/test_launcher/queries/full_regex_query_test.rb +153 -0
- data/test/test_launcher/queries/generic_query_test.rb +23 -0
- data/test/test_launcher/queries/line_number_query_test.rb +107 -0
- data/test/test_launcher/queries/multi_term_query_test.rb +138 -0
- data/test/test_launcher/queries/path_query_test.rb +192 -0
- data/test/test_launcher/queries/search_query_test.rb +54 -0
- data/test/test_launcher/queries/single_term_query_test.rb +36 -0
- data/test/test_launcher/queries/specified_name_query_test.rb +112 -0
- data/test/test_launcher/rspec_integration_test.rb +27 -41
- data/test/test_launcher/search/git_test.rb +2 -0
- metadata +49 -10
- data/lib/test_launcher/frameworks/implementation/collection.rb +0 -36
- data/lib/test_launcher/frameworks/implementation/consolidator.rb +0 -83
- data/lib/test_launcher/frameworks/implementation/locator.rb +0 -118
- data/lib/test_launcher/frameworks.rb +0 -20
- data/lib/test_launcher/request.rb +0 -36
- data/test/test_launcher/frameworks/implementation/locator_test.rb +0 -166
@@ -0,0 +1,346 @@
|
|
1
|
+
module TestLauncher
|
2
|
+
module Queries
|
3
|
+
class CommandFinder
|
4
|
+
def initialize(request)
|
5
|
+
@request = request
|
6
|
+
end
|
7
|
+
|
8
|
+
def specified_name
|
9
|
+
commandify(SpecifiedNameQuery)
|
10
|
+
end
|
11
|
+
|
12
|
+
def multi_search_term
|
13
|
+
commandify(MultiTermQuery)
|
14
|
+
end
|
15
|
+
|
16
|
+
def by_path
|
17
|
+
commandify(PathQuery)
|
18
|
+
end
|
19
|
+
|
20
|
+
def example_name
|
21
|
+
commandify(ExampleNameQuery)
|
22
|
+
end
|
23
|
+
|
24
|
+
def from_full_regex
|
25
|
+
commandify(FullRegexQuery)
|
26
|
+
end
|
27
|
+
|
28
|
+
def single_search_term
|
29
|
+
commandify(SingleTermQuery)
|
30
|
+
end
|
31
|
+
|
32
|
+
def full_search
|
33
|
+
commandify(SearchQuery)
|
34
|
+
end
|
35
|
+
|
36
|
+
def generic_search
|
37
|
+
commandify(GenericQuery)
|
38
|
+
end
|
39
|
+
|
40
|
+
def line_number
|
41
|
+
commandify(LineNumberQuery)
|
42
|
+
end
|
43
|
+
|
44
|
+
def request
|
45
|
+
@request
|
46
|
+
end
|
47
|
+
|
48
|
+
def commandify(klass)
|
49
|
+
klass.new(
|
50
|
+
request,
|
51
|
+
self
|
52
|
+
).command
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class BaseQuery
|
57
|
+
attr_reader :shell, :searcher, :request
|
58
|
+
def initialize(request, command_finder)
|
59
|
+
@request = request
|
60
|
+
@command_finder = command_finder
|
61
|
+
end
|
62
|
+
|
63
|
+
def command
|
64
|
+
raise NotImplementedError
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def test_cases
|
70
|
+
raise NotImplementedError
|
71
|
+
end
|
72
|
+
|
73
|
+
def runner
|
74
|
+
request.runner
|
75
|
+
end
|
76
|
+
|
77
|
+
def shell
|
78
|
+
request.shell
|
79
|
+
end
|
80
|
+
|
81
|
+
def searcher
|
82
|
+
request.searcher
|
83
|
+
end
|
84
|
+
|
85
|
+
def one_file?
|
86
|
+
file_count == 1
|
87
|
+
end
|
88
|
+
|
89
|
+
def file_count
|
90
|
+
@file_count ||= test_cases.map {|tc| tc.file }.uniq.size
|
91
|
+
end
|
92
|
+
|
93
|
+
def most_recently_edited_test_case
|
94
|
+
@most_recently_edited_test_case ||= test_cases.sort_by(&:mtime).last
|
95
|
+
end
|
96
|
+
|
97
|
+
def pluralize(count, singular)
|
98
|
+
phrase = "#{count} #{singular}"
|
99
|
+
if count == 1
|
100
|
+
phrase
|
101
|
+
else
|
102
|
+
"#{phrase}s"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def command_finder
|
107
|
+
@command_finder
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class SpecifiedNameQuery < BaseQuery
|
112
|
+
def command
|
113
|
+
return unless file
|
114
|
+
|
115
|
+
shell.notify("Found matching test.")
|
116
|
+
runner.single_example(test_case)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_case
|
120
|
+
request.test_case(
|
121
|
+
file: file,
|
122
|
+
example: request.example_name,
|
123
|
+
request: request,
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
def file
|
128
|
+
if potential_files.size == 0
|
129
|
+
shell.warn("Could not locate file: #{request.search_string}")
|
130
|
+
elsif potential_files.size > 1
|
131
|
+
shell.warn("Too many files matched: #{request.search_string}")
|
132
|
+
else
|
133
|
+
potential_files.first
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def potential_files
|
138
|
+
@potential_files ||= searcher.test_files(request.search_string)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
class MultiTermQuery < BaseQuery
|
143
|
+
def command
|
144
|
+
return if test_cases.empty?
|
145
|
+
|
146
|
+
shell.notify("Found #{pluralize(file_count, "file")}.")
|
147
|
+
runner.multiple_files(test_cases)
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_cases
|
151
|
+
@test_cases ||= files.map { |file_path|
|
152
|
+
request.test_case(
|
153
|
+
file: file_path,
|
154
|
+
request: request,
|
155
|
+
)
|
156
|
+
}
|
157
|
+
end
|
158
|
+
|
159
|
+
def files
|
160
|
+
if found_files.any? {|files_array| files_array.empty? }
|
161
|
+
if !found_files.all? {|files_array| files_array.empty? }
|
162
|
+
shell.warn("It looks like you're searching for multiple files, but we couldn't identify them all.")
|
163
|
+
end
|
164
|
+
[]
|
165
|
+
else
|
166
|
+
found_files.flatten.uniq
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def found_files
|
171
|
+
@found_files ||= queries.map {|query|
|
172
|
+
searcher.test_files(query)
|
173
|
+
}
|
174
|
+
end
|
175
|
+
|
176
|
+
def queries
|
177
|
+
@queries ||= request.search_string.split(" ")
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
class PathQuery < BaseQuery
|
182
|
+
def command
|
183
|
+
return if test_cases.empty?
|
184
|
+
|
185
|
+
if one_file?
|
186
|
+
shell.notify "Found #{pluralize(file_count, "file")}."
|
187
|
+
runner.single_file(test_cases.first)
|
188
|
+
elsif request.run_all?
|
189
|
+
shell.notify "Found #{pluralize(file_count, "file")}."
|
190
|
+
runner.multiple_files(test_cases)
|
191
|
+
else
|
192
|
+
shell.notify "Found #{pluralize(file_count, "file")}."
|
193
|
+
shell.notify "Running most recently edited. Run with '--all' to run all the tests."
|
194
|
+
runner.single_file(most_recently_edited_test_case)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_cases
|
199
|
+
@test_cases ||= files_found_by_path.map { |file_path|
|
200
|
+
request.test_case(file: file_path, request: request)
|
201
|
+
}
|
202
|
+
end
|
203
|
+
|
204
|
+
def files_found_by_path
|
205
|
+
@files_found_by_path ||= searcher.test_files(request.search_string)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
class ExampleNameQuery < BaseQuery
|
210
|
+
def command
|
211
|
+
return if test_cases.empty?
|
212
|
+
|
213
|
+
if one_example?
|
214
|
+
shell.notify("Found 1 example in 1 file.")
|
215
|
+
runner.single_example(test_cases.first)
|
216
|
+
elsif one_file?
|
217
|
+
shell.notify("Found #{test_cases.size} examples in 1 file.")
|
218
|
+
runner.multiple_examples_same_file(test_cases) # it will regex with the query
|
219
|
+
elsif request.run_all?
|
220
|
+
shell.notify "Found #{pluralize(test_cases.size, "example")} in #{pluralize(file_count, "file")}."
|
221
|
+
runner.multiple_files(test_cases)
|
222
|
+
else
|
223
|
+
shell.notify "Found #{pluralize(test_cases.size, "example")} in #{pluralize(file_count, "file")}."
|
224
|
+
shell.notify "Running most recently edited. Run with '--all' to run all the tests."
|
225
|
+
runner.single_example(most_recently_edited_test_case) # let it regex the query
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_cases
|
230
|
+
@test_cases ||=
|
231
|
+
examples_found_by_name.map { |grep_result|
|
232
|
+
request.test_case(
|
233
|
+
file: grep_result[:file],
|
234
|
+
example: request.search_string,
|
235
|
+
line_number: grep_result[:line_number],
|
236
|
+
request: request
|
237
|
+
)
|
238
|
+
}
|
239
|
+
end
|
240
|
+
|
241
|
+
def examples_found_by_name
|
242
|
+
@examples_found_by_name ||= searcher.examples(request.search_string)
|
243
|
+
end
|
244
|
+
|
245
|
+
def one_example?
|
246
|
+
test_cases.size == 1
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
class FullRegexQuery < BaseQuery
|
251
|
+
def command
|
252
|
+
return if test_cases.empty?
|
253
|
+
|
254
|
+
if one_file?
|
255
|
+
shell.notify "Found #{pluralize(file_count, "file")}."
|
256
|
+
runner.single_file(test_cases.first)
|
257
|
+
elsif request.run_all?
|
258
|
+
shell.notify "Found #{pluralize(file_count, "file")}."
|
259
|
+
runner.multiple_files(test_cases)
|
260
|
+
else
|
261
|
+
shell.notify "Found #{pluralize(file_count, "file")}."
|
262
|
+
shell.notify "Running most recently edited. Run with '--all' to run all the tests."
|
263
|
+
runner.single_file(most_recently_edited_test_case)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def test_cases
|
268
|
+
@test_cases ||=
|
269
|
+
files_found_by_full_regex
|
270
|
+
.uniq { |grep_result| grep_result[:file] }
|
271
|
+
.map { |grep_result|
|
272
|
+
request.test_case(
|
273
|
+
file: grep_result[:file],
|
274
|
+
request: request
|
275
|
+
)
|
276
|
+
}
|
277
|
+
end
|
278
|
+
|
279
|
+
def files_found_by_full_regex
|
280
|
+
@files_found_by_full_regex ||= searcher.grep(request.search_string)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
class LineNumberQuery < BaseQuery
|
285
|
+
LINE_SPLIT_REGEX = /\A(?<file>.*):(?<line_number>\d+)\Z/
|
286
|
+
|
287
|
+
def command
|
288
|
+
match = request.search_string.match(LINE_SPLIT_REGEX)
|
289
|
+
return unless match
|
290
|
+
|
291
|
+
search_result = searcher.by_line(match[:file], match[:line_number].to_i)
|
292
|
+
return unless search_result
|
293
|
+
|
294
|
+
if search_result[:line_number]
|
295
|
+
shell.notify("Found 1 example on line #{search_result[:line_number]}.")
|
296
|
+
runner.single_example(request.test_case(file: search_result[:file], line_number: search_result[:line_number], example: search_result[:example_name], request: request))
|
297
|
+
else
|
298
|
+
shell.notify("Found file, but line is not inside an example.")
|
299
|
+
runner.single_file(request.test_case(file: search_result[:file], request: request))
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
class SingleTermQuery < BaseQuery
|
306
|
+
def command
|
307
|
+
[
|
308
|
+
:by_path,
|
309
|
+
:example_name,
|
310
|
+
:from_full_regex,
|
311
|
+
]
|
312
|
+
.each { |command_type|
|
313
|
+
command = command_finder.public_send(command_type)
|
314
|
+
return command if command
|
315
|
+
}
|
316
|
+
nil
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
class SearchQuery < BaseQuery
|
321
|
+
def command
|
322
|
+
{
|
323
|
+
multi_search_term: request.search_string.include?(" "),
|
324
|
+
line_number: request.search_string.include?(":"),
|
325
|
+
single_search_term: true
|
326
|
+
}.each {|command_type, valid|
|
327
|
+
next unless valid
|
328
|
+
|
329
|
+
command = command_finder.public_send(command_type)
|
330
|
+
return command if command
|
331
|
+
}
|
332
|
+
nil
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
class GenericQuery < BaseQuery
|
337
|
+
def command
|
338
|
+
if request.example_name
|
339
|
+
command_finder.specified_name
|
340
|
+
else
|
341
|
+
command_finder.full_search
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
@@ -1,19 +1,8 @@
|
|
1
|
-
require "test_launcher/request"
|
2
1
|
require "test_launcher/frameworks/minitest"
|
3
2
|
require "test_launcher/shell/runner"
|
4
3
|
|
5
4
|
module TestLauncher
|
6
5
|
module Rubymine
|
7
|
-
class MinimalRequest
|
8
|
-
def initialize(disable_spring:)
|
9
|
-
@disable_spring = disable_spring
|
10
|
-
end
|
11
|
-
|
12
|
-
def disable_spring?
|
13
|
-
@disable_spring
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
6
|
class Launcher
|
18
7
|
def initialize(args:, shell:, request:)
|
19
8
|
@args = args
|
@@ -40,7 +29,7 @@ module TestLauncher
|
|
40
29
|
|
41
30
|
def command
|
42
31
|
if test_case.is_example?
|
43
|
-
Frameworks::Minitest::Runner.new.single_example(test_case
|
32
|
+
Frameworks::Minitest::Runner.new.single_example(test_case)
|
44
33
|
else
|
45
34
|
Frameworks::Minitest::Runner.new.single_file(test_case)
|
46
35
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require "test_launcher/rubymine/launcher"
|
2
1
|
require "test_launcher/shell/runner"
|
3
|
-
require "test_launcher/
|
2
|
+
require "test_launcher/rubymine/launcher"
|
3
|
+
require "test_launcher/rubymine/request"
|
4
4
|
|
5
5
|
# To allow us to simply specify our run configuration as:
|
6
6
|
#
|
@@ -20,15 +20,22 @@ require "test_launcher/request"
|
|
20
20
|
# So we throw them in the same bucket and let the launcher figure it
|
21
21
|
# out. It doesn't matter since we will `exec` a new command anyway.
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
module TestLauncher
|
24
|
+
module Rubymine
|
25
|
+
def self.launch
|
26
|
+
shell = TestLauncher::Shell::Runner.new(log_path: "/dev/null")
|
27
|
+
|
28
|
+
request = Request.new(
|
29
|
+
disable_spring: ENV["DISABLE_SPRING"]
|
30
|
+
)
|
31
|
+
|
32
|
+
Launcher.new(
|
33
|
+
args: [$0].concat(ARGV),
|
34
|
+
shell: shell,
|
35
|
+
request: request
|
36
|
+
).launch
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
29
40
|
|
30
|
-
TestLauncher::Rubymine
|
31
|
-
args: [$0].concat(ARGV),
|
32
|
-
shell: TestLauncher::Shell::Runner.new(log_path: "/dev/null"),
|
33
|
-
request: dummy_request
|
34
|
-
).launch
|
41
|
+
TestLauncher::Rubymine.launch
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require "test_launcher/base_error"
|
2
|
+
|
3
|
+
module TestLauncher
|
4
|
+
module Search
|
5
|
+
class Ag
|
6
|
+
NotInRepoError = Class.new(BaseError)
|
7
|
+
class Interface
|
8
|
+
attr_reader :shell
|
9
|
+
|
10
|
+
def initialize(shell)
|
11
|
+
@shell = shell
|
12
|
+
end
|
13
|
+
|
14
|
+
def ls_files(pattern)
|
15
|
+
shell.run("ag -g '.*#{pattern_to_regex(pattern)}.*'")
|
16
|
+
end
|
17
|
+
|
18
|
+
def grep(regex, file_pattern)
|
19
|
+
shell.run("ag '#{regex}' --file-search-regex '#{pattern_to_regex(file_pattern)}'")
|
20
|
+
end
|
21
|
+
|
22
|
+
def root_path
|
23
|
+
shell.run("git rev-parse --show-toplevel").first.tap do
|
24
|
+
if $? != 0
|
25
|
+
raise NotInRepoError, "test_launcher must be used in a git repository"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def pattern_to_regex(pattern)
|
31
|
+
pattern.gsub("*", ".*")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :interface
|
36
|
+
|
37
|
+
def initialize(shell, interface=Interface.new(shell))
|
38
|
+
@interface = interface
|
39
|
+
Dir.chdir(root_path) # MOVE ME!
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_files(pattern)
|
43
|
+
relative_pattern = strip_system_path(pattern)
|
44
|
+
interface.ls_files(relative_pattern).map {|f| system_path(f)}
|
45
|
+
end
|
46
|
+
|
47
|
+
def grep(regex, file_pattern: '*')
|
48
|
+
results = interface.grep(regex, file_pattern)
|
49
|
+
results.map do |result|
|
50
|
+
interpret_grep_result(result)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def interpret_grep_result(grep_result)
|
58
|
+
splits = grep_result.split(/:/)
|
59
|
+
file = splits.shift.strip
|
60
|
+
line_number = splits.shift.strip.to_i
|
61
|
+
# we rejoin on ':' because our
|
62
|
+
# code may have colons inside of it.
|
63
|
+
#
|
64
|
+
# example:
|
65
|
+
# path/to/file:126: run_method(a: A, b: B)
|
66
|
+
#
|
67
|
+
# so shift the first one out, then
|
68
|
+
# rejoin the rest
|
69
|
+
line = splits.join(':').strip
|
70
|
+
|
71
|
+
# TODO: Oh goodness, why is this not a class
|
72
|
+
{
|
73
|
+
:file => system_path(file),
|
74
|
+
:line_number => line_number.to_i,
|
75
|
+
:line => line,
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def system_path(file)
|
80
|
+
File.join(root_path, file)
|
81
|
+
end
|
82
|
+
|
83
|
+
def strip_system_path(file)
|
84
|
+
file.sub(/^#{root_path}\//, '')
|
85
|
+
end
|
86
|
+
|
87
|
+
def root_path
|
88
|
+
@root_path ||= interface.root_path
|
89
|
+
end
|
90
|
+
|
91
|
+
def shell
|
92
|
+
@shell
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -17,7 +17,7 @@ module TestLauncher
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def grep(regex, file_pattern)
|
20
|
-
shell.run("git grep --untracked --extended-regexp '#{regex}' -- '#{file_pattern}'")
|
20
|
+
shell.run("git grep --line-number --untracked --extended-regexp '#{regex}' -- '#{file_pattern}'")
|
21
21
|
end
|
22
22
|
|
23
23
|
def root_path
|
@@ -48,23 +48,27 @@ module TestLauncher
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
|
51
52
|
private
|
52
53
|
|
53
54
|
def interpret_grep_result(grep_result)
|
54
55
|
splits = grep_result.split(/:/)
|
55
56
|
file = splits.shift.strip
|
57
|
+
line_number = splits.shift.strip.to_i
|
56
58
|
# we rejoin on ':' because our
|
57
59
|
# code may have colons inside of it.
|
58
60
|
#
|
59
61
|
# example:
|
60
|
-
# path/to/file: run_method(a: A, b: B)
|
62
|
+
# path/to/file:126: run_method(a: A, b: B)
|
61
63
|
#
|
62
64
|
# so shift the first one out, then
|
63
65
|
# rejoin the rest
|
64
66
|
line = splits.join(':').strip
|
65
67
|
|
68
|
+
# TODO: Oh goodness, why is this not a class
|
66
69
|
{
|
67
70
|
:file => system_path(file),
|
71
|
+
:line_number => line_number.to_i,
|
68
72
|
:line => line,
|
69
73
|
}
|
70
74
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'test_launcher/search/ag'
|
2
|
+
require 'test_launcher/search/git'
|
3
|
+
|
4
|
+
module TestLauncher
|
5
|
+
module Search
|
6
|
+
def self.searcher(shell)
|
7
|
+
`which ag`
|
8
|
+
implementation =
|
9
|
+
if $?.success?
|
10
|
+
Search::Ag
|
11
|
+
else
|
12
|
+
Search::Git
|
13
|
+
end
|
14
|
+
|
15
|
+
implementation.new(shell)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -11,7 +11,7 @@ module TestLauncher
|
|
11
11
|
attr_accessor :log_path, :queue
|
12
12
|
private :log_path, :queue
|
13
13
|
|
14
|
-
def initialize(log_path:)
|
14
|
+
def initialize(log_path: "/dev/null")
|
15
15
|
@log_path = log_path
|
16
16
|
%x{echo "" > #{log_path}}
|
17
17
|
end
|
@@ -25,6 +25,7 @@ module TestLauncher
|
|
25
25
|
|
26
26
|
def exec(cmd)
|
27
27
|
notify cmd
|
28
|
+
$stdout.flush
|
28
29
|
Bundler.clean_exec(cmd)
|
29
30
|
end
|
30
31
|
|
data/lib/test_launcher.rb
CHANGED
@@ -1,27 +1 @@
|
|
1
1
|
require "test_launcher/version"
|
2
|
-
|
3
|
-
require "test_launcher/base_error"
|
4
|
-
require "test_launcher/shell/runner"
|
5
|
-
require "test_launcher/search/git"
|
6
|
-
require "test_launcher/frameworks"
|
7
|
-
|
8
|
-
module TestLauncher
|
9
|
-
def self.launch(request)
|
10
|
-
shell = Shell::Runner.new(log_path: "/tmp/test_launcher.log")
|
11
|
-
searcher = Search::Git.new(shell)
|
12
|
-
|
13
|
-
command = Frameworks.locate(
|
14
|
-
request: request,
|
15
|
-
shell: shell,
|
16
|
-
searcher: searcher
|
17
|
-
)
|
18
|
-
|
19
|
-
if command
|
20
|
-
shell.exec command
|
21
|
-
else
|
22
|
-
shell.warn "No tests found."
|
23
|
-
end
|
24
|
-
rescue BaseError => e
|
25
|
-
shell.warn(e)
|
26
|
-
end
|
27
|
-
end
|
data/test/test_helper.rb
CHANGED
@@ -4,6 +4,7 @@ require "mocha/mini_test"
|
|
4
4
|
require "pry"
|
5
5
|
|
6
6
|
require "test_launcher"
|
7
|
+
require "test_launcher/shell/runner"
|
7
8
|
|
8
9
|
class TestLauncher::Shell::Runner
|
9
10
|
def exec(cmd)
|
@@ -48,7 +49,7 @@ class TestCase < Minitest::Test
|
|
48
49
|
end
|
49
50
|
|
50
51
|
def recall(method)
|
51
|
-
instance_variable_get(:"@#{method}")
|
52
|
+
instance_variable_get(:"@#{method}") || []
|
52
53
|
end
|
53
54
|
end
|
54
55
|
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "test_launcher/search/git"
|
2
|
+
require "test_launcher/shell/runner"
|
3
|
+
|
4
|
+
require "test_launcher/cli"
|
5
|
+
require "test_helpers/mocks"
|
6
|
+
|
7
|
+
module TestLauncher
|
8
|
+
module IntegrationHelper
|
9
|
+
include DefaultMocks
|
10
|
+
|
11
|
+
class IntegrationShell < Shell::Runner
|
12
|
+
def exec(string)
|
13
|
+
raise "Cannot exec twice!" if defined?(@exec)
|
14
|
+
@exec = string
|
15
|
+
end
|
16
|
+
|
17
|
+
def recall_exec
|
18
|
+
@exec
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def system_path(relative_dir)
|
25
|
+
File.join(Dir.pwd, relative_dir)
|
26
|
+
end
|
27
|
+
|
28
|
+
def launch(search_string, run_all: false, framework:, name: nil)
|
29
|
+
argv = [search_string, "--framework", framework]
|
30
|
+
argv << "--all" if run_all
|
31
|
+
argv.concat(["--name", name]) if name
|
32
|
+
env = {}
|
33
|
+
CLI.launch(argv, env, shell: shell_mock)
|
34
|
+
end
|
35
|
+
|
36
|
+
def shell_mock
|
37
|
+
@shell_mock ||= IntegrationShell.new
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|