rspec 0.4.0 → 0.5.0
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.
- 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
|