rspec 0.5.2 → 0.5.3

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 (37) hide show
  1. data/CHANGES +10 -2
  2. data/Rakefile +22 -30
  3. data/doc/src/default.css +11 -10
  4. data/doc/src/documentation/api.page +15 -82
  5. data/doc/src/documentation/mocks.page +12 -55
  6. data/doc/src/meta.info +4 -1
  7. data/examples/airport_spec.rb +0 -1
  8. data/examples/empty_stack_spec.rb +1 -0
  9. data/examples/stack_spec.rb +1 -0
  10. data/examples/team_spec.rb +30 -0
  11. data/lib/spec/api.rb +1 -0
  12. data/lib/spec/api/duck_type.rb +16 -0
  13. data/lib/spec/api/expectations.rb +4 -4
  14. data/lib/spec/api/mock.rb +1 -0
  15. data/lib/spec/runner/backtrace_tweaker.rb +1 -2
  16. data/lib/spec/runner/context.rb +2 -3
  17. data/lib/spec/runner/context_runner.rb +2 -2
  18. data/lib/spec/runner/execution_context.rb +4 -0
  19. data/lib/spec/runner/option_parser.rb +3 -2
  20. data/lib/spec/runner/simple_text_reporter.rb +11 -25
  21. data/lib/spec/runner/specification.rb +1 -2
  22. data/lib/spec/version.rb +1 -1
  23. data/test/{rake → rcov}/rcov_testtask.rb +4 -4
  24. data/test/rcov/rcov_verify.rb +28 -0
  25. data/test/spec/api/duck_type_test.rb +19 -0
  26. data/test/spec/api/mock_arg_constraints_test.rb +20 -0
  27. data/test/spec/runner/backtrace_tweaker_test.rb +16 -8
  28. data/test/spec/runner/context_runner_test.rb +3 -3
  29. data/test/spec/runner/context_test.rb +2 -2
  30. data/test/spec/runner/execution_context_test.rb +7 -0
  31. data/test/spec/runner/option_parser_test.rb +12 -2
  32. data/test/spec/runner/simple_text_reporter_test.rb +18 -47
  33. data/test/spec/runner/specification_test.rb +5 -5
  34. data/test/spec/tool/command_line_test.rb +0 -1
  35. data/test/test_helper.rb +1 -0
  36. metadata +9 -7
  37. data/doc/src/download.page +0 -7
@@ -9,31 +9,21 @@ RSpec contains a full featured Mock Objects framework.
9
9
  h3. Creating a mock
10
10
 
11
11
  <pre>
12
- <code>
13
12
  mock(<name>)
14
- </code>
15
13
  </pre>
16
14
 
17
- This creates a new mock with the given name (a string) and registers it. When
18
- the specification finishes, all registered mocks are verified.
15
+ This creates a new mock with the given name (a string) and registers it. When the specification finishes, all registered mocks are verified.
19
16
 
20
17
  <pre>
21
- <code>
22
18
  mock(<name>, <options>)
23
- </code>
24
19
  </pre>
25
20
 
26
- As above, but allows you to specific options to tweak the mock's behaviour.
27
- The <code>options</code> argument is a hash. Currently the only supported option is
28
- <code>:null_object</code>. Setting this to true (i.e. <code>:null_object => true</code>) instructs the
29
- mock to ignore (quietly consume) any messages it hasn't been told to expect.
21
+ As above, but allows you to specific options to tweak the mock's behaviour. The <code>options</code> argument is a hash. Currently the only supported option is <code>:null_object</code>. Setting this to true (i.e. <code>:null_object => true</code>) instructs the mock to ignore (quietly consume) any messages it hasn't been told to expect.
30
22
 
31
23
  h3. Expecting Messages
32
24
 
33
25
  <pre>
34
- <code>
35
26
  mock.should.receive(<message>)
36
- </code>
37
27
  </pre>
38
28
 
39
29
  The <code>message</code> argument is a symbol that is the name of a message that you want
@@ -46,9 +36,7 @@ by the mock, the block is evaluated, and passed any arguments. The result is
46
36
  the return value of the message. For example:
47
37
 
48
38
  <pre>
49
- <code>
50
39
  @mock.should.receive(:random_call) {| a | a.should.be true}
51
- </code>
52
40
  </pre>
53
41
 
54
42
  This allows arbitrary argument validation and result computation.
@@ -56,27 +44,21 @@ This allows arbitrary argument validation and result computation.
56
44
  h3. Expecting Arguments
57
45
 
58
46
  <pre>
59
- <code>
60
47
  mock.should.receive(:msg).with(<args>)
61
48
  mock.should.receive(:msg).with(1, 2, 3)
62
- </code>
63
49
  </pre>
64
50
 
65
51
  The <code>args</code> argument is a series of arguments (e..g. 1, 2, 3) that are expected
66
52
  to be passed as arguments to the associated message.
67
53
 
68
54
  <pre>
69
- <code>
70
55
  mock.should.receive(:msg).with(:no_args)
71
- </code>
72
56
  </pre>
73
57
 
74
58
  No arguments are to be accepted by the message.
75
59
 
76
60
  <pre>
77
- <code>
78
61
  mock.should.receive(:msg).with(:any_args)
79
- </code>
80
62
  </pre>
81
63
 
82
64
  Any arguments are to be accepted by the message. This includes cases where no
@@ -92,9 +74,7 @@ h4. :anything
92
74
  accepts any value for this argument
93
75
 
94
76
  <pre>
95
- <code>
96
77
  mock.should.receive(:msg).with(1, :anything, "A")
97
- </code>
98
78
  </pre>
99
79
 
100
80
  h4. :numeric
@@ -102,9 +82,7 @@ h4. :numeric
102
82
  accepts any numeric value for this argument
103
83
 
104
84
  <pre>
105
- <code>
106
85
  mock.should.receive(:msg).with(a, :numeric, "b")
107
- </code>
108
86
  </pre>
109
87
 
110
88
  h4. :boolean
@@ -112,9 +90,7 @@ h4. :boolean
112
90
  accepts a boolean value for this argument
113
91
 
114
92
  <pre>
115
- <code>
116
93
  mock.should.receive(:msg).with(a, :boolean, "b")
117
- </code>
118
94
  </pre>
119
95
 
120
96
  h4. :string
@@ -122,74 +98,65 @@ h4. :string
122
98
  accepts any string for this argument
123
99
 
124
100
  <pre>
125
- <code>
126
101
  mock.should.receive(:msg).with(a, :string, "b")
127
- </code>
128
102
  </pre>
129
103
 
104
+ h4. duck_type(message(s))
105
+
106
+ accepts any object that responds to the prescribed message(s)
107
+
108
+ <pre>
109
+ #accepts a Fixnum for the second arg
110
+ mock.should.receive(:msg).with(a, duck_type(:abs, :div), "b")
111
+ </pre>
112
+
130
113
  h3. Receive Counts
131
114
 
132
115
  <pre>
133
- <code>
134
116
  mock.should.receive(:msg).never
135
- </code>
136
117
  </pre>
137
118
 
138
119
  A problem is reported if the message is ever received.
139
120
 
140
121
  <pre>
141
- <code>
142
122
  mock.should.receive(:msg).any.number.of.times
143
- </code>
144
123
  </pre>
145
124
 
146
125
  The message can be received 0 or more times.
147
126
 
148
127
  <pre>
149
- <code>
150
128
  mock.should.receive(:msg).once
151
- </code>
152
129
  </pre>
153
130
 
154
131
  A problem is reported is the message is never received, or it is received more
155
132
  than once.
156
133
 
157
134
  <pre>
158
- <code>
159
135
  mock.should.receive(:msg).twice
160
- </code>
161
136
  </pre>
162
137
 
163
138
  A problem is reported is the message is received anything but two times.
164
139
 
165
140
  <pre>
166
- <code>
167
141
  mock.should.receive(:msg).exactly(n).times
168
- </code>
169
142
  </pre>
170
143
 
171
144
  A problem is reported is the message is received anything but n times.
172
145
 
173
146
  <pre>
174
- <code>
175
147
  mock.should.receive(:msg).at.least(:once)
176
- </code>
177
148
  </pre>
178
149
 
179
150
  A problem is reported if the message is never received.
180
151
 
181
152
  <pre>
182
- <code>
183
153
  mock.should.receive(:msg).at.least(:twice)
184
- </code>
185
154
  </pre>
186
155
 
187
156
  A problem is reported is the message is never received or is received only once.
188
157
 
189
158
  <pre>
190
- <code>
191
159
  mock.should.receive(:msg).at.least(n).times
192
- </code>
193
160
  </pre>
194
161
 
195
162
  A problem is reported is the message is received fewer than n times.
@@ -197,27 +164,21 @@ A problem is reported is the message is received fewer than n times.
197
164
  h3. Return Values
198
165
 
199
166
  <pre>
200
- <code>
201
167
  mock.should.receive(:msg).once.and.return(<value>)
202
- </code>
203
168
  </pre>
204
169
 
205
170
  When the expected message is received, <code>value</code> will be returned as the result.
206
171
 
207
172
  <pre>
208
- <code>
209
173
  and.return([<value-1>, <value-2>, ..., <value-n>])
210
- </code>
211
174
  </pre>
212
175
 
213
176
  When the expected message is received, <code>value-i</code> will be returned as the result
214
- for the ith reception of the message. Once i > n, <code>value-n</code> is returned for all
177
+ for the ith reception of the message. Once <code>i > n</code>, <code>value-n</code> is returned for all
215
178
  subsequent receives of the message.
216
179
 
217
180
  <pre>
218
- <code>
219
181
  mock.should.receive(:msg).once.and.return {...}
220
- </code>
221
182
  </pre>
222
183
 
223
184
  When the expected message is received, the result of evaluating the supplied
@@ -226,18 +187,14 @@ as parts of the message. This capability can be used to compute return values
226
187
  based on the arguments. For example:
227
188
 
228
189
  <pre>
229
- <code>
230
190
  mock.should.receive(:msg).once.and.return {|a, b| a + b}
231
- </code>
232
191
  </pre>
233
192
 
234
193
  h3. Raising and Throwing
235
194
 
236
195
  <pre>
237
- <code>
238
196
  mock.should.receive(:msg).once.and.raise(<exception>)
239
197
  mock.should.receive(:msg).once.and.throw(<symbol>)
240
- </code>
241
198
  </pre>
242
199
 
243
200
  These instruct the mock to raise an exception or throw a symbol instead of returning a value.
@@ -11,7 +11,10 @@ documentation:
11
11
  title: Documentation
12
12
  orderInfo: 4
13
13
 
14
- download.page:
14
+ download.html:
15
+ title: Download
16
+ inMenu: true
17
+ dest: http://rubyforge.org/frs/?group_id=797
15
18
  orderInfo: 5
16
19
 
17
20
  tools:
@@ -19,7 +19,6 @@ module Kernel
19
19
  alias topic context
20
20
  end
21
21
 
22
-
23
22
  topic "Airport at home" do
24
23
  setup do
25
24
  @airport = Airport.new
@@ -1,3 +1,4 @@
1
+ require File.dirname(__FILE__) + '/../lib/spec'
1
2
  require File.dirname(__FILE__) + "/stack"
2
3
 
3
4
  context "An empty stack" do
@@ -1,3 +1,4 @@
1
+ require File.dirname(__FILE__) + '/../lib/spec'
1
2
  require File.dirname(__FILE__) + "/stack"
2
3
 
3
4
  context "An empty stack" do
@@ -0,0 +1,30 @@
1
+ require File.dirname(__FILE__) + '/../lib/spec'
2
+
3
+ class Team
4
+ attr_reader :players
5
+ def initialize
6
+ @players = Players.new
7
+ end
8
+ end
9
+
10
+ class Players
11
+ def size
12
+ 0
13
+ end
14
+ end
15
+
16
+ context "A new team" do
17
+
18
+ setup do
19
+ @team = Team.new
20
+ end
21
+
22
+ specify "should have 3 players (failing example)" do
23
+ @team.should.have(3).players
24
+ end
25
+
26
+ specify "should have 1 player (failing example)" do
27
+ @team.players.size.should.be 1
28
+ end
29
+
30
+ end
@@ -1,4 +1,5 @@
1
1
  require 'spec/api/exceptions'
2
2
  require 'spec/api/mock'
3
+ require 'spec/api/duck_type'
3
4
  require 'spec/api/expectations'
4
5
  require 'spec/api/helper'
@@ -0,0 +1,16 @@
1
+ module Spec
2
+ module Api
3
+
4
+ class DuckType
5
+ def initialize(*methods_to_respond_do)
6
+ @methods_to_respond_do = methods_to_respond_do
7
+ end
8
+
9
+ def walks_like?(obj)
10
+ @methods_to_respond_do.each { |sym| return false unless obj.respond_to? sym }
11
+ return true
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -1,9 +1,9 @@
1
1
  module Spec
2
2
  module ObjectExpectations
3
- def should
4
- ShouldHelper.new self
5
- end
6
- end
3
+ def should
4
+ ShouldHelper.new self
5
+ end
6
+ end
7
7
  end
8
8
 
9
9
  class Object
@@ -88,6 +88,7 @@ module Spec
88
88
  next if @expected_params[i] == :numeric and args[i].is_a?Numeric
89
89
  next if @expected_params[i] == :boolean and args[i].is_a?TrueClass or args[i].is_a?FalseClass
90
90
  next if @expected_params[i] == :string and args[i].is_a?String
91
+ next if @expected_params[i].is_a? DuckType and @expected_params[i].walks_like? args[i]
91
92
  return false unless args[i] == @expected_params[i]
92
93
  end
93
94
  return true
@@ -5,8 +5,7 @@ module Spec
5
5
  return if error.backtrace.nil?
6
6
  error.backtrace.collect! do |line|
7
7
  line = line.split(':in')[0] + ":in `#{spec_name}'" if line.include?('__instance_exec')
8
- line = nil if line.include? '/lib/spec/api/helper/should_base.rb'
9
- line = nil if line.include? '/lib/spec/api/helper/should_negator.rb' unless line.nil?
8
+ line = nil if line =~ /\/lib\/spec\/api\/helper\/.+[helper|base|negator].rb/
10
9
  line
11
10
  end
12
11
  error.backtrace.compact!
@@ -13,13 +13,12 @@ module Spec
13
13
  @specifications = []
14
14
  @name = name
15
15
  instance_exec(&context_block)
16
- @@context_runner.add_context(self) unless @@context_runner.nil?
17
16
  ContextRunner.standalone(self) if @@context_runner.nil?
18
- @calling_line = caller(0)[2].split(":in")[0]
17
+ @@context_runner.add_context(self) unless @@context_runner.nil?
19
18
  end
20
19
 
21
20
  def run(reporter)
22
- reporter.add_context(@name, @calling_line)
21
+ reporter.add_context(@name)
23
22
  @specifications.each do |specification|
24
23
  specification.run(reporter, @setup_block, @teardown_block)
25
24
  end
@@ -4,8 +4,8 @@ module Spec
4
4
  module Runner
5
5
  class ContextRunner
6
6
 
7
- def self.standalone context
8
- context_runner = ContextRunner.new(ARGV, true)
7
+ def self.standalone(context, args=ARGV)
8
+ context_runner = ContextRunner.new(args, true)
9
9
  context_runner.add_context context
10
10
  context_runner.run
11
11
  end
@@ -11,6 +11,10 @@ module Spec
11
11
  mock
12
12
  end
13
13
 
14
+ def duck_type(*args)
15
+ return Api::DuckType.new(*args)
16
+ end
17
+
14
18
  def violated(message="")
15
19
  raise Spec::Api::ExpectationNotMetError.new(message)
16
20
  end
@@ -15,7 +15,8 @@ module Spec
15
15
  opts.separator ""
16
16
 
17
17
  opts.on("-o", "--of [FILE]", "Set the output file (defaults to STDOUT)") do |outfile|
18
- options.out = outfile unless outfile.nil?
18
+ options.out = StringIO.new if outfile == "stringio"
19
+ options.out = outfile unless outfile.nil? or outfile == "stringio"
19
20
  exit if outfile.nil?
20
21
  end
21
22
 
@@ -33,7 +34,7 @@ module Spec
33
34
  end
34
35
 
35
36
  opts.on_tail("-h", "--help", "Show this message") do
36
- err.puts opts
37
+ out.puts opts
37
38
  exit if out == $stdout
38
39
  end
39
40
 
@@ -6,24 +6,23 @@ module Spec
6
6
  @context_names = []
7
7
  @errors = []
8
8
  @spec_names = []
9
- @failures = []
10
9
  @verbose = verbose
11
10
  @backtrace_tweaker = backtrace_tweaker
12
11
  end
13
12
 
14
- def add_context(name, calling_line=nil)
13
+ def add_context(name)
15
14
  @output << "\n" if @context_names.empty? unless @verbose
16
15
  @output << "\n#{name}\n" if @verbose
17
- @context_names << [name, calling_line]
16
+ @context_names << name
18
17
  end
19
18
 
20
- def add_spec(name, calling_line, errors=[])
19
+ def add_spec(name, errors=[])
21
20
  if errors.empty?
22
21
  spec_passed(name)
23
22
  else
24
23
  errors.each { |error| @backtrace_tweaker.tweak_backtrace(error, name) }
25
24
  # only show the first one (there might be more)
26
- spec_failed(name, calling_line, errors[0])
25
+ spec_failed(name, errors[0])
27
26
  end
28
27
  end
29
28
 
@@ -37,7 +36,7 @@ module Spec
37
36
 
38
37
  def dump
39
38
  @output << "\n"
40
- dump_failures
39
+ dump_errors
41
40
  @output << "\n\n" unless @errors.empty?
42
41
  @output << "\n" if @errors.empty?
43
42
  @output << "Finished in " << (duration).to_s << " seconds\n\n"
@@ -47,16 +46,14 @@ module Spec
47
46
  @output << "\n"
48
47
  end
49
48
 
50
- def dump_failures
49
+ def dump_errors
51
50
  return if @errors.empty?
52
51
  @output << "\n"
53
- @failures.inject(1) do |index, failure|
52
+ @errors.inject(1) do |index, error|
54
53
  @output << "\n\n" if index > 1
55
54
  @output << index.to_s << ")\n"
56
- @output << "#{failure.error.message} (#{failure.error.class.name})\n"
57
- @output << "Context: #{failure.context_name} [#{failure.context_line}]\n"
58
- @output << "Specification: #{failure.spec_name} [#{failure.spec_line}]\n"
59
- dump_backtrace(failure.error.backtrace)
55
+ @output << "#{error.message} (#{error.class.name})\n"
56
+ dump_backtrace(error.backtrace)
60
57
  index + 1
61
58
  end
62
59
  end
@@ -78,25 +75,14 @@ module Spec
78
75
  @output << '.' unless @verbose
79
76
  end
80
77
 
81
- def spec_failed(name, calling_line, error)
78
+ def spec_failed(name, error)
82
79
  @spec_names << name
83
80
  @errors << error
84
- @failures << Failure.new(@context_names.last[0], @context_names.last[1], name, calling_line, error)
85
- @output << "- #{name} (FAILED - #{@failures.length})\n" if @verbose
81
+ @output << "- #{name} (FAILED - #{@errors.length})\n" if @verbose
86
82
  @output << 'F' unless @verbose
87
83
  end
88
84
 
89
85
  end
90
86
 
91
- class Failure
92
- attr_reader :context_name, :context_line, :spec_name, :spec_line, :error
93
- def initialize(context_name, context_line, spec_name, spec_line, error)
94
- @context_name = context_name
95
- @context_line = context_line
96
- @spec_name = spec_name
97
- @spec_line = spec_line
98
- @error = error
99
- end
100
- end
101
87
  end
102
88
  end