rspec 0.9.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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