rspec 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. data/.document +4 -4
  2. data/{History.txt → History.rdoc} +27 -4
  3. data/Manifest.txt +18 -7
  4. data/{README.txt → README.rdoc} +0 -0
  5. data/Rakefile +16 -9
  6. data/{Ruby1.9.markdown → Ruby1.9.rdoc} +3 -3
  7. data/TODO.txt +0 -7
  8. data/Upgrade.rdoc +110 -0
  9. data/features/matchers/create_matcher.feature +40 -0
  10. data/features/matchers/create_matcher_outside_rspec.feature +39 -0
  11. data/features/pending/pending_examples.feature +5 -5
  12. data/features/step_definitions/running_rspec.rb +13 -0
  13. data/features/subject/explicit_subject.feature +31 -0
  14. data/features/subject/implicit_subject.feature +31 -0
  15. data/lib/spec/adapters/mock_frameworks/flexmock.rb +1 -0
  16. data/lib/spec/adapters/mock_frameworks/mocha.rb +1 -0
  17. data/lib/spec/adapters/mock_frameworks/rr.rb +1 -0
  18. data/lib/spec/adapters/mock_frameworks/rspec.rb +12 -10
  19. data/lib/spec/dsl.rb +0 -1
  20. data/lib/spec/dsl/main.rb +3 -3
  21. data/lib/spec/example.rb +4 -3
  22. data/lib/spec/example/example_group_factory.rb +1 -3
  23. data/lib/spec/example/example_group_methods.rb +22 -28
  24. data/lib/spec/example/example_group_proxy.rb +64 -0
  25. data/lib/spec/example/example_methods.rb +8 -11
  26. data/lib/spec/example/example_proxy.rb +42 -0
  27. data/lib/spec/example/shared_example_group.rb +1 -1
  28. data/lib/spec/example/subject.rb +14 -3
  29. data/lib/spec/expectations.rb +1 -1
  30. data/lib/spec/expectations/differs/default.rb +46 -49
  31. data/lib/spec/expectations/differs/load-diff-lcs.rb +12 -0
  32. data/lib/spec/interop/test/unit/testcase.rb +2 -2
  33. data/lib/spec/matchers.rb +49 -9
  34. data/lib/spec/matchers/be.rb +12 -15
  35. data/lib/spec/matchers/change.rb +1 -0
  36. data/lib/spec/matchers/dsl.rb +15 -0
  37. data/lib/spec/matchers/have.rb +9 -8
  38. data/lib/spec/matchers/include.rb +2 -16
  39. data/lib/spec/matchers/match_array.rb +2 -14
  40. data/lib/spec/matchers/matcher.rb +16 -11
  41. data/lib/spec/matchers/pretty.rb +36 -0
  42. data/lib/spec/matchers/raise_error.rb +9 -8
  43. data/lib/spec/matchers/simple_matcher.rb +1 -0
  44. data/lib/spec/matchers/throw_symbol.rb +1 -1
  45. data/lib/spec/mocks/argument_expectation.rb +2 -0
  46. data/lib/spec/mocks/message_expectation.rb +2 -0
  47. data/lib/spec/mocks/proxy.rb +9 -10
  48. data/lib/spec/runner.rb +1 -0
  49. data/lib/spec/runner/extensions/kernel.rb +9 -0
  50. data/lib/spec/runner/formatter/base_formatter.rb +22 -9
  51. data/lib/spec/runner/formatter/html_formatter.rb +2 -1
  52. data/lib/spec/runner/heckle_runner.rb +1 -0
  53. data/lib/spec/runner/option_parser.rb +4 -1
  54. data/lib/spec/runner/options.rb +11 -0
  55. data/lib/spec/runner/spec_parser.rb +15 -22
  56. data/lib/spec/version.rb +4 -6
  57. data/spec/autotest/autotest_helper.rb +6 -1
  58. data/spec/spec/dsl/main_spec.rb +3 -3
  59. data/spec/spec/example/example_group_factory_spec.rb +11 -23
  60. data/spec/spec/example/example_group_methods_spec.rb +45 -20
  61. data/spec/spec/example/example_group_proxy_spec.rb +63 -0
  62. data/spec/spec/example/example_group_spec.rb +15 -0
  63. data/spec/spec/example/example_methods_spec.rb +5 -35
  64. data/spec/spec/example/example_proxy_spec.rb +47 -0
  65. data/spec/spec/example/nested_example_group_spec.rb +3 -3
  66. data/spec/spec/example/shared_example_group_spec.rb +4 -4
  67. data/spec/spec/example/subject_spec.rb +77 -0
  68. data/spec/spec/matchers/be_close_spec.rb +10 -10
  69. data/spec/spec/matchers/be_instance_of_spec.rb +13 -8
  70. data/spec/spec/matchers/be_kind_of_spec.rb +10 -8
  71. data/spec/spec/{dsl/matchers_spec.rb → matchers/dsl_spec.rb} +4 -4
  72. data/spec/spec/matchers/matcher_spec.rb +53 -1
  73. data/spec/spec/matchers/matchers_spec.rb +2 -0
  74. data/spec/spec/package/bin_spec_spec.rb +4 -4
  75. data/spec/spec/runner/command_line_spec.rb +2 -2
  76. data/spec/spec/runner/formatter/failing_example_groups_formatter_spec.rb +4 -4
  77. data/spec/spec/runner/formatter/failing_examples_formatter_spec.rb +2 -2
  78. data/spec/spec/runner/formatter/html_formatted-1.8.4.html +1 -1
  79. data/spec/spec/runner/formatter/html_formatted-1.8.5-jruby.html +1 -1
  80. data/spec/spec/runner/formatter/html_formatted-1.8.5.html +1 -1
  81. data/spec/spec/runner/formatter/html_formatted-1.8.6-jruby.html +1 -1
  82. data/spec/spec/runner/formatter/html_formatted-1.8.6.html +1 -1
  83. data/spec/spec/runner/formatter/html_formatted-1.8.7.html +1 -1
  84. data/spec/spec/runner/formatter/html_formatted-1.9.1.html +1 -1
  85. data/spec/spec/runner/formatter/nested_text_formatter_spec.rb +12 -11
  86. data/spec/spec/runner/formatter/profile_formatter_spec.rb +2 -2
  87. data/spec/spec/runner/formatter/progress_bar_formatter_spec.rb +2 -2
  88. data/spec/spec/runner/formatter/specdoc_formatter_spec.rb +2 -2
  89. data/spec/spec/runner/formatter/text_mate_formatted-1.8.4.html +1 -1
  90. data/spec/spec/runner/formatter/text_mate_formatted-1.8.6.html +1 -1
  91. data/spec/spec/runner/formatter/text_mate_formatted-1.8.7.html +1 -1
  92. data/spec/spec/runner/formatter/text_mate_formatted-1.9.1.html +1 -1
  93. data/spec/spec/runner/option_parser_spec.rb +20 -0
  94. data/spec/spec/runner/options_spec.rb +23 -1
  95. data/spec/spec/runner/reporter_spec.rb +20 -17
  96. data/spec/spec/runner/spec_parser_spec.rb +1 -1
  97. metadata +33 -15
  98. data/Upgrade.markdown +0 -63
  99. data/lib/spec/dsl/matchers.rb +0 -13
  100. data/lib/spec/example/example_description.rb +0 -15
@@ -18,18 +18,16 @@ module Spec
18
18
  # description
19
19
  # => "should start with a balance of 0"
20
20
  def description
21
- @_defined_description || ::Spec::Matchers.generated_description || "NO NAME"
21
+ @_proxy.description || ::Spec::Matchers.generated_description || "NO NAME"
22
22
  end
23
23
 
24
24
  def options # :nodoc:
25
- @_options
25
+ @_proxy.options
26
26
  end
27
27
 
28
28
  def execute(run_options, instance_variables) # :nodoc:
29
- # FIXME - there is no reason to have example_started pass a name
30
- # - in fact, it would introduce bugs in cases where no docstring
31
- # is passed to it()
32
- run_options.reporter.example_started("")
29
+ puts caller unless caller(0)[1] =~ /example_group_methods/
30
+ run_options.reporter.example_started(@_proxy)
33
31
  set_instance_variables_from_hash(instance_variables)
34
32
 
35
33
  execution_error = nil
@@ -47,7 +45,7 @@ module Spec
47
45
  end
48
46
  end
49
47
 
50
- run_options.reporter.example_finished(ExampleDescription.new(description, options), execution_error)
48
+ run_options.reporter.example_finished(@_proxy.update(description), execution_error)
51
49
  success = execution_error.nil? || ExamplePendingError === execution_error
52
50
  end
53
51
 
@@ -77,7 +75,7 @@ module Spec
77
75
  def set_instance_variables_from_hash(ivars) # :nodoc:
78
76
  ivars.each do |variable_name, value|
79
77
  # Ruby 1.9 requires variable.to_s on the next line
80
- unless ['@_defined_description', '@_options', '@_implementation', '@method_name'].include?(variable_name.to_s)
78
+ unless ['@_proxy', '@_implementation', '@method_name'].include?(variable_name.to_s)
81
79
  instance_variable_set variable_name, value
82
80
  end
83
81
  end
@@ -107,9 +105,8 @@ WARNING
107
105
  example_group_hierarchy.run_after_each(self)
108
106
  end
109
107
 
110
- def initialize(description, options={}, &implementation)
111
- @_options = options
112
- @_defined_description = description
108
+ def initialize(example_proxy, &implementation)
109
+ @_proxy = example_proxy
113
110
  @_implementation = implementation
114
111
  @_backtrace = caller
115
112
  end
@@ -0,0 +1,42 @@
1
+ module Spec
2
+ module Example
3
+ # Lightweight representation of an example. This is the object
4
+ # that is passed to example-related methods in
5
+ # Spec::Runner::Formatter::BaseFormatter
6
+ class ExampleProxy
7
+
8
+ def initialize(description=nil, options={}, location=nil) # :nodoc:
9
+ @description, @options, @location = description, options, location
10
+ end
11
+
12
+ # This is the docstring passed to the <tt>it()</tt> method or any
13
+ # of its aliases
14
+ attr_reader :description
15
+
16
+ # Internal use only - used to store options to pass to example
17
+ # when it is initialized
18
+ attr_reader :options # :nodoc:
19
+
20
+ # The file and line number at which the represented example
21
+ # was declared. This is extracted from <tt>caller</tt>, and is therefore
22
+ # formatted as an individual line in a backtrace.
23
+ attr_reader :location
24
+
25
+ # Deprecated - use location()
26
+ def backtrace
27
+ location
28
+ end
29
+
30
+ # Convenience method for example group - updates the value of
31
+ # <tt>description</tt> and returns self.
32
+ def update(description) # :nodoc:
33
+ @description = description
34
+ self
35
+ end
36
+
37
+ def ==(other) # :nodoc:
38
+ (other.description == description) & (other.backtrace == backtrace)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -39,7 +39,7 @@ module Spec
39
39
  end
40
40
 
41
41
  def expanded_path(example_group)
42
- File.expand_path(example_group.spec_path)
42
+ File.expand_path(example_group.location)
43
43
  end
44
44
  end
45
45
 
@@ -15,12 +15,23 @@ module Spec
15
15
  #
16
16
  # See +ExampleMethods#should+ for more information about this approach.
17
17
  def subject(&block)
18
- if block.nil?
19
- @_subject_block || (described_class ? lambda {described_class.new} : lambda {description_args.first})
18
+ block.nil? ?
19
+ explicit_subject || implicit_subject : @_explicit_subject_block = block
20
+ end
21
+
22
+ def explicit_subject
23
+ if defined?(@_explicit_subject_block)
24
+ @_explicit_subject_block
25
+ elsif super_subject = superclass.instance_variable_get('@_explicit_subject_block')
26
+ super_subject
20
27
  else
21
- @_subject_block = block
28
+ nil
22
29
  end
23
30
  end
31
+
32
+ def implicit_subject
33
+ (described_class ? lambda {described_class.new} : lambda {description_args.first})
34
+ end
24
35
  end
25
36
 
26
37
  module ExampleMethods
@@ -31,7 +31,7 @@ module Spec
31
31
  # matchers is quite simple. See Spec::Matchers for details.
32
32
  module Expectations
33
33
  def self.differ
34
- @differ
34
+ defined?(@differ) ? @differ : nil
35
35
  end
36
36
 
37
37
  def self.differ=(differ)
@@ -1,64 +1,61 @@
1
- begin
2
- require 'diff/lcs' #necessary due to loading bug on some machines - not sure why - DaC
3
- require 'diff/lcs/hunk'
4
- rescue LoadError ; raise "You must gem install diff-lcs to use diffing" ; end
5
-
1
+ require File.join(File.dirname(__FILE__), "/load-diff-lcs")
6
2
  require 'pp'
7
3
 
8
4
  module Spec
9
5
  module Expectations
10
6
  module Differs
7
+ unless defined?(Default)
8
+ class Default
9
+ def initialize(options)
10
+ @options = options
11
+ end
11
12
 
12
- # TODO add some rdoc
13
- class Default
14
- def initialize(options)
15
- @options = options
16
- end
17
-
18
- # This is snagged from diff/lcs/ldiff.rb (which is a commandline tool)
19
- def diff_as_string(data_new, data_old)
20
- data_old = data_old.split(/\n/).map! { |e| e.chomp }
21
- data_new = data_new.split(/\n/).map! { |e| e.chomp }
22
- output = ""
23
- diffs = Diff::LCS.diff(data_old, data_new)
24
- return output if diffs.empty?
25
- oldhunk = hunk = nil
26
- file_length_difference = 0
27
- diffs.each do |piece|
28
- begin
29
- hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, context_lines,
30
- file_length_difference)
31
- file_length_difference = hunk.file_length_difference
32
- next unless oldhunk
33
- # Hunks may overlap, which is why we need to be careful when our
34
- # diff includes lines of context. Otherwise, we might print
35
- # redundant lines.
36
- if (context_lines > 0) and hunk.overlaps?(oldhunk)
37
- hunk.unshift(oldhunk)
38
- else
39
- output << oldhunk.diff(format)
13
+ # This is snagged from diff/lcs/ldiff.rb (which is a commandline tool)
14
+ def diff_as_string(data_new, data_old)
15
+ data_old = data_old.split(/\n/).map! { |e| e.chomp }
16
+ data_new = data_new.split(/\n/).map! { |e| e.chomp }
17
+ output = ""
18
+ diffs = Diff::LCS.diff(data_old, data_new)
19
+ return output if diffs.empty?
20
+ oldhunk = hunk = nil
21
+ file_length_difference = 0
22
+ diffs.each do |piece|
23
+ begin
24
+ hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, context_lines,
25
+ file_length_difference)
26
+ file_length_difference = hunk.file_length_difference
27
+ next unless oldhunk
28
+ # Hunks may overlap, which is why we need to be careful when our
29
+ # diff includes lines of context. Otherwise, we might print
30
+ # redundant lines.
31
+ if (context_lines > 0) and hunk.overlaps?(oldhunk)
32
+ hunk.unshift(oldhunk)
33
+ else
34
+ output << oldhunk.diff(format)
35
+ end
36
+ ensure
37
+ oldhunk = hunk
38
+ output << "\n"
40
39
  end
41
- ensure
42
- oldhunk = hunk
43
- output << "\n"
44
- end
40
+ end
41
+ #Handle the last remaining hunk
42
+ output << oldhunk.diff(format) << "\n"
45
43
  end
46
- #Handle the last remaining hunk
47
- output << oldhunk.diff(format) << "\n"
48
- end
49
44
 
50
- def diff_as_object(target,expected)
51
- diff_as_string(PP.pp(target,""), PP.pp(expected,""))
52
- end
45
+ def diff_as_object(target,expected)
46
+ diff_as_string(PP.pp(target,""), PP.pp(expected,""))
47
+ end
53
48
 
54
- protected
55
- def format
56
- @options.diff_format
57
- end
49
+ protected
50
+ def format
51
+ @options.diff_format
52
+ end
58
53
 
59
- def context_lines
60
- @options.context_lines
54
+ def context_lines
55
+ @options.context_lines
56
+ end
61
57
  end
58
+
62
59
  end
63
60
  end
64
61
  end
@@ -0,0 +1,12 @@
1
+ begin
2
+ require 'diff/lcs'
3
+ rescue LoadError
4
+ begin
5
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
6
+ require 'diff/lcs'
7
+ rescue LoadError
8
+ raise "You must gem install diff-lcs to use diffing"
9
+ end
10
+ end
11
+
12
+ require 'diff/lcs/hunk'
@@ -40,10 +40,10 @@ module Test
40
40
  before(:each) {setup}
41
41
  after(:each) {teardown}
42
42
 
43
- def initialize(description, options={}, &implementation)
43
+ def initialize(description, &implementation)
44
44
  super
45
45
  # Some Test::Unit extensions depend on @method_name being present.
46
- @method_name = description
46
+ @method_name = description.description
47
47
  @_result = ::Test::Unit::TestResult.new
48
48
  end
49
49
 
@@ -1,4 +1,5 @@
1
1
  require 'spec/matchers/extensions/instance_exec'
2
+ require 'spec/matchers/pretty'
2
3
  require 'spec/matchers/matcher'
3
4
  require 'spec/matchers/operator_matcher'
4
5
  require 'spec/matchers/be'
@@ -24,6 +25,7 @@ require 'spec/matchers/simple_matcher'
24
25
  require 'spec/matchers/throw_symbol'
25
26
  require 'spec/matchers/wrap_expectation'
26
27
  require 'spec/matchers/compatibility'
28
+ require 'spec/matchers/dsl'
27
29
 
28
30
  module Spec
29
31
 
@@ -82,14 +84,17 @@ module Spec
82
84
  # You can use this feature to invoke any predicate that begins with "has_", whether it is
83
85
  # part of the Ruby libraries (like +Hash#has_key?+) or a method you wrote on your own class.
84
86
  #
85
- # == Custom Expectation Matchers
87
+ # == Custom Matchers
86
88
  #
87
89
  # When you find that none of the stock Expectation Matchers provide a natural
88
- # feeling expectation, you can very easily write your own.
90
+ # feeling expectation, you can very easily write your own using RSpec's matcher
91
+ # DSL or writing one from scratch.
89
92
  #
90
- # For example, imagine that you are writing a game in which players can
91
- # be in various zones on a virtual board. To specify that bob should
92
- # be in zone 4, you could say:
93
+ # === Matcher DSL
94
+ #
95
+ # Imagine that you are writing a game in which players can be in various
96
+ # zones on a virtual board. To specify that bob should be in zone 4, you
97
+ # could say:
93
98
  #
94
99
  # bob.current_zone.should eql(Zone.new("4"))
95
100
  #
@@ -101,7 +106,42 @@ module Spec
101
106
  #
102
107
  # bob.should_not be_in_zone("3")
103
108
  #
104
- # To do this, you would need to write a class like this:
109
+ # You can create such a matcher like so:
110
+ #
111
+ # Spec::Matchers.create :be_in_zone do |zone|
112
+ # match do |player|
113
+ # player.in_zone?(zone)
114
+ # end
115
+ # end
116
+ #
117
+ # This will generate a <tt>be_in_zone</tt> method that returns a matcher
118
+ # with logical default messages for failures. You can override the failure
119
+ # messages and the generated description as follows:
120
+ #
121
+ # Spec::Matchers.create :be_in_zone do |zone|
122
+ # match do |player|
123
+ # player.in_zone?(zone)
124
+ # end
125
+ # failure_message_for_should do |player|
126
+ # # generate and return the appropriate string.
127
+ # end
128
+ # failure_message_for_should_not do |player|
129
+ # # generate and return the appropriate string.
130
+ # end
131
+ # description do
132
+ # # generate and return the appropriate string.
133
+ # end
134
+ # end
135
+ #
136
+ # Each of the message-generation methods has access to the block arguments
137
+ # passed to the <tt>create</tt> method (in this case, <tt>zone</tt>). The
138
+ # failure message methods (<tt>failure_message_for_should</tt> and
139
+ # <tt>failure_message_for_should_not</tt>) are passed the actual value (the
140
+ # receiver of <tt>should</tt> or <tt>should_not</tt>).
141
+ #
142
+ # === Custom Matcher from scratch
143
+ #
144
+ # You could also write a custom matcher from scratch, as follows:
105
145
  #
106
146
  # class BeInZone
107
147
  # def initialize(expected)
@@ -111,10 +151,10 @@ module Spec
111
151
  # @target = target
112
152
  # @target.current_zone.eql?(Zone.new(@expected))
113
153
  # end
114
- # def failure_message
154
+ # def failure_message_for_should
115
155
  # "expected #{@target.inspect} to be in Zone #{@expected}"
116
156
  # end
117
- # def negative_failure_message
157
+ # def failure_message_for_should_not
118
158
  # "expected #{@target.inspect} not to be in Zone #{@expected}"
119
159
  # end
120
160
  # end
@@ -152,4 +192,4 @@ module Spec
152
192
  # end
153
193
  #
154
194
  module Matchers; end
155
- end
195
+ end
@@ -2,9 +2,12 @@ module Spec
2
2
  module Matchers
3
3
 
4
4
  class Be #:nodoc:
5
+ include Spec::Matchers::Pretty
6
+
5
7
  def initialize(*args)
6
8
  @expected = args.empty? ? true : set_expected(args.shift)
7
9
  @args = args
10
+ @comparison_method = nil
8
11
  end
9
12
 
10
13
  def matches?(actual)
@@ -98,6 +101,9 @@ it reads really poorly.
98
101
  end
99
102
 
100
103
  def prefix
104
+ # FIXME - this is a bit goofy - but we get failures
105
+ # if just defining @prefix = nil in initialize
106
+ @prefix = nil unless defined?(@prefix)
101
107
  @prefix
102
108
  end
103
109
 
@@ -107,7 +113,9 @@ it reads really poorly.
107
113
 
108
114
  def handling_predicate?
109
115
  return false if [true, false, nil].include?(expected)
110
- return @handling_predicate
116
+ # FIXME - this is a bit goofy - but we get failures
117
+ # if just defining @handling_predicate = nil or false in initialize
118
+ return defined?(@handling_predicate) ? @handling_predicate : nil
111
119
  end
112
120
 
113
121
  def predicate
@@ -142,19 +150,8 @@ it reads really poorly.
142
150
  split_words(prefix)
143
151
  end
144
152
 
145
- def split_words(sym)
146
- sym.to_s.gsub(/_/,' ')
147
- end
148
-
149
153
  def args_to_sentence
150
- case @args.length
151
- when 0
152
- ""
153
- when 1
154
- " #{@args[0]}"
155
- else
156
- " #{@args[0...-1].join(', ')} and #{@args[-1]}"
157
- end
154
+ to_sentence(@args)
158
155
  end
159
156
 
160
157
  end
@@ -163,9 +160,9 @@ it reads really poorly.
163
160
  # should be_true
164
161
  # should be_false
165
162
  # should be_nil
166
- # should be_arbitrary_predicate(*args)
163
+ # should be_[arbitrary_predicate](*args)
167
164
  # should_not be_nil
168
- # should_not be_arbitrary_predicate(*args)
165
+ # should_not be_[arbitrary_predicate](*args)
169
166
  #
170
167
  # Given true, false, or nil, will pass if actual value is
171
168
  # true, false or nil (respectively). Given no args means
@@ -6,6 +6,7 @@ module Spec
6
6
  def initialize(receiver=nil, message=nil, &block)
7
7
  @message = message || "result"
8
8
  @value_proc = block || lambda {receiver.__send__(message)}
9
+ @to = @from = @minimum = @maximum = @amount = nil
9
10
  end
10
11
 
11
12
  def matches?(event_proc)