test_launcher 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/bin/test_launcher +39 -0
- data/bin/test_runner +1 -0
- data/lib/test_launcher.rb +4 -0
- data/lib/test_launcher/searchers/git_searcher.rb +38 -0
- data/lib/test_launcher/shell/color.rb +26 -0
- data/lib/test_launcher/shell/runner.rb +66 -0
- data/lib/test_launcher/tests/minitest/consolidator.rb +85 -0
- data/lib/test_launcher/tests/minitest/finder.rb +50 -0
- data/lib/test_launcher/tests/minitest/wrappers/multiple_files.rb +23 -0
- data/lib/test_launcher/tests/minitest/wrappers/multiple_roots.rb +23 -0
- data/lib/test_launcher/tests/minitest/wrappers/single_file.rb +29 -0
- data/lib/test_launcher/tests/minitest/wrappers/single_root.rb +27 -0
- data/lib/test_launcher/tests/minitest/wrappers/single_test.rb +37 -0
- data/lib/test_launcher/utils/path.rb +32 -0
- data/lib/test_launcher/utils/pluralize.rb +14 -0
- data/lib/test_launcher/version.rb +3 -0
- data/test/test_helper.rb +45 -0
- data/test/test_launcher/searchers/git_searcher_test.rb +50 -0
- data/test/test_launcher/tests/minitest/consolidator_integration_test.rb +191 -0
- data/test/test_launcher/tests/minitest/finder_test.rb +71 -0
- data/test_launcher.gemspec +23 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bbd6981a7b53e9af503b959d87bd3dc21bc312a0
|
4
|
+
data.tar.gz: 1c2978d49096d3af9cc704c30d83eb1c554cff48
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 30a4da05547da73f41746d1a839052493938964094700ea009a9ff37c3506a8d1e9ec348a4cbe6c62fba22ff4587e0bea2fc7b8e9714dff7b7f99468e2ce4a24
|
7
|
+
data.tar.gz: 6d3fb76d08ef634a12108f74643e86f58e88b601b493e07f7ce72b2ef029a1fcb6562b8ffc5c162af223aa6f693fb49ca7523d1261c951defd923ba821b9490d
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Pete Kinnecom
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# TestLauncher
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'test_launcher'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install test_launcher
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it ( https://github.com/[my-github-username]/test_launcher/fork )
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/test_launcher
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
require "test_launcher/searchers/git_searcher"
|
5
|
+
require "test_launcher/tests/minitest/finder"
|
6
|
+
require "test_launcher/tests/minitest/consolidator"
|
7
|
+
require "test_launcher/shell/runner"
|
8
|
+
|
9
|
+
class CLI < Thor
|
10
|
+
|
11
|
+
desc "find", <<-DESC
|
12
|
+
Find tests and run them. By trying to match an individual test or the name of a test file(s).
|
13
|
+
DESC
|
14
|
+
option :all, type: :boolean, desc: %{Run all tests found!}, default: false
|
15
|
+
|
16
|
+
def find(input)
|
17
|
+
if input == '--help'
|
18
|
+
`test_launcher --help find`
|
19
|
+
exit
|
20
|
+
end
|
21
|
+
|
22
|
+
shell = TestLauncher::Shell::Runner.new(
|
23
|
+
log_path: '/tmp/test_launcher.log',
|
24
|
+
working_directory: '.',
|
25
|
+
|
26
|
+
)
|
27
|
+
|
28
|
+
searcher = TestLauncher::Searchers::GitSearcher.new(shell)
|
29
|
+
search_results = TestLauncher::Tests::Minitest::Finder.find(input, searcher)
|
30
|
+
|
31
|
+
test_wrapper = TestLauncher::Tests::Minitest::Consolidator.consolidate(search_results, shell, options[:all])
|
32
|
+
|
33
|
+
shell.exec test_wrapper.to_command
|
34
|
+
end
|
35
|
+
|
36
|
+
default_task :find
|
37
|
+
end
|
38
|
+
|
39
|
+
CLI.start(ARGV)
|
data/bin/test_runner
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
puts "`test_runner` no longer exists. Please use `test_launcher` instead (update any aliases you may have)"
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module TestLauncher
|
2
|
+
module Searchers
|
3
|
+
class GitSearcher < Struct.new(:shell)
|
4
|
+
|
5
|
+
def find_files(pattern)
|
6
|
+
shell.run("git ls-files '*#{pattern}*'")
|
7
|
+
end
|
8
|
+
|
9
|
+
def grep(regex, file_pattern: '*')
|
10
|
+
results = shell.run("git grep --untracked '#{regex}' -- '#{file_pattern}'")
|
11
|
+
results.map do |result|
|
12
|
+
interpret_grep_result(result)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def interpret_grep_result(grep_result)
|
19
|
+
splits = grep_result.split(/:/)
|
20
|
+
file = splits.shift.strip
|
21
|
+
# we rejoin on ':' because our
|
22
|
+
# code may have colons inside of it.
|
23
|
+
#
|
24
|
+
# example:
|
25
|
+
# path/to/file: run_method(a: A, b: B)
|
26
|
+
#
|
27
|
+
# so shift the first one out, then
|
28
|
+
# rejoin the rest
|
29
|
+
line = splits.join(':').strip
|
30
|
+
|
31
|
+
{
|
32
|
+
:file => file,
|
33
|
+
:line => line,
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module TestLauncher
|
2
|
+
module Shell
|
3
|
+
module Color
|
4
|
+
CODES = {
|
5
|
+
red: 31,
|
6
|
+
green: 32,
|
7
|
+
yellow: 33,
|
8
|
+
pink: 35,
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
CODES.each do |color, code|
|
12
|
+
self.send(:define_method, color) do |string|
|
13
|
+
colorize(string, code)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# colorization
|
20
|
+
def colorize(string, color_code)
|
21
|
+
"\e[#{color_code}m#{string}\e[0m"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "test_launcher/shell/color"
|
2
|
+
require "test_launcher/utils/path"
|
3
|
+
|
4
|
+
module TestLauncher
|
5
|
+
module Shell
|
6
|
+
class Runner
|
7
|
+
include Color
|
8
|
+
|
9
|
+
CommandFailureError = Class.new(StandardError)
|
10
|
+
|
11
|
+
attr_accessor :working_directory, :log_path, :queue
|
12
|
+
private :working_directory, :log_path, :queue
|
13
|
+
|
14
|
+
def initialize(log_path:, working_directory:)
|
15
|
+
@working_directory = working_directory
|
16
|
+
@log_path = log_path
|
17
|
+
|
18
|
+
%x{echo "" > #{log_path}}
|
19
|
+
Dir.chdir(%x[ git rev-parse --show-toplevel ].chomp)
|
20
|
+
end
|
21
|
+
|
22
|
+
def run(cmd, dir: working_directory, &block)
|
23
|
+
command = "cd #{Utils::Path.relative_join(dir)} && #{cmd}"
|
24
|
+
handle_output_for(command)
|
25
|
+
|
26
|
+
shell_out(command).split("\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
def exec(cmd)
|
30
|
+
notify cmd
|
31
|
+
Kernel.exec cmd
|
32
|
+
end
|
33
|
+
|
34
|
+
def warn(msg)
|
35
|
+
log msg.to_s
|
36
|
+
print "#{red(msg.to_s)}\n"
|
37
|
+
end
|
38
|
+
|
39
|
+
def notify(msg)
|
40
|
+
log msg.to_s
|
41
|
+
print "#{yellow(msg.to_s)}\n"
|
42
|
+
end
|
43
|
+
|
44
|
+
def confirm?(question)
|
45
|
+
warn "#{question} [Yn]"
|
46
|
+
answer = STDIN.gets.strip.downcase
|
47
|
+
return answer != 'n'
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def log(msg)
|
53
|
+
%x{echo "#{msg.to_s}" >> #{log_path}}
|
54
|
+
end
|
55
|
+
|
56
|
+
def handle_output_for(cmd)
|
57
|
+
log(cmd)
|
58
|
+
end
|
59
|
+
|
60
|
+
def shell_out(command)
|
61
|
+
%x{ set -o pipefail && #{command} 2>> #{log_path} | tee -a #{log_path} }.chomp
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require "test_launcher/utils/path"
|
2
|
+
|
3
|
+
require "test_launcher/tests/minitest/wrappers/single_test"
|
4
|
+
require "test_launcher/tests/minitest/wrappers/single_file"
|
5
|
+
require "test_launcher/tests/minitest/wrappers/multiple_files"
|
6
|
+
require "test_launcher/utils/pluralize"
|
7
|
+
|
8
|
+
module TestLauncher
|
9
|
+
module Tests
|
10
|
+
module Minitest
|
11
|
+
class Consolidator < Struct.new(:search_results, :shell, :run_all)
|
12
|
+
include Utils::Pluralize
|
13
|
+
|
14
|
+
def self.consolidate(*args)
|
15
|
+
new(*args).consolidate
|
16
|
+
end
|
17
|
+
|
18
|
+
def consolidate
|
19
|
+
if search_results.empty?
|
20
|
+
shell.warn "Could not find any tests."
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
|
24
|
+
if methods_found? && one_result?
|
25
|
+
shell.notify "Found #{methods_count_phrase} in #{file_count_phrase}."
|
26
|
+
Wrappers::SingleTest.new(search_results.first)
|
27
|
+
elsif methods_found? && same_file?
|
28
|
+
shell.notify "Multiple test methods match in 1 file."
|
29
|
+
Wrappers::SingleFile.new(search_results.first[:file])
|
30
|
+
elsif methods_found? && run_last_edited?
|
31
|
+
shell.notify "Found #{methods_count_phrase} in #{file_count_phrase}."
|
32
|
+
shell.notify "Running most recently edited. Run with '--all' to run all the tests."
|
33
|
+
Wrappers::SingleTest.new(last_edited)
|
34
|
+
elsif files_found? && same_file?
|
35
|
+
shell.notify "Found #{file_count_phrase}."
|
36
|
+
Wrappers::SingleFile.new(search_results.first[:file])
|
37
|
+
elsif files_found? && run_last_edited?
|
38
|
+
shell.notify "Found #{file_count_phrase}."
|
39
|
+
shell.notify "Running most recently edited. Run with '--all' to run all the tests."
|
40
|
+
Wrappers::SingleFile.new(last_edited[:file])
|
41
|
+
else
|
42
|
+
shell.notify "Found #{file_count_phrase}."
|
43
|
+
Wrappers::MultipleFiles.wrap(search_results.map {|r| r[:file] }, shell)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def same_file?
|
48
|
+
file_count == 1
|
49
|
+
end
|
50
|
+
|
51
|
+
def one_result?
|
52
|
+
same_file? && search_results.first[:line]
|
53
|
+
end
|
54
|
+
|
55
|
+
def methods_found?
|
56
|
+
!! search_results.first[:line]
|
57
|
+
end
|
58
|
+
|
59
|
+
def files_found?
|
60
|
+
! methods_found?
|
61
|
+
end
|
62
|
+
|
63
|
+
def run_last_edited?
|
64
|
+
! run_all
|
65
|
+
end
|
66
|
+
|
67
|
+
def last_edited
|
68
|
+
search_results.sort_by {|r| File.mtime(r[:file])}.last
|
69
|
+
end
|
70
|
+
|
71
|
+
def file_count
|
72
|
+
search_results.group_by {|f| f[:file]}.size
|
73
|
+
end
|
74
|
+
|
75
|
+
def methods_count_phrase
|
76
|
+
pluralize(search_results.size, "test method")
|
77
|
+
end
|
78
|
+
|
79
|
+
def file_count_phrase
|
80
|
+
pluralize(file_count, "file")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "test_launcher/searchers/git_searcher"
|
2
|
+
|
3
|
+
module TestLauncher
|
4
|
+
module Tests
|
5
|
+
module Minitest
|
6
|
+
class Finder < Struct.new(:query, :searcher)
|
7
|
+
|
8
|
+
def self.find(query, searcher)
|
9
|
+
new(query, searcher).find
|
10
|
+
end
|
11
|
+
|
12
|
+
def find
|
13
|
+
return tests_found_by_absolute_path if query.match(/^\//)
|
14
|
+
|
15
|
+
return tests_found_by_name unless tests_found_by_name.empty?
|
16
|
+
|
17
|
+
return tests_found_by_file_name unless tests_found_by_file_name.empty?
|
18
|
+
|
19
|
+
return tests_found_by_full_regex unless tests_found_by_full_regex.empty?
|
20
|
+
|
21
|
+
[]
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def tests_found_by_absolute_path
|
27
|
+
relative_file_path = query.sub(Dir.pwd, '').sub(/^\//, '')
|
28
|
+
[ {file: relative_file_path} ]
|
29
|
+
end
|
30
|
+
|
31
|
+
def tests_found_by_name
|
32
|
+
@tests_found_by_name ||= full_regex_search("^\s*def .*#{query}.*")
|
33
|
+
end
|
34
|
+
|
35
|
+
def tests_found_by_file_name
|
36
|
+
@tests_found_by_file_name ||= searcher.find_files(query).select { |f| f.match(/_test\.rb/) }.map {|f| {file: f} }
|
37
|
+
end
|
38
|
+
|
39
|
+
def tests_found_by_full_regex
|
40
|
+
# we ignore the matched line since we don't know what to do with it
|
41
|
+
@tests_found_by_full_regex ||= full_regex_search(query).map {|t| {file: t[:file]} }
|
42
|
+
end
|
43
|
+
|
44
|
+
def full_regex_search(regex)
|
45
|
+
searcher.grep(regex, file_pattern: '*_test.rb')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "test_launcher/tests/minitest/wrappers/single_root"
|
2
|
+
require "test_launcher/tests/minitest/wrappers/multiple_roots"
|
3
|
+
|
4
|
+
module TestLauncher
|
5
|
+
module Tests
|
6
|
+
module Minitest
|
7
|
+
module Wrappers
|
8
|
+
module MultipleFiles
|
9
|
+
|
10
|
+
def self.wrap(files, shell)
|
11
|
+
wrapper = MultipleRoots.new(files, shell)
|
12
|
+
|
13
|
+
if wrapper.roots.size > 1
|
14
|
+
wrapper
|
15
|
+
else
|
16
|
+
wrapper.roots.first
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "test_launcher/utils/path"
|
2
|
+
|
3
|
+
module TestLauncher
|
4
|
+
module Tests
|
5
|
+
module Minitest
|
6
|
+
module Wrappers
|
7
|
+
class MultipleRoots
|
8
|
+
|
9
|
+
attr_reader :roots, :shell
|
10
|
+
|
11
|
+
def initialize(files, shell)
|
12
|
+
@shell = shell
|
13
|
+
@roots = files.map {|f| SingleFile.new(f)}.group_by {|f| f.app_root}.map {|root, _files| SingleRoot.new(_files, shell)}
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_command
|
17
|
+
roots.map(&:to_command).join("; cd -;\n\n")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "test_launcher/utils/path"
|
2
|
+
|
3
|
+
module TestLauncher
|
4
|
+
module Tests
|
5
|
+
module Minitest
|
6
|
+
module Wrappers
|
7
|
+
class SingleFile < Struct.new(:file)
|
8
|
+
|
9
|
+
def to_command
|
10
|
+
%{cd #{File.join(app_root)} && ruby -I test #{File.join(relative_test_path)}}
|
11
|
+
end
|
12
|
+
|
13
|
+
def app_root
|
14
|
+
exploded_path = Utils::Path.split(file)
|
15
|
+
|
16
|
+
path = exploded_path[0...exploded_path.rindex("test")]
|
17
|
+
File.join(path)
|
18
|
+
end
|
19
|
+
|
20
|
+
def relative_test_path
|
21
|
+
exploded_path = Utils::Path.split(file)
|
22
|
+
path = exploded_path[exploded_path.rindex("test")..-1]
|
23
|
+
File.join(path)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "test_launcher/utils/path"
|
2
|
+
|
3
|
+
module TestLauncher
|
4
|
+
module Tests
|
5
|
+
module Minitest
|
6
|
+
module Wrappers
|
7
|
+
class SingleRoot
|
8
|
+
|
9
|
+
attr_reader :files, :shell
|
10
|
+
|
11
|
+
def initialize(files, shell)
|
12
|
+
@shell = shell
|
13
|
+
@files = files.map {|f| f.is_a?(SingleFile) ? f : SingleFile.new(f)}
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_command
|
17
|
+
%{cd #{app_root} && ruby -I test -e 'ARGV.each { |file| require(Dir.pwd + "/" + file) }' #{files.map(&:relative_test_path).join(" ")}}
|
18
|
+
end
|
19
|
+
|
20
|
+
def app_root
|
21
|
+
files.first.app_root
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "test_launcher/utils/path"
|
2
|
+
|
3
|
+
module TestLauncher
|
4
|
+
module Tests
|
5
|
+
module Minitest
|
6
|
+
module Wrappers
|
7
|
+
class SingleTest
|
8
|
+
|
9
|
+
attr_reader :file, :name
|
10
|
+
private :file, :name
|
11
|
+
|
12
|
+
def initialize(file:, line:)
|
13
|
+
@file = file
|
14
|
+
@name = line[/\s*def\s+(.*)/, 1]
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_command
|
18
|
+
%{cd #{app_root} && ruby -I test #{relative_test_path} --name=/#{name}/}
|
19
|
+
end
|
20
|
+
|
21
|
+
def app_root
|
22
|
+
exploded_path = Utils::Path.split(file)
|
23
|
+
|
24
|
+
path = exploded_path[0...exploded_path.rindex("test")]
|
25
|
+
File.join(path)
|
26
|
+
end
|
27
|
+
|
28
|
+
def relative_test_path
|
29
|
+
exploded_path = Utils::Path.split(file)
|
30
|
+
path = exploded_path[exploded_path.rindex("test")..-1]
|
31
|
+
File.join(path)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
module TestLauncher
|
4
|
+
module Utils
|
5
|
+
module Path
|
6
|
+
|
7
|
+
def self.split(filename)
|
8
|
+
self.prepend_pwd(Pathname.new(filename).each_filename.to_a)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.path_for(filename)
|
12
|
+
self.split(File.split(file)[0])
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.join(*array)
|
16
|
+
File.join(*array)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.prepend_pwd(dirs)
|
20
|
+
if dirs[0] == "."
|
21
|
+
dirs
|
22
|
+
else
|
23
|
+
["."] + dirs
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.relative_join(array)
|
28
|
+
join(prepend_pwd(array))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.split(File.dirname(__FILE__))[0], 'lib'))
|
2
|
+
require "minitest/autorun"
|
3
|
+
require "mocha/mini_test"
|
4
|
+
|
5
|
+
class TestCase < Minitest::Test
|
6
|
+
class DummyShell
|
7
|
+
|
8
|
+
def method_missing(method, *args)
|
9
|
+
instance_variable_set(:"@#{method}", [args])
|
10
|
+
|
11
|
+
self.class.send(:define_method, method) do |*a|
|
12
|
+
if ! instance_variable_get(:"@#{method}")
|
13
|
+
instance_variable_set(:"@#{method}", [a])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def recall(method)
|
19
|
+
instance_variable_get(:"@#{method}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def assert_notified(string)
|
24
|
+
unless dummy_shell.recall(:notify).flatten.include?(string)
|
25
|
+
flunk <<-FLUNK
|
26
|
+
could not find: "#{string}"
|
27
|
+
shell.notify called with:
|
28
|
+
#{dummy_shell.recall(:notify)}
|
29
|
+
FLUNK
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def assert_paragraphs_equal(expected, actual)
|
34
|
+
expecteds = expected.split("\n").map {|l| l.to_s.strip}
|
35
|
+
actuals = actual.split("\n").map {|l| l.to_s.strip}
|
36
|
+
|
37
|
+
assert_equal expecteds, actuals
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def dummy_shell
|
43
|
+
@dummy_shell ||= DummyShell.new
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require "test_launcher/searchers/git_searcher"
|
3
|
+
|
4
|
+
module TestLauncher
|
5
|
+
module Searchers
|
6
|
+
class MockShell
|
7
|
+
def run(cmd)
|
8
|
+
if cmd == "git ls-files '*file_pattern*'"
|
9
|
+
[
|
10
|
+
"file/path/one.rb",
|
11
|
+
"another_file/path/two.rb",
|
12
|
+
]
|
13
|
+
elsif cmd == "git grep --untracked 'regex' -- 'file_pattern'"
|
14
|
+
[
|
15
|
+
"file/path/one.rb: some_lines(of_code)",
|
16
|
+
"another_file/path/two.rb: Class::Thing::Stuff.new",
|
17
|
+
]
|
18
|
+
else
|
19
|
+
raise ArgumentError.new("unmocked command")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class GitSearcherTest < TestCase
|
25
|
+
|
26
|
+
def test_find_files
|
27
|
+
searcher = GitSearcher.new(MockShell.new)
|
28
|
+
|
29
|
+
assert_equal ["file/path/one.rb", "another_file/path/two.rb"], searcher.find_files("file_pattern")
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_grep
|
33
|
+
searcher = GitSearcher.new(MockShell.new)
|
34
|
+
|
35
|
+
expected = [
|
36
|
+
{
|
37
|
+
file: "file/path/one.rb",
|
38
|
+
line: "some_lines(of_code)",
|
39
|
+
},
|
40
|
+
{
|
41
|
+
file: "another_file/path/two.rb",
|
42
|
+
line: "Class::Thing::Stuff.new",
|
43
|
+
}
|
44
|
+
]
|
45
|
+
|
46
|
+
assert_equal expected, searcher.grep("regex", file_pattern: "file_pattern")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require "test_launcher/tests/minitest/consolidator"
|
3
|
+
|
4
|
+
module TestLauncher
|
5
|
+
module Tests
|
6
|
+
module Minitest
|
7
|
+
class ConsolidatorIntegrationTest < TestCase
|
8
|
+
|
9
|
+
def test_single_test_method__no_sub_dir
|
10
|
+
search_results = [
|
11
|
+
{
|
12
|
+
file: "test/dir/file_test.rb",
|
13
|
+
line: "def test_launcher",
|
14
|
+
},
|
15
|
+
]
|
16
|
+
|
17
|
+
consolidator = Consolidator.new(search_results, dummy_shell, false)
|
18
|
+
assert_equal "cd . && ruby -I test test/dir/file_test.rb --name=/test_launcher/", consolidator.consolidate.to_command
|
19
|
+
assert_notified "Found 1 test method in 1 file."
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_single_test_method__with_sub_dir
|
23
|
+
search_results = [
|
24
|
+
{
|
25
|
+
file: "engines/lawnmower/test/dir/file_test.rb",
|
26
|
+
line: "def test_launcher",
|
27
|
+
}
|
28
|
+
]
|
29
|
+
|
30
|
+
consolidator = Consolidator.new(search_results, dummy_shell, false)
|
31
|
+
assert_equal "cd ./engines/lawnmower && ruby -I test test/dir/file_test.rb --name=/test_launcher/", consolidator.consolidate.to_command
|
32
|
+
assert_notified "Found 1 test method in 1 file."
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_multiple_test_methods_in_same_file
|
36
|
+
search_results = [
|
37
|
+
{
|
38
|
+
file: "test/dir/file_test.rb",
|
39
|
+
line: "def test_launcher",
|
40
|
+
},
|
41
|
+
{
|
42
|
+
file: "test/dir/file_test.rb",
|
43
|
+
line: "def test_launcher_again",
|
44
|
+
},
|
45
|
+
{
|
46
|
+
file: "test/dir/file_test.rb",
|
47
|
+
line: "def test_launcher_some_more",
|
48
|
+
},
|
49
|
+
]
|
50
|
+
|
51
|
+
consolidator = Consolidator.new(search_results, dummy_shell, false)
|
52
|
+
|
53
|
+
assert_equal "cd . && ruby -I test test/dir/file_test.rb --name=/test_launcher/", consolidator.consolidate.to_command
|
54
|
+
assert_notified "Found 3 test methods in 1 file."
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_multiple_test_methods_in_different_files__last_edited
|
58
|
+
search_results = [
|
59
|
+
{
|
60
|
+
file: "test/dir/file_test.rb",
|
61
|
+
line: "def test_launcher",
|
62
|
+
},
|
63
|
+
{
|
64
|
+
file: "test/other_dir/different_test.rb",
|
65
|
+
line: "def test_launcher",
|
66
|
+
},
|
67
|
+
]
|
68
|
+
|
69
|
+
consolidator = Consolidator.new(search_results, dummy_shell, false)
|
70
|
+
|
71
|
+
File.expects(:mtime).with("test/dir/file_test.rb").returns(Time.new(2014, 01, 01))
|
72
|
+
File.expects(:mtime).with("test/other_dir/different_test.rb").returns(Time.new(2013, 01, 01))
|
73
|
+
|
74
|
+
assert_equal "cd . && ruby -I test test/dir/file_test.rb --name=/test_launcher/", consolidator.consolidate.to_command
|
75
|
+
assert_notified "Found 2 test methods in 2 files."
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_multiple_test_methods_in_different_files__run_all__same_root
|
79
|
+
search_results = [
|
80
|
+
{
|
81
|
+
file: "test/dir/file_test.rb",
|
82
|
+
line: "def test_launcher",
|
83
|
+
},
|
84
|
+
{
|
85
|
+
file: "test/other_dir/different_test.rb",
|
86
|
+
line: "def test_launcher",
|
87
|
+
},
|
88
|
+
]
|
89
|
+
|
90
|
+
consolidator = Consolidator.new(search_results, dummy_shell, true)
|
91
|
+
|
92
|
+
assert_equal %{cd . && ruby -I test -e 'ARGV.each { |file| require(Dir.pwd + "/" + file) }' test/dir/file_test.rb test/other_dir/different_test.rb}, consolidator.consolidate.to_command
|
93
|
+
assert_notified "Found 2 files."
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_multiple_test_methods_in_different_files__run_all__different_roots
|
97
|
+
search_results = [
|
98
|
+
{
|
99
|
+
file: "engine1/test/dir/file_test.rb",
|
100
|
+
line: "def test_launcher",
|
101
|
+
},
|
102
|
+
{
|
103
|
+
file: "engine2/root2/test/other_dir/different_test.rb",
|
104
|
+
line: "def test_launcher",
|
105
|
+
},
|
106
|
+
]
|
107
|
+
|
108
|
+
consolidator = Consolidator.new(search_results, dummy_shell, true)
|
109
|
+
expected = <<-SHELL
|
110
|
+
cd ./engine1 && ruby -I test -e 'ARGV.each { |file| require(Dir.pwd + \"/\" + file) }' test/dir/file_test.rb; cd -;
|
111
|
+
|
112
|
+
cd ./engine2/root2 && ruby -I test -e 'ARGV.each { |file| require(Dir.pwd + \"/\" + file) }' test/other_dir/different_test.rb
|
113
|
+
SHELL
|
114
|
+
|
115
|
+
assert_paragraphs_equal expected, consolidator.consolidate.to_command
|
116
|
+
assert_notified "Found 2 files."
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_one_file_found
|
120
|
+
search_results = [
|
121
|
+
{
|
122
|
+
file: "engine1/test/dir/file_test.rb",
|
123
|
+
},
|
124
|
+
]
|
125
|
+
|
126
|
+
consolidator = Consolidator.new(search_results, dummy_shell, true)
|
127
|
+
|
128
|
+
assert_equal "cd ./engine1 && ruby -I test test/dir/file_test.rb", consolidator.consolidate.to_command
|
129
|
+
assert_notified "Found 1 file."
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_multiple_files__last_edited
|
133
|
+
search_results = [
|
134
|
+
{
|
135
|
+
file: "test/dir/file_test.rb",
|
136
|
+
},
|
137
|
+
{
|
138
|
+
file: "test/other_dir/different_test.rb",
|
139
|
+
},
|
140
|
+
]
|
141
|
+
|
142
|
+
consolidator = Consolidator.new(search_results, dummy_shell, false)
|
143
|
+
|
144
|
+
File.expects(:mtime).with("test/dir/file_test.rb").returns(Time.new(2014, 01, 01))
|
145
|
+
File.expects(:mtime).with("test/other_dir/different_test.rb").returns(Time.new(2013, 01, 01))
|
146
|
+
|
147
|
+
assert_equal "cd . && ruby -I test test/dir/file_test.rb", consolidator.consolidate.to_command
|
148
|
+
assert_notified "Found 2 files."
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_multiple_files__run_all__same_root
|
152
|
+
search_results = [
|
153
|
+
{
|
154
|
+
file: "engine1/test/dir/file_test.rb",
|
155
|
+
},
|
156
|
+
{
|
157
|
+
file: "engine1/test/other_dir/different_test.rb",
|
158
|
+
},
|
159
|
+
]
|
160
|
+
|
161
|
+
consolidator = Consolidator.new(search_results, dummy_shell, true)
|
162
|
+
expected = %{cd ./engine1 && ruby -I test -e 'ARGV.each { |file| require(Dir.pwd + \"/\" + file) }' test/dir/file_test.rb test/other_dir/different_test.rb}
|
163
|
+
|
164
|
+
assert_equal expected, consolidator.consolidate.to_command
|
165
|
+
assert_notified "Found 2 files."
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_multiple_files__run_all__different_roots
|
169
|
+
search_results = [
|
170
|
+
{
|
171
|
+
file: "engine1/test/dir/file_test.rb",
|
172
|
+
},
|
173
|
+
{
|
174
|
+
file: "engine2/root2/test/other_dir/different_test.rb",
|
175
|
+
},
|
176
|
+
]
|
177
|
+
|
178
|
+
consolidator = Consolidator.new(search_results, dummy_shell, true)
|
179
|
+
expected = <<-SHELL
|
180
|
+
cd ./engine1 && ruby -I test -e 'ARGV.each { |file| require(Dir.pwd + \"/\" + file) }' test/dir/file_test.rb; cd -;
|
181
|
+
|
182
|
+
cd ./engine2/root2 && ruby -I test -e 'ARGV.each { |file| require(Dir.pwd + \"/\" + file) }' test/other_dir/different_test.rb
|
183
|
+
SHELL
|
184
|
+
|
185
|
+
assert_paragraphs_equal expected, consolidator.consolidate.to_command
|
186
|
+
assert_notified "Found 2 files."
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require "test_launcher/tests/minitest/finder"
|
3
|
+
|
4
|
+
module TestLauncher
|
5
|
+
module Tests
|
6
|
+
module Minitest
|
7
|
+
class FinderTest < TestCase
|
8
|
+
|
9
|
+
def test_find__absolute_path
|
10
|
+
Dir.expects(:pwd).returns("/absolute/path/root")
|
11
|
+
results = Finder.find("/absolute/path/root/test/dir/file_test.rb", "searcher_stub")
|
12
|
+
assert_equal [{file: "test/dir/file_test.rb"}], results
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_find__found_by_name
|
16
|
+
expected = [{file: "test/file.rb", line: "def test_name"}]
|
17
|
+
searcher_mock = mock do
|
18
|
+
stubs(:grep).with("^\s*def .*test_name.*", file_pattern: "*_test.rb").returns(expected)
|
19
|
+
end
|
20
|
+
|
21
|
+
assert_equal expected, Finder.find("test_name", searcher_mock)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_find__found_by_file_name
|
25
|
+
searcher_mock = mock do
|
26
|
+
stubs(:grep).returns([])
|
27
|
+
stubs(:find_files).with("file_query").returns([
|
28
|
+
"dir/test/non_test_file_query.rb",
|
29
|
+
"dir/thing/file_query_test.rb",
|
30
|
+
"other_dir/other_thing/other_file_query_test.rb",
|
31
|
+
])
|
32
|
+
end
|
33
|
+
|
34
|
+
expected = [
|
35
|
+
{ file: "dir/thing/file_query_test.rb" },
|
36
|
+
{ file: "other_dir/other_thing/other_file_query_test.rb" },
|
37
|
+
]
|
38
|
+
|
39
|
+
assert_equal expected, Finder.find("file_query", searcher_mock)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_find__found_by_full_regex
|
43
|
+
searcher_mock = mock do
|
44
|
+
stubs(:grep).returns([])
|
45
|
+
stubs(:find_files).returns([])
|
46
|
+
|
47
|
+
stubs(:grep).with("full_regex_search", file_pattern: "*_test.rb").returns([
|
48
|
+
{ file: "path/to/file_test.rb", line: "random_match"},
|
49
|
+
{ file: "path/to/other_file_test.rb", line: "random_match_2"}
|
50
|
+
])
|
51
|
+
end
|
52
|
+
|
53
|
+
expected = [
|
54
|
+
{file: "path/to/file_test.rb"},
|
55
|
+
{file: "path/to/other_file_test.rb"}
|
56
|
+
]
|
57
|
+
assert_equal expected, Finder.find("full_regex_search", searcher_mock)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_find__nothing_found
|
61
|
+
searcher_mock = mock do
|
62
|
+
stubs(:grep).returns([])
|
63
|
+
stubs(:find_files).returns([])
|
64
|
+
end
|
65
|
+
|
66
|
+
assert_equal [], Finder.find("query", searcher_mock)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'test_launcher/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "test_launcher"
|
8
|
+
spec.version = TestLauncher::VERSION
|
9
|
+
spec.authors = ["Pete Kinnecom"]
|
10
|
+
spec.email = ["pete.kinnecom@appfolio.com"]
|
11
|
+
spec.summary = %q{Easily run tests}
|
12
|
+
spec.description = %q{no really}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: test_launcher
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pete Kinnecom
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: no really
|
42
|
+
email:
|
43
|
+
- pete.kinnecom@appfolio.com
|
44
|
+
executables:
|
45
|
+
- test_launcher
|
46
|
+
- test_runner
|
47
|
+
extensions: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
files:
|
50
|
+
- ".gitignore"
|
51
|
+
- Gemfile
|
52
|
+
- LICENSE.txt
|
53
|
+
- README.md
|
54
|
+
- Rakefile
|
55
|
+
- bin/test_launcher
|
56
|
+
- bin/test_runner
|
57
|
+
- lib/test_launcher.rb
|
58
|
+
- lib/test_launcher/searchers/git_searcher.rb
|
59
|
+
- lib/test_launcher/shell/color.rb
|
60
|
+
- lib/test_launcher/shell/runner.rb
|
61
|
+
- lib/test_launcher/tests/minitest/consolidator.rb
|
62
|
+
- lib/test_launcher/tests/minitest/finder.rb
|
63
|
+
- lib/test_launcher/tests/minitest/wrappers/multiple_files.rb
|
64
|
+
- lib/test_launcher/tests/minitest/wrappers/multiple_roots.rb
|
65
|
+
- lib/test_launcher/tests/minitest/wrappers/single_file.rb
|
66
|
+
- lib/test_launcher/tests/minitest/wrappers/single_root.rb
|
67
|
+
- lib/test_launcher/tests/minitest/wrappers/single_test.rb
|
68
|
+
- lib/test_launcher/utils/path.rb
|
69
|
+
- lib/test_launcher/utils/pluralize.rb
|
70
|
+
- lib/test_launcher/version.rb
|
71
|
+
- test/test_helper.rb
|
72
|
+
- test/test_launcher/searchers/git_searcher_test.rb
|
73
|
+
- test/test_launcher/tests/minitest/consolidator_integration_test.rb
|
74
|
+
- test/test_launcher/tests/minitest/finder_test.rb
|
75
|
+
- test_launcher.gemspec
|
76
|
+
homepage: ''
|
77
|
+
licenses:
|
78
|
+
- MIT
|
79
|
+
metadata: {}
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
requirements: []
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 2.4.3
|
97
|
+
signing_key:
|
98
|
+
specification_version: 4
|
99
|
+
summary: Easily run tests
|
100
|
+
test_files:
|
101
|
+
- test/test_helper.rb
|
102
|
+
- test/test_launcher/searchers/git_searcher_test.rb
|
103
|
+
- test/test_launcher/tests/minitest/consolidator_integration_test.rb
|
104
|
+
- test/test_launcher/tests/minitest/finder_test.rb
|
105
|
+
has_rdoc:
|