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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -0
  3. data/bin/test_launcher +2 -5
  4. data/lib/test_launcher/cli/input_parser.rb +37 -12
  5. data/lib/test_launcher/cli/query.rb +30 -0
  6. data/lib/test_launcher/cli/request.rb +61 -0
  7. data/lib/test_launcher/cli.rb +44 -0
  8. data/lib/test_launcher/frameworks/base.rb +26 -7
  9. data/lib/test_launcher/frameworks/elixir.rb +84 -0
  10. data/lib/test_launcher/frameworks/implementation/test_case.rb +4 -7
  11. data/lib/test_launcher/frameworks/minitest.rb +80 -23
  12. data/lib/test_launcher/frameworks/rspec.rb +38 -13
  13. data/lib/test_launcher/queries.rb +346 -0
  14. data/lib/test_launcher/rubymine/launcher.rb +1 -12
  15. data/lib/test_launcher/rubymine/request.rb +15 -0
  16. data/lib/test_launcher/rubymine.rb +20 -13
  17. data/lib/test_launcher/search/ag.rb +96 -0
  18. data/lib/test_launcher/search/git.rb +6 -2
  19. data/lib/test_launcher/search.rb +18 -0
  20. data/lib/test_launcher/shell/runner.rb +2 -1
  21. data/lib/test_launcher/version.rb +1 -1
  22. data/lib/test_launcher.rb +0 -26
  23. data/test/test_helper.rb +2 -1
  24. data/test/test_helpers/integration_helper.rb +40 -0
  25. data/test/test_helpers/mock.rb +59 -0
  26. data/test/test_helpers/mock_searcher.rb +1 -0
  27. data/test/test_helpers/mocks/searcher_mock.rb +82 -0
  28. data/test/test_helpers/mocks.rb +76 -0
  29. data/test/test_launcher/cli/input_parser_test.rb +72 -0
  30. data/test/test_launcher/frameworks/minitest/runner_test.rb +72 -0
  31. data/test/test_launcher/frameworks/minitest/searcher_test.rb +109 -0
  32. data/test/test_launcher/frameworks/rspec/runner_test.rb +76 -0
  33. data/test/test_launcher/frameworks/rspec/searcher_test.rb +54 -0
  34. data/test/test_launcher/minitest_integration_test.rb +31 -40
  35. data/test/test_launcher/queries/example_name_query_test.rb +217 -0
  36. data/test/test_launcher/queries/full_regex_query_test.rb +153 -0
  37. data/test/test_launcher/queries/generic_query_test.rb +23 -0
  38. data/test/test_launcher/queries/line_number_query_test.rb +107 -0
  39. data/test/test_launcher/queries/multi_term_query_test.rb +138 -0
  40. data/test/test_launcher/queries/path_query_test.rb +192 -0
  41. data/test/test_launcher/queries/search_query_test.rb +54 -0
  42. data/test/test_launcher/queries/single_term_query_test.rb +36 -0
  43. data/test/test_launcher/queries/specified_name_query_test.rb +112 -0
  44. data/test/test_launcher/rspec_integration_test.rb +27 -41
  45. data/test/test_launcher/search/git_test.rb +2 -0
  46. metadata +49 -10
  47. data/lib/test_launcher/frameworks/implementation/collection.rb +0 -36
  48. data/lib/test_launcher/frameworks/implementation/consolidator.rb +0 -83
  49. data/lib/test_launcher/frameworks/implementation/locator.rb +0 -118
  50. data/lib/test_launcher/frameworks.rb +0 -20
  51. data/lib/test_launcher/request.rb +0 -36
  52. data/test/test_launcher/frameworks/implementation/locator_test.rb +0 -166
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f9fcdbdd5ed1a8eb6fc871ec897647a78fdfb3b1
4
- data.tar.gz: 2d87fa49f026322a2786e31a34ab5a73aac6e9e6
3
+ metadata.gz: e18c5338873c55199563af9ddc95cf56e55efe76
4
+ data.tar.gz: 6c0f7ff4e88fe6cfbcc6feecae0aed593783b6c0
5
5
  SHA512:
6
- metadata.gz: a01f5d870505778646f8b267a61874b67be0c37edd6d567fff1a9ba542f3ef71ab4249c24fc8c93768df2b27fb25a0bfcc90150051b880c2967e364a86392163
7
- data.tar.gz: 221391e05a08f49b8b15f05466c2cfae573cbbfa552471e8f8b3ff7acfa5326356f6f1ad9dae0757765997c461d7365a7cd9c4f965f01d4e426e309895ec787c
6
+ metadata.gz: acb65869157cd0f35d51e713df0e0ac917773320a412b305644f0e19539221ecc92cb4e25ec32d3b853b203c5a4931efda457a0c0882988f4502c1d4ab3c06c6
7
+ data.tar.gz: 1b42332fa3e556a0ca035da62641a452fed3b607d4cc0026c6309c4dc7e2ffa096193db1b8385a7ae345386320b014ff37a48519c328f7b1c4ab58192fc8d23d
data/README.md CHANGED
@@ -101,6 +101,24 @@ git diff --name-only --diff-filter=ACMTUXB origin/master | grep _test.rb | xargs
101
101
  ```
102
102
  (see https://git-scm.com/docs/git-diff)
103
103
 
104
+
105
+ ```
106
+ function tdiff()
107
+ {
108
+ git diff --name-only --diff-filter=ACMTUXB $@ | grep _test.rb | xargs test_launcher
109
+ }
110
+
111
+ # Now you can:
112
+
113
+ tdiff
114
+
115
+ # or
116
+
117
+ tdiff origin/master
118
+ ```
119
+
120
+ Super fun!
121
+
104
122
  #Installation
105
123
 
106
124
  To install:
data/bin/test_launcher CHANGED
@@ -1,8 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "test_launcher/cli/input_parser"
4
- require "test_launcher"
3
+ require "test_launcher/cli"
5
4
 
6
- cli = TestLauncher::CLI::InputParser.new(ARGV)
7
-
8
- TestLauncher.launch(cli.request)
5
+ TestLauncher::CLI.launch(ARGV, ENV)
@@ -1,7 +1,11 @@
1
1
  require "optparse"
2
2
 
3
3
  require "test_launcher/version"
4
- require "test_launcher/request"
4
+
5
+ require "test_launcher/frameworks/rspec"
6
+ require "test_launcher/frameworks/minitest"
7
+ require "test_launcher/frameworks/elixir"
8
+ require "test_launcher/cli/request"
5
9
 
6
10
  module TestLauncher
7
11
  module CLI
@@ -19,8 +23,9 @@ VERSION: #{TestLauncher::VERSION}
19
23
 
20
24
  DESC
21
25
 
22
- def initialize(args)
23
- @query = args
26
+ def initialize(args, env)
27
+ @search_string = args
28
+ @env = env
24
29
  @options = {}
25
30
  option_parser.parse!(args)
26
31
  rescue OptionParser::ParseError
@@ -30,18 +35,34 @@ VERSION: #{TestLauncher::VERSION}
30
35
  exit
31
36
  end
32
37
 
33
- def request
34
- if @query.size == 0
38
+ def requests(shell:, searcher:)
39
+ if @search_string.size == 0
35
40
  puts option_parser
36
41
  exit
37
42
  end
38
43
 
39
- Request.new(
40
- query: @query.join(" "),
41
- run_all: @options[:run_all],
42
- disable_spring: ENV["DISABLE_SPRING"],
43
- framework: @options[:framework]
44
- )
44
+ frameworks =
45
+ if @options[:framework] == "rspec"
46
+ [Frameworks::RSpec]
47
+ elsif @options[:framework] == "minitest"
48
+ [Frameworks::Minitest]
49
+ elsif @options[:framework] == "elixir"
50
+ [Frameworks::Elixir]
51
+ else
52
+ [Frameworks::Minitest, Frameworks::RSpec, Frameworks::Elixir]
53
+ end
54
+
55
+ frameworks.map {|framework|
56
+ Request.new(
57
+ search_string: @search_string.join(" "),
58
+ run_all: !!@options[:run_all],
59
+ disable_spring: !!@env["DISABLE_SPRING"],
60
+ example_name: @options[:name],
61
+ framework: framework,
62
+ shell: shell,
63
+ searcher: searcher
64
+ )
65
+ }
45
66
  end
46
67
 
47
68
  def options
@@ -68,9 +89,13 @@ VERSION: #{TestLauncher::VERSION}
68
89
  exit
69
90
  end
70
91
 
71
- opts.on("-f", "--framework framework", "The testing framework being used. Valid options: ['minitest', 'rspec', 'guess']. Defaults to 'guess'") do |framework|
92
+ opts.on("-f", "--framework framework", "The testing framework being used. Valid options: ['minitest', 'rspec', 'elixir', 'guess']. Defaults to 'guess'") do |framework|
72
93
  options[:framework] = framework
73
94
  end
95
+
96
+ opts.on("-n", "--name name", "Minitest name of testcase to run") do |name|
97
+ options[:name] = name
98
+ end
74
99
  end
75
100
  end
76
101
  end
@@ -0,0 +1,30 @@
1
+ require "test_launcher/base_error"
2
+ require "test_launcher/queries"
3
+ require "test_launcher/cli/request"
4
+
5
+ module TestLauncher
6
+ module CLI
7
+ class Query < BaseQuery
8
+ attr_reader :shell, :searcher
9
+
10
+ def command
11
+ def queries
12
+ requests.map {|request| Queries::GenericQuery.new(request: request)}
13
+ end
14
+
15
+ def requests
16
+ @frameworks.map {|framework|
17
+ Request.new(
18
+ framework: framework,
19
+ search_string: @search_string,
20
+ run_all: @run_all,
21
+ disable_spring: @disable_spring,
22
+ example_name: @example_name,
23
+ shell: shell,
24
+ searcher: searcher
25
+ )
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,61 @@
1
+ module TestLauncher
2
+ module CLI
3
+ class Request
4
+ def initialize(
5
+ search_string:,
6
+ framework:,
7
+ run_all: false,
8
+ disable_spring: false,
9
+ example_name: nil,
10
+ shell:,
11
+ searcher:
12
+ )
13
+ @search_string = search_string
14
+ @framework = framework
15
+ @run_all = run_all
16
+ @disable_spring = disable_spring
17
+ @example_name = example_name
18
+ @shell = shell
19
+ @searcher = searcher
20
+ end
21
+
22
+ def search_string
23
+ @search_string
24
+ end
25
+
26
+ def run_all?
27
+ @run_all
28
+ end
29
+
30
+ def disable_spring?
31
+ @disable_spring
32
+ end
33
+
34
+ def example_name
35
+ @example_name
36
+ end
37
+
38
+ def searcher
39
+ framework.searcher(@searcher)
40
+ end
41
+
42
+ def runner(*a)
43
+ framework.runner(*a)
44
+ end
45
+
46
+ def test_case(*a)
47
+ framework.test_case(*a)
48
+ end
49
+
50
+ def shell
51
+ @shell
52
+ end
53
+
54
+ private
55
+
56
+ def framework
57
+ @framework
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,44 @@
1
+ require "test_launcher/shell/runner"
2
+ require "test_launcher/search"
3
+ require "test_launcher/cli/input_parser"
4
+ require "test_launcher/queries"
5
+
6
+ module TestLauncher
7
+ module CLI
8
+
9
+ class MultiRequestQuery < Struct.new(:requests)
10
+
11
+ def command
12
+ command = nil
13
+ command_finders.each do |command_finder|
14
+ command = command_finder.generic_search
15
+ break if command
16
+ end
17
+ command
18
+ end
19
+
20
+ def command_finders
21
+ requests.map {|request| Queries::CommandFinder.new(request)}
22
+ end
23
+ end
24
+
25
+ def self.launch(argv, env, shell: Shell::Runner.new(log_path: "/tmp/test_launcher.log"))
26
+ searcher = Search.searcher(shell)
27
+
28
+ requests = CLI::InputParser.new(
29
+ argv,
30
+ env
31
+ ).requests(shell: shell, searcher: searcher)
32
+
33
+ command = MultiRequestQuery.new(requests).command
34
+
35
+ if command
36
+ shell.exec command
37
+ else
38
+ shell.warn "No tests found."
39
+ end
40
+ rescue BaseError => e
41
+ shell.warn(e)
42
+ end
43
+ end
44
+ end
@@ -1,23 +1,38 @@
1
- require "test_launcher/frameworks/implementation/locator"
2
1
  require "test_launcher/frameworks/implementation/test_case"
3
- require "test_launcher/frameworks/implementation/consolidator"
4
2
 
5
3
  module TestLauncher
6
4
  module Frameworks
7
5
  module Base
8
- class Locator < Implementation::Locator
6
+ class Searcher < Struct.new(:raw_searcher)
7
+ def test_files(query)
8
+ raw_searcher
9
+ .find_files(query)
10
+ .select {|f| f.match(file_name_regex)}
11
+ end
12
+
13
+ def examples(query)
14
+ grep(example_name_regex(query))
15
+ end
16
+
17
+ def grep(regex)
18
+ raw_searcher.grep(regex, file_pattern: file_name_pattern)
19
+ end
20
+
21
+ def by_line(file_pattern, line_number)
22
+ raise NotImplementedError
23
+ end
24
+
25
+ private
26
+
9
27
  def file_name_regex
10
- # for ruby to match on file names
11
28
  raise NotImplementedError
12
29
  end
13
30
 
14
31
  def file_name_pattern
15
- # for bash to match on file names
16
32
  raise NotImplementedError
17
33
  end
18
34
 
19
- def regex_pattern
20
- # to match on examples
35
+ def example_name_regex(query)
21
36
  raise NotImplementedError
22
37
  end
23
38
  end
@@ -27,6 +42,10 @@ module TestLauncher
27
42
  raise NotImplementedError
28
43
  end
29
44
 
45
+ def multiple_examples_same_file(test_cases)
46
+ raise NotImplementedError
47
+ end
48
+
30
49
  def one_or_more_files(test_cases)
31
50
  raise NotImplementedError
32
51
  end
@@ -0,0 +1,84 @@
1
+ require "test_launcher/frameworks/base"
2
+ require "test_launcher/base_error"
3
+
4
+ module TestLauncher
5
+ module Frameworks
6
+ module Elixir
7
+ def self.active?
8
+ # Do not do this outside of the shell.
9
+ ! Dir.glob("**/test/**/*.exs").empty?
10
+ end
11
+
12
+ def self.test_case(*a)
13
+ TestCase.new(*a)
14
+ end
15
+
16
+ def self.searcher(*a)
17
+ Searcher.new(*a)
18
+ end
19
+
20
+ def self.runner(*a)
21
+ Runner.new(*a)
22
+ end
23
+
24
+ class Searcher < Base::Searcher
25
+ MultipleByLineMatches = Class.new(BaseError)
26
+
27
+ def by_line(file_pattern, line_number)
28
+ files = test_files(file_pattern)
29
+ return unless files.any?
30
+ raise multiple_files_error if files.size > 1
31
+
32
+ {
33
+ file: files.first,
34
+ line_number: line_number
35
+ }
36
+ end
37
+
38
+ private
39
+
40
+ def file_name_regex
41
+ /.*_test\.exs$/
42
+ end
43
+
44
+ def file_name_pattern
45
+ "*_test.exs"
46
+ end
47
+
48
+ def example_name_regex(query="")
49
+ "^\s*test\s+\".*#{query}.*\"\s+do"
50
+ end
51
+
52
+ def multiple_files_error
53
+ MultipleByLineMatches.new(<<-MSG)
54
+ It looks like you are running a line number in a test file.
55
+
56
+ Multiple files have been found that match your query.
57
+
58
+ This case is not supported.
59
+ MSG
60
+ end
61
+ end
62
+
63
+ class Runner < Base::Runner
64
+ def single_example(test_case)
65
+ %{cd #{test_case.app_root} && mix test #{test_case.file}:#{test_case.line_number}}
66
+ end
67
+
68
+ def multiple_examples_same_file(test_cases)
69
+ one_or_more_files(test_cases.first)
70
+ end
71
+
72
+ def one_or_more_files(test_cases)
73
+ %{cd #{test_cases.first.app_root} && mix test #{test_cases.map(&:file).join(" ")}}
74
+ end
75
+ end
76
+
77
+ class TestCase < Base::TestCase
78
+ def test_root_dir_name
79
+ "test"
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -4,15 +4,16 @@ module TestLauncher
4
4
  module Frameworks
5
5
  module Implementation
6
6
  class TestCase
7
- attr_reader :file, :example, :request
7
+ attr_reader :file, :example, :request, :line_number
8
8
 
9
9
  def self.from_search(file:, query:, request:)
10
10
  new(file: file, example: query, request: request)
11
11
  end
12
12
 
13
- def initialize(file:, example: nil, request:)
13
+ def initialize(file:, example: nil, request:, line_number: nil)
14
14
  @file = file
15
15
  @example = example
16
+ @line_number = line_number
16
17
  @request = request
17
18
  end
18
19
 
@@ -31,7 +32,7 @@ module TestLauncher
31
32
  while !candidates.empty?
32
33
  if candidates.last == test_root_dir_name
33
34
  root_path = File.join("/", candidates[0..-2])
34
- return root_path if Dir.entries(root_path).any? {|e| e.match /Gemfile|gemspec/}
35
+ return root_path if Dir.entries(root_path).any? {|e| e.match /Gemfile|gemspec|mix.exs/} # TODO: extract this
35
36
  end
36
37
 
37
38
  candidates.pop
@@ -46,10 +47,6 @@ module TestLauncher
46
47
  File.join(app_root, test_root_dir_name)
47
48
  end
48
49
 
49
- def runner
50
- raise NotImplementedError
51
- end
52
-
53
50
  def test_root_dir_name
54
51
  raise NotImplementedError
55
52
  end
@@ -1,53 +1,104 @@
1
+ require 'shellwords'
1
2
  require "test_launcher/frameworks/base"
3
+ require "test_launcher/base_error"
2
4
 
3
5
  module TestLauncher
4
6
  module Frameworks
5
7
  module Minitest
6
-
7
8
  def self.active?
9
+ # Do not do this outside of the shell.
8
10
  ! Dir.glob("**/test/**/*_test.rb").empty?
9
11
  end
10
12
 
11
- class Runner < Base::Runner
12
- def single_example(test_case, exact_match: false)
13
+ def self.test_case(*a)
14
+ TestCase.new(*a)
15
+ end
13
16
 
14
- name =
15
- if exact_match
16
- "--name=#{test_case.example}"
17
- else
18
- "--name=/#{test_case.example}/"
19
- end
17
+ def self.searcher(*a)
18
+ Searcher.new(*a)
19
+ end
20
20
 
21
- %{cd #{test_case.app_root} && #{test_case.runner} #{test_case.file} #{name}}
22
- end
21
+ def self.runner(*a)
22
+ Runner.new(*a)
23
+ end
23
24
 
24
- def one_or_more_files(test_cases)
25
- %{cd #{test_cases.first.app_root} && #{test_cases.first.runner} #{test_cases.map(&:file).join(" ")}}
25
+ class Searcher < Base::Searcher
26
+ MultipleByLineMatches = Class.new(BaseError)
27
+
28
+ def by_line(file_pattern, line_number)
29
+ files = test_files(file_pattern)
30
+ return unless files.any?
31
+ raise multiple_files_error if files.size > 1
32
+ #
33
+ file = files.first
34
+ grep_results = raw_searcher.grep(example_name_regex, file_pattern: file)
35
+ # return unless grep_results.any?
36
+ best_result =
37
+ grep_results
38
+ .select {|r| line_number >= r[:line_number]}
39
+ .min_by {|r| line_number - r[:line_number]}
40
+
41
+ if best_result
42
+ {
43
+ file: best_result[:file],
44
+ example_name: best_result[:line].match(/(test_\w+)/)[1],
45
+ line_number: best_result[:line_number]
46
+ }
47
+ else
48
+ # line number outside of example. Run whole file
49
+ {
50
+ file: grep_results.first[:file]
51
+ }
52
+ end
26
53
  end
27
- end
28
54
 
29
- class Locator < Base::Locator
30
55
  private
31
56
 
32
57
  def file_name_regex
33
- /.*_test\.rb/
58
+ /.*_test\.rb$/
34
59
  end
35
60
 
36
61
  def file_name_pattern
37
62
  "*_test.rb"
38
63
  end
39
64
 
40
- def regex_pattern
41
- "^\s*def test_.*#{request.query.sub(/^test_/, "")}.*"
65
+ def example_name_regex(query="")
66
+ if query.match(/^test_/)
67
+ "^\s*def\s+#{query}.*"
68
+ else
69
+ "^\s*def\s+test_.*#{query}.*"
70
+ end
42
71
  end
43
72
 
44
- def test_case_class
45
- TestCase
73
+ def multiple_files_error
74
+ MultipleByLineMatches.new(<<-MSG)
75
+ It looks like you are running a line number in a test file.
76
+
77
+ Multiple files have been found that match your query.
78
+
79
+ This case is not supported.
80
+ MSG
46
81
  end
82
+
47
83
  end
48
84
 
49
- class TestCase < Base::TestCase
85
+ class Runner < Base::Runner
86
+ def single_example(test_case, name: test_case.example)
50
87
 
88
+ %{cd #{test_case.app_root} && #{test_case.runner} #{test_case.file} --name=/#{Shellwords.escape(name)}/}
89
+ end
90
+
91
+ def multiple_examples_same_file(test_cases)
92
+ test_case = test_cases.first
93
+ single_example(test_cases.first)
94
+ end
95
+
96
+ def one_or_more_files(test_cases)
97
+ %{cd #{test_cases.first.app_root} && #{test_cases.first.multiple_files_runner} #{test_cases.map(&:file).join(" ")}}
98
+ end
99
+ end
100
+
101
+ class TestCase < Base::TestCase
51
102
  def runner
52
103
  if spring_enabled?
53
104
  "bundle exec spring testunit"
@@ -58,12 +109,19 @@ module TestLauncher
58
109
  end
59
110
  end
60
111
 
112
+ def multiple_files_runner
113
+ if spring_enabled?
114
+ "bundle exec spring testunit"
115
+ else
116
+ "bundle exec ruby -I test -e 'ARGV.each {|f| require(f)}'"
117
+ end
118
+ end
119
+
61
120
  def test_root_dir_name
62
121
  "test"
63
122
  end
64
123
 
65
124
  def spring_enabled?
66
- # TODO: move ENV reference to options hash
67
125
  return false if request.disable_spring?
68
126
 
69
127
  [
@@ -73,7 +131,6 @@ module TestLauncher
73
131
  File.exist?(File.join(app_root, f))
74
132
  }
75
133
  end
76
-
77
134
  end
78
135
  end
79
136
  end
@@ -1,5 +1,4 @@
1
1
  require "shellwords"
2
-
3
2
  require "test_launcher/frameworks/base"
4
3
 
5
4
  module TestLauncher
@@ -10,17 +9,31 @@ module TestLauncher
10
9
  ! Dir.glob("**/*_spec.rb").empty?
11
10
  end
12
11
 
13
- class Runner < Base::Runner
14
- def single_example(test_case)
15
- %{cd #{test_case.app_root} && rspec #{test_case.file} --example #{Shellwords.escape(test_case.example)}}
16
- end
12
+ def self.test_case(*a)
13
+ TestCase.new(*a)
14
+ end
17
15
 
18
- def one_or_more_files(test_cases)
19
- %{cd #{test_cases.first.app_root} && rspec #{test_cases.map(&:file).join(" ")}}
20
- end
16
+ def self.searcher(*a)
17
+ Searcher.new(*a)
18
+ end
19
+
20
+ def self.runner(*a)
21
+ Runner.new(*a)
21
22
  end
22
23
 
23
- class Locator < Base::Locator
24
+ class Searcher < Base::Searcher
25
+
26
+ def by_line(file_pattern, line_number)
27
+ files = test_files(file_pattern)
28
+ return unless files.any?
29
+ raise multiple_files_error if files.size > 1
30
+
31
+ {
32
+ file: files.first,
33
+ line_number: line_number
34
+ }
35
+ end
36
+
24
37
  private
25
38
 
26
39
  def file_name_regex
@@ -31,12 +44,24 @@ module TestLauncher
31
44
  '*_spec.rb'
32
45
  end
33
46
 
34
- def regex_pattern
35
- "^\s*(it|context|(RSpec.)?describe) .*#{request.query}.* do.*"
47
+ def example_name_regex(query)
48
+ "^\s*(it|context|(RSpec.)?describe) .*#{query}.* do.*"
49
+ end
50
+ end
51
+
52
+ class Runner < Base::Runner
53
+ def single_example(test_case, **_)
54
+ %{cd #{test_case.app_root} && rspec #{test_case.file} --example #{Shellwords.escape(test_case.example)}}
55
+ end
56
+
57
+ def multiple_examples_same_file(test_cases)
58
+ test_case = test_cases.first
59
+ single_example(test_case)
36
60
  end
37
61
 
38
- def test_case_class
39
- TestCase
62
+
63
+ def one_or_more_files(test_cases)
64
+ %{cd #{test_cases.first.app_root} && rspec #{test_cases.map(&:file).join(" ")}}
40
65
  end
41
66
  end
42
67