lib/testrbl.rb in testrbl-0.1.17 vs lib/testrbl.rb in testrbl-0.2.0
- old
+ new
@@ -5,102 +5,128 @@
/^(\s+)(should|test|it)\s+['"](.*)['"]\s+do\s*(?:#.*)?$/,
/^(\s+)(context)\s+['"]?(.*?)['"]?\s+do\s*(?:#.*)?$/,
/^(\s+)def\s+(test_)([a-z_\d]+)\s*(?:#.*)?$/
]
+ OPTION_WITH_ARGUMENT = ["-I", "-r", "-n", "-e"]
+
# copied from minitest
MINITEST_NAME_RE = if RUBY_VERSION >= "1.9"
Regexp.new("[^[[:word:]]]+")
else
/\W+/u
end
INTERPOLATION = /\\\#\\\{.*?\\\}/
def self.run_from_cli(argv)
- i_test, file, line = detect_usable(argv)
- if file and line
- file = localize(file)
- run "#{ruby} #{i_test}#{file} -n '/#{pattern_from_file(File.readlines(file), line)}/'"
- elsif file
- run "#{ruby} #{i_test}#{file}"
- elsif argv.all?{|f| File.file?(f) } # testrb has a lot of weird issues vs test-unit, so try to avoid it
- run "#{ruby} #{argv.map{|f| "-r #{localize(f)}" }.join(" ")} -e ''"
- else # pass though
- # no bundle exec: projects with mini and unit-test do not run well via bundle exec testrb
- run ["testrb"] + argv
+ files, options = partition_argv(argv)
+ 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 + [file, "-n", "/#{pattern_from_file(File.readlines(file), line)}/"] + options)
+ else
+ if files.all? { |f| File.file?(f) } and options.none? { |arg| arg =~ /^-n/ }
+ run(ruby + load_options + files.map { |f| "-r#{f}" } + options + ["-e", ""])
+ 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
- # useable e.g. via zeus
+ # usable via external tools like zeus
def self.pattern_from_file(lines, line)
- search = lines[0..(line.to_i-1)].reverse
+ possible_lines = lines[0..(line.to_i-1)].reverse
last_spaces = " " * 100
- found = search.map{|line| pattern_from_line(line) }.compact
+ found = possible_lines.map { |line| test_pattern_from_line(line) }.compact
+
+ # pattern and the groups it is nested under (like describe - describe - it)
patterns = found.select do |spaces, name|
last_spaces = spaces if spaces.size < last_spaces.size
end.map(&:last)
- use = []
- found_final = false
- patterns.each do |pattern|
- is_final = pattern.end_with?("$")
- next if is_final && found_final
- found_final = is_final
- use << pattern
- end
+ return filter_duplicate_final(patterns).reverse.join(".*") if found.size > 0
- return use.reverse.join(".*") if found.size > 0
-
raise "no test found before line #{line}"
end
+ # only keep 1 pattern that stops matching via $
+ def self.filter_duplicate_final(patterns)
+ found_final = 0
+ patterns.reject { |p| p.end_with?("$") and (found_final += 1) > 1 }
+ end
+
private
+ def self.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 self.localize(file)
file =~ /^[-a-z\d_]/ ? "./#{file}" : file
end
- def self.detect_usable(argv)
- argv = argv.dup # do not mess up args
- i_test = "-Itest " if ((argv.delete("-I") and argv.delete("test")) or argv.delete("-Itest"))
-
- return unless argv.size == 1
-
- if argv.first =~ /^(\S+):(\d+)$/
- [i_test, $1, $2]
- elsif File.file?(argv.first)
- [i_test, argv.first, false]
+ def self.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 self.ruby
if File.file?("Gemfile")
- "ruby -rbundler/setup" # faster then bundle exec ruby
+ ["ruby", "-rbundler/setup"] # faster then bundle exec ruby
else
- "ruby"
+ ["ruby"]
end
end
def self.run(command)
- command = [*command]
puts command.join(" ")
STDOUT.flush # if exec fails horribly we at least see some output
Kernel.exec *command
end
- def self.pattern_from_line(line)
+ def self.test_pattern_from_line(line)
PATTERNS.each do |r|
next unless line =~ r
whitespace, method, test_name = $1, $2, $3
- return [whitespace, pattern_from_match(method, test_name)]
+ return [whitespace, test_pattern_from_match(method, test_name)]
end
nil
end
- def self.pattern_from_match(method, test_name)
+ def self.test_pattern_from_match(method, test_name)
regex = Regexp.escape(test_name).gsub("\\ "," ").gsub(INTERPOLATION, ".*")
if method == "should"
optional_test_name = "(?:\(.*\))?"
regex = "#{method} #{regex}\. #{optional_test_name}$"