rspec 0.9.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. data/CHANGES +24 -0
  2. data/EXAMPLES.rd +6 -2
  3. data/README +9 -9
  4. data/Rakefile +32 -29
  5. data/examples/not_yet_implemented_spec.rb +12 -0
  6. data/examples/shared_behaviours_example.rb +8 -0
  7. data/examples/stack_spec.rb +1 -0
  8. data/lib/spec/dsl/behaviour.rb +21 -6
  9. data/lib/spec/dsl/behaviour_callbacks.rb +44 -26
  10. data/lib/spec/dsl/behaviour_eval.rb +21 -12
  11. data/lib/spec/dsl/behaviour_factory.rb +23 -13
  12. data/lib/spec/dsl/configuration.rb +85 -5
  13. data/lib/spec/dsl/description.rb +14 -6
  14. data/lib/spec/dsl/example.rb +2 -2
  15. data/lib/spec/matchers.rb +5 -5
  16. data/lib/spec/matchers/be.rb +16 -0
  17. data/lib/spec/matchers/operator_matcher.rb +21 -1
  18. data/lib/spec/matchers/raise_error.rb +1 -1
  19. data/lib/spec/rake/verify_rcov.rb +5 -1
  20. data/lib/spec/runner.rb +7 -27
  21. data/lib/spec/runner/behaviour_runner.rb +1 -1
  22. data/lib/spec/runner/extensions/kernel.rb +20 -0
  23. data/lib/spec/runner/formatter/base_formatter.rb +6 -1
  24. data/lib/spec/runner/formatter/base_text_formatter.rb +10 -2
  25. data/lib/spec/runner/formatter/failing_behaviours_formatter.rb +1 -1
  26. data/lib/spec/runner/formatter/failing_examples_formatter.rb +1 -1
  27. data/lib/spec/runner/formatter/html_formatter.rb +63 -31
  28. data/lib/spec/runner/formatter/progress_bar_formatter.rb +5 -0
  29. data/lib/spec/runner/formatter/rdoc_formatter.rb +4 -0
  30. data/lib/spec/runner/formatter/specdoc_formatter.rb +6 -1
  31. data/lib/spec/runner/option_parser.rb +1 -1
  32. data/lib/spec/runner/reporter.rb +13 -4
  33. data/lib/spec/runner/spec_parser.rb +1 -1
  34. data/lib/spec/version.rb +5 -5
  35. data/spec/spec/dsl/behaviour_spec.rb +88 -24
  36. data/spec/spec/dsl/configuration_spec.rb +8 -1
  37. data/spec/spec/dsl/example_class_spec.rb +1 -1
  38. data/spec/spec/dsl/example_instance_spec.rb +5 -5
  39. data/spec/spec/dsl/shared_behaviour_spec.rb +24 -2
  40. data/spec/spec/matchers/be_spec.rb +20 -2
  41. data/spec/spec/matchers/operator_matcher_spec.rb +158 -0
  42. data/spec/spec/runner/command_line_spec.rb +5 -4
  43. data/spec/spec/runner/drb_command_line_spec.rb +15 -8
  44. data/spec/spec/runner/formatter/html_formatter_spec.rb +22 -5
  45. data/spec/spec/runner/formatter/progress_bar_formatter_dry_run_spec.rb +1 -1
  46. data/spec/spec/runner/formatter/progress_bar_formatter_spec.rb +7 -2
  47. data/spec/spec/runner/formatter/rdoc_formatter_dry_run_spec.rb +1 -1
  48. data/spec/spec/runner/formatter/rdoc_formatter_spec.rb +6 -1
  49. data/spec/spec/runner/formatter/specdoc_formatter_dry_run_spec.rb +1 -1
  50. data/spec/spec/runner/formatter/specdoc_formatter_spec.rb +15 -5
  51. data/spec/spec/runner/option_parser_spec.rb +5 -0
  52. data/spec/spec/runner/reporter_spec.rb +23 -5
  53. data/spec/spec/runner/spec_matcher_spec.rb +1 -1
  54. data/spec/spec/runner/spec_parser_spec.rb +1 -1
  55. data/spec/spec_helper.rb +38 -2
  56. metadata +41 -42
  57. data/spec/spec/matchers/should_===_spec.rb +0 -38
  58. data/spec/spec/matchers/should_==_spec.rb +0 -37
  59. data/spec/spec/matchers/should_=~_spec.rb +0 -36
@@ -6,27 +6,37 @@ module Spec
6
6
 
7
7
  BEHAVIOUR_CLASSES = {:default => Spec::DSL::Behaviour}
8
8
 
9
- def add_behaviour_class(key, value)
10
- BEHAVIOUR_CLASSES[key] = value
9
+ # Registers a behaviour class +klass+ with the symbol
10
+ # +behaviour_type+. For example:
11
+ #
12
+ # Spec::DSL::BehaviourFactory.add_behaviour_class(:farm, Spec::Farm::DSL::FarmBehaviour)
13
+ #
14
+ # This will cause Kernel#describe from a file living in
15
+ # <tt>spec/farm</tt> to create behaviour instances of type
16
+ # Spec::Farm::DSL::FarmBehaviour.
17
+ def add_behaviour_class(behaviour_type, klass)
18
+ BEHAVIOUR_CLASSES[behaviour_type] = klass
11
19
  end
12
20
 
13
- def remove_behaviour_class(key)
14
- BEHAVIOUR_CLASSES.delete(key)
21
+ def remove_behaviour_class(behaviour_type)
22
+ BEHAVIOUR_CLASSES.delete(behaviour_type)
15
23
  end
16
24
 
17
25
  def create(*args, &block)
18
- return BEHAVIOUR_CLASSES[behaviour_type(*args)].new(*args, &block)
19
- end
20
-
21
- private
22
-
23
- def behaviour_type(*args)
24
26
  opts = Hash === args.last ? args.last : {}
25
- opts[:behaviour_type] ? opts[:behaviour_type] : :default
27
+ if opts[:shared]
28
+ behaviour_type = :default
29
+ elsif opts[:behaviour_type]
30
+ behaviour_type = opts[:behaviour_type]
31
+ elsif opts[:spec_path] =~ /spec\/(#{BEHAVIOUR_CLASSES.keys.join('|')})/
32
+ behaviour_type = $1.to_sym
33
+ else
34
+ behaviour_type = :default
35
+ end
36
+ return BEHAVIOUR_CLASSES[behaviour_type].new(*args, &block)
26
37
  end
27
-
38
+
28
39
  end
29
-
30
40
  end
31
41
  end
32
42
  end
@@ -2,6 +2,27 @@ module Spec
2
2
  module DSL
3
3
  class Configuration
4
4
 
5
+ # Chooses what mock framework to use. Example:
6
+ #
7
+ # Spec::Runner.configure do |config|
8
+ # config.mock_with :rspec # or :mocha, or :flexmock
9
+ # end
10
+ #
11
+ # To use any other mock framework, you'll have to provide
12
+ # your own adapter. This is simply a module that responds to
13
+ # setup_mocks_for_rspec, verify_mocks_for_rspec and teardown_mocks_for_rspec.
14
+ # These are your hooks into the lifecycle of a given example. RSpec will
15
+ # call setup_mocks_for_rspec before running anything else in each Example.
16
+ # After executing the #after methods, RSpec will then call verify_mocks_for_rspec
17
+ # and teardown_mocks_for_rspec (this is guaranteed to run even if there are
18
+ # failures in verify_mocks_for_rspec).
19
+ #
20
+ # Once you've defined this module, you can pass that to mock_with:
21
+ #
22
+ # Spec::Runner.configure do |config|
23
+ # config.mock_with MyMockFrameworkAdapter
24
+ # end
25
+ #
5
26
  def mock_with(mock_framework)
6
27
  @mock_framework = case mock_framework
7
28
  when Symbol
@@ -11,23 +32,82 @@ module Spec
11
32
  end
12
33
  end
13
34
 
14
- def mock_framework
35
+ def mock_framework # :nodoc:
15
36
  @mock_framework ||= mock_framework_path("rspec")
16
37
  end
17
38
 
18
- def include(*mods)
19
- # mods.each {|mod|included_modules << mod}
20
- included_modules.push(*mods)
39
+ # Declares modules to be included in all behaviours (<tt>describe</tt> blocks).
40
+ #
41
+ # config.include(My::Bottle, My::Cup)
42
+ #
43
+ # If you want to restrict the inclusion to a subset of all the behaviours then
44
+ # specify this in a Hash as the last argument:
45
+ #
46
+ # config.include(My::Pony, My::Horse, :behaviour_type => :farm)
47
+ #
48
+ # Only behaviours that have that type will get the modules included:
49
+ #
50
+ # describe "Downtown", :behaviour_type => :city do
51
+ # # Will *not* get My::Pony and My::Horse included
52
+ # end
53
+ #
54
+ # describe "Old Mac Donald", :behaviour_type => :farm do
55
+ # # *Will* get My::Pony and My::Horse included
56
+ # end
57
+ #
58
+ def include(*args)
59
+ included_modules.push(*args)
21
60
  end
22
61
 
23
- def included_modules
62
+ def included_modules # :nodoc:
24
63
  @included_modules ||= []
25
64
  end
26
65
 
66
+ # Defines global predicate matchers. Example:
67
+ #
68
+ # config.predicate_matchers[:swim] = :can_swim?
69
+ #
70
+ # This makes it possible to say:
71
+ #
72
+ # person.should swim # passes if person.should_swim? returns true
73
+ #
27
74
  def predicate_matchers
28
75
  @predicate_matchers ||= {}
29
76
  end
30
77
 
78
+ # Prepends a global <tt>before</tt> block to all behaviours.
79
+ # See #append_before for filtering semantics.
80
+ def prepend_before(*args, &proc)
81
+ Behaviour.prepend_before(*args, &proc)
82
+ end
83
+ # Appends a global <tt>before</tt> block to all behaviours.
84
+ #
85
+ # If you want to restrict the block to a subset of all the behaviours then
86
+ # specify this in a Hash as the last argument:
87
+ #
88
+ # config.prepend_before(:all, :behaviour_type => :farm)
89
+ #
90
+ # or
91
+ #
92
+ # config.prepend_before(:behaviour_type => :farm)
93
+ #
94
+ def append_before(*args, &proc)
95
+ Behaviour.append_before(*args, &proc)
96
+ end
97
+ alias_method :before, :append_before
98
+
99
+ # Prepends a global <tt>after</tt> block to all behaviours.
100
+ # See #append_before for filtering semantics.
101
+ def prepend_after(*args, &proc)
102
+ Behaviour.prepend_after(*args, &proc)
103
+ end
104
+ alias_method :after, :prepend_after
105
+ # Appends a global <tt>after</tt> block to all behaviours.
106
+ # See #append_before for filtering semantics.
107
+ def append_after(*args, &proc)
108
+ Behaviour.append_after(*args, &proc)
109
+ end
110
+
31
111
  private
32
112
 
33
113
  def mock_framework_path(framework_name)
@@ -1,17 +1,25 @@
1
1
  module Spec
2
2
  module DSL
3
3
  class Description
4
+ module ClassMethods
5
+ def generate_description(*args)
6
+ description = args.shift.to_s
7
+ unless args.empty?
8
+ suffix = args.shift.to_s
9
+ description << " " unless suffix =~ /^\s|\.|#/
10
+ description << suffix
11
+ end
12
+ description
13
+ end
14
+ end
15
+ extend ClassMethods
16
+
4
17
  attr_reader :description, :described_type
5
18
 
6
19
  def initialize(*args)
7
20
  args, @options = args_and_options(*args)
8
21
  @described_type = args.first unless args.first.is_a?(String)
9
- @description = args.shift.to_s
10
- unless args.empty?
11
- suffix = args.shift.to_s
12
- @description << " " unless suffix =~ /^\s|\.|#/
13
- @description << suffix
14
- end
22
+ @description = self.class.generate_description(*args)
15
23
  end
16
24
 
17
25
  def [](key)
@@ -26,7 +26,7 @@ module Spec
26
26
  end
27
27
 
28
28
  ExampleShouldRaiseHandler.new(@from, @options).handle(errors)
29
- reporter.example_finished(description, errors.first, location) if reporter
29
+ reporter.example_finished(description, errors.first, location, @example_block.nil?) if reporter
30
30
  end
31
31
 
32
32
  def matches?(matcher, specified_examples)
@@ -70,7 +70,7 @@ module Spec
70
70
 
71
71
  def run_example(execution_context, errors)
72
72
  begin
73
- execution_context.instance_eval(&@example_block)
73
+ execution_context.instance_eval(&@example_block) if @example_block
74
74
  return true
75
75
  rescue Exception => e
76
76
  @failed = true
@@ -86,15 +86,15 @@ module Spec
86
86
  # def initialize(expected)
87
87
  # @expected = expected
88
88
  # end
89
- # def matches?(actual)
90
- # @actual = actual
91
- # bob.current_zone.eql?(Zone.new(@expected))
89
+ # def matches?(target)
90
+ # @target = target
91
+ # @target.current_zone.eql?(Zone.new(@expected))
92
92
  # end
93
93
  # def failure_message
94
- # "expected #{@actual.inspect} to be in Zone #{@expected}"
94
+ # "expected #{@target.inspect} to be in Zone #{@expected}"
95
95
  # end
96
96
  # def negative_failure_message
97
- # "expected #{@actual.inspect} not to be in Zone #{@expected}"
97
+ # "expected #{@target.inspect} not to be in Zone #{@expected}"
98
98
  # end
99
99
  # end
100
100
  #
@@ -57,8 +57,24 @@ module Spec
57
57
  return @actual <= @expected if @less_than_or_equal
58
58
  return @actual >= @expected if @greater_than_or_equal
59
59
  return @actual > @expected if @greater_than
60
+ return @actual == @expected if @double_equal
61
+ return @actual === @expected if @triple_equal
60
62
  return @actual.equal?(@expected)
61
63
  end
64
+
65
+ def ==(expected)
66
+ @double_equal = true
67
+ @comparison = "== "
68
+ @expected = expected
69
+ self
70
+ end
71
+
72
+ def ===(expected)
73
+ @triple_equal = true
74
+ @comparison = "=== "
75
+ @expected = expected
76
+ self
77
+ end
62
78
 
63
79
  def <(expected)
64
80
  @less_than = true
@@ -21,6 +21,26 @@ module Spec
21
21
  __delegate_method_missing_to_target("=~", expected)
22
22
  end
23
23
 
24
+ def >(expected)
25
+ @expected = expected
26
+ __delegate_method_missing_to_target(">", expected)
27
+ end
28
+
29
+ def >=(expected)
30
+ @expected = expected
31
+ __delegate_method_missing_to_target(">=", expected)
32
+ end
33
+
34
+ def <(expected)
35
+ @expected = expected
36
+ __delegate_method_missing_to_target("<", expected)
37
+ end
38
+
39
+ def <=(expected)
40
+ @expected = expected
41
+ __delegate_method_missing_to_target("<=", expected)
42
+ end
43
+
24
44
  def fail_with_message(message)
25
45
  Spec::Expectations.fail_with(message, @expected, @target)
26
46
  end
@@ -33,7 +53,7 @@ module Spec
33
53
  ::Spec::Matchers.generated_description = "should #{operator} #{expected.inspect}"
34
54
  return if @target.send(operator, expected)
35
55
  return fail_with_message("expected #{expected.inspect}, got #{@target.inspect} (using #{operator})") if ['==','==='].include?(operator)
36
- return fail_with_message("expected =~ #{expected.inspect}, got #{@target.inspect}")
56
+ return fail_with_message("expected #{operator} #{expected.inspect}, got #{@target.inspect}")
37
57
  end
38
58
 
39
59
  end
@@ -24,7 +24,7 @@ module Spec
24
24
  @raised_other = true
25
25
  end
26
26
  else
27
- if @actual_error.message == @expected_message
27
+ if @expected_message == @actual_error.message
28
28
  @raised_expected_error = true
29
29
  else
30
30
  @raised_other = true
@@ -19,10 +19,14 @@ module RCov
19
19
  # exception.
20
20
  attr_accessor :threshold
21
21
 
22
+ # Require the threshold value be met exactly. This is the default.
23
+ attr_accessor :require_exact_threshold
24
+
22
25
  def initialize(name=:verify_rcov)
23
26
  @name = name
24
27
  @index_html = 'coverage/index.html'
25
28
  @verbose = true
29
+ @require_exact_threshold = true
26
30
  yield self if block_given?
27
31
  raise "Threshold must be set" if @threshold.nil?
28
32
  define
@@ -41,7 +45,7 @@ module RCov
41
45
  end
42
46
  puts "Coverage: #{total_coverage}% (threshold: #{threshold}%)" if verbose
43
47
  raise "Coverage must be at least #{threshold}% but was #{total_coverage}%" if total_coverage < threshold
44
- raise "Coverage has increased above the threshold of #{threshold}% to #{total_coverage}%. You should update your threshold value." if total_coverage > threshold
48
+ raise "Coverage has increased above the threshold of #{threshold}% to #{total_coverage}%. You should update your threshold value." if (total_coverage > threshold) and require_exact_threshold
45
49
  end
46
50
  end
47
51
  end
@@ -147,38 +147,18 @@ module Spec
147
147
  end
148
148
 
149
149
  # Use this to configure various configurable aspects of
150
- # RSpec. For example, to choose a mock framework from
151
- # RSpec, mocha and flexmock, you can do this:
150
+ # RSpec:
152
151
  #
153
- # Spec::Runner.configure do |config|
154
- # config.mock_with :rspec #or :mocha, or :flexmock
152
+ # Spec::Runner.configure do |configuration|
153
+ # # Configure RSpec here
155
154
  # end
156
155
  #
157
- # To use any other mock framework, you'll have to provide
158
- # your own adapter. This is simply a module that responds to
159
- # setup_mocks_for_rspec, verify_mocks_for_rspec and teardown_mocks_for_rspec.
160
- # These are your hooks into the lifecycle of a given example. RSpec will
161
- # call setup_mocks_for_rspec before running anything else in each Example.
162
- # After executing the #after methods, RSpec will then call verify_mocks_for_rspec
163
- # and teardown_mocks_for_rspec (this is guaranteed to run even if there are
164
- # failures in verify_mocks_for_rspec).
156
+ # The yielded <tt>configuration</tt> object is a
157
+ # Spec::DSL::Configuration instance. See its RDoc
158
+ # for details about what you can do with it.
165
159
  #
166
- # Once you've defined this module, you can pass that to mock_with:
167
- #
168
- # Spec::Runner.configure do |config|
169
- # config.mock_with MyMockFrameworkAdapter
170
- # end
171
- #
172
- # You can also configure the following items:
173
- #
174
- # # include SomeModule in every Behaviour
175
- # config.include SomeModule
176
- #
177
- # # generate a do_something predicate_matcher for every Behaviour
178
- # # - See Spec::DSL::Behaviour#predicate_matchers
179
- # config.predicate_matchers[:does_something?] = :do_something
180
160
  def configure
181
- yield configuration
161
+ yield configuration if @configuration.nil?
182
162
  end
183
163
  end
184
164
  end
@@ -82,7 +82,7 @@ module Spec
82
82
 
83
83
  def load_specs(paths)
84
84
  paths.each do |path|
85
- load path
85
+ require path
86
86
  end
87
87
  end
88
88
 
@@ -1,6 +1,26 @@
1
1
  module Kernel
2
+ # Creates and registers an instance of a Spec::DSL::Behaviour (or a subclass).
3
+ # The instantiated behaviour class depends on the directory of the file
4
+ # calling this method. For example, Spec::Rails will use different
5
+ # classes for specs living in <tt>spec/models</tt>, <tt>spec/helpers</tt>,
6
+ # <tt>spec/views</tt> and <tt>spec/controllers</tt>.
7
+ #
8
+ # It is also possible to override autodiscovery of the behaviour class
9
+ # with an options Hash as the last argument:
10
+ #
11
+ # describe "name", :behaviour_type => :something_special do ...
12
+ #
13
+ # The reason for using different behaviour classes is to have
14
+ # different matcher methods available from within the <tt>describe</tt>
15
+ # block.
16
+ #
17
+ # See Spec::DSL::BehaviourFactory#add_behaviour_class for details about
18
+ # how to register special Spec::DSL::Behaviour implementations.
19
+ #
2
20
  def describe(*args, &block)
3
21
  raise ArgumentError if args.empty?
22
+ args << {} unless Hash === args.last
23
+ args.last[:spec_path] = caller(0)[1]
4
24
  register_behaviour(Spec::DSL::BehaviourFactory.create(*args, &block))
5
25
  end
6
26
  alias :context :describe
@@ -40,6 +40,11 @@ module Spec
40
40
  # (starting at 1) and +failure+ is the associated Failure object.
41
41
  def example_failed(name, counter, failure)
42
42
  end
43
+
44
+ # This method is invoked when an example is not yet implemented (i.e. has not been provided a block).
45
+ # +name+ is the name of the example.
46
+ def example_not_implemented(name)
47
+ end
43
48
 
44
49
  # This method is invoked after all of the examples have executed. The next method
45
50
  # to be invoked after this one is #dump_failure (once for each failed example),
@@ -54,7 +59,7 @@ module Spec
54
59
  end
55
60
 
56
61
  # This method is invoked at the very end.
57
- def dump_summary(duration, example_count, failure_count)
62
+ def dump_summary(duration, example_count, failure_count, not_implemented_count)
58
63
  end
59
64
 
60
65
  end
@@ -46,14 +46,21 @@ module Spec
46
46
  @output.flush
47
47
  end
48
48
 
49
- def dump_summary(duration, example_count, failure_count)
49
+ def dump_summary(duration, example_count, failure_count, not_implemented_count)
50
50
  return if @dry_run
51
51
  @output.puts
52
52
  @output.puts "Finished in #{duration} seconds"
53
53
  @output.puts
54
+
54
55
  summary = "#{example_count} example#{'s' unless example_count == 1}, #{failure_count} failure#{'s' unless failure_count == 1}"
56
+ summary << ", #{not_implemented_count} not implemented" if not_implemented_count > 0
57
+
55
58
  if failure_count == 0
56
- @output.puts green(summary)
59
+ if not_implemented_count > 0
60
+ @output.puts yellow(summary)
61
+ else
62
+ @output.puts green(summary)
63
+ end
57
64
  else
58
65
  @output.puts red(summary)
59
66
  end
@@ -87,6 +94,7 @@ module Spec
87
94
  def red(text); colour(text, "\e[31m"); end
88
95
  def green(text); colour(text, "\e[32m"); end
89
96
  def magenta(text); colour(text, "\e[35m"); end
97
+ def yellow(text); colour(text, "\e[33m"); end
90
98
 
91
99
  end
92
100
  end