rspec 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +7 -12
- data/Rakefile +17 -12
- data/TUTORIAL +1 -1
- data/WHY_RSPEC +115 -0
- data/bin/spec +17 -4
- data/bin/test2rspec +35 -0
- data/examples/airport_spec.rb +35 -0
- data/examples/mocking_spec.rb +16 -0
- data/examples/spec_framework_spec.rb +28 -0
- data/examples/stack.rb +36 -0
- data/examples/stack_spec.rb +112 -0
- data/lib/spec.rb +5 -18
- data/lib/spec/api.rb +4 -0
- data/lib/spec/{exceptions.rb → api/exceptions.rb} +1 -1
- data/lib/spec/{expectations.rb → api/expectations.rb} +5 -4
- data/lib/spec/api/helper.rb +10 -0
- data/lib/spec/{have_helper.rb → api/helper/have_helper.rb} +1 -1
- data/lib/spec/{instance_helper.rb → api/helper/instance_helper.rb} +0 -0
- data/lib/spec/{instance_negator.rb → api/helper/instance_negator.rb} +0 -0
- data/lib/spec/{kind_helper.rb → api/helper/kind_helper.rb} +0 -0
- data/lib/spec/{kind_negator.rb → api/helper/kind_negator.rb} +0 -0
- data/lib/spec/{respond_helper.rb → api/helper/respond_helper.rb} +0 -0
- data/lib/spec/{respond_negator.rb → api/helper/respond_negator.rb} +0 -0
- data/lib/spec/{should_base.rb → api/helper/should_base.rb} +6 -4
- data/lib/spec/{should_helper.rb → api/helper/should_helper.rb} +12 -0
- data/lib/spec/{should_negator.rb → api/helper/should_negator.rb} +11 -0
- data/lib/spec/api/mock.rb +184 -0
- data/lib/spec/rake/spectask.rb +153 -0
- data/lib/spec/runner.rb +9 -0
- data/lib/spec/runner/backtrace_tweaker.rb +17 -0
- data/lib/spec/runner/context.rb +47 -0
- data/lib/spec/runner/context_runner.rb +52 -0
- data/lib/spec/runner/execution_context.rb +15 -0
- data/lib/spec/runner/instance_exec.rb +15 -0
- data/lib/spec/runner/kernel_ext.rb +6 -0
- data/lib/spec/runner/option_parser.rb +41 -0
- data/lib/spec/runner/rdoc_formatter.rb +17 -0
- data/lib/spec/runner/simple_text_reporter.rb +92 -0
- data/lib/spec/runner/specification.rb +42 -0
- data/lib/spec/tool/command_line.rb +39 -0
- data/lib/spec/tool/test_unit_translator.rb +112 -0
- data/lib/spec/version.rb +13 -0
- data/test/spec/api/helper/arbitrary_predicate_test.rb +121 -0
- data/test/spec/api/helper/containment_test.rb +117 -0
- data/test/spec/api/helper/equality_test.rb +46 -0
- data/test/spec/api/helper/identity_test.rb +68 -0
- data/test/spec/api/helper/raising_test.rb +50 -0
- data/test/spec/api/helper/regex_matching_test.rb +38 -0
- data/test/spec/api/helper/should_satisfy_test.rb +37 -0
- data/test/spec/api/helper/throwing_test.rb +56 -0
- data/test/spec/api/helper/true_false_special_case_test.rb +87 -0
- data/test/spec/api/helper/typing_test.rb +107 -0
- data/test/spec/api/mock_test.rb +161 -0
- data/test/spec/runner/backtrace_tweaker_test.rb +20 -0
- data/test/spec/runner/context_runner_test.rb +19 -0
- data/test/spec/runner/context_test.rb +29 -0
- data/test/spec/runner/execution_context_test.rb +13 -0
- data/test/spec/runner/option_parser_test.rb +50 -0
- data/test/spec/runner/rdoc_formatter_test.rb +23 -0
- data/test/spec/runner/simple_text_reporter_test.rb +128 -0
- data/test/spec/runner/specification_test.rb +70 -0
- data/test/spec/tool/command_line_test.rb +22 -0
- data/test/spec/tool/test_unit_api_spec.rb +61 -0
- data/test/spec/tool/test_unit_api_test.rb +61 -0
- data/test/spec/tool/test_unit_translator_test.rb +29 -0
- data/test/test_helper.rb +8 -0
- metadata +89 -67
- data/examples/add_specification_spec.rb +0 -15
- data/examples/craps.rb +0 -15
- data/examples/craps_spec.rb +0 -105
- data/examples/dsl_spec.rb +0 -8
- data/examples/movie.rb +0 -7
- data/examples/movie_list.rb +0 -19
- data/examples/movie_spec.rb +0 -37
- data/lib/spec/collector.rb +0 -17
- data/lib/spec/context.rb +0 -89
- data/lib/spec/dsl.rb +0 -23
- data/lib/spec/gui_runner.rb +0 -59
- data/lib/spec/mock.rb +0 -183
- data/lib/spec/text_runner.rb +0 -75
- data/test/collection_owner.rb +0 -48
- data/test/context_fixtures_test.rb +0 -71
- data/test/context_run_test.rb +0 -174
- data/test/dsl_test.rb +0 -48
- data/test/error_reporting_test.rb +0 -225
- data/test/expectations_for_should_have_test.rb +0 -144
- data/test/expectations_test.rb +0 -592
- data/test/get_classes.rb +0 -6
- data/test/gui_runner_test.rb +0 -162
- data/test/mock_test.rb +0 -157
- data/test/spec_collection_test.rb +0 -39
- data/test/specification_addition_test.rb +0 -29
- data/test/specification_identification_test.rb +0 -71
- data/test/text_runner_test.rb +0 -146
data/examples/movie_spec.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'spec'
|
2
|
-
require 'movie'
|
3
|
-
require 'movie_list'
|
4
|
-
|
5
|
-
class EmptyMovieList < Spec::Context
|
6
|
-
|
7
|
-
def setup
|
8
|
-
@list = MovieList.new
|
9
|
-
end
|
10
|
-
|
11
|
-
def should_have_size_of_0
|
12
|
-
@list.size.should.equal 0
|
13
|
-
end
|
14
|
-
|
15
|
-
def should_not_include_star_wars
|
16
|
-
@list.should.not.include "Star Wars"
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
class OneMovieList < Spec::Context
|
22
|
-
|
23
|
-
def setup
|
24
|
-
@list = MovieList.new
|
25
|
-
star_wars = Movie.new "Star Wars"
|
26
|
-
@list.add star_wars
|
27
|
-
end
|
28
|
-
|
29
|
-
def should_have_size_of_1
|
30
|
-
@list.size.should.equal 1
|
31
|
-
end
|
32
|
-
|
33
|
-
def should_include_star_wars
|
34
|
-
@list.should.include "Star Wars"
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
data/lib/spec/collector.rb
DELETED
data/lib/spec/context.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
require 'spec'
|
2
|
-
|
3
|
-
module Spec
|
4
|
-
# TODO: Could we try to make this a mixin (Module) instead? It would make it easier to
|
5
|
-
# create extensions that can be mixed and matched (AH).
|
6
|
-
class Context
|
7
|
-
|
8
|
-
def initialize(specification=nil)
|
9
|
-
@specification = specification
|
10
|
-
@mocks = []
|
11
|
-
end
|
12
|
-
|
13
|
-
def setup
|
14
|
-
end
|
15
|
-
|
16
|
-
def teardown
|
17
|
-
end
|
18
|
-
|
19
|
-
# Creates a new named mock that will be automatically verified after #teardown
|
20
|
-
# has run. By using this method instead of Mock#new you don't have to worry about
|
21
|
-
# forgetting to verify your mocks.
|
22
|
-
def mock(name)
|
23
|
-
mock = Mock.new(name)
|
24
|
-
@mocks << mock
|
25
|
-
mock
|
26
|
-
end
|
27
|
-
|
28
|
-
# Immediately violates the current specification with +message+.
|
29
|
-
def violated(message="")
|
30
|
-
raise Spec::Exceptions::ExpectationNotMetError.new(message)
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.collection
|
34
|
-
specs = []
|
35
|
-
self.specifications.each do |spec|
|
36
|
-
specs << self.new(spec.to_sym)
|
37
|
-
end
|
38
|
-
|
39
|
-
return specs
|
40
|
-
end
|
41
|
-
|
42
|
-
def run(result_listener)
|
43
|
-
result = false
|
44
|
-
|
45
|
-
result_listener.spec(@specification)
|
46
|
-
setup
|
47
|
-
begin
|
48
|
-
__send__(@specification)
|
49
|
-
result_listener.pass(@specification)
|
50
|
-
rescue Exception
|
51
|
-
result_listener.failure(@specification, $!)
|
52
|
-
ensure
|
53
|
-
begin
|
54
|
-
teardown
|
55
|
-
verify_mocks
|
56
|
-
rescue Exception
|
57
|
-
result_listener.failure(@specification, $!)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
return result
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.add_specification(name, &block)
|
65
|
-
self.send(:define_method, name.to_sym, Proc.new { || block.call })
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
def self.my_methods
|
71
|
-
self.instance_methods - self.superclass.instance_methods
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.specification_name?(name)
|
75
|
-
return false unless self.new.method(name).arity == 0
|
76
|
-
return false if name[0..0] == '_'
|
77
|
-
true
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.specifications
|
81
|
-
return self.my_methods.select {|spec| self.specification_name?(spec)}
|
82
|
-
end
|
83
|
-
|
84
|
-
def verify_mocks
|
85
|
-
@mocks.each{|m| m.__verify}
|
86
|
-
end
|
87
|
-
|
88
|
-
end
|
89
|
-
end
|
data/lib/spec/dsl.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'spec'
|
2
|
-
|
3
|
-
module DSLExtensions
|
4
|
-
|
5
|
-
def context(name)
|
6
|
-
eval "$#{name} = Class.new(Spec::Context)"
|
7
|
-
$current_context = eval "$#{name}"
|
8
|
-
end
|
9
|
-
|
10
|
-
def specification(name, &block)
|
11
|
-
$default_context ||= Class.new(Spec::Context)
|
12
|
-
$current_context = $default_context if $current_context.nil?
|
13
|
-
|
14
|
-
$current_context.add_specification(name.to_sym, &block)
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
class Object
|
20
|
-
include DSLExtensions
|
21
|
-
end
|
22
|
-
|
23
|
-
alias example specification if ENV['USER'] == 'marick'
|
data/lib/spec/gui_runner.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
@socket
|
3
|
-
module Spec
|
4
|
-
class GuiRunner
|
5
|
-
|
6
|
-
def initialize(port)
|
7
|
-
@failures = Array.new
|
8
|
-
@specification_count = 0
|
9
|
-
@failure_count = 0
|
10
|
-
@failed = false
|
11
|
-
@socket = TCPSocket.new("127.0.0.1", port)
|
12
|
-
@socket << "connected\n"
|
13
|
-
end
|
14
|
-
|
15
|
-
def run(context_or_collection = Spec::Collector)
|
16
|
-
specs = context_or_collection.collection
|
17
|
-
start_run specs.size
|
18
|
-
specs.each {|spec| spec.run(self)}
|
19
|
-
end_run
|
20
|
-
@socket.shutdown
|
21
|
-
end
|
22
|
-
|
23
|
-
def spec(spec)
|
24
|
-
@failed = false
|
25
|
-
end
|
26
|
-
|
27
|
-
def pass(spec)
|
28
|
-
@socket << "passed\n"
|
29
|
-
end
|
30
|
-
|
31
|
-
def failure(spec, exception)
|
32
|
-
return if @failed
|
33
|
-
@socket << "failed\n"
|
34
|
-
@failed = true
|
35
|
-
dump_failure(exception)
|
36
|
-
end
|
37
|
-
|
38
|
-
def start_run(number_of_specs)
|
39
|
-
@socket << "start #{number_of_specs.to_i}\n"
|
40
|
-
end
|
41
|
-
|
42
|
-
def end_run
|
43
|
-
@socket << "end\n"
|
44
|
-
end
|
45
|
-
|
46
|
-
def dump_failure(exception)
|
47
|
-
@socket << "#{exception.message} (#{exception.class.name})\n"
|
48
|
-
dump_backtrace(exception.backtrace)
|
49
|
-
@socket << "!\n"
|
50
|
-
end
|
51
|
-
|
52
|
-
def dump_backtrace(trace)
|
53
|
-
lines = trace.reject {|line| line.include? "lib/spec"}.reject {|line | line.include? "./spec:"}
|
54
|
-
@socket << lines.join("\n")
|
55
|
-
@socket << "\n"
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
end
|
data/lib/spec/mock.rb
DELETED
@@ -1,183 +0,0 @@
|
|
1
|
-
require 'spec'
|
2
|
-
|
3
|
-
class Mock
|
4
|
-
|
5
|
-
DEFAULT_OPTIONS = {
|
6
|
-
:null_object => false
|
7
|
-
}
|
8
|
-
# Creates a new mock with a +name+ (that will be used in error messages only)
|
9
|
-
# Options:
|
10
|
-
# * :null_object - if true, the mock object acts as a forgiving null object allowing any message to be sent to it.
|
11
|
-
def initialize(name, options={})
|
12
|
-
@name = name
|
13
|
-
@options = DEFAULT_OPTIONS.dup.merge(options)
|
14
|
-
@expectations = []
|
15
|
-
end
|
16
|
-
|
17
|
-
# AH: How about renaming this to should_receive. This would be:
|
18
|
-
# * well aligned with the rest of the API (should)
|
19
|
-
# * emphasize the dynamic oo lingo from smalltalk using 'message' instead of 'method'
|
20
|
-
def should_receive(sym, &block)
|
21
|
-
expected_from = caller(1)[0]
|
22
|
-
expectation = MessageExpectation.new(@name, expected_from, sym, block_given? ? block : nil)
|
23
|
-
@expectations << expectation
|
24
|
-
expectation
|
25
|
-
end
|
26
|
-
|
27
|
-
def __verify
|
28
|
-
@expectations.each do |expectation|
|
29
|
-
expectation.verify_messages_received
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def method_missing(sym, *args, &block)
|
34
|
-
# TODO: use find_expectation(sym, args) which will lookup based on sym, args and strict mode.
|
35
|
-
if expectation = find_matching_expectation(sym, *args)
|
36
|
-
expectation.verify_message(args, block)
|
37
|
-
else
|
38
|
-
begin
|
39
|
-
# act as null object if method is missing and we ignore them. return value too!
|
40
|
-
@options[:null_object] ? self : super(sym, *args, &block)
|
41
|
-
rescue NoMethodError
|
42
|
-
raise Spec::Exceptions::MockExpectationError, "Mock '#{@name}' received unexpected message '#{sym.to_s}' with " + (args.collect{|arg| "<#{arg}:#{arg.class.name}>"}.join(", "))
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def find_matching_expectation(sym, *args)
|
50
|
-
expectation = @expectations.find {|expectation| expectation.matches(sym, args)}
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
# Represents the expection of the reception of a message
|
56
|
-
class MessageExpectation
|
57
|
-
|
58
|
-
def initialize(mock_name, expected_from, sym, block)
|
59
|
-
@mock_name = mock_name
|
60
|
-
@expected_from = expected_from
|
61
|
-
@sym = sym
|
62
|
-
@method_block = block
|
63
|
-
@block = proc {}
|
64
|
-
@received_count = 0
|
65
|
-
@expected_received_count = 1
|
66
|
-
@expected_params = nil
|
67
|
-
@consecutive = false
|
68
|
-
end
|
69
|
-
|
70
|
-
def matches(sym, args)
|
71
|
-
@sym == sym and (@expected_params.nil? or @expected_params == args)
|
72
|
-
end
|
73
|
-
|
74
|
-
# This method is called at the end of a spec, after teardown.
|
75
|
-
def verify_messages_received
|
76
|
-
# TODO: this doesn't provide good enough error messages to fix the error.
|
77
|
-
# Error msg should tell exactly what went wrong. (AH).
|
78
|
-
|
79
|
-
return if @expected_received_count == -2
|
80
|
-
return if (@expected_received_count == -1) && (@received_count > 0)
|
81
|
-
return if @expected_received_count == @received_count
|
82
|
-
|
83
|
-
expected_signature = nil
|
84
|
-
if @expected_params.nil?
|
85
|
-
expected_signature = @sym
|
86
|
-
else
|
87
|
-
params = @expected_params.collect{|param| "<#{param}:#{param.class.name}>"}.join(", ")
|
88
|
-
expected_signature = "#{@sym}(#{params})"
|
89
|
-
end
|
90
|
-
|
91
|
-
count_message = "{@expected_received_count} times"
|
92
|
-
count_message = "at least once" if (@expected_received_count == -1)
|
93
|
-
count_message = "never" if (@expected_received_count == 0)
|
94
|
-
count_message = "once" if (@expected_received_count == 1)
|
95
|
-
count_message = "twice" if (@expected_received_count == 2)
|
96
|
-
|
97
|
-
message = "#{@expected_from}: Mock '#{@mock_name}' expected #{expected_signature} #{count_message}, but received it #{@received_count} times"
|
98
|
-
raise Spec::Exceptions::MockExpectationError, message
|
99
|
-
end
|
100
|
-
|
101
|
-
# This method is called when a method is invoked on a mock
|
102
|
-
def verify_message(args, block)
|
103
|
-
unless @method_block.nil?
|
104
|
-
begin
|
105
|
-
result = @method_block.call(*args)
|
106
|
-
rescue Spec::Exceptions::ExpectationNotMetError => detail
|
107
|
-
raise Spec::Exceptions::MockExpectationError, "Call expectation violated with: " + $!
|
108
|
-
end
|
109
|
-
@received_count += 1
|
110
|
-
return result
|
111
|
-
end
|
112
|
-
|
113
|
-
unless @expected_params.nil? or @expected_params == args
|
114
|
-
raise Spec::Exceptions::MockExpectationError,
|
115
|
-
"#{@sym}: Parameter mismatch: Expected <#{@expected_params}>, got <#{args}>"
|
116
|
-
end
|
117
|
-
args << block unless block.nil?
|
118
|
-
@received_count += 1
|
119
|
-
value = @block.call(*args)
|
120
|
-
|
121
|
-
return value unless @consecutive
|
122
|
-
|
123
|
-
value[[@received_count, value.size].min - 1]
|
124
|
-
end
|
125
|
-
|
126
|
-
def with(*args)
|
127
|
-
@expected_params = args
|
128
|
-
self
|
129
|
-
end
|
130
|
-
|
131
|
-
def with_no_args
|
132
|
-
@expected_params = []
|
133
|
-
self
|
134
|
-
end
|
135
|
-
|
136
|
-
def with_any_args
|
137
|
-
@expected_params = nil
|
138
|
-
self
|
139
|
-
end
|
140
|
-
|
141
|
-
def at_least_once
|
142
|
-
@expected_received_count = -1
|
143
|
-
self
|
144
|
-
end
|
145
|
-
|
146
|
-
def any_number_of_times
|
147
|
-
@expected_received_count = -2
|
148
|
-
self
|
149
|
-
end
|
150
|
-
|
151
|
-
def never
|
152
|
-
@expected_received_count = 0
|
153
|
-
self
|
154
|
-
end
|
155
|
-
|
156
|
-
def once
|
157
|
-
@expected_received_count = 1
|
158
|
-
self
|
159
|
-
end
|
160
|
-
|
161
|
-
def twice
|
162
|
-
@expected_received_count = 2
|
163
|
-
self
|
164
|
-
end
|
165
|
-
|
166
|
-
def returns(value=nil,&block)
|
167
|
-
@block = block_given? ? block : proc { value }
|
168
|
-
end
|
169
|
-
|
170
|
-
def returns_consecutively(value=[nil],&block)
|
171
|
-
@consecutive = true
|
172
|
-
@block = block_given? ? block : proc { value }
|
173
|
-
end
|
174
|
-
|
175
|
-
# this reads better in English IMHO: (AH)
|
176
|
-
# uri_specs.should_receive(:[]).with(:overview).and_return("http://some.host/look_here/\#{path}")
|
177
|
-
alias :and_return :returns
|
178
|
-
alias :and_return_consecutively :returns_consecutively
|
179
|
-
|
180
|
-
end
|
181
|
-
|
182
|
-
class Counter
|
183
|
-
end
|
data/lib/spec/text_runner.rb
DELETED
@@ -1,75 +0,0 @@
|
|
1
|
-
module Spec
|
2
|
-
class TextRunner
|
3
|
-
|
4
|
-
def initialize(appendable = $stdout)
|
5
|
-
@failures = Array.new
|
6
|
-
@specification_count = 0
|
7
|
-
@failure_count = 0
|
8
|
-
@failed = false
|
9
|
-
@output = appendable
|
10
|
-
end
|
11
|
-
|
12
|
-
def run(context_or_collection = Spec::Collector)
|
13
|
-
start_run
|
14
|
-
context_or_collection.collection.each {|context| context.run(self)}
|
15
|
-
end_run
|
16
|
-
end
|
17
|
-
|
18
|
-
def spec(spec)
|
19
|
-
@specification_count += 1
|
20
|
-
@failed = false
|
21
|
-
end
|
22
|
-
|
23
|
-
def pass(spec)
|
24
|
-
@output << "."
|
25
|
-
end
|
26
|
-
|
27
|
-
def failure(spec, exception)
|
28
|
-
@output << "X" unless @failed
|
29
|
-
@failure_count += 1 unless @failed
|
30
|
-
@failed = true
|
31
|
-
@failures << exception
|
32
|
-
end
|
33
|
-
|
34
|
-
def start_run
|
35
|
-
@output << "\n"
|
36
|
-
@start_time = Time.new
|
37
|
-
end
|
38
|
-
|
39
|
-
def end_run
|
40
|
-
@end_time = Time.new
|
41
|
-
@output << "\n\n"
|
42
|
-
|
43
|
-
dump_failures
|
44
|
-
|
45
|
-
dump_duration(@end_time - @start_time)
|
46
|
-
|
47
|
-
dump_counts
|
48
|
-
end
|
49
|
-
|
50
|
-
def dump_failures
|
51
|
-
@failures.inject(1) do |index, exception|
|
52
|
-
@output << index.to_s << ")\n"
|
53
|
-
@output << "#{exception.message} (#{exception.class.name})\n"
|
54
|
-
dump_backtrace(exception.backtrace)
|
55
|
-
index + 1
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def dump_backtrace(trace)
|
60
|
-
lines = trace.reject {|line| line.include? "lib/spec"}.reject {|line | line.include? "./spec:"}
|
61
|
-
@output << lines.join("\n")
|
62
|
-
@output << "\n\n"
|
63
|
-
end
|
64
|
-
|
65
|
-
def dump_duration(duration)
|
66
|
-
@output << "Finished in " << duration.to_s << " seconds\n"
|
67
|
-
end
|
68
|
-
|
69
|
-
def dump_counts
|
70
|
-
@output << "\n" << @specification_count.to_s << " specifications, "
|
71
|
-
@output << @failure_count.to_s << " failures\n"
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
75
|
-
end
|