1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
# BEGIN generated by rake update, do not modify
# https://raw.githubusercontent.com/grosser/testrbl/master/lib/testrbl.rb
module Maxitest
module Testrbl
PATTERNS = [
/^(\s+)(should|test|it)(\s+|\s*\(\s*)['"](.*)['"](\s*\))?\s+do\s*(?:#.*)?$/,
/^(\s+)(context|describe)(\s+|\s*\(\s*)['"]?(.*?)['"]?(\s*\))?\s+do\s*(?:#.*)?$/,
/^(\s+)def(\s+)(test_)([a-z_\d]+)\s*(?:#.*)?$/
]
OPTION_WITH_ARGUMENT = ["-I", "-r", "-n", "--name", "-e", "--exclude", "-s", "--seed"]
INTERPOLATION = /\\\#\\\{.*?\\\}/
class << self
def run_from_cli(argv)
files, options = partition_argv(argv)
files.concat(changed_files) if options.delete("--changed")
files = ["test"] if files.empty?
files = files.map { |f| localize(f) }
load_options, options = partition_options(options)
if files.size == 1 and files.first =~ /^(\S+):(\d+)$/
file = $1
line = $2
run(ruby + load_options + line_pattern_option(file, line) + options)
else
if files.size == 1 and File.file?(files.first)
run(ruby + load_options + files + options)
elsif options.none? { |arg| arg =~ /^-n/ }
seed = if seed = options.index("--seed")
["--"] + options.slice!(seed, 2)
else
[]
end
files = files.map { |f| File.directory?(f) ? all_test_files_in(f) : f }.flatten
run(ruby + load_options + files.map { |f| "-r#{f}" } + options + ["-e", ""] + seed)
else # pass though
# no bundle exec: projects with mini and unit-test do not run well via bundle exec testrb
run ["testrb"] + argv
end
end
end
# overwritten by maxitest to just return line
def line_pattern_option(file, line)
[file, "-n", "/#{pattern_from_file(File.readlines(file), line)}/"]
end
# usable via external tools like zeus
def pattern_from_file(lines, line)
possible_lines = lines[0..(line.to_i-1)].reverse
found = possible_lines.map { |line| test_pattern_from_line(line) || block_start_from_line(line) }.compact
# pattern and the groups it is nested under (like describe - describe - it)
last_spaces = " " * 100
patterns = found.select do |spaces, name|
last_spaces = spaces if spaces.size < last_spaces.size
end.map(&:last).compact
return filter_duplicate_final(patterns).reverse.join(".*") if found.size > 0
raise "no test found before line #{line}"
end
# only keep 1 pattern that stops matching via $
def filter_duplicate_final(patterns)
found_final = 0
patterns.reject { |p| p.end_with?("$") and (found_final += 1) > 1 }
end
private
def all_test_files_in(folder)
Dir[File.join(folder, "{**/,}*_{test,spec}.rb")].uniq
end
def partition_options(options)
next_is_before = false
options.partition do |option|
if next_is_before
next_is_before = false
true
else
if option =~ /^-(r|I)/
next_is_before = (option.size == 2)
true
else
false
end
end
end
end
# fix 1.9 not being able to load local files
def localize(file)
file =~ /^[-a-z\d_]/ ? "./#{file}" : file
end
def partition_argv(argv)
next_is_option = false
argv.partition do |arg|
if next_is_option
next_is_option = false
else
if arg =~ /^-.$/ or arg =~ /^--/ # single letter option followed by argument like -I test or long options like --verbose
next_is_option = true if OPTION_WITH_ARGUMENT.include?(arg)
false
elsif arg =~ /^-/ # multi letter option like -Itest
false
else
true
end
end
end
end
def changed_files
changed_files = sh("git status -s").split("\n").map { |l| l.strip.split(/\s+/, 2)[1] }
if changed_files.empty?
# user wants to test last commit and not current diff
changed_files = sh("git show --name-only").split("\n\n").last.split("\n")
end
# we only want test files that were added or changed (not deleted)
changed_files.select { |f| f =~ /_(test|spec)\.rb$/ && File.exist?(f) }
end
def sh(command)
result = `#{command}`
raise "Failed: #{command} -> #{result}" unless $?.success?
result
end
def ruby
if File.file?("Gemfile")
["ruby", "-rbundler/setup"] # faster then bundle exec ruby
else
["ruby"]
end
end
def run(command)
puts command.join(" ")
STDOUT.flush # if exec fails horribly we at least see some output
Kernel.exec *command
end
def block_start_from_line(line)
if line =~ /^(\s*).* do( \|.*\|)?$/
[$1, nil]
end
end
def test_pattern_from_line(line)
PATTERNS.each do |r|
next unless line =~ r
whitespace, method, test_name = $1, $2, $4
return [whitespace, test_pattern_from_match(method, test_name)]
end
nil
end
def test_pattern_from_match(method, test_name)
regex = Regexp.escape(test_name).gsub("\\ "," ").gsub(INTERPOLATION, ".*")
regex = if method == "test"
# test "xxx -_ yyy"
# test-unit: "test: xxx -_ yyy"
# activesupport: "test_xxx_-__yyy"
"^test(: |_)#{regex.gsub(" ", ".")}$"
elsif method == "describe" || (method == "context" && !via_shoulda?)
"#{regex}(::)?"
elsif method == "should" && via_shoulda?
optional_test_name = "(?:\(.*\))?"
"#{method} #{regex}\. #{optional_test_name}$"
elsif ["it", "should"].include?(method) # minitest aliases for shoulda
"#test_\\d+_#{regex}$"
else
regex
end
regex.gsub("'", ".")
end
def via_shoulda?
return @via_shoulda if defined?(@via_shoulda)
@via_shoulda = !File.exist?("Gemfile.lock") || File.read("Gemfile.lock").include?(" shoulda-context ")
end
end
end
end
# END generated by rake update, do not modify
|