mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-22 02:00:12 +01:00
Added Rspec and Webrat plugins and started porting Selenium on Rails tests to Rspec Plain Text Stories driving Webrat driving Selenium.
This commit is contained in:
parent
0600756bbf
commit
0f7d6f7a1d
602 changed files with 47788 additions and 29 deletions
57
vendor/plugins/rspec/lib/spec/runner/backtrace_tweaker.rb
vendored
Normal file
57
vendor/plugins/rspec/lib/spec/runner/backtrace_tweaker.rb
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
module Spec
|
||||
module Runner
|
||||
class BacktraceTweaker
|
||||
def clean_up_double_slashes(line)
|
||||
line.gsub!('//','/')
|
||||
end
|
||||
end
|
||||
|
||||
class NoisyBacktraceTweaker < BacktraceTweaker
|
||||
def tweak_backtrace(error)
|
||||
return if error.backtrace.nil?
|
||||
error.backtrace.each do |line|
|
||||
clean_up_double_slashes(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Tweaks raised Exceptions to mask noisy (unneeded) parts of the backtrace
|
||||
class QuietBacktraceTweaker < BacktraceTweaker
|
||||
unless defined?(IGNORE_PATTERNS)
|
||||
root_dir = File.expand_path(File.join(__FILE__, '..', '..', '..', '..'))
|
||||
spec_files = Dir["#{root_dir}/lib/*"].map do |path|
|
||||
subpath = path[root_dir.length..-1]
|
||||
/#{subpath}/
|
||||
end
|
||||
IGNORE_PATTERNS = spec_files + [
|
||||
/\/lib\/ruby\//,
|
||||
/bin\/spec:/,
|
||||
/bin\/rcov:/,
|
||||
/lib\/rspec-rails/,
|
||||
/vendor\/rails/,
|
||||
# TextMate's Ruby and RSpec plugins
|
||||
/Ruby\.tmbundle\/Support\/tmruby.rb:/,
|
||||
/RSpec\.tmbundle\/Support\/lib/,
|
||||
/temp_textmate\./,
|
||||
/mock_frameworks\/rspec/,
|
||||
/spec_server/
|
||||
]
|
||||
end
|
||||
|
||||
def tweak_backtrace(error)
|
||||
return if error.backtrace.nil?
|
||||
error.backtrace.collect! do |line|
|
||||
clean_up_double_slashes(line)
|
||||
IGNORE_PATTERNS.each do |ignore|
|
||||
if line =~ ignore
|
||||
line = nil
|
||||
break
|
||||
end
|
||||
end
|
||||
line
|
||||
end
|
||||
error.backtrace.compact!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
16
vendor/plugins/rspec/lib/spec/runner/class_and_arguments_parser.rb
vendored
Normal file
16
vendor/plugins/rspec/lib/spec/runner/class_and_arguments_parser.rb
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
module Spec
|
||||
module Runner
|
||||
class ClassAndArgumentsParser
|
||||
class << self
|
||||
def parse(s)
|
||||
if s =~ /([a-zA-Z_]+(?:::[a-zA-Z_]+)*):?(.*)/
|
||||
arg = $2 == "" ? nil : $2
|
||||
[$1, arg]
|
||||
else
|
||||
raise "Couldn't parse #{s.inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
28
vendor/plugins/rspec/lib/spec/runner/command_line.rb
vendored
Normal file
28
vendor/plugins/rspec/lib/spec/runner/command_line.rb
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
require 'spec/runner/option_parser'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
# Facade to run specs without having to fork a new ruby process (using `spec ...`)
|
||||
class CommandLine
|
||||
class << self
|
||||
# Runs specs. +argv+ is the commandline args as per the spec commandline API, +err+
|
||||
# and +out+ are the streams output will be written to.
|
||||
def run(instance_rspec_options)
|
||||
# NOTE - this call to init_rspec_options is not spec'd, but neither is any of this
|
||||
# swapping of $rspec_options. That is all here to enable rspec to run against itself
|
||||
# and maintain coverage in a single process. Therefore, DO NOT mess with this stuff
|
||||
# unless you know what you are doing!
|
||||
init_rspec_options(instance_rspec_options)
|
||||
orig_rspec_options = rspec_options
|
||||
begin
|
||||
$rspec_options = instance_rspec_options
|
||||
return $rspec_options.run_examples
|
||||
ensure
|
||||
::Spec.run = true
|
||||
$rspec_options = orig_rspec_options
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
20
vendor/plugins/rspec/lib/spec/runner/drb_command_line.rb
vendored
Normal file
20
vendor/plugins/rspec/lib/spec/runner/drb_command_line.rb
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
require "drb/drb"
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
# Facade to run specs by connecting to a DRB server
|
||||
class DrbCommandLine
|
||||
# Runs specs on a DRB server. Note that this API is similar to that of
|
||||
# CommandLine - making it possible for clients to use both interchangeably.
|
||||
def self.run(options)
|
||||
begin
|
||||
DRb.start_service
|
||||
spec_server = DRbObject.new_with_uri("druby://127.0.0.1:8989")
|
||||
spec_server.run(options.argv, options.error_stream, options.output_stream)
|
||||
rescue DRb::DRbConnError => e
|
||||
options.error_stream.puts "No server is running"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
59
vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb
vendored
Normal file
59
vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
module Spec
|
||||
module Runner
|
||||
class ExampleGroupRunner
|
||||
def initialize(options)
|
||||
@options = options
|
||||
end
|
||||
|
||||
def load_files(files)
|
||||
# It's important that loading files (or choosing not to) stays the
|
||||
# responsibility of the ExampleGroupRunner. Some implementations (like)
|
||||
# the one using DRb may choose *not* to load files, but instead tell
|
||||
# someone else to do it over the wire.
|
||||
files.each do |file|
|
||||
load file
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
prepare
|
||||
success = true
|
||||
example_groups.each do |example_group|
|
||||
success = success & example_group.run
|
||||
end
|
||||
return success
|
||||
ensure
|
||||
finish
|
||||
end
|
||||
|
||||
protected
|
||||
def prepare
|
||||
reporter.start(number_of_examples)
|
||||
example_groups.reverse! if reverse
|
||||
end
|
||||
|
||||
def finish
|
||||
reporter.end
|
||||
reporter.dump
|
||||
end
|
||||
|
||||
def reporter
|
||||
@options.reporter
|
||||
end
|
||||
|
||||
def reverse
|
||||
@options.reverse
|
||||
end
|
||||
|
||||
def example_groups
|
||||
@options.example_groups
|
||||
end
|
||||
|
||||
def number_of_examples
|
||||
@options.number_of_examples
|
||||
end
|
||||
end
|
||||
# TODO: BT - Deprecate BehaviourRunner?
|
||||
BehaviourRunner = ExampleGroupRunner
|
||||
end
|
||||
end
|
||||
77
vendor/plugins/rspec/lib/spec/runner/formatter/base_formatter.rb
vendored
Normal file
77
vendor/plugins/rspec/lib/spec/runner/formatter/base_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
# Baseclass for formatters that implements all required methods as no-ops.
|
||||
class BaseFormatter
|
||||
attr_accessor :example_group, :options, :where
|
||||
def initialize(options, where)
|
||||
@options = options
|
||||
@where = where
|
||||
end
|
||||
|
||||
# This method is invoked before any examples are run, right after
|
||||
# they have all been collected. This can be useful for special
|
||||
# formatters that need to provide progress on feedback (graphical ones)
|
||||
#
|
||||
# This method will only be invoked once, and the next one to be invoked
|
||||
# is #add_example_group
|
||||
def start(example_count)
|
||||
end
|
||||
|
||||
# This method is invoked at the beginning of the execution of each example_group.
|
||||
# +example_group+ is the example_group.
|
||||
#
|
||||
# The next method to be invoked after this is #example_failed or #example_finished
|
||||
def add_example_group(example_group)
|
||||
@example_group = example_group
|
||||
end
|
||||
|
||||
# This method is invoked when an +example+ starts.
|
||||
def example_started(example)
|
||||
end
|
||||
|
||||
# This method is invoked when an +example+ passes.
|
||||
def example_passed(example)
|
||||
end
|
||||
|
||||
# This method is invoked when an +example+ fails, i.e. an exception occurred
|
||||
# inside it (such as a failed should or other exception). +counter+ is the
|
||||
# sequence number of the failure (starting at 1) and +failure+ is the associated
|
||||
# Failure object.
|
||||
def example_failed(example, counter, failure)
|
||||
end
|
||||
|
||||
# This method is invoked when an example is not yet implemented (i.e. has not
|
||||
# been provided a block), or when an ExamplePendingError is raised.
|
||||
# +message+ is the message from the ExamplePendingError, if it exists, or the
|
||||
# default value of "Not Yet Implemented"
|
||||
def example_pending(example, message)
|
||||
end
|
||||
|
||||
# This method is invoked after all of the examples have executed. The next method
|
||||
# to be invoked after this one is #dump_failure (once for each failed example),
|
||||
def start_dump
|
||||
end
|
||||
|
||||
# Dumps detailed information about an example failure.
|
||||
# This method is invoked for each failed example after all examples have run. +counter+ is the sequence number
|
||||
# of the associated example. +failure+ is a Failure object, which contains detailed
|
||||
# information about the failure.
|
||||
def dump_failure(counter, failure)
|
||||
end
|
||||
|
||||
# This method is invoked after the dumping of examples and failures.
|
||||
def dump_summary(duration, example_count, failure_count, pending_count)
|
||||
end
|
||||
|
||||
# This gets invoked after the summary if option is set to do so.
|
||||
def dump_pending
|
||||
end
|
||||
|
||||
# This method is invoked at the very end. Allows the formatter to clean up, like closing open streams.
|
||||
def close
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
130
vendor/plugins/rspec/lib/spec/runner/formatter/base_text_formatter.rb
vendored
Normal file
130
vendor/plugins/rspec/lib/spec/runner/formatter/base_text_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
require 'spec/runner/formatter/base_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
# Baseclass for text-based formatters. Can in fact be used for
|
||||
# non-text based ones too - just ignore the +output+ constructor
|
||||
# argument.
|
||||
class BaseTextFormatter < BaseFormatter
|
||||
attr_reader :output, :pending_examples
|
||||
# Creates a new instance that will write to +where+. If +where+ is a
|
||||
# String, output will be written to the File with that name, otherwise
|
||||
# +where+ is exected to be an IO (or an object that responds to #puts and #write).
|
||||
def initialize(options, where)
|
||||
super
|
||||
if where.is_a?(String)
|
||||
@output = File.open(where, 'w')
|
||||
elsif where == STDOUT
|
||||
@output = Kernel
|
||||
def @output.flush
|
||||
STDOUT.flush
|
||||
end
|
||||
else
|
||||
@output = where
|
||||
end
|
||||
@pending_examples = []
|
||||
end
|
||||
|
||||
def example_pending(example, message)
|
||||
@pending_examples << [example.__full_description, message]
|
||||
end
|
||||
|
||||
def dump_failure(counter, failure)
|
||||
@output.puts
|
||||
@output.puts "#{counter.to_s})"
|
||||
@output.puts colourise("#{failure.header}\n#{failure.exception.message}", failure)
|
||||
@output.puts format_backtrace(failure.exception.backtrace)
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def colourise(s, failure)
|
||||
if(failure.expectation_not_met?)
|
||||
red(s)
|
||||
elsif(failure.pending_fixed?)
|
||||
blue(s)
|
||||
else
|
||||
magenta(s)
|
||||
end
|
||||
end
|
||||
|
||||
def dump_summary(duration, example_count, failure_count, pending_count)
|
||||
return if dry_run?
|
||||
@output.puts
|
||||
@output.puts "Finished in #{duration} seconds"
|
||||
@output.puts
|
||||
|
||||
summary = "#{example_count} example#{'s' unless example_count == 1}, #{failure_count} failure#{'s' unless failure_count == 1}"
|
||||
summary << ", #{pending_count} pending" if pending_count > 0
|
||||
|
||||
if failure_count == 0
|
||||
if pending_count > 0
|
||||
@output.puts yellow(summary)
|
||||
else
|
||||
@output.puts green(summary)
|
||||
end
|
||||
else
|
||||
@output.puts red(summary)
|
||||
end
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def dump_pending
|
||||
unless @pending_examples.empty?
|
||||
@output.puts
|
||||
@output.puts "Pending:"
|
||||
@pending_examples.each do |pending_example|
|
||||
@output.puts "#{pending_example[0]} (#{pending_example[1]})"
|
||||
end
|
||||
end
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def close
|
||||
if IO === @output
|
||||
@output.close
|
||||
end
|
||||
end
|
||||
|
||||
def format_backtrace(backtrace)
|
||||
return "" if backtrace.nil?
|
||||
backtrace.map { |line| backtrace_line(line) }.join("\n")
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def colour?
|
||||
@options.colour ? true : false
|
||||
end
|
||||
|
||||
def dry_run?
|
||||
@options.dry_run ? true : false
|
||||
end
|
||||
|
||||
def backtrace_line(line)
|
||||
line.sub(/\A([^:]+:\d+)$/, '\\1:')
|
||||
end
|
||||
|
||||
def colour(text, colour_code)
|
||||
return text unless colour? && output_to_tty?
|
||||
"#{colour_code}#{text}\e[0m"
|
||||
end
|
||||
|
||||
def output_to_tty?
|
||||
begin
|
||||
@output == Kernel || @output.tty?
|
||||
rescue NoMethodError
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def green(text); colour(text, "\e[32m"); end
|
||||
def red(text); colour(text, "\e[31m"); end
|
||||
def magenta(text); colour(text, "\e[35m"); end
|
||||
def yellow(text); colour(text, "\e[33m"); end
|
||||
def blue(text); colour(text, "\e[34m"); end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
27
vendor/plugins/rspec/lib/spec/runner/formatter/failing_example_groups_formatter.rb
vendored
Normal file
27
vendor/plugins/rspec/lib/spec/runner/formatter/failing_example_groups_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class FailingExampleGroupsFormatter < BaseTextFormatter
|
||||
def example_failed(example, counter, failure)
|
||||
if @example_group
|
||||
description_parts = @example_group.description_parts.collect do |description|
|
||||
description =~ /(.*) \(druby.*\)$/ ? $1 : description
|
||||
end
|
||||
@output.puts ::Spec::Example::ExampleGroupMethods.description_text(*description_parts)
|
||||
|
||||
@output.flush
|
||||
@example_group = nil
|
||||
end
|
||||
end
|
||||
|
||||
def dump_failure(counter, failure)
|
||||
end
|
||||
|
||||
def dump_summary(duration, example_count, failure_count, pending_count)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
20
vendor/plugins/rspec/lib/spec/runner/formatter/failing_examples_formatter.rb
vendored
Normal file
20
vendor/plugins/rspec/lib/spec/runner/formatter/failing_examples_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class FailingExamplesFormatter < BaseTextFormatter
|
||||
def example_failed(example, counter, failure)
|
||||
@output.puts "#{example_group.description} #{example.description}"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def dump_failure(counter, failure)
|
||||
end
|
||||
|
||||
def dump_summary(duration, example_count, failure_count, pending_count)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
337
vendor/plugins/rspec/lib/spec/runner/formatter/html_formatter.rb
vendored
Normal file
337
vendor/plugins/rspec/lib/spec/runner/formatter/html_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
require 'erb'
|
||||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class HtmlFormatter < BaseTextFormatter
|
||||
include ERB::Util # for the #h method
|
||||
|
||||
def initialize(options, output)
|
||||
super
|
||||
@example_group_number = 0
|
||||
@example_number = 0
|
||||
end
|
||||
|
||||
def method_missing(sym, *args)
|
||||
# no-op
|
||||
end
|
||||
|
||||
# The number of the currently running example_group
|
||||
def example_group_number
|
||||
@example_group_number
|
||||
end
|
||||
|
||||
# The number of the currently running example (a global counter)
|
||||
def example_number
|
||||
@example_number
|
||||
end
|
||||
|
||||
def start(example_count)
|
||||
@example_count = example_count
|
||||
|
||||
@output.puts html_header
|
||||
@output.puts report_header
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def add_example_group(example_group)
|
||||
super
|
||||
@example_group_red = false
|
||||
@example_group_red = false
|
||||
@example_group_number += 1
|
||||
unless example_group_number == 1
|
||||
@output.puts " </dl>"
|
||||
@output.puts "</div>"
|
||||
end
|
||||
@output.puts "<div class=\"example_group\">"
|
||||
@output.puts " <dl>"
|
||||
@output.puts " <dt id=\"example_group_#{example_group_number}\">#{h(example_group.description)}</dt>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def start_dump
|
||||
@output.puts " </dl>"
|
||||
@output.puts "</div>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def example_started(example)
|
||||
@example_number += 1
|
||||
end
|
||||
|
||||
def example_passed(example)
|
||||
move_progress
|
||||
@output.puts " <dd class=\"spec passed\"><span class=\"passed_spec_name\">#{h(example.description)}</span></dd>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def example_failed(example, counter, failure)
|
||||
extra = extra_failure_content(failure)
|
||||
failure_style = failure.pending_fixed? ? 'pending_fixed' : 'failed'
|
||||
@output.puts " <script type=\"text/javascript\">makeRed('rspec-header');</script>" unless @header_red
|
||||
@header_red = true
|
||||
@output.puts " <script type=\"text/javascript\">makeRed('example_group_#{example_group_number}');</script>" unless @example_group_red
|
||||
@example_group_red = true
|
||||
move_progress
|
||||
@output.puts " <dd class=\"spec #{failure_style}\">"
|
||||
@output.puts " <span class=\"failed_spec_name\">#{h(example.description)}</span>"
|
||||
@output.puts " <div class=\"failure\" id=\"failure_#{counter}\">"
|
||||
@output.puts " <div class=\"message\"><pre>#{h(failure.exception.message)}</pre></div>" unless failure.exception.nil?
|
||||
@output.puts " <div class=\"backtrace\"><pre>#{format_backtrace(failure.exception.backtrace)}</pre></div>" unless failure.exception.nil?
|
||||
@output.puts extra unless extra == ""
|
||||
@output.puts " </div>"
|
||||
@output.puts " </dd>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def example_pending(example, message)
|
||||
@output.puts " <script type=\"text/javascript\">makeYellow('rspec-header');</script>" unless @header_red
|
||||
@output.puts " <script type=\"text/javascript\">makeYellow('example_group_#{example_group_number}');</script>" unless @example_group_red
|
||||
move_progress
|
||||
@output.puts " <dd class=\"spec not_implemented\"><span class=\"not_implemented_spec_name\">#{h(example.description)} (PENDING: #{h(message)})</span></dd>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
# Override this method if you wish to output extra HTML for a failed spec. For example, you
|
||||
# could output links to images or other files produced during the specs.
|
||||
#
|
||||
def extra_failure_content(failure)
|
||||
require 'spec/runner/formatter/snippet_extractor'
|
||||
@snippet_extractor ||= SnippetExtractor.new
|
||||
" <pre class=\"ruby\"><code>#{@snippet_extractor.snippet(failure.exception)}</code></pre>"
|
||||
end
|
||||
|
||||
def move_progress
|
||||
@output.puts " <script type=\"text/javascript\">moveProgressBar('#{percent_done}');</script>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def percent_done
|
||||
result = 100.0
|
||||
if @example_count != 0
|
||||
result = ((example_number).to_f / @example_count.to_f * 1000).to_i / 10.0
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def dump_failure(counter, failure)
|
||||
end
|
||||
|
||||
def dump_summary(duration, example_count, failure_count, pending_count)
|
||||
if dry_run?
|
||||
totals = "This was a dry-run"
|
||||
else
|
||||
totals = "#{example_count} example#{'s' unless example_count == 1}, #{failure_count} failure#{'s' unless failure_count == 1}"
|
||||
totals << ", #{pending_count} pending" if pending_count > 0
|
||||
end
|
||||
@output.puts "<script type=\"text/javascript\">document.getElementById('duration').innerHTML = \"Finished in <strong>#{duration} seconds</strong>\";</script>"
|
||||
@output.puts "<script type=\"text/javascript\">document.getElementById('totals').innerHTML = \"#{totals}\";</script>"
|
||||
@output.puts "</div>"
|
||||
@output.puts "</div>"
|
||||
@output.puts "</body>"
|
||||
@output.puts "</html>"
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def html_header
|
||||
<<-EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>RSpec results</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="Expires" content="-1" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #fff;
|
||||
font-size: 80%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
EOF
|
||||
end
|
||||
|
||||
def report_header
|
||||
<<-EOF
|
||||
<div class="rspec-report">
|
||||
<script type="text/javascript">
|
||||
// <![CDATA[
|
||||
#{global_scripts}
|
||||
// ]]>
|
||||
</script>
|
||||
<style type="text/css">
|
||||
#{global_styles}
|
||||
</style>
|
||||
|
||||
<div id="rspec-header">
|
||||
<h1>RSpec Results</h1>
|
||||
|
||||
<div id="summary">
|
||||
<p id="totals"> </p>
|
||||
<p id="duration"> </p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="results">
|
||||
EOF
|
||||
end
|
||||
|
||||
def global_scripts
|
||||
<<-EOF
|
||||
function moveProgressBar(percentDone) {
|
||||
document.getElementById("rspec-header").style.width = percentDone +"%";
|
||||
}
|
||||
function makeRed(element_id) {
|
||||
document.getElementById(element_id).style.background = '#C40D0D';
|
||||
document.getElementById(element_id).style.color = '#FFFFFF';
|
||||
}
|
||||
|
||||
function makeYellow(element_id) {
|
||||
if (element_id == "rspec-header" && document.getElementById(element_id).style.background != '#C40D0D')
|
||||
{
|
||||
document.getElementById(element_id).style.background = '#FAF834';
|
||||
document.getElementById(element_id).style.color = '#000000';
|
||||
}
|
||||
else
|
||||
{
|
||||
document.getElementById(element_id).style.background = '#FAF834';
|
||||
document.getElementById(element_id).style.color = '#000000';
|
||||
}
|
||||
}
|
||||
EOF
|
||||
end
|
||||
|
||||
def global_styles
|
||||
<<-EOF
|
||||
#rspec-header {
|
||||
background: #65C400; color: #fff;
|
||||
}
|
||||
|
||||
.rspec-report h1 {
|
||||
margin: 0px 10px 0px 10px;
|
||||
padding: 10px;
|
||||
font-family: "Lucida Grande", Helvetica, sans-serif;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
#summary {
|
||||
margin: 0; padding: 5px 10px;
|
||||
font-family: "Lucida Grande", Helvetica, sans-serif;
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
#summary p {
|
||||
margin: 0 0 0 2px;
|
||||
}
|
||||
|
||||
#summary #totals {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.example_group {
|
||||
margin: 0 10px 5px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin: 0; padding: 0 0 5px;
|
||||
font: normal 11px "Lucida Grande", Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
dt {
|
||||
padding: 3px;
|
||||
background: #65C400;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin: 5px 0 5px 5px;
|
||||
padding: 3px 3px 3px 18px;
|
||||
}
|
||||
|
||||
dd.spec.passed {
|
||||
border-left: 5px solid #65C400;
|
||||
border-bottom: 1px solid #65C400;
|
||||
background: #DBFFB4; color: #3D7700;
|
||||
}
|
||||
|
||||
dd.spec.failed {
|
||||
border-left: 5px solid #C20000;
|
||||
border-bottom: 1px solid #C20000;
|
||||
color: #C20000; background: #FFFBD3;
|
||||
}
|
||||
|
||||
dd.spec.not_implemented {
|
||||
border-left: 5px solid #FAF834;
|
||||
border-bottom: 1px solid #FAF834;
|
||||
background: #FCFB98; color: #131313;
|
||||
}
|
||||
|
||||
dd.spec.pending_fixed {
|
||||
border-left: 5px solid #0000C2;
|
||||
border-bottom: 1px solid #0000C2;
|
||||
color: #0000C2; background: #D3FBFF;
|
||||
}
|
||||
|
||||
.backtrace {
|
||||
color: #000;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #BE5C00;
|
||||
}
|
||||
|
||||
/* Ruby code, style similar to vibrant ink */
|
||||
.ruby {
|
||||
font-size: 12px;
|
||||
font-family: monospace;
|
||||
color: white;
|
||||
background-color: black;
|
||||
padding: 0.1em 0 0.2em 0;
|
||||
}
|
||||
|
||||
.ruby .keyword { color: #FF6600; }
|
||||
.ruby .constant { color: #339999; }
|
||||
.ruby .attribute { color: white; }
|
||||
.ruby .global { color: white; }
|
||||
.ruby .module { color: white; }
|
||||
.ruby .class { color: white; }
|
||||
.ruby .string { color: #66FF00; }
|
||||
.ruby .ident { color: white; }
|
||||
.ruby .method { color: #FFCC00; }
|
||||
.ruby .number { color: white; }
|
||||
.ruby .char { color: white; }
|
||||
.ruby .comment { color: #9933CC; }
|
||||
.ruby .symbol { color: white; }
|
||||
.ruby .regex { color: #44B4CC; }
|
||||
.ruby .punct { color: white; }
|
||||
.ruby .escape { color: white; }
|
||||
.ruby .interp { color: white; }
|
||||
.ruby .expr { color: white; }
|
||||
|
||||
.ruby .offending { background-color: gray; }
|
||||
.ruby .linenum {
|
||||
width: 75px;
|
||||
padding: 0.1em 1em 0.2em 0;
|
||||
color: #000000;
|
||||
background-color: #FFFBD3;
|
||||
}
|
||||
EOF
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
65
vendor/plugins/rspec/lib/spec/runner/formatter/nested_text_formatter.rb
vendored
Normal file
65
vendor/plugins/rspec/lib/spec/runner/formatter/nested_text_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class NestedTextFormatter < BaseTextFormatter
|
||||
attr_reader :previous_nested_example_groups
|
||||
def initialize(options, where)
|
||||
super
|
||||
@previous_nested_example_groups = []
|
||||
end
|
||||
|
||||
def add_example_group(example_group)
|
||||
super
|
||||
|
||||
current_nested_example_groups = described_example_group_chain
|
||||
current_nested_example_groups.each_with_index do |nested_example_group, i|
|
||||
unless nested_example_group == previous_nested_example_groups[i]
|
||||
output.puts "#{' ' * i}#{nested_example_group.description_args}"
|
||||
end
|
||||
end
|
||||
|
||||
@previous_nested_example_groups = described_example_group_chain
|
||||
end
|
||||
|
||||
def example_failed(example, counter, failure)
|
||||
message = if failure.expectation_not_met?
|
||||
"#{current_indentation}#{example.description} (FAILED - #{counter})"
|
||||
else
|
||||
"#{current_indentation}#{example.description} (ERROR - #{counter})"
|
||||
end
|
||||
|
||||
output.puts(failure.expectation_not_met? ? red(message) : magenta(message))
|
||||
output.flush
|
||||
end
|
||||
|
||||
def example_passed(example)
|
||||
message = "#{current_indentation}#{example.description}"
|
||||
output.puts green(message)
|
||||
output.flush
|
||||
end
|
||||
|
||||
def example_pending(example, message)
|
||||
super
|
||||
output.puts yellow("#{current_indentation}#{example.description} (PENDING: #{message})")
|
||||
output.flush
|
||||
end
|
||||
|
||||
def current_indentation
|
||||
' ' * previous_nested_example_groups.length
|
||||
end
|
||||
|
||||
def described_example_group_chain
|
||||
example_group_chain = []
|
||||
example_group.send(:execute_in_class_hierarchy) do |parent_example_group|
|
||||
if parent_example_group.description_args && !parent_example_group.description_args.empty?
|
||||
example_group_chain << parent_example_group
|
||||
end
|
||||
end
|
||||
example_group_chain
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
51
vendor/plugins/rspec/lib/spec/runner/formatter/profile_formatter.rb
vendored
Normal file
51
vendor/plugins/rspec/lib/spec/runner/formatter/profile_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
require 'spec/runner/formatter/progress_bar_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class ProfileFormatter < ProgressBarFormatter
|
||||
|
||||
def initialize(options, where)
|
||||
super
|
||||
@example_times = []
|
||||
end
|
||||
|
||||
def start(count)
|
||||
@output.puts "Profiling enabled."
|
||||
end
|
||||
|
||||
def example_started(example)
|
||||
@time = Time.now
|
||||
end
|
||||
|
||||
def example_passed(example)
|
||||
super
|
||||
@example_times << [
|
||||
example_group.description,
|
||||
example.description,
|
||||
Time.now - @time
|
||||
]
|
||||
end
|
||||
|
||||
def start_dump
|
||||
super
|
||||
@output.puts "\n\nTop 10 slowest examples:\n"
|
||||
|
||||
@example_times = @example_times.sort_by do |description, example, time|
|
||||
time
|
||||
end.reverse
|
||||
|
||||
@example_times[0..9].each do |description, example, time|
|
||||
@output.print red(sprintf("%.7f", time))
|
||||
@output.puts " #{description} #{example}"
|
||||
end
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def method_missing(sym, *args)
|
||||
# ignore
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
34
vendor/plugins/rspec/lib/spec/runner/formatter/progress_bar_formatter.rb
vendored
Normal file
34
vendor/plugins/rspec/lib/spec/runner/formatter/progress_bar_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class ProgressBarFormatter < BaseTextFormatter
|
||||
def example_failed(example, counter, failure)
|
||||
@output.print colourise('F', failure)
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def example_passed(example)
|
||||
@output.print green('.')
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def example_pending(example, message)
|
||||
super
|
||||
@output.print yellow('P')
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def start_dump
|
||||
@output.puts
|
||||
@output.flush
|
||||
end
|
||||
|
||||
def method_missing(sym, *args)
|
||||
# ignore
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
52
vendor/plugins/rspec/lib/spec/runner/formatter/snippet_extractor.rb
vendored
Normal file
52
vendor/plugins/rspec/lib/spec/runner/formatter/snippet_extractor.rb
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
# This class extracts code snippets by looking at the backtrace of the passed error
|
||||
class SnippetExtractor #:nodoc:
|
||||
class NullConverter; def convert(code, pre); code; end; end #:nodoc:
|
||||
begin; require 'rubygems'; require 'syntax/convertors/html'; @@converter = Syntax::Convertors::HTML.for_syntax "ruby"; rescue LoadError => e; @@converter = NullConverter.new; end
|
||||
|
||||
def snippet(error)
|
||||
raw_code, line = snippet_for(error.backtrace[0])
|
||||
highlighted = @@converter.convert(raw_code, false)
|
||||
highlighted << "\n<span class=\"comment\"># gem install syntax to get syntax highlighting</span>" if @@converter.is_a?(NullConverter)
|
||||
post_process(highlighted, line)
|
||||
end
|
||||
|
||||
def snippet_for(error_line)
|
||||
if error_line =~ /(.*):(\d+)/
|
||||
file = $1
|
||||
line = $2.to_i
|
||||
[lines_around(file, line), line]
|
||||
else
|
||||
["# Couldn't get snippet for #{error_line}", 1]
|
||||
end
|
||||
end
|
||||
|
||||
def lines_around(file, line)
|
||||
if File.file?(file)
|
||||
lines = File.open(file).read.split("\n")
|
||||
min = [0, line-3].max
|
||||
max = [line+1, lines.length-1].min
|
||||
selected_lines = []
|
||||
selected_lines.join("\n")
|
||||
lines[min..max].join("\n")
|
||||
else
|
||||
"# Couldn't get snippet for #{file}"
|
||||
end
|
||||
end
|
||||
|
||||
def post_process(highlighted, offending_line)
|
||||
new_lines = []
|
||||
highlighted.split("\n").each_with_index do |line, i|
|
||||
new_line = "<span class=\"linenum\">#{offending_line+i-2}</span>#{line}"
|
||||
new_line = "<span class=\"offending\">#{new_line}</span>" if i == 2
|
||||
new_lines << new_line
|
||||
end
|
||||
new_lines.join("\n")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
39
vendor/plugins/rspec/lib/spec/runner/formatter/specdoc_formatter.rb
vendored
Normal file
39
vendor/plugins/rspec/lib/spec/runner/formatter/specdoc_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class SpecdocFormatter < BaseTextFormatter
|
||||
def add_example_group(example_group)
|
||||
super
|
||||
output.puts
|
||||
output.puts example_group.description
|
||||
output.flush
|
||||
end
|
||||
|
||||
def example_failed(example, counter, failure)
|
||||
message = if failure.expectation_not_met?
|
||||
"- #{example.description} (FAILED - #{counter})"
|
||||
else
|
||||
"- #{example.description} (ERROR - #{counter})"
|
||||
end
|
||||
|
||||
output.puts(failure.expectation_not_met? ? red(message) : magenta(message))
|
||||
output.flush
|
||||
end
|
||||
|
||||
def example_passed(example)
|
||||
message = "- #{example.description}"
|
||||
output.puts green(message)
|
||||
output.flush
|
||||
end
|
||||
|
||||
def example_pending(example, message)
|
||||
super
|
||||
output.puts yellow("- #{example.description} (PENDING: #{message})")
|
||||
output.flush
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
161
vendor/plugins/rspec/lib/spec/runner/formatter/story/html_formatter.rb
vendored
Normal file
161
vendor/plugins/rspec/lib/spec/runner/formatter/story/html_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
require 'erb'
|
||||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
module Story
|
||||
class HtmlFormatter < BaseTextFormatter
|
||||
include ERB::Util
|
||||
|
||||
def initialize(options, where)
|
||||
super
|
||||
@previous_type = nil
|
||||
@scenario_text = ""
|
||||
@story_text = ""
|
||||
@scenario_failed = false
|
||||
@story_failed = false
|
||||
end
|
||||
|
||||
def run_started(count)
|
||||
@output.puts <<-EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>Stories</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="Expires" content="-1" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<script src="javascripts/prototype.js" type="text/javascript"></script>
|
||||
<script src="javascripts/scriptaculous.js" type="text/javascript"></script>
|
||||
<script src="javascripts/rspec.js" type="text/javascript"></script>
|
||||
<link href="stylesheets/rspec.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
EOF
|
||||
end
|
||||
|
||||
def collected_steps(steps)
|
||||
unless steps.empty?
|
||||
@output.puts " <ul id=\"stock_steps\" style=\"display: none;\">"
|
||||
steps.each do |step|
|
||||
@output.puts " <li>#{step}</li>"
|
||||
end
|
||||
@output.puts " </ul>"
|
||||
end
|
||||
end
|
||||
|
||||
def run_ended
|
||||
@output.puts <<-EOF
|
||||
</div>
|
||||
</body>
|
||||
</head>
|
||||
EOF
|
||||
end
|
||||
|
||||
def story_started(title, narrative)
|
||||
@story_failed = false
|
||||
@story_text = <<-EOF
|
||||
<dt>Story: #{h title}</dt>
|
||||
<dd>
|
||||
<p>
|
||||
#{h(narrative).split("\n").join("<br />")}
|
||||
</p>
|
||||
EOF
|
||||
end
|
||||
|
||||
def story_ended(title, narrative)
|
||||
if @story_failed
|
||||
@output.puts <<-EOF
|
||||
<dl class="story failed">
|
||||
EOF
|
||||
else
|
||||
@output.puts <<-EOF
|
||||
<dl class="story passed">
|
||||
EOF
|
||||
end
|
||||
@output.puts <<-EOF
|
||||
#{@story_text}
|
||||
</dd>
|
||||
</dl>
|
||||
EOF
|
||||
end
|
||||
|
||||
def scenario_started(story_title, scenario_name)
|
||||
@scenario_failed = false
|
||||
@scenario_text = <<-EOF
|
||||
<dt>Scenario: #{h scenario_name}</dt>
|
||||
<dd>
|
||||
<ul class="steps">
|
||||
EOF
|
||||
end
|
||||
|
||||
def scenario_ended
|
||||
if @scenario_failed
|
||||
@story_text += <<-EOF
|
||||
<dl class="failed">
|
||||
EOF
|
||||
else
|
||||
@story_text += <<-EOF
|
||||
<dl class="passed">
|
||||
EOF
|
||||
end
|
||||
|
||||
@story_text += <<-EOF
|
||||
#{@scenario_text}
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
EOF
|
||||
end
|
||||
|
||||
def found_scenario(type, description)
|
||||
end
|
||||
|
||||
def scenario_succeeded(story_title, scenario_name)
|
||||
scenario_ended
|
||||
end
|
||||
|
||||
def scenario_pending(story_title, scenario_name, reason)
|
||||
scenario_ended
|
||||
end
|
||||
|
||||
def scenario_failed(story_title, scenario_name, err)
|
||||
@scenario_failed = true
|
||||
@story_failed = true
|
||||
scenario_ended
|
||||
end
|
||||
|
||||
def step_upcoming(type, description, *args)
|
||||
end
|
||||
|
||||
def step_succeeded(type, description, *args)
|
||||
print_step('passed', type, description, *args) # TODO: uses succeeded CSS class
|
||||
end
|
||||
|
||||
def step_pending(type, description, *args)
|
||||
print_step('pending', type, description, *args)
|
||||
end
|
||||
|
||||
def step_failed(type, description, *args)
|
||||
print_step('failed', type, description, *args)
|
||||
end
|
||||
|
||||
def print_step(klass, type, description, *args)
|
||||
spans = args.map { |arg| "<span class=\"param\">#{arg}</span>" }
|
||||
desc_string = description.step_name
|
||||
arg_regexp = description.arg_regexp
|
||||
i = -1
|
||||
inner = type.to_s.capitalize + ' ' + desc_string.gsub(arg_regexp) { |param| spans[i+=1] }
|
||||
@scenario_text += " <li class=\"#{klass}\">#{inner}</li>\n"
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
188
vendor/plugins/rspec/lib/spec/runner/formatter/story/plain_text_formatter.rb
vendored
Normal file
188
vendor/plugins/rspec/lib/spec/runner/formatter/story/plain_text_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
require 'spec/runner/formatter/base_text_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
module Story
|
||||
class PlainTextFormatter < BaseTextFormatter
|
||||
def initialize(options, where)
|
||||
super
|
||||
@successful_scenario_count = 0
|
||||
@pending_scenario_count = 0
|
||||
|
||||
@pre_story_pending_count = 0
|
||||
@pre_story_successful_count = 0
|
||||
|
||||
@failed_scenarios = []
|
||||
@pending_steps = []
|
||||
@previous_type = nil
|
||||
|
||||
@scenario_body_text = ""
|
||||
@story_body_text = ""
|
||||
|
||||
@scenario_head_text = ""
|
||||
@story_head_text = ""
|
||||
|
||||
@scenario_failed = false
|
||||
@story_failed = false
|
||||
end
|
||||
|
||||
def run_started(count)
|
||||
@count = count
|
||||
@output.puts "Running #@count scenarios\n\n"
|
||||
end
|
||||
|
||||
def story_started(title, narrative)
|
||||
@pre_story_pending_count = @pending_scenario_count
|
||||
@pre_story_successful_count = @successful_scenario_count
|
||||
|
||||
@current_story_title = title
|
||||
@story_failed = false
|
||||
@story_body_text = ""
|
||||
@story_head_text = "Story: #{title}\n\n"
|
||||
|
||||
narrative.each_line do |line|
|
||||
@story_head_text += " "
|
||||
@story_head_text += line
|
||||
end
|
||||
end
|
||||
|
||||
def story_ended(title, narrative)
|
||||
if @story_failed
|
||||
@output.print red(@story_head_text)
|
||||
elsif @pre_story_successful_count == @successful_scenario_count &&
|
||||
@pending_scenario_count >= @pre_story_pending_count
|
||||
@output.print yellow(@story_head_text)
|
||||
else
|
||||
@output.print green(@story_head_text)
|
||||
end
|
||||
@output.print @story_body_text
|
||||
@output.puts
|
||||
@output.puts
|
||||
end
|
||||
|
||||
def scenario_started(story_title, scenario_name)
|
||||
@current_scenario_name = scenario_name
|
||||
@scenario_already_failed = false
|
||||
@scenario_head_text = "\n\n Scenario: #{scenario_name}"
|
||||
@scenario_body_text = ""
|
||||
@scenario_ok = true
|
||||
@scenario_pending = false
|
||||
@scenario_failed = false
|
||||
end
|
||||
|
||||
def scenario_succeeded(story_title, scenario_name)
|
||||
@successful_scenario_count += 1
|
||||
scenario_ended
|
||||
end
|
||||
|
||||
def scenario_failed(story_title, scenario_name, err)
|
||||
@options.backtrace_tweaker.tweak_backtrace(err)
|
||||
@failed_scenarios << [story_title, scenario_name, err] unless @scenario_already_failed
|
||||
@scenario_already_failed = true
|
||||
@story_failed = true
|
||||
@scenario_failed = true
|
||||
scenario_ended
|
||||
end
|
||||
|
||||
def scenario_pending(story_title, scenario_name, msg)
|
||||
@pending_scenario_count += 1 unless @scenario_already_failed
|
||||
@scenario_pending = true
|
||||
@scenario_already_failed = true
|
||||
scenario_ended
|
||||
end
|
||||
|
||||
def scenario_ended
|
||||
if @scenario_failed
|
||||
@story_body_text += red(@scenario_head_text)
|
||||
elsif @scenario_pending
|
||||
@story_body_text += yellow(@scenario_head_text)
|
||||
else
|
||||
@story_body_text += green(@scenario_head_text)
|
||||
end
|
||||
@story_body_text += @scenario_body_text
|
||||
end
|
||||
|
||||
def run_ended
|
||||
@output.puts "#@count scenarios: #@successful_scenario_count succeeded, #{@failed_scenarios.size} failed, #@pending_scenario_count pending"
|
||||
unless @pending_steps.empty?
|
||||
@output.puts "\nPending Steps:"
|
||||
@pending_steps.each_with_index do |pending, i|
|
||||
story_name, scenario_name, msg = pending
|
||||
@output.puts "#{i+1}) #{story_name} (#{scenario_name}): #{msg}"
|
||||
end
|
||||
end
|
||||
unless @failed_scenarios.empty?
|
||||
@output.print "\nFAILURES:"
|
||||
@failed_scenarios.each_with_index do |failure, i|
|
||||
title, scenario_name, err = failure
|
||||
@output.print %[
|
||||
#{i+1}) #{title} (#{scenario_name}) FAILED
|
||||
#{err.class}: #{err.message}
|
||||
#{err.backtrace.join("\n")}
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def step_upcoming(type, description, *args)
|
||||
end
|
||||
|
||||
def step_succeeded(type, description, *args)
|
||||
found_step(type, description, false, false, *args)
|
||||
end
|
||||
|
||||
def step_pending(type, description, *args)
|
||||
found_step(type, description, false, true, *args)
|
||||
@pending_steps << [@current_story_title, @current_scenario_name, description]
|
||||
@scenario_body_text += yellow(" (PENDING)")
|
||||
@scenario_pending = true
|
||||
@scenario_ok = false
|
||||
end
|
||||
|
||||
def step_failed(type, description, *args)
|
||||
found_step(type, description, true, @scenario_pending, *args)
|
||||
if @scenario_pending
|
||||
@scenario_body_text += yellow(" (SKIPPED)")
|
||||
else
|
||||
@scenario_body_text += red(@scenario_ok ? " (FAILED)" : " (SKIPPED)")
|
||||
end
|
||||
@scenario_ok = false
|
||||
end
|
||||
|
||||
def collected_steps(steps)
|
||||
end
|
||||
|
||||
def method_missing(sym, *args, &block) #:nodoc:
|
||||
# noop - ignore unknown messages
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def found_step(type, description, failed, pending, *args)
|
||||
desc_string = description.step_name
|
||||
arg_regexp = description.arg_regexp
|
||||
text = if(type == @previous_type)
|
||||
"\n And "
|
||||
else
|
||||
"\n\n #{type.to_s.capitalize} "
|
||||
end
|
||||
i = -1
|
||||
text << desc_string.gsub(arg_regexp) { |param| args[i+=1] }
|
||||
if pending
|
||||
@scenario_body_text += yellow(text)
|
||||
else
|
||||
@scenario_body_text += (failed ? red(text) : green(text))
|
||||
end
|
||||
|
||||
if type == :'given scenario'
|
||||
@previous_type = :given
|
||||
else
|
||||
@previous_type = type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
16
vendor/plugins/rspec/lib/spec/runner/formatter/text_mate_formatter.rb
vendored
Normal file
16
vendor/plugins/rspec/lib/spec/runner/formatter/text_mate_formatter.rb
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
require 'spec/runner/formatter/html_formatter'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
# Formats backtraces so they're clickable by TextMate
|
||||
class TextMateFormatter < HtmlFormatter
|
||||
def backtrace_line(line)
|
||||
line.gsub(/([^:]*\.rb):(\d*)/) do
|
||||
"<a href=\"txmt://open?url=file://#{File.expand_path($1)}&line=#{$2}\">#{$1}:#{$2}</a> "
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
72
vendor/plugins/rspec/lib/spec/runner/heckle_runner.rb
vendored
Normal file
72
vendor/plugins/rspec/lib/spec/runner/heckle_runner.rb
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
begin
|
||||
require 'rubygems'
|
||||
require 'heckle'
|
||||
rescue LoadError ; raise "You must gem install heckle to use --heckle" ; end
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
# Creates a new Heckler configured to heckle all methods in the classes
|
||||
# whose name matches +filter+
|
||||
class HeckleRunner
|
||||
def initialize(filter, heckle_class=Heckler)
|
||||
@filter = filter
|
||||
@heckle_class = heckle_class
|
||||
end
|
||||
|
||||
# Runs all the example groups held by +rspec_options+ once for each of the
|
||||
# methods in the matched classes.
|
||||
def heckle_with
|
||||
if @filter =~ /(.*)[#\.](.*)/
|
||||
heckle_method($1, $2)
|
||||
else
|
||||
heckle_class_or_module(@filter)
|
||||
end
|
||||
end
|
||||
|
||||
def heckle_method(class_name, method_name)
|
||||
verify_constant(class_name)
|
||||
heckle = @heckle_class.new(class_name, method_name, rspec_options)
|
||||
heckle.validate
|
||||
end
|
||||
|
||||
def heckle_class_or_module(class_or_module_name)
|
||||
verify_constant(class_or_module_name)
|
||||
pattern = /^#{class_or_module_name}/
|
||||
classes = []
|
||||
ObjectSpace.each_object(Class) do |klass|
|
||||
classes << klass if klass.name =~ pattern
|
||||
end
|
||||
|
||||
classes.each do |klass|
|
||||
klass.instance_methods(false).each do |method_name|
|
||||
heckle = @heckle_class.new(klass.name, method_name, rspec_options)
|
||||
heckle.validate
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def verify_constant(name)
|
||||
begin
|
||||
# This is defined in Heckle
|
||||
name.to_class
|
||||
rescue
|
||||
raise "Heckling failed - \"#{name}\" is not a known class or module"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#Supports Heckle 1.2 and prior (earlier versions used Heckle::Base)
|
||||
class Heckler < (Heckle.const_defined?(:Base) ? Heckle::Base : Heckle)
|
||||
def initialize(klass_name, method_name, rspec_options)
|
||||
super(klass_name, method_name)
|
||||
@rspec_options = rspec_options
|
||||
end
|
||||
|
||||
def tests_pass?
|
||||
success = @rspec_options.run_examples
|
||||
success
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
10
vendor/plugins/rspec/lib/spec/runner/heckle_runner_unsupported.rb
vendored
Normal file
10
vendor/plugins/rspec/lib/spec/runner/heckle_runner_unsupported.rb
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
module Spec
|
||||
module Runner
|
||||
# Dummy implementation for Windows that just fails (Heckle is not supported on Windows)
|
||||
class HeckleRunner
|
||||
def initialize(filter)
|
||||
raise "Heckle not supported on Windows"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
203
vendor/plugins/rspec/lib/spec/runner/option_parser.rb
vendored
Normal file
203
vendor/plugins/rspec/lib/spec/runner/option_parser.rb
vendored
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
require 'optparse'
|
||||
require 'stringio'
|
||||
|
||||
module Spec
|
||||
module Runner
|
||||
class OptionParser < ::OptionParser
|
||||
class << self
|
||||
def parse(args, err, out)
|
||||
parser = new(err, out)
|
||||
parser.parse(args)
|
||||
parser.options
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :options
|
||||
|
||||
OPTIONS = {
|
||||
:pattern => ["-p", "--pattern [PATTERN]","Limit files loaded to those matching this pattern. Defaults to '**/*_spec.rb'",
|
||||
"Separate multiple patterns with commas.",
|
||||
"Applies only to directories named on the command line (files",
|
||||
"named explicitly on the command line will be loaded regardless)."],
|
||||
:diff => ["-D", "--diff [FORMAT]","Show diff of objects that are expected to be equal when they are not",
|
||||
"Builtin formats: unified|u|context|c",
|
||||
"You can also specify a custom differ class",
|
||||
"(in which case you should also specify --require)"],
|
||||
:colour => ["-c", "--colour", "--color", "Show coloured (red/green) output"],
|
||||
:example => ["-e", "--example [NAME|FILE_NAME]", "Execute example(s) with matching name(s). If the argument is",
|
||||
"the path to an existing file (typically generated by a previous",
|
||||
"run using --format failing_examples:file.txt), then the examples",
|
||||
"on each line of thatfile will be executed. If the file is empty,",
|
||||
"all examples will be run (as if --example was not specified).",
|
||||
" ",
|
||||
"If the argument is not an existing file, then it is treated as",
|
||||
"an example name directly, causing RSpec to run just the example",
|
||||
"matching that name"],
|
||||
:specification => ["-s", "--specification [NAME]", "DEPRECATED - use -e instead", "(This will be removed when autotest works with -e)"],
|
||||
:line => ["-l", "--line LINE_NUMBER", Integer, "Execute behaviout or specification at given line.",
|
||||
"(does not work for dynamically generated specs)"],
|
||||
:format => ["-f", "--format FORMAT[:WHERE]","Specifies what format to use for output. Specify WHERE to tell",
|
||||
"the formatter where to write the output. All built-in formats",
|
||||
"expect WHERE to be a file name, and will write to STDOUT if it's",
|
||||
"not specified. The --format option may be specified several times",
|
||||
"if you want several outputs",
|
||||
" ",
|
||||
"Builtin formats for examples: ",
|
||||
"progress|p : Text progress",
|
||||
"profile|o : Text progress with profiling of 10 slowest examples",
|
||||
"specdoc|s : Example doc as text",
|
||||
"indented|i : Example doc as indented text",
|
||||
"html|h : A nice HTML report",
|
||||
"failing_examples|e : Write all failing examples - input for --example",
|
||||
"failing_example_groups|g : Write all failing example groups - input for --example",
|
||||
" ",
|
||||
"Builtin formats for stories: ",
|
||||
"plain|p : Plain Text",
|
||||
"html|h : A nice HTML report",
|
||||
" ",
|
||||
"FORMAT can also be the name of a custom formatter class",
|
||||
"(in which case you should also specify --require to load it)"],
|
||||
:require => ["-r", "--require FILE", "Require FILE before running specs",
|
||||
"Useful for loading custom formatters or other extensions.",
|
||||
"If this option is used it must come before the others"],
|
||||
:backtrace => ["-b", "--backtrace", "Output full backtrace"],
|
||||
:loadby => ["-L", "--loadby STRATEGY", "Specify the strategy by which spec files should be loaded.",
|
||||
"STRATEGY can currently only be 'mtime' (File modification time)",
|
||||
"By default, spec files are loaded in alphabetical order if --loadby",
|
||||
"is not specified."],
|
||||
:reverse => ["-R", "--reverse", "Run examples in reverse order"],
|
||||
:timeout => ["-t", "--timeout FLOAT", "Interrupt and fail each example that doesn't complete in the",
|
||||
"specified time"],
|
||||
:heckle => ["-H", "--heckle CODE", "If all examples pass, this will mutate the classes and methods",
|
||||
"identified by CODE little by little and run all the examples again",
|
||||
"for each mutation. The intent is that for each mutation, at least",
|
||||
"one example *should* fail, and RSpec will tell you if this is not the",
|
||||
"case. CODE should be either Some::Module, Some::Class or",
|
||||
"Some::Fabulous#method}"],
|
||||
:dry_run => ["-d", "--dry-run", "Invokes formatters without executing the examples."],
|
||||
:options_file => ["-O", "--options PATH", "Read options from a file"],
|
||||
:generate_options => ["-G", "--generate-options PATH", "Generate an options file for --options"],
|
||||
:runner => ["-U", "--runner RUNNER", "Use a custom Runner."],
|
||||
:drb => ["-X", "--drb", "Run examples via DRb. (For example against script/spec_server)"],
|
||||
:version => ["-v", "--version", "Show version"],
|
||||
:help => ["-h", "--help", "You're looking at it"]
|
||||
}
|
||||
|
||||
def initialize(err, out)
|
||||
super()
|
||||
@error_stream = err
|
||||
@out_stream = out
|
||||
@options = Options.new(@error_stream, @out_stream)
|
||||
|
||||
@file_factory = File
|
||||
|
||||
self.banner = "Usage: spec (FILE|DIRECTORY|GLOB)+ [options]"
|
||||
self.separator ""
|
||||
on(*OPTIONS[:pattern]) {|pattern| @options.filename_pattern = pattern}
|
||||
on(*OPTIONS[:diff]) {|diff| @options.parse_diff(diff)}
|
||||
on(*OPTIONS[:colour]) {@options.colour = true}
|
||||
on(*OPTIONS[:example]) {|example| @options.parse_example(example)}
|
||||
on(*OPTIONS[:specification]) {|example| @options.parse_example(example)}
|
||||
on(*OPTIONS[:line]) {|line_number| @options.line_number = line_number.to_i}
|
||||
on(*OPTIONS[:format]) {|format| @options.parse_format(format)}
|
||||
on(*OPTIONS[:require]) {|requires| invoke_requires(requires)}
|
||||
on(*OPTIONS[:backtrace]) {@options.backtrace_tweaker = NoisyBacktraceTweaker.new}
|
||||
on(*OPTIONS[:loadby]) {|loadby| @options.loadby = loadby}
|
||||
on(*OPTIONS[:reverse]) {@options.reverse = true}
|
||||
on(*OPTIONS[:timeout]) {|timeout| @options.timeout = timeout.to_f}
|
||||
on(*OPTIONS[:heckle]) {|heckle| @options.load_heckle_runner(heckle)}
|
||||
on(*OPTIONS[:dry_run]) {@options.dry_run = true}
|
||||
on(*OPTIONS[:options_file]) {|options_file| parse_options_file(options_file)}
|
||||
on(*OPTIONS[:generate_options]) {|options_file|}
|
||||
on(*OPTIONS[:runner]) {|runner| @options.user_input_for_runner = runner}
|
||||
on(*OPTIONS[:drb]) {}
|
||||
on(*OPTIONS[:version]) {parse_version}
|
||||
on_tail(*OPTIONS[:help]) {parse_help}
|
||||
end
|
||||
|
||||
def order!(argv, &blk)
|
||||
@argv = argv
|
||||
@options.argv = @argv.dup
|
||||
return if parse_generate_options
|
||||
return if parse_drb
|
||||
|
||||
super(@argv) do |file|
|
||||
@options.files << file
|
||||
blk.call(file) if blk
|
||||
end
|
||||
|
||||
@options
|
||||
end
|
||||
|
||||
protected
|
||||
def invoke_requires(requires)
|
||||
requires.split(",").each do |file|
|
||||
require file
|
||||
end
|
||||
end
|
||||
|
||||
def parse_options_file(options_file)
|
||||
option_file_args = IO.readlines(options_file).map {|l| l.chomp.split " "}.flatten
|
||||
@argv.push(*option_file_args)
|
||||
# TODO - this is a brute force solution to http://rspec.lighthouseapp.com/projects/5645/tickets/293.
|
||||
# Let's look for a cleaner way. Might not be one. But let's look. If not, perhaps
|
||||
# this can be moved to a different method to indicate the special handling for drb?
|
||||
parse_drb(@argv)
|
||||
end
|
||||
|
||||
def parse_generate_options
|
||||
# Remove the --generate-options option and the argument before writing to file
|
||||
options_file = nil
|
||||
['-G', '--generate-options'].each do |option|
|
||||
if index = @argv.index(option)
|
||||
@argv.delete_at(index)
|
||||
options_file = @argv.delete_at(index)
|
||||
end
|
||||
end
|
||||
|
||||
if options_file
|
||||
write_generated_options(options_file)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def write_generated_options(options_file)
|
||||
File.open(options_file, 'w') do |io|
|
||||
io.puts @argv.join("\n")
|
||||
end
|
||||
@out_stream.puts "\nOptions written to #{options_file}. You can now use these options with:"
|
||||
@out_stream.puts "spec --options #{options_file}"
|
||||
@options.examples_should_not_be_run
|
||||
end
|
||||
|
||||
def parse_drb(argv = nil)
|
||||
argv ||= @options.argv # TODO - see note about about http://rspec.lighthouseapp.com/projects/5645/tickets/293
|
||||
is_drb = false
|
||||
is_drb ||= argv.delete(OPTIONS[:drb][0])
|
||||
is_drb ||= argv.delete(OPTIONS[:drb][1])
|
||||
return false unless is_drb
|
||||
@options.examples_should_not_be_run
|
||||
DrbCommandLine.run(
|
||||
self.class.parse(argv, @error_stream, @out_stream)
|
||||
)
|
||||
true
|
||||
end
|
||||
|
||||
def parse_version
|
||||
@out_stream.puts ::Spec::VERSION::DESCRIPTION
|
||||
exit if stdout?
|
||||
end
|
||||
|
||||
def parse_help
|
||||
@out_stream.puts self
|
||||
exit if stdout?
|
||||
end
|
||||
|
||||
def stdout?
|
||||
@out_stream == $stdout
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
309
vendor/plugins/rspec/lib/spec/runner/options.rb
vendored
Normal file
309
vendor/plugins/rspec/lib/spec/runner/options.rb
vendored
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
module Spec
|
||||
module Runner
|
||||
class Options
|
||||
FILE_SORTERS = {
|
||||
'mtime' => lambda {|file_a, file_b| File.mtime(file_b) <=> File.mtime(file_a)}
|
||||
}
|
||||
|
||||
EXAMPLE_FORMATTERS = { # Load these lazily for better speed
|
||||
'specdoc' => ['spec/runner/formatter/specdoc_formatter', 'Formatter::SpecdocFormatter'],
|
||||
's' => ['spec/runner/formatter/specdoc_formatter', 'Formatter::SpecdocFormatter'],
|
||||
'nested' => ['spec/runner/formatter/nested_text_formatter', 'Formatter::NestedTextFormatter'],
|
||||
'n' => ['spec/runner/formatter/nested_text_formatter', 'Formatter::NestedTextFormatter'],
|
||||
'html' => ['spec/runner/formatter/html_formatter', 'Formatter::HtmlFormatter'],
|
||||
'h' => ['spec/runner/formatter/html_formatter', 'Formatter::HtmlFormatter'],
|
||||
'progress' => ['spec/runner/formatter/progress_bar_formatter', 'Formatter::ProgressBarFormatter'],
|
||||
'p' => ['spec/runner/formatter/progress_bar_formatter', 'Formatter::ProgressBarFormatter'],
|
||||
'failing_examples' => ['spec/runner/formatter/failing_examples_formatter', 'Formatter::FailingExamplesFormatter'],
|
||||
'e' => ['spec/runner/formatter/failing_examples_formatter', 'Formatter::FailingExamplesFormatter'],
|
||||
'failing_example_groups' => ['spec/runner/formatter/failing_example_groups_formatter', 'Formatter::FailingExampleGroupsFormatter'],
|
||||
'g' => ['spec/runner/formatter/failing_example_groups_formatter', 'Formatter::FailingExampleGroupsFormatter'],
|
||||
'profile' => ['spec/runner/formatter/profile_formatter', 'Formatter::ProfileFormatter'],
|
||||
'o' => ['spec/runner/formatter/profile_formatter', 'Formatter::ProfileFormatter'],
|
||||
'textmate' => ['spec/runner/formatter/text_mate_formatter', 'Formatter::TextMateFormatter']
|
||||
}
|
||||
|
||||
STORY_FORMATTERS = {
|
||||
'plain' => ['spec/runner/formatter/story/plain_text_formatter', 'Formatter::Story::PlainTextFormatter'],
|
||||
'p' => ['spec/runner/formatter/story/plain_text_formatter', 'Formatter::Story::PlainTextFormatter'],
|
||||
'html' => ['spec/runner/formatter/story/html_formatter', 'Formatter::Story::HtmlFormatter'],
|
||||
'h' => ['spec/runner/formatter/story/html_formatter', 'Formatter::Story::HtmlFormatter']
|
||||
}
|
||||
|
||||
attr_accessor(
|
||||
:filename_pattern,
|
||||
:backtrace_tweaker,
|
||||
:context_lines,
|
||||
:diff_format,
|
||||
:dry_run,
|
||||
:profile,
|
||||
:examples,
|
||||
:heckle_runner,
|
||||
:line_number,
|
||||
:loadby,
|
||||
:reporter,
|
||||
:reverse,
|
||||
:timeout,
|
||||
:verbose,
|
||||
:user_input_for_runner,
|
||||
:error_stream,
|
||||
:output_stream,
|
||||
:before_suite_parts,
|
||||
:after_suite_parts,
|
||||
# TODO: BT - Figure out a better name
|
||||
:argv
|
||||
)
|
||||
attr_reader :colour, :differ_class, :files, :example_groups
|
||||
|
||||
def initialize(error_stream, output_stream)
|
||||
@error_stream = error_stream
|
||||
@output_stream = output_stream
|
||||
@filename_pattern = "**/*_spec.rb"
|
||||
@backtrace_tweaker = QuietBacktraceTweaker.new
|
||||
@examples = []
|
||||
@colour = false
|
||||
@profile = false
|
||||
@dry_run = false
|
||||
@reporter = Reporter.new(self)
|
||||
@context_lines = 3
|
||||
@diff_format = :unified
|
||||
@files = []
|
||||
@example_groups = []
|
||||
@result = nil
|
||||
@examples_run = false
|
||||
@examples_should_be_run = nil
|
||||
@user_input_for_runner = nil
|
||||
@before_suite_parts = []
|
||||
@after_suite_parts = []
|
||||
end
|
||||
|
||||
def add_example_group(example_group)
|
||||
@example_groups << example_group
|
||||
end
|
||||
|
||||
def remove_example_group(example_group)
|
||||
@example_groups.delete(example_group)
|
||||
end
|
||||
|
||||
def run_examples
|
||||
return true unless examples_should_be_run?
|
||||
success = true
|
||||
begin
|
||||
before_suite_parts.each do |part|
|
||||
part.call
|
||||
end
|
||||
runner = custom_runner || ExampleGroupRunner.new(self)
|
||||
|
||||
unless @files_loaded
|
||||
runner.load_files(files_to_load)
|
||||
@files_loaded = true
|
||||
end
|
||||
|
||||
if example_groups.empty?
|
||||
true
|
||||
else
|
||||
set_spec_from_line_number if line_number
|
||||
success = runner.run
|
||||
@examples_run = true
|
||||
heckle if heckle_runner
|
||||
success
|
||||
end
|
||||
ensure
|
||||
after_suite_parts.each do |part|
|
||||
part.call(success)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def examples_run?
|
||||
@examples_run
|
||||
end
|
||||
|
||||
def examples_should_not_be_run
|
||||
@examples_should_be_run = false
|
||||
end
|
||||
|
||||
def colour=(colour)
|
||||
@colour = colour
|
||||
if @colour && RUBY_PLATFORM =~ /win32/ ;\
|
||||
begin ;\
|
||||
require 'rubygems' ;\
|
||||
require 'Win32/Console/ANSI' ;\
|
||||
rescue LoadError ;\
|
||||
warn "You must 'gem install win32console' to use colour on Windows" ;\
|
||||
@colour = false ;\
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def parse_diff(format)
|
||||
case format
|
||||
when :context, 'context', 'c'
|
||||
@diff_format = :context
|
||||
default_differ
|
||||
when :unified, 'unified', 'u', '', nil
|
||||
@diff_format = :unified
|
||||
default_differ
|
||||
else
|
||||
@diff_format = :custom
|
||||
self.differ_class = load_class(format, 'differ', '--diff')
|
||||
end
|
||||
end
|
||||
|
||||
def parse_example(example)
|
||||
if(File.file?(example))
|
||||
@examples = File.open(example).read.split("\n")
|
||||
else
|
||||
@examples = [example]
|
||||
end
|
||||
end
|
||||
|
||||
def parse_format(format_arg)
|
||||
format, where = ClassAndArgumentsParser.parse(format_arg)
|
||||
unless where
|
||||
raise "When using several --format options only one of them can be without a file" if @out_used
|
||||
where = @output_stream
|
||||
@out_used = true
|
||||
end
|
||||
@format_options ||= []
|
||||
@format_options << [format, where]
|
||||
end
|
||||
|
||||
def formatters
|
||||
@format_options ||= [['progress', @output_stream]]
|
||||
@formatters ||= load_formatters(@format_options, EXAMPLE_FORMATTERS)
|
||||
end
|
||||
|
||||
def story_formatters
|
||||
@format_options ||= [['plain', @output_stream]]
|
||||
@formatters ||= load_formatters(@format_options, STORY_FORMATTERS)
|
||||
end
|
||||
|
||||
def load_formatters(format_options, formatters)
|
||||
format_options.map do |format, where|
|
||||
formatter_type = if formatters[format]
|
||||
require formatters[format][0]
|
||||
eval(formatters[format][1], binding, __FILE__, __LINE__)
|
||||
else
|
||||
load_class(format, 'formatter', '--format')
|
||||
end
|
||||
formatter_type.new(self, where)
|
||||
end
|
||||
end
|
||||
|
||||
def load_heckle_runner(heckle)
|
||||
suffix = [/mswin/, /java/].detect{|p| p =~ RUBY_PLATFORM} ? '_unsupported' : ''
|
||||
require "spec/runner/heckle_runner#{suffix}"
|
||||
@heckle_runner = HeckleRunner.new(heckle)
|
||||
end
|
||||
|
||||
def number_of_examples
|
||||
total = 0
|
||||
@example_groups.each do |example_group|
|
||||
total += example_group.number_of_examples
|
||||
end
|
||||
total
|
||||
end
|
||||
|
||||
def files_to_load
|
||||
result = []
|
||||
sorted_files.each do |file|
|
||||
if File.directory?(file)
|
||||
filename_pattern.split(",").each do |pattern|
|
||||
result += Dir[File.expand_path("#{file}/#{pattern.strip}")]
|
||||
end
|
||||
elsif File.file?(file)
|
||||
result << file
|
||||
else
|
||||
raise "File or directory not found: #{file}"
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
protected
|
||||
def examples_should_be_run?
|
||||
return @examples_should_be_run unless @examples_should_be_run.nil?
|
||||
@examples_should_be_run = true
|
||||
end
|
||||
|
||||
def differ_class=(klass)
|
||||
return unless klass
|
||||
@differ_class = klass
|
||||
Spec::Expectations.differ = self.differ_class.new(self)
|
||||
end
|
||||
|
||||
def load_class(name, kind, option)
|
||||
if name =~ /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/
|
||||
arg = $2 == "" ? nil : $2
|
||||
[$1, arg]
|
||||
else
|
||||
m = "#{name.inspect} is not a valid class name"
|
||||
@error_stream.puts m
|
||||
raise m
|
||||
end
|
||||
begin
|
||||
eval(name, binding, __FILE__, __LINE__)
|
||||
rescue NameError => e
|
||||
@error_stream.puts "Couldn't find #{kind} class #{name}"
|
||||
@error_stream.puts "Make sure the --require option is specified *before* #{option}"
|
||||
if $_spec_spec ; raise e ; else exit(1) ; end
|
||||
end
|
||||
end
|
||||
|
||||
def custom_runner
|
||||
return nil unless custom_runner?
|
||||
klass_name, arg = ClassAndArgumentsParser.parse(user_input_for_runner)
|
||||
runner_type = load_class(klass_name, 'behaviour runner', '--runner')
|
||||
return runner_type.new(self, arg)
|
||||
end
|
||||
|
||||
def custom_runner?
|
||||
return user_input_for_runner ? true : false
|
||||
end
|
||||
|
||||
def heckle
|
||||
heckle_runner = self.heckle_runner
|
||||
self.heckle_runner = nil
|
||||
heckle_runner.heckle_with
|
||||
end
|
||||
|
||||
def sorted_files
|
||||
return sorter ? files.sort(&sorter) : files
|
||||
end
|
||||
|
||||
def sorter
|
||||
FILE_SORTERS[loadby]
|
||||
end
|
||||
|
||||
def default_differ
|
||||
require 'spec/expectations/differs/default'
|
||||
self.differ_class = Spec::Expectations::Differs::Default
|
||||
end
|
||||
|
||||
def set_spec_from_line_number
|
||||
if examples.empty?
|
||||
if files.length == 1
|
||||
if File.directory?(files[0])
|
||||
error_stream.puts "You must specify one file, not a directory when using the --line option"
|
||||
exit(1) if stderr?
|
||||
else
|
||||
example = SpecParser.new.spec_name_for(files[0], line_number)
|
||||
@examples = [example]
|
||||
end
|
||||
else
|
||||
error_stream.puts "Only one file can be specified when using the --line option: #{files.inspect}"
|
||||
exit(3) if stderr?
|
||||
end
|
||||
else
|
||||
error_stream.puts "You cannot use both --line and --example"
|
||||
exit(4) if stderr?
|
||||
end
|
||||
end
|
||||
|
||||
def stderr?
|
||||
@error_stream == $stderr
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
147
vendor/plugins/rspec/lib/spec/runner/reporter.rb
vendored
Normal file
147
vendor/plugins/rspec/lib/spec/runner/reporter.rb
vendored
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
module Spec
|
||||
module Runner
|
||||
class Reporter
|
||||
attr_reader :options, :example_groups
|
||||
|
||||
def initialize(options)
|
||||
@options = options
|
||||
@options.reporter = self
|
||||
clear
|
||||
end
|
||||
|
||||
def add_example_group(example_group)
|
||||
formatters.each do |f|
|
||||
f.add_example_group(example_group)
|
||||
end
|
||||
example_groups << example_group
|
||||
end
|
||||
|
||||
def example_started(example)
|
||||
formatters.each{|f| f.example_started(example)}
|
||||
end
|
||||
|
||||
def example_finished(example, error=nil)
|
||||
@examples << example
|
||||
|
||||
if error.nil?
|
||||
example_passed(example)
|
||||
elsif Spec::Example::ExamplePendingError === error
|
||||
example_pending(example, error.message)
|
||||
else
|
||||
example_failed(example, error)
|
||||
end
|
||||
end
|
||||
|
||||
def failure(example, error)
|
||||
backtrace_tweaker.tweak_backtrace(error)
|
||||
failure = Failure.new(example, error)
|
||||
@failures << failure
|
||||
formatters.each do |f|
|
||||
f.example_failed(example, @failures.length, failure)
|
||||
end
|
||||
end
|
||||
alias_method :example_failed, :failure
|
||||
|
||||
def start(number_of_examples)
|
||||
clear
|
||||
@start_time = Time.new
|
||||
formatters.each{|f| f.start(number_of_examples)}
|
||||
end
|
||||
|
||||
def end
|
||||
@end_time = Time.new
|
||||
end
|
||||
|
||||
# Dumps the summary and returns the total number of failures
|
||||
def dump
|
||||
formatters.each{|f| f.start_dump}
|
||||
dump_pending
|
||||
dump_failures
|
||||
formatters.each do |f|
|
||||
f.dump_summary(duration, @examples.length, @failures.length, @pending_count)
|
||||
f.close
|
||||
end
|
||||
@failures.length
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def formatters
|
||||
@options.formatters
|
||||
end
|
||||
|
||||
def backtrace_tweaker
|
||||
@options.backtrace_tweaker
|
||||
end
|
||||
|
||||
def clear
|
||||
@example_groups = []
|
||||
@failures = []
|
||||
@pending_count = 0
|
||||
@examples = []
|
||||
@start_time = nil
|
||||
@end_time = nil
|
||||
end
|
||||
|
||||
def dump_failures
|
||||
return if @failures.empty?
|
||||
@failures.inject(1) do |index, failure|
|
||||
formatters.each{|f| f.dump_failure(index, failure)}
|
||||
index + 1
|
||||
end
|
||||
end
|
||||
|
||||
def dump_pending
|
||||
formatters.each{|f| f.dump_pending}
|
||||
end
|
||||
|
||||
def duration
|
||||
return @end_time - @start_time unless (@end_time.nil? or @start_time.nil?)
|
||||
return "0.0"
|
||||
end
|
||||
|
||||
def example_passed(example)
|
||||
formatters.each{|f| f.example_passed(example)}
|
||||
end
|
||||
|
||||
def example_pending(example, message="Not Yet Implemented")
|
||||
@pending_count += 1
|
||||
formatters.each do |f|
|
||||
f.example_pending(example, message)
|
||||
end
|
||||
end
|
||||
|
||||
class Failure
|
||||
attr_reader :example, :exception
|
||||
|
||||
def initialize(example, exception)
|
||||
@example = example
|
||||
@exception = exception
|
||||
end
|
||||
|
||||
def header
|
||||
if expectation_not_met?
|
||||
"'#{example_name}' FAILED"
|
||||
elsif pending_fixed?
|
||||
"'#{example_name}' FIXED"
|
||||
else
|
||||
"#{@exception.class.name} in '#{example_name}'"
|
||||
end
|
||||
end
|
||||
|
||||
def pending_fixed?
|
||||
@exception.is_a?(Spec::Example::PendingExampleFixedError)
|
||||
end
|
||||
|
||||
def expectation_not_met?
|
||||
@exception.is_a?(Spec::Expectations::ExpectationNotMetError)
|
||||
end
|
||||
|
||||
protected
|
||||
def example_name
|
||||
@example.__full_description
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
71
vendor/plugins/rspec/lib/spec/runner/spec_parser.rb
vendored
Normal file
71
vendor/plugins/rspec/lib/spec/runner/spec_parser.rb
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
module Spec
|
||||
module Runner
|
||||
# Parses a spec file and finds the nearest example for a given line number.
|
||||
class SpecParser
|
||||
attr_reader :best_match
|
||||
|
||||
def initialize
|
||||
@best_match = {}
|
||||
end
|
||||
|
||||
def spec_name_for(file, line_number)
|
||||
best_match.clear
|
||||
file = File.expand_path(file)
|
||||
rspec_options.example_groups.each do |example_group|
|
||||
consider_example_groups_for_best_match example_group, file, line_number
|
||||
|
||||
example_group.examples.each do |example|
|
||||
consider_example_for_best_match example, example_group, file, line_number
|
||||
end
|
||||
end
|
||||
if best_match[:example_group]
|
||||
if best_match[:example]
|
||||
"#{best_match[:example_group].description} #{best_match[:example].description}"
|
||||
else
|
||||
best_match[:example_group].description
|
||||
end
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def consider_example_groups_for_best_match(example_group, file, line_number)
|
||||
parsed_backtrace = parse_backtrace(example_group.registration_backtrace)
|
||||
parsed_backtrace.each do |example_file, example_line|
|
||||
if is_best_match?(file, line_number, example_file, example_line)
|
||||
best_match.clear
|
||||
best_match[:example_group] = example_group
|
||||
best_match[:line] = example_line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def consider_example_for_best_match(example, example_group, file, line_number)
|
||||
parsed_backtrace = parse_backtrace(example.implementation_backtrace)
|
||||
parsed_backtrace.each do |example_file, example_line|
|
||||
if is_best_match?(file, line_number, example_file, example_line)
|
||||
best_match.clear
|
||||
best_match[:example_group] = example_group
|
||||
best_match[:example] = example
|
||||
best_match[:line] = example_line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def is_best_match?(file, line_number, example_file, example_line)
|
||||
file == File.expand_path(example_file) &&
|
||||
example_line <= line_number &&
|
||||
example_line > best_match[:line].to_i
|
||||
end
|
||||
|
||||
def parse_backtrace(backtrace)
|
||||
backtrace.collect do |trace_line|
|
||||
split_line = trace_line.split(':')
|
||||
[split_line[0], Integer(split_line[1])]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue