rspec 0.5.2 → 0.5.3

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