diff options
Diffstat (limited to 'vendor/plugins/rspec/lib/spec/runner')
22 files changed, 595 insertions, 746 deletions
diff --git a/vendor/plugins/rspec/lib/spec/runner/backtrace_tweaker.rb b/vendor/plugins/rspec/lib/spec/runner/backtrace_tweaker.rb index 587e57d90..a3cb7d9bd 100644 --- a/vendor/plugins/rspec/lib/spec/runner/backtrace_tweaker.rb +++ b/vendor/plugins/rspec/lib/spec/runner/backtrace_tweaker.rb @@ -1,31 +1,53 @@ module Spec module Runner class BacktraceTweaker + def initialize(*patterns) + @ignore_patterns = [] + end + def clean_up_double_slashes(line) line.gsub!('//','/') end - end - class NoisyBacktraceTweaker < BacktraceTweaker + def ignore_patterns(*patterns) + # do nothing. Only QuietBacktraceTweaker ignores patterns. + end + + def ignored_patterns + [] + end + def tweak_backtrace(error) return if error.backtrace.nil? - error.backtrace.each do |line| - clean_up_double_slashes(line) + tweaked = error.backtrace.collect do |message| + clean_up_double_slashes(message) + kept_lines = message.split("\n").select do |line| + ignored_patterns.each do |ignore| + break if line =~ ignore + end + end + kept_lines.empty?? nil : kept_lines.join("\n") end + error.set_backtrace(tweaked.select {|line| line}) end end + class NoisyBacktraceTweaker < BacktraceTweaker + 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] + spec_files = Dir["lib/*"].map do |path| + subpath = path[1..-1] /#{subpath}/ end IGNORE_PATTERNS = spec_files + [ + /\/rspec-[^\/]*\/lib\/spec\//, + /\/spork-[^\/]*\/lib\/spork\//, /\/lib\/ruby\//, /bin\/spec:/, + /bin\/spork:/, /bin\/rcov:/, /lib\/rspec-rails/, /vendor\/rails/, @@ -37,20 +59,18 @@ module Spec /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! + + def initialize(*patterns) + super + ignore_patterns(*patterns) + end + + def ignore_patterns(*patterns) + @ignore_patterns += patterns.flatten.map { |pattern| Regexp.new(pattern) } + end + + def ignored_patterns + IGNORE_PATTERNS + @ignore_patterns end end end diff --git a/vendor/plugins/rspec/lib/spec/runner/class_and_arguments_parser.rb b/vendor/plugins/rspec/lib/spec/runner/class_and_arguments_parser.rb index 65dc4519c..a49ade26e 100644 --- a/vendor/plugins/rspec/lib/spec/runner/class_and_arguments_parser.rb +++ b/vendor/plugins/rspec/lib/spec/runner/class_and_arguments_parser.rb @@ -1,16 +1,14 @@ 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 + def self.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
\ No newline at end of file +end diff --git a/vendor/plugins/rspec/lib/spec/runner/command_line.rb b/vendor/plugins/rspec/lib/spec/runner/command_line.rb index 9849c4853..35a7e3159 100644 --- a/vendor/plugins/rspec/lib/spec/runner/command_line.rb +++ b/vendor/plugins/rspec/lib/spec/runner/command_line.rb @@ -2,26 +2,13 @@ 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 + def self.run(tmp_options=Spec::Runner.options) + orig_options = Spec::Runner.options + Spec::Runner.use tmp_options + tmp_options.run_examples + ensure + Spec::Runner.use orig_options end end end diff --git a/vendor/plugins/rspec/lib/spec/runner/drb_command_line.rb b/vendor/plugins/rspec/lib/spec/runner/drb_command_line.rb index 6c340cfea..058a8e1df 100644 --- a/vendor/plugins/rspec/lib/spec/runner/drb_command_line.rb +++ b/vendor/plugins/rspec/lib/spec/runner/drb_command_line.rb @@ -8,11 +8,17 @@ module Spec # 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://localhost:8989") + begin; \ + DRb.start_service("druby://localhost:0"); \ + rescue SocketError; \ + DRb.start_service("druby://:0"); \ + end + 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 + true + rescue DRb::DRbConnError options.error_stream.puts "No server is running" + false end end end diff --git a/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb b/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb index 7275c6a88..67dc99509 100644 --- a/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb +++ b/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb @@ -6,6 +6,7 @@ module Spec end def load_files(files) + $KCODE = 'u' if RUBY_VERSION.to_f < 1.9 # 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 @@ -19,14 +20,15 @@ module Spec prepare success = true example_groups.each do |example_group| - success = success & example_group.run + success = success & example_group.run(@options) end return success ensure finish end - protected + protected + def prepare reporter.start(number_of_examples) example_groups.reverse! if reverse @@ -53,7 +55,5 @@ module Spec @options.number_of_examples end end - # TODO: BT - Deprecate BehaviourRunner? - BehaviourRunner = ExampleGroupRunner end -end
\ No newline at end of file +end diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/base_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/base_formatter.rb index a1269b513..0fbc12ce4 100644 --- a/vendor/plugins/rspec/lib/spec/runner/formatter/base_formatter.rb +++ b/vendor/plugins/rspec/lib/spec/runner/formatter/base_formatter.rb @@ -1,12 +1,29 @@ module Spec module Runner module Formatter - # Baseclass for formatters that implements all required methods as no-ops. + # Formatter base-class, which implements all required methods as no-ops, with the exception class BaseFormatter - attr_accessor :example_group, :options, :where - def initialize(options, where) - @options = options - @where = where + # Formatters are initialized with <tt>options</tt> and <tt>output</tt> + # arguments. RSpec's built-in formatters already expect this, and any + # custom formatters should as well. + # + # ==== Parameters + # options:: + # A struct containing boolean values for colour, autospec, + # and dry_run + # output:: + # Used by RSpec's built-in formatters to determine where to + # write the output. Default is <tt>STDOUT</tt>, otherwise a + # filename is expected. + # + # === Example + # If you invoke the <tt>spec</tt> command with: + # + # --format progress:progress_report.txt + # + # ... the value of <tt>output</tt> will be progress_report.txt. If you + # don't identify an output destination, the default is STDOUT. + def initialize(options, output) end # This method is invoked before any examples are run, right after @@ -14,42 +31,77 @@ module Spec # 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 + # is #example_group_started + # + # ==== Parameters + # example_count:: the total number of examples to be run 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. + # This method is invoked at the beginning of the execution of each + # example_group. The next method to be invoked after this is + # #example_started # - # The next method to be invoked after this is #example_failed or #example_finished - def add_example_group(example_group) - @example_group = example_group + # ==== Parameters + # example_group_proxy:: instance of Spec::Example::ExampleGroupProxy + def example_group_started(example_group_proxy) + end + + # Deprecated - use example_group_started instead + def add_example_group(example_group_proxy) + Spec.deprecate("BaseFormatter#add_example_group", "BaseFormatter#example_group_started") + example_group_started(example_group_proxy) end - # This method is invoked when an +example+ starts. - def example_started(example) + # This method is invoked when an +example+ starts. The next method to be + # invoked after this is #example_passed, #example_failed, or + # #example_pending + # + # ==== Parameters + # example_proxy:: instance of Spec::Example::ExampleProxy + def example_started(example_proxy) end # This method is invoked when an +example+ passes. - def example_passed(example) + # +example_proxy+ is the same instance of Spec::Example::ExampleProxy + # that was passed to example_started + # + # ==== Parameters + # example_proxy:: instance of Spec::Example::ExampleProxy + def example_passed(example_proxy) 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) + # inside it (such as a failed should or other exception). + # + # ==== Parameters + # example_proxy:: + # The same instance of Spec::Example::ExampleProxy that was passed + # to <tt>example_started</tt> + # + # counter:: the sequential number of this failure + # + # failure:: instance of Spec::Runner::Reporter::Failure + def example_failed(example_proxy, 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) + # default value of "Not Yet Implemented". +deprecated_pending_location+ is + # deprecated - use example_proxy.location instead + # + # ==== Parameters + # example_proxy:: instance of Spec::Example::ExampleProxy + # message:: + # the message passed to the pending message, or an internal + # default + # + def example_pending(example_proxy, message, deprecated_pending_location=nil) 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), + # to be invoked after this one is #dump_failure (once for each failed example) def start_dump end @@ -57,14 +109,24 @@ module Spec # 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. + # + # ==== Parameters + # counter:: the sequential number of this failure + # failure:: instance of Spec::Runner::Reporter::Failure def dump_failure(counter, failure) end # This method is invoked after the dumping of examples and failures. + # + # ==== Parameters + # duration:: the total time for the entire run + # example_count:: the number of examples run + # failure_count:: the number of examples that failed + # pending_count:: the number of examples that are pending def dump_summary(duration, example_count, failure_count, pending_count) end - # This gets invoked after the summary if option is set to do so. + # This gets invoked after the summary def dump_pending end diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/base_text_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/base_text_formatter.rb index bad023db7..ee8db75a4 100644 --- a/vendor/plugins/rspec/lib/spec/runner/formatter/base_text_formatter.rb +++ b/vendor/plugins/rspec/lib/spec/runner/formatter/base_text_formatter.rb @@ -1,4 +1,5 @@ require 'spec/runner/formatter/base_formatter' +require 'fileutils' module Spec module Runner @@ -7,47 +8,47 @@ module Spec # 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 + attr_reader :output, :example_group + # Creates a new instance that will write to +output+. If +output+ 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 + # +output+ is exected to be an IO (or an object that responds to #puts + # and #write). + def initialize(options, output) + @options = options + if String === output + FileUtils.mkdir_p(File.dirname(output)) + @output = File.open(output, 'w') else - @output = where + @output = output end @pending_examples = [] end + + def example_group_started(example_group_proxy) + @example_group = example_group_proxy + end - def example_pending(example, message) - @pending_examples << [example.__full_description, message] + def example_pending(example, message, deprecated_pending_location=nil) + @pending_examples << ["#{@example_group.description} #{example.description}", message, example.location] 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 colorize_failure("#{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 + def colorize_failure(message, failure) + failure.pending_fixed? ? blue(message) : red(message) end - + + def colourise(message, failure) + Spec::deprecate("BaseTextFormatter#colourise", "colorize_failure") + colorize_failure(message, failure) + end + def dump_summary(duration, example_count, failure_count, pending_count) return if dry_run? @output.puts @@ -74,16 +75,15 @@ module Spec @output.puts @output.puts "Pending:" @pending_examples.each do |pending_example| - @output.puts "#{pending_example[0]} (#{pending_example[1]})" + @output.puts "\n#{pending_example[0]} (#{pending_example[1]})" + @output.puts "#{pending_example[2]}\n" end end @output.flush end def close - if IO === @output - @output.close - end + @output.close if (IO === @output) & (@output != $stdout) end def format_backtrace(backtrace) @@ -94,11 +94,15 @@ module Spec protected def colour? - @options.colour ? true : false + !!@options.colour end def dry_run? - @options.dry_run ? true : false + !!@options.dry_run + end + + def autospec? + !!@options.autospec || ENV.has_key?("AUTOTEST") end def backtrace_line(line) @@ -106,13 +110,18 @@ module Spec end def colour(text, colour_code) - return text unless colour? && output_to_tty? + return text if output_to_file? + return text unless ENV['RSPEC_COLOR'] || (colour? & (autospec? || output_to_tty?)) "#{colour_code}#{text}\e[0m" end + def output_to_file? + File === @output + end + def output_to_tty? begin - @output == Kernel || @output.tty? + @output.tty? rescue NoMethodError false end @@ -120,10 +129,13 @@ module Spec 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 + def magenta(text) + Spec::deprecate("BaseTextFormatter#magenta") + red(text) + end end end end diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/failing_example_groups_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/failing_example_groups_formatter.rb index 8d39bc572..31729438b 100644 --- a/vendor/plugins/rspec/lib/spec/runner/formatter/failing_example_groups_formatter.rb +++ b/vendor/plugins/rspec/lib/spec/runner/formatter/failing_example_groups_formatter.rb @@ -6,21 +6,19 @@ module Spec 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.puts @example_group.description.gsub(/ \(druby.*\)/,"") @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 diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/html_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/html_formatter.rb index e5368f2cb..2d0c65d1b 100644 --- a/vendor/plugins/rspec/lib/spec/runner/formatter/html_formatter.rb +++ b/vendor/plugins/rspec/lib/spec/runner/formatter/html_formatter.rb @@ -1,22 +1,21 @@ require 'erb' require 'spec/runner/formatter/base_text_formatter' +require 'spec/runner/formatter/no_op_method_missing' module Spec module Runner module Formatter class HtmlFormatter < BaseTextFormatter include ERB::Util # for the #h method + include NOOPMethodMissing def initialize(options, output) super @example_group_number = 0 @example_number = 0 + @header_red = nil end - def method_missing(sym, *args) - # no-op - end - # The number of the currently running example_group def example_group_number @example_group_number @@ -35,10 +34,9 @@ module Spec @output.flush end - def add_example_group(example_group) + def example_group_started(example_group) super @example_group_red = false - @example_group_red = false @example_group_number += 1 unless example_group_number == 1 @output.puts " </dl>" @@ -85,7 +83,7 @@ module Spec @output.flush end - def example_pending(example, message) + def example_pending(example, message, deprecated_pending_location=nil) @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 @@ -154,14 +152,6 @@ module Spec font-size: 80%; } </style> -</head> -<body> -EOF - end - - def report_header - <<-EOF -<div class="rspec-report"> <script type="text/javascript"> // <![CDATA[ #{global_scripts} @@ -170,9 +160,19 @@ EOF <style type="text/css"> #{global_styles} </style> +</head> +<body> +EOF + end + + def report_header + <<-EOF +<div class="rspec-report"> <div id="rspec-header"> - <h1>RSpec Results</h1> + <div id="label"> + <h1>RSpec Code Examples</h1> + </div> <div id="summary"> <p id="totals"> </p> @@ -212,7 +212,7 @@ EOF def global_styles <<-EOF #rspec-header { - background: #65C400; color: #fff; + background: #65C400; color: #fff; height: 4em; } .rspec-report h1 { @@ -220,15 +220,16 @@ EOF padding: 10px; font-family: "Lucida Grande", Helvetica, sans-serif; font-size: 1.8em; + position: absolute; } #summary { margin: 0; padding: 5px 10px; font-family: "Lucida Grande", Helvetica, sans-serif; text-align: right; - position: absolute; top: 0px; right: 0px; + float:right; } #summary p { diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/nested_text_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/nested_text_formatter.rb index f9aa5f67c..5caec5a4d 100644 --- a/vendor/plugins/rspec/lib/spec/runner/formatter/nested_text_formatter.rb +++ b/vendor/plugins/rspec/lib/spec/runner/formatter/nested_text_formatter.rb @@ -4,33 +4,25 @@ module Spec module Runner module Formatter class NestedTextFormatter < BaseTextFormatter - attr_reader :previous_nested_example_groups def initialize(options, where) super - @previous_nested_example_groups = [] + @last_nested_descriptions = [] end - def add_example_group(example_group) + def example_group_started(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}" + example_group.nested_descriptions.each_with_index do |nested_description, i| + unless nested_description == @last_nested_descriptions[i] + output.puts "#{' ' * i}#{nested_description}" end end - @previous_nested_example_groups = described_example_group_chain + @last_nested_descriptions = example_group.nested_descriptions 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.puts(red("#{current_indentation}#{example.description} (FAILED - #{counter})")) output.flush end @@ -40,24 +32,14 @@ module Spec output.flush end - def example_pending(example, message) + def example_pending(example, message, deprecated_pending_location=nil) 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 + ' ' * @last_nested_descriptions.length end end end diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/profile_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/profile_formatter.rb index 8671d721e..3784f3ac7 100644 --- a/vendor/plugins/rspec/lib/spec/runner/formatter/profile_formatter.rb +++ b/vendor/plugins/rspec/lib/spec/runner/formatter/profile_formatter.rb @@ -41,10 +41,6 @@ module Spec end @output.flush end - - def method_missing(sym, *args) - # ignore - end end end end diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/progress_bar_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/progress_bar_formatter.rb index 032a2872d..862f87a44 100644 --- a/vendor/plugins/rspec/lib/spec/runner/formatter/progress_bar_formatter.rb +++ b/vendor/plugins/rspec/lib/spec/runner/formatter/progress_bar_formatter.rb @@ -1,11 +1,14 @@ require 'spec/runner/formatter/base_text_formatter' +require 'spec/runner/formatter/no_op_method_missing' module Spec module Runner module Formatter class ProgressBarFormatter < BaseTextFormatter + include NOOPMethodMissing + def example_failed(example, counter, failure) - @output.print colourise('F', failure) + @output.print colorize_failure('F', failure) @output.flush end @@ -14,9 +17,9 @@ module Spec @output.flush end - def example_pending(example, message) + def example_pending(example, message, deprecated_pending_location=nil) super - @output.print yellow('P') + @output.print yellow('*') @output.flush end @@ -24,10 +27,6 @@ module Spec @output.puts @output.flush end - - def method_missing(sym, *args) - # ignore - end end end end diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/snippet_extractor.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/snippet_extractor.rb index 41119fe46..4f34e5fee 100644 --- a/vendor/plugins/rspec/lib/spec/runner/formatter/snippet_extractor.rb +++ b/vendor/plugins/rspec/lib/spec/runner/formatter/snippet_extractor.rb @@ -4,7 +4,7 @@ module Spec # 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 + begin; 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]) diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/specdoc_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/specdoc_formatter.rb index facf1a65a..7204f2147 100644 --- a/vendor/plugins/rspec/lib/spec/runner/formatter/specdoc_formatter.rb +++ b/vendor/plugins/rspec/lib/spec/runner/formatter/specdoc_formatter.rb @@ -4,7 +4,7 @@ module Spec module Runner module Formatter class SpecdocFormatter < BaseTextFormatter - def add_example_group(example_group) + def example_group_started(example_group) super output.puts output.puts example_group.description @@ -12,13 +12,7 @@ module Spec 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.puts(red("- #{example.description} (FAILED - #{counter})")) output.flush end @@ -28,7 +22,7 @@ module Spec output.flush end - def example_pending(example, message) + def example_pending(example, message, deprecated_pending_location=nil) super output.puts yellow("- #{example.description} (PENDING: #{message})") output.flush diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/story/html_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/story/html_formatter.rb deleted file mode 100644 index 5a8134683..000000000 --- a/vendor/plugins/rspec/lib/spec/runner/formatter/story/html_formatter.rb +++ /dev/null @@ -1,128 +0,0 @@ -require 'erb' -require 'spec/runner/formatter/base_text_formatter' - -module Spec - module Runner - module Formatter - module Story - class HtmlFormatter < BaseTextFormatter - include ERB::Util - - 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) - @output.puts <<-EOF - <dl class="story passed"> - <dt>Story: #{h title}</dt> - <dd> - <p> - #{h(narrative).split("\n").join("<br />")} - </p> -EOF - end - - def story_ended(title, narrative) - @output.puts <<-EOF - </dd> - </dl> -EOF - end - - def scenario_started(story_title, scenario_name) - @output.puts <<-EOF - <dl class="passed"> - <dt>Scenario: #{h scenario_name}</dt> - <dd> - <ul class="steps"> -EOF - end - - def scenario_ended - @output.puts <<-EOF - </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_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] } - @output.puts " <li class=\"#{klass}\">#{inner}</li>" - end - end - end - end - end -end
\ No newline at end of file diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/story/plain_text_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/story/plain_text_formatter.rb deleted file mode 100644 index 31cd614cb..000000000 --- a/vendor/plugins/rspec/lib/spec/runner/formatter/story/plain_text_formatter.rb +++ /dev/null @@ -1,142 +0,0 @@ -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 - @failed_scenarios = [] - @pending_steps = [] - @previous_type = nil - end - - def run_started(count) - @count = count - @output.puts "Running #@count scenarios\n\n" - end - - def story_started(title, narrative) - @current_story_title = title - @output.puts "Story: #{title}\n\n" - narrative.each_line do |line| - @output.print " " - @output.print line - end - end - - def story_ended(title, narrative) - @output.puts - @output.puts - end - - def scenario_started(story_title, scenario_name) - @current_scenario_name = scenario_name - @scenario_already_failed = false - @output.print "\n\n Scenario: #{scenario_name}" - @scenario_ok = true - @scenario_pending = false - end - - def scenario_succeeded(story_title, scenario_name) - @successful_scenario_count += 1 - 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 - end - - def scenario_pending(story_title, scenario_name, msg) - @pending_scenario_count += 1 unless @scenario_already_failed - @scenario_pending = true - @scenario_already_failed = true - 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] - @output.print 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 - @output.print yellow(" (SKIPPED)") - else - @output.print 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 - @output.print yellow(text) - else - @output.print(failed ? red(text) : green(text)) - end - - if type == :'given scenario' - @previous_type = :given - else - @previous_type = type - end - end - end - end - end - end -end diff --git a/vendor/plugins/rspec/lib/spec/runner/heckle_runner.rb b/vendor/plugins/rspec/lib/spec/runner/heckle_runner.rb index 7695fe794..5c81ea846 100644 --- a/vendor/plugins/rspec/lib/spec/runner/heckle_runner.rb +++ b/vendor/plugins/rspec/lib/spec/runner/heckle_runner.rb @@ -1,72 +1,72 @@ -begin - require 'rubygems' - require 'heckle' -rescue LoadError ; raise "You must gem install heckle to use --heckle" ; end +if Spec::Ruby.version.to_f < 1.9 + begin + require 'rubygems' unless ENV['NO_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) + 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 - 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 + # 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_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 + def heckle_method(class_name, method_name) + verify_constant(class_name) + heckle = @heckle_class.new(class_name, method_name, Spec::Runner.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 + classes.each do |klass| + klass.instance_methods(false).each do |method_name| + heckle = @heckle_class.new(klass.name, method_name, Spec::Runner.options) + heckle.validate + end 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" + 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 - 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 + class Heckler < 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 + def tests_pass? + @rspec_options.run_examples + end + end end end -end +end
\ No newline at end of file diff --git a/vendor/plugins/rspec/lib/spec/runner/heckle_runner_unsupported.rb b/vendor/plugins/rspec/lib/spec/runner/heckle_runner_unsupported.rb index 02aa37953..35ff86e10 100644 --- a/vendor/plugins/rspec/lib/spec/runner/heckle_runner_unsupported.rb +++ b/vendor/plugins/rspec/lib/spec/runner/heckle_runner_unsupported.rb @@ -3,7 +3,7 @@ module Spec # Dummy implementation for Windows that just fails (Heckle is not supported on Windows) class HeckleRunner def initialize(filter) - raise "Heckle not supported on Windows" + raise "Heckle is not supported on Windows or Ruby 1.9" end end end diff --git a/vendor/plugins/rspec/lib/spec/runner/option_parser.rb b/vendor/plugins/rspec/lib/spec/runner/option_parser.rb index 91525e089..fbbf444a9 100644 --- a/vendor/plugins/rspec/lib/spec/runner/option_parser.rb +++ b/vendor/plugins/rspec/lib/spec/runner/option_parser.rb @@ -10,6 +10,10 @@ module Spec parser.parse(args) parser.options end + + def spec_command? + $0.split('/').last == 'spec' + end end attr_reader :options @@ -27,34 +31,30 @@ module Spec :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,", + "on each line of that file 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)"], + :line => ["-l", "--line LINE_NUMBER", Integer, "Execute example group or example at given line.", + "(does not work for dynamically generated examples)"], :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", + "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", + "Builtin formats:", + "silent|l : No output", "progress|p : Text-based progress bar", + "profile|o : Text-based progress bar with profiling of 10 slowest examples", + "specdoc|s : Code example doc strings", + "nested|n : Code example doc strings with nested groups indented", "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", @@ -78,6 +78,7 @@ module Spec :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."], + :debug => ["-u", "--debugger", "Enable ruby-debugging."], :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"] @@ -91,37 +92,49 @@ module Spec @file_factory = File - self.banner = "Usage: spec (FILE|DIRECTORY|GLOB)+ [options]" + self.banner = "Usage: spec (FILE(:LINE)?|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[: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|} 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} + on(*OPTIONS[:runner]) {|runner| @options.user_input_for_runner = runner} + on(*OPTIONS[:debug]) {@options.debug = true} + on(*OPTIONS[:drb]) {} + on(*OPTIONS[:version]) {parse_version} + on("--autospec") {@options.autospec = true} + on_tail(*OPTIONS[:help]) {parse_help} end def order!(argv, &blk) - @argv = argv + @argv = argv.dup + @argv = (@argv.empty? & self.class.spec_command?) ? ['--help'] : @argv + + # Parse options file first + parse_file_options(:options_file, :parse_options_file) + @options.argv = @argv.dup - return if parse_generate_options + return if parse_file_options(:generate_options, :write_options_file) return if parse_drb - + super(@argv) do |file| + if file =~ /^(.+):(\d+)$/ + file = $1 + @options.line_number = $2.to_i + end + @options.files << file blk.call(file) if blk end @@ -129,41 +142,46 @@ module Spec @options end - protected + 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 + def parse_file_options(option_name, action) + # Remove the file option and the argument before handling the file options_file = nil - ['-G', '--generate-options'].each do |option| + options_list = OPTIONS[option_name][0..1] + options_list[1].gsub!(" PATH", "") + options_list.each do |option| if index = @argv.index(option) @argv.delete_at(index) options_file = @argv.delete_at(index) end end + if options_file.nil? && + File.exist?('spec/spec.opts') && + !@argv.any?{|a| a =~ /^\-/ } + options_file = 'spec/spec.opts' + end + if options_file - write_generated_options(options_file) + send(action, options_file) return true else return false end end - - def write_generated_options(options_file) + + def parse_options_file(options_file) + option_file_args = File.readlines(options_file).map {|l| l.chomp.split " "}.flatten + @argv.push(*option_file_args) + end + + def write_options_file(options_file) File.open(options_file, 'w') do |io| io.puts @argv.join("\n") end @@ -172,28 +190,30 @@ module Spec @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 + def parse_drb + argv = @options.argv 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 + if DrbCommandLine.run(self.class.parse(argv, @error_stream, @out_stream)) + @options.examples_should_not_be_run + true + else + @error_stream.puts "Running specs locally:" + false + end end def parse_version - @out_stream.puts ::Spec::VERSION::DESCRIPTION + @out_stream.puts ::Spec::VERSION::SUMMARY exit if stdout? end def parse_help @out_stream.puts self exit if stdout? - end + end def stdout? @out_stream == $stdout diff --git a/vendor/plugins/rspec/lib/spec/runner/options.rb b/vendor/plugins/rspec/lib/spec/runner/options.rb index 6716464af..e0179e80e 100644 --- a/vendor/plugins/rspec/lib/spec/runner/options.rb +++ b/vendor/plugins/rspec/lib/spec/runner/options.rb @@ -1,3 +1,5 @@ +require 'ostruct' + module Spec module Runner class Options @@ -6,9 +8,11 @@ module Spec } EXAMPLE_FORMATTERS = { # Load these lazily for better speed + 'silent' => ['spec/runner/formatter/silent_formatter', 'Formatter::SilentFormatter'], + 'l' => ['spec/runner/formatter/silent_formatter', 'Formatter::SilentFormatter'], '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'], + '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'], @@ -23,22 +27,16 @@ module Spec '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( + :autospec, # hack to tell :filename_pattern, :backtrace_tweaker, :context_lines, :diff_format, :dry_run, :profile, - :examples, :heckle_runner, + :debug, :line_number, :loadby, :reporter, @@ -48,12 +46,10 @@ module Spec :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 + attr_reader :colour, :differ_class, :files, :examples, :example_groups def initialize(error_stream, output_stream) @error_stream = error_stream @@ -64,6 +60,7 @@ module Spec @colour = false @profile = false @dry_run = false + @debug = false @reporter = Reporter.new(self) @context_lines = 3 @diff_format = :unified @@ -73,32 +70,80 @@ module Spec @examples_run = false @examples_should_be_run = nil @user_input_for_runner = nil - @before_suite_parts = [] @after_suite_parts = [] + @files_loaded = false + @out_used = nil end def add_example_group(example_group) @example_groups << example_group end + def line_number_requested? + !!line_number + end + + def example_line + Spec::Runner::LineNumberQuery.new(self).example_line_for(files.first, line_number) + end + def remove_example_group(example_group) @example_groups.delete(example_group) end + def require_ruby_debug + require 'rubygems' unless ENV['NO_RUBYGEMS'] + require 'ruby-debug' + end + + def project_root # :nodoc: + require 'pathname' + @project_root ||= determine_project_root + end + + def determine_project_root # :nodoc: + # This is borrowed (slightly modified) from Scott Taylors + # project_path project: + # http://github.com/smtlaissezfaire/project_path + Pathname(File.expand_path('.')).ascend do |path| + if File.exists?(File.join(path, "spec")) + return path + end + end + end + + def add_dir_from_project_root_to_load_path(dir, load_path=$LOAD_PATH) # :nodoc: + return if project_root.nil? + full_dir = File.join(project_root, dir) + load_path.unshift full_dir unless load_path.include?(full_dir) + end + def run_examples + require_ruby_debug if debug 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 + ['spec','lib'].each do |dir| + add_dir_from_project_root_to_load_path(dir) + end runner.load_files(files_to_load) @files_loaded = true end + define_predicate_matchers + plugin_mock_framework + ignore_backtrace_patterns + + # TODO - this has to happen after the files get loaded, + # otherwise the before_suite_parts are not populated + # from the configuration. There is no spec for this + # directly, but features/before_and_after_blocks/before_and_after_blocks.story + # will fail if this happens before the files are loaded. + before_suite_parts.each { |part| part.call } + if example_groups.empty? true else @@ -110,25 +155,40 @@ module Spec end ensure after_suite_parts.each do |part| - part.call(success) + part.arity < 1 ? part.call : part.call(success) end end end + def before_suite_parts + Spec::Example::BeforeAndAfterHooks.before_suite_parts + end + + def after_suite_parts + Spec::Example::BeforeAndAfterHooks.after_suite_parts + end + def examples_run? @examples_run end def examples_should_not_be_run @examples_should_be_run = false - end + end + + def mock_framework + # TODO - don't like this dependency - perhaps store this in here instead? + Spec::Runner.configuration.mock_framework + end def colour=(colour) @colour = colour - if @colour && RUBY_PLATFORM =~ /win32/ ;\ + if @colour && RUBY_PLATFORM =~ /mswin|mingw/ ;\ begin ;\ - require 'rubygems' ;\ + replace_output = @output_stream.equal?($stdout) ;\ + require 'rubygems' unless ENV['NO_RUBYGEMS'] ;\ require 'Win32/Console/ANSI' ;\ + @output_stream = $stdout if replace_output ;\ rescue LoadError ;\ warn "You must 'gem install win32console' to use colour on Windows" ;\ @colour = false ;\ @@ -152,7 +212,7 @@ module Spec def parse_example(example) if(File.file?(example)) - @examples = File.open(example).read.split("\n") + @examples = [File.open(example).read.split("\n")].flatten else @examples = [example] end @@ -168,17 +228,12 @@ module Spec @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] @@ -187,22 +242,31 @@ module Spec else load_class(format, 'formatter', '--format') end - formatter_type.new(self, where) + formatter_type.new(formatter_options, where) end end + def formatter_options + @formatter_options ||= OpenStruct.new( + :colour => colour, + :autospec => autospec, + :dry_run => dry_run + ) + end + + def which_heckle_runner + ([/mswin/, /java/].detect{|p| p =~ RUBY_PLATFORM} || Spec::Ruby.version.to_f == 1.9) ? "spec/runner/heckle_runner_unsupported" : "spec/runner/heckle_runner" + 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) + @format_options ||= [['silent', @output_stream]] + require which_heckle_runner + @heckle_runner = ::Spec::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 + return examples.size unless examples.empty? + @example_groups.inject(0) {|sum, group| sum + group.number_of_examples} end def files_to_load @@ -220,13 +284,40 @@ module Spec end result end - - protected + + def dry_run? + @dry_run == true + end + + protected + + def define_predicate_matchers + Spec::Runner.configuration.predicate_matchers.each_pair do |matcher_method, method_on_object| + Spec::Example::ExampleMethods::__send__ :define_method, matcher_method do |*args| + eval("be_#{method_on_object.to_s.gsub('?','')}(*args)") + end + end + end + + def plugin_mock_framework + case mock_framework + when Module + Spec::Example::ExampleMethods.__send__ :include, mock_framework + else + require mock_framework + Spec::Example::ExampleMethods.__send__ :include, Spec::Adapters::MockFramework + end + end + + def ignore_backtrace_patterns + @backtrace_tweaker.ignore_patterns Spec::Runner.configuration.ignored_backtrace_patterns + end + 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 @@ -250,24 +341,24 @@ module Spec 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') + runner_type = load_class(klass_name, 'example group 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 @@ -277,26 +368,26 @@ module Spec end def default_differ - require 'spec/expectations/differs/default' - self.differ_class = Spec::Expectations::Differs::Default + require 'spec/runner/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" + error_stream.puts "You must specify one file, not a directory when providing a line number" exit(1) if stderr? else - example = SpecParser.new.spec_name_for(files[0], line_number) + example = LineNumberQuery.new(self).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}" + error_stream.puts "Only one file can be specified when providing a line number: #{files.inspect}" exit(3) if stderr? end else - error_stream.puts "You cannot use both --line and --example" + error_stream.puts "You cannot use --example and specify a line number" exit(4) if stderr? end end diff --git a/vendor/plugins/rspec/lib/spec/runner/reporter.rb b/vendor/plugins/rspec/lib/spec/runner/reporter.rb index 66db38406..0fae7d137 100644 --- a/vendor/plugins/rspec/lib/spec/runner/reporter.rb +++ b/vendor/plugins/rspec/lib/spec/runner/reporter.rb @@ -1,19 +1,23 @@ module Spec module Runner class Reporter - attr_reader :options, :example_groups + attr_reader :options def initialize(options) @options = options @options.reporter = self - clear + @failures = [] + @pending_count = 0 + @example_count = 0 + @start_time = nil + @end_time = nil end - def add_example_group(example_group) + def example_group_started(example_group) + @example_group = example_group formatters.each do |f| - f.add_example_group(example_group) + f.example_group_started(example_group) end - example_groups << example_group end def example_started(example) @@ -21,29 +25,27 @@ module Spec end def example_finished(example, error=nil) - @examples << example + @example_count += 1 if error.nil? example_passed(example) elsif Spec::Example::ExamplePendingError === error - example_pending(example, error.message) + example_pending(example, example.location, error.message) else example_failed(example, error) end end - def failure(example, error) + def example_failed(example, error) backtrace_tweaker.tweak_backtrace(error) - failure = Failure.new(example, error) + failure = Failure.new(@example_group.description, example.description, 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 @@ -58,12 +60,51 @@ module Spec dump_pending dump_failures formatters.each do |f| - f.dump_summary(duration, @examples.length, @failures.length, @pending_count) + f.dump_summary(duration, @example_count, @failures.length, @pending_count) f.close end @failures.length end + class Failure + def initialize(group_description, example_description, exception) # :nodoc: + @example_name = "#{group_description} #{example_description}" + @exception = exception + end + + # The Exception object raised + attr_reader :exception + + # Header messsage for reporting this failure, including the name of the + # example and an indicator of the type of failure. FAILED indicates a + # failed expectation. FIXED indicates a pending example that passes, and + # no longer needs to be pending. RuntimeError indicates that a + # RuntimeError occured. + # + # == Examples + # + # 'A new account should have a zero balance' FAILED + # 'A new account should have a zero balance' FIXED + # RuntimeError in 'A new account should have a zero balance' + 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? # :nodoc: + @exception.is_a?(Spec::Example::PendingExampleFixedError) + end + + def expectation_not_met? # :nodoc: + @exception.is_a?(Spec::Expectations::ExpectationNotMetError) + end + end + private def formatters @@ -74,15 +115,6 @@ module Spec @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| @@ -103,45 +135,37 @@ module Spec def example_passed(example) formatters.each{|f| f.example_passed(example)} end + + EXAMPLE_PENDING_DEPRECATION_WARNING = <<-WARNING + +********************************************************************* +DEPRECATION WARNING: RSpec's formatters have changed example_pending +to accept two arguments instead of three. Please see the rdoc +for Spec::Runner::Formatter::BaseFormatter#example_pending +for more information. + +Please update any custom formatters to accept only two arguments +to example_pending. Support for example_pending with two arguments +and this warning message will be removed after the RSpec 2.0 release. +********************************************************************* +WARNING - def example_pending(example, message="Not Yet Implemented") + def example_pending(example, ignore, 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" + formatters.each do |formatter| + if formatter_uses_deprecated_example_pending_method?(formatter) + Spec.warn EXAMPLE_PENDING_DEPRECATION_WARNING + formatter.example_pending(example, message, example.location) else - "#{@exception.class.name} in '#{example_name}'" + formatter.example_pending(example, message) 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 + + def formatter_uses_deprecated_example_pending_method?(formatter) + formatter.method(:example_pending).arity == 3 + end + end end end diff --git a/vendor/plugins/rspec/lib/spec/runner/spec_parser.rb b/vendor/plugins/rspec/lib/spec/runner/spec_parser.rb deleted file mode 100644 index 8beb384e9..000000000 --- a/vendor/plugins/rspec/lib/spec/runner/spec_parser.rb +++ /dev/null @@ -1,71 +0,0 @@ -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 |