flexmock 1.0.2 → 1.0.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.
- data/README.rdoc +34 -25
- data/TAGS +2192 -117
- data/lib/flexmock/core.rb +6 -1
- data/lib/flexmock/default_framework_adapter.rb +1 -0
- data/lib/flexmock/expectation.rb +10 -2
- data/lib/flexmock/expectation_director.rb +2 -2
- data/lib/flexmock/mock_container.rb +14 -13
- data/lib/flexmock/partial_mock.rb +13 -4
- data/lib/flexmock/recorder.rb +2 -1
- data/lib/flexmock/rspec.rb +1 -0
- data/lib/flexmock/spy_describers.rb +13 -3
- data/lib/flexmock/test_unit_integration.rb +11 -0
- data/lib/flexmock/validators.rb +35 -8
- data/lib/flexmock/version.rb +1 -1
- data/test/assert_spy_called_test.rb +17 -0
- data/test/base_class_test.rb +11 -1
- data/test/demeter_mocking_test.rb +1 -1
- data/test/new_instances_test.rb +1 -1
- data/test/record_mode_test.rb +6 -6
- data/test/rspec_integration/integration_spec.rb +1 -1
- data/test/should_receive_test.rb +38 -22
- data/test/test_setup.rb +41 -1
- metadata +2 -2
data/lib/flexmock/core.rb
CHANGED
@@ -197,9 +197,14 @@ class FlexMock
|
|
197
197
|
# See Expectation for a list of declarators that can be used.
|
198
198
|
#
|
199
199
|
def should_receive(*args)
|
200
|
+
location = caller.first
|
201
|
+
flexmock_define_expectation(location, *args)
|
202
|
+
end
|
203
|
+
|
204
|
+
def flexmock_define_expectation(location, *args)
|
200
205
|
@last_expectation = ContainerHelper.parse_should_args(self, args) do |sym|
|
201
206
|
@expectations[sym] ||= ExpectationDirector.new(sym)
|
202
|
-
result = Expectation.new(self, sym)
|
207
|
+
result = Expectation.new(self, sym, location)
|
203
208
|
@expectations[sym] << result
|
204
209
|
override_existing_method(sym) if flexmock_respond_to?(sym)
|
205
210
|
result = ExplicitNeeded.new(result, sym, @base_class) if
|
data/lib/flexmock/expectation.rb
CHANGED
@@ -32,9 +32,10 @@ class FlexMock
|
|
32
32
|
attr_accessor :mock
|
33
33
|
|
34
34
|
# Create an expectation for a method named +sym+.
|
35
|
-
def initialize(mock, sym)
|
35
|
+
def initialize(mock, sym, location)
|
36
36
|
@mock = mock
|
37
37
|
@sym = sym
|
38
|
+
@location = location
|
38
39
|
@expected_args = nil
|
39
40
|
@count_validators = []
|
40
41
|
@count_validator_class = ExactCountValidator
|
@@ -392,6 +393,13 @@ class FlexMock
|
|
392
393
|
expectations.defaultify_expectation(self) if expectations
|
393
394
|
end
|
394
395
|
|
396
|
+
def flexmock_location_filter
|
397
|
+
yield
|
398
|
+
rescue Exception => ex
|
399
|
+
ex.backtrace.insert(0, @location)
|
400
|
+
raise ex
|
401
|
+
end
|
402
|
+
|
395
403
|
end
|
396
404
|
|
397
405
|
##########################################################################
|
@@ -434,7 +442,7 @@ class FlexMock
|
|
434
442
|
# Start a new method expectation. The following constraints will be
|
435
443
|
# applied to the new expectation.
|
436
444
|
def should_receive(*args, &block)
|
437
|
-
@expectations.first.mock.
|
445
|
+
@expectations.first.mock.flexmock_define_expectation(caller.first, *args, &block)
|
438
446
|
end
|
439
447
|
|
440
448
|
# Return a string representations
|
@@ -37,8 +37,8 @@ class FlexMock
|
|
37
37
|
# criteria.
|
38
38
|
def call(*args)
|
39
39
|
exp = find_expectation(*args)
|
40
|
-
FlexMock.check(
|
41
|
-
FlexMock.format_args(@sym, args)) { ! exp.nil? }
|
40
|
+
FlexMock.check(
|
41
|
+
"no matching handler found for " + FlexMock.format_args(@sym, args)) { ! exp.nil? }
|
42
42
|
exp.verify_call(*args)
|
43
43
|
end
|
44
44
|
|
@@ -117,6 +117,7 @@ class FlexMock
|
|
117
117
|
# the mock object.
|
118
118
|
#
|
119
119
|
def flexmock(*args)
|
120
|
+
location = caller.first
|
120
121
|
name = nil
|
121
122
|
quick_defs = {}
|
122
123
|
domain_obj = nil
|
@@ -160,10 +161,10 @@ class FlexMock
|
|
160
161
|
result = mock
|
161
162
|
end
|
162
163
|
mock.flexmock_based_on(base_class) if base_class
|
163
|
-
mock.
|
164
|
+
mock.flexmock_define_expectation(location, quick_defs)
|
164
165
|
yield(mock) if block_given?
|
165
166
|
flexmock_remember(mock)
|
166
|
-
ContainerHelper.add_model_methods(mock, model_class, id) if model_class
|
167
|
+
ContainerHelper.add_model_methods(mock, model_class, id, location) if model_class
|
167
168
|
result
|
168
169
|
end
|
169
170
|
alias flexstub flexmock
|
@@ -230,29 +231,29 @@ class FlexMock
|
|
230
231
|
|
231
232
|
# Automatically add mocks for some common methods in ActiveRecord
|
232
233
|
# models.
|
233
|
-
def add_model_methods(mock, model_class, id)
|
234
|
+
def add_model_methods(mock, model_class, id, location)
|
234
235
|
container = mock.flexmock_container
|
235
236
|
|
236
237
|
mock_errors = container.flexmock("errors")
|
237
|
-
mock_errors.
|
238
|
-
mock_errors.
|
238
|
+
mock_errors.flexmock_define_expectation(location, :count).and_return(0).by_default
|
239
|
+
mock_errors.flexmock_define_expectation(location, :full_messages).and_return([]).by_default
|
239
240
|
|
240
|
-
mock.
|
241
|
-
mock.
|
242
|
-
mock.
|
243
|
-
mock.
|
244
|
-
mock.
|
241
|
+
mock.flexmock_define_expectation(location, :id).and_return(id).by_default
|
242
|
+
mock.flexmock_define_expectation(location, :to_params).and_return(id.to_s).by_default
|
243
|
+
mock.flexmock_define_expectation(location, :new_record?).and_return(false).by_default
|
244
|
+
mock.flexmock_define_expectation(location, :class).and_return(model_class).by_default
|
245
|
+
mock.flexmock_define_expectation(location, :errors).and_return(mock_errors).by_default
|
245
246
|
|
246
247
|
# HACK: Ruby 1.9 needs the following lambda so that model_class
|
247
248
|
# is correctly bound below.
|
248
249
|
lambda { }
|
249
|
-
mock.
|
250
|
+
mock.flexmock_define_expectation(location, :is_a?).with(any).and_return { |other|
|
250
251
|
other == model_class
|
251
252
|
}.by_default
|
252
|
-
mock.
|
253
|
+
mock.flexmock_define_expectation(location, :instance_of?).with(any).and_return { |other|
|
253
254
|
other == model_class
|
254
255
|
}.by_default
|
255
|
-
mock.
|
256
|
+
mock.flexmock_define_expectation(location, :kind_of?).with(any).and_return { |other|
|
256
257
|
model_class.ancestors.include?(other)
|
257
258
|
}.by_default
|
258
259
|
end
|
@@ -33,6 +33,7 @@ class FlexMock
|
|
33
33
|
|
34
34
|
MOCK_METHODS = [
|
35
35
|
:should_receive, :new_instances,
|
36
|
+
:should_receive_with_location,
|
36
37
|
:flexmock_get, :flexmock_teardown, :flexmock_verify,
|
37
38
|
:flexmock_received?, :flexmock_calls,
|
38
39
|
]
|
@@ -79,11 +80,16 @@ class FlexMock
|
|
79
80
|
#
|
80
81
|
# See Expectation for a list of declarators that can be used.
|
81
82
|
def should_receive(*args)
|
83
|
+
location = caller.first
|
84
|
+
flexmock_define_expectation(location, *args)
|
85
|
+
end
|
86
|
+
|
87
|
+
def flexmock_define_expectation(location, *args)
|
82
88
|
ContainerHelper.parse_should_args(@mock, args) do |sym|
|
83
89
|
unless @methods_proxied.include?(sym)
|
84
90
|
hide_existing_method(sym)
|
85
91
|
end
|
86
|
-
ex = @mock.
|
92
|
+
ex = @mock.flexmock_define_expectation(location, sym)
|
87
93
|
ex.mock = self
|
88
94
|
ex
|
89
95
|
end
|
@@ -123,14 +129,17 @@ class FlexMock
|
|
123
129
|
#
|
124
130
|
def new_instances(*allocators, &block)
|
125
131
|
fail ArgumentError, "new_instances requires a Class to stub" unless Class === @obj
|
132
|
+
location = caller.first
|
126
133
|
allocators = [:new] if allocators.empty?
|
127
134
|
result = ExpectationRecorder.new
|
128
135
|
allocators.each do |allocate_method|
|
129
136
|
check_allocate_method(allocate_method)
|
130
|
-
# HACK: Without the following lambda, Ruby 1.9
|
131
|
-
# the allocate_method parameter
|
137
|
+
# HACK: Without the following lambda, Some versions of Ruby 1.9
|
138
|
+
# would not bind the allocate_method parameter
|
139
|
+
# correctly. I don't think it is necessary for recent
|
140
|
+
# versions.
|
132
141
|
lambda { }
|
133
|
-
self.
|
142
|
+
self.flexmock_define_expectation(location, allocate_method).and_return { |*args|
|
134
143
|
new_obj = invoke_original(allocate_method, args)
|
135
144
|
mock = flexmock_container.flexmock(new_obj)
|
136
145
|
block.call(mock) if block_given?
|
data/lib/flexmock/recorder.rb
CHANGED
@@ -57,7 +57,8 @@ class FlexMock
|
|
57
57
|
# Record an expectation for receiving the method +sym+ with the
|
58
58
|
# given arguments.
|
59
59
|
def method_missing(sym, *args, &block)
|
60
|
-
|
60
|
+
location = caller.first
|
61
|
+
expectation = @mock.flexmock_define_expectation(location, sym).and_return(&block)
|
61
62
|
if strict?
|
62
63
|
args = args.collect { |arg| eq(arg) }
|
63
64
|
expectation.with(*args).ordered.once
|
data/lib/flexmock/rspec.rb
CHANGED
@@ -19,9 +19,19 @@ class FlexMock
|
|
19
19
|
result << times_description(options[:times])
|
20
20
|
result << block_description(options[:with_block])
|
21
21
|
result << ".\n"
|
22
|
-
result <<
|
23
|
-
|
24
|
-
|
22
|
+
result << describe_calls(spy)
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
def describe_calls(spy)
|
27
|
+
result = ''
|
28
|
+
if spy.flexmock_calls.empty?
|
29
|
+
result << "No messages have been received\n"
|
30
|
+
else
|
31
|
+
result << "The following messages have been received:\n"
|
32
|
+
spy.flexmock_calls.each do |call_sym, call_args|
|
33
|
+
result << " " << call_description(call_sym, call_args) << "\n"
|
34
|
+
end
|
25
35
|
end
|
26
36
|
result
|
27
37
|
end
|
@@ -46,6 +46,17 @@ class FlexMock
|
|
46
46
|
#
|
47
47
|
class TestUnitFrameworkAdapter
|
48
48
|
include Test::Unit::Assertions
|
49
|
+
|
50
|
+
def assert_block(msg, &block)
|
51
|
+
unless yield
|
52
|
+
msg = msg.call if msg.is_a?(Proc)
|
53
|
+
super(msg) { false }
|
54
|
+
end
|
55
|
+
rescue assertion_failed_error => ex
|
56
|
+
ex.message.sub!(/Expected block to return true value./,'')
|
57
|
+
raise ex
|
58
|
+
end
|
59
|
+
|
49
60
|
def assertion_failed_error
|
50
61
|
defined?(Test::Unit::AssertionFailedError) ? Test::Unit::AssertionFailedError : MiniTest::Assertion
|
51
62
|
end
|
data/lib/flexmock/validators.rb
CHANGED
@@ -10,6 +10,7 @@
|
|
10
10
|
#+++
|
11
11
|
|
12
12
|
require 'flexmock/noop'
|
13
|
+
require 'flexmock/spy_describers'
|
13
14
|
|
14
15
|
class FlexMock
|
15
16
|
|
@@ -17,6 +18,8 @@ class FlexMock
|
|
17
18
|
# Base class for all the count validators.
|
18
19
|
#
|
19
20
|
class CountValidator
|
21
|
+
include FlexMock::SpyDescribers
|
22
|
+
|
20
23
|
def initialize(expectation, limit)
|
21
24
|
@exp = expectation
|
22
25
|
@limit = limit
|
@@ -28,6 +31,10 @@ class FlexMock
|
|
28
31
|
def eligible?(n)
|
29
32
|
n < @limit
|
30
33
|
end
|
34
|
+
|
35
|
+
def calls(n)
|
36
|
+
n == 1 ? "call" : "calls"
|
37
|
+
end
|
31
38
|
end
|
32
39
|
|
33
40
|
####################################################################
|
@@ -37,8 +44,16 @@ class FlexMock
|
|
37
44
|
# Validate that the method expectation was called exactly +n+
|
38
45
|
# times.
|
39
46
|
def validate(n)
|
40
|
-
|
41
|
-
|
47
|
+
@exp.flexmock_location_filter do
|
48
|
+
FlexMock.framework_adapter.assert_block(
|
49
|
+
lambda {
|
50
|
+
"Method '#{@exp}' called incorrect number of times\n" +
|
51
|
+
"#{@limit} #{calls(@limit)} expected\n" +
|
52
|
+
"#{n} matching #{calls(n)} found\n" +
|
53
|
+
describe_calls(@exp.mock)
|
54
|
+
}
|
55
|
+
) { @limit == n }
|
56
|
+
end
|
42
57
|
end
|
43
58
|
end
|
44
59
|
|
@@ -49,9 +64,15 @@ class FlexMock
|
|
49
64
|
# Validate the method expectation was called no more than +n+
|
50
65
|
# times.
|
51
66
|
def validate(n)
|
52
|
-
|
53
|
-
|
54
|
-
|
67
|
+
@exp.flexmock_location_filter do
|
68
|
+
FlexMock.framework_adapter.assert_block(
|
69
|
+
lambda {
|
70
|
+
"Method '#{@exp}' called incorrect number of times\n" +
|
71
|
+
"At least #{@limit} #{calls(@limit)} expected\n" +
|
72
|
+
"#{n} matching #{calls(n)} found\n" +
|
73
|
+
describe_calls(@exp.mock)
|
74
|
+
}) { n >= @limit }
|
75
|
+
end
|
55
76
|
end
|
56
77
|
|
57
78
|
# If the expectation has been called +n+ times, is it still
|
@@ -69,9 +90,15 @@ class FlexMock
|
|
69
90
|
class AtMostCountValidator < CountValidator
|
70
91
|
# Validate the method expectation was called at least +n+ times.
|
71
92
|
def validate(n)
|
72
|
-
|
73
|
-
|
74
|
-
|
93
|
+
@exp.flexmock_location_filter do
|
94
|
+
FlexMock.framework_adapter.assert_block(
|
95
|
+
lambda {
|
96
|
+
"Method '#{@exp}' called incorrect number of times\n" +
|
97
|
+
"At most #{@limit} #{calls(@limit)} expected\n" +
|
98
|
+
"#{n} matching #{calls(n)} found\n" +
|
99
|
+
describe_calls(@exp.mock)
|
100
|
+
}) { n <= @limit }
|
101
|
+
end
|
75
102
|
end
|
76
103
|
end
|
77
104
|
end
|
data/lib/flexmock/version.rb
CHANGED
@@ -76,6 +76,23 @@ class AssertSpyCalledTest < Test::Unit::TestCase
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
+
def test_assert_error_lists_calls_actually_made
|
80
|
+
spy.foo
|
81
|
+
spy.bar(1)
|
82
|
+
ex = assert_fails(/The following messages have been received/) do
|
83
|
+
assert_spy_called spy, :baz
|
84
|
+
end
|
85
|
+
assert_match(/ foo\(\)/, ex.message)
|
86
|
+
assert_match(/ bar\(1\)/, ex.message)
|
87
|
+
assert_no_match(/ baz\(\)/, ex.message)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_assert_errors_say_no_calls_made
|
91
|
+
ex = assert_fails(/No messages have been received/) do
|
92
|
+
assert_spy_called spy, :baz
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
79
96
|
private
|
80
97
|
|
81
98
|
def assert_fails(message_pattern)
|
data/test/base_class_test.rb
CHANGED
@@ -21,10 +21,20 @@ class BaseClassTest < Test::Unit::TestCase
|
|
21
21
|
@mock ||= flexmock(:on, FooBar)
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
24
|
+
def test_base_class_auto_mocks_class
|
25
25
|
assert_equal FooBar, mock.class
|
26
26
|
end
|
27
27
|
|
28
|
+
def test_base_class_auto_mocks_base_class_methods
|
29
|
+
assert_equal FlexMock.undefined, mock.foo
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_base_class_does_not_mock_non_base_class_methods
|
33
|
+
assert_raise(NoMethodError) do
|
34
|
+
mock.fuzz
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
28
38
|
def test_can_stub_existing_methods
|
29
39
|
mock.should_receive(:foo => :bar)
|
30
40
|
assert_equal :bar, mock.foo
|
@@ -65,7 +65,7 @@ class TestDemeterMocking < Test::Unit::TestCase
|
|
65
65
|
def test_conflicting_mock_declarations_in_reverse_order_does_not_raise_error
|
66
66
|
# Not all conflicting definitions can be detected.
|
67
67
|
m = flexmock("A")
|
68
|
-
assert_failure
|
68
|
+
assert_failure do
|
69
69
|
m.should_receive("child.other").and_return(:other)
|
70
70
|
m.should_receive("child").and_return(:xyzzy)
|
71
71
|
assert_equal :xyzzy, m.child.other
|
data/test/new_instances_test.rb
CHANGED
@@ -96,7 +96,7 @@ class TestNewInstances < Test::Unit::TestCase
|
|
96
96
|
|
97
97
|
Dog.new
|
98
98
|
ex = assert_raise(assertion_failed_error) { flexmock_teardown }
|
99
|
-
assert_match(/method 'bark\(.*\)' called incorrect number of times
|
99
|
+
assert_match(/method 'bark\(.*\)' called incorrect number of times/i, ex.message)
|
100
100
|
end
|
101
101
|
|
102
102
|
def test_new_instances_reports_error_on_non_classes
|
data/test/record_mode_test.rb
CHANGED
@@ -71,7 +71,7 @@ class TestRecordMode < Test::Unit::TestCase
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def test_recording_mode_should_validate_args_with_equals
|
74
|
-
|
74
|
+
assert_mock_failure(:deep => true, :line => __LINE__+5) do
|
75
75
|
FlexMock.use("mock") do |mock|
|
76
76
|
mock.should_expect do |r|
|
77
77
|
r.f(1)
|
@@ -82,7 +82,7 @@ class TestRecordMode < Test::Unit::TestCase
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def test_recording_mode_should_allow_arg_contraint_validation
|
85
|
-
|
85
|
+
assert_mock_failure(:deep => true, :line => __LINE__+5) do
|
86
86
|
FlexMock.use("mock") do |mock|
|
87
87
|
mock.should_expect do |r|
|
88
88
|
r.f(1)
|
@@ -93,7 +93,7 @@ class TestRecordMode < Test::Unit::TestCase
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def test_recording_mode_should_handle_multiplicity_contraints
|
96
|
-
|
96
|
+
assert_mock_failure(:line => __LINE__+3) do
|
97
97
|
FlexMock.use("mock") do |mock|
|
98
98
|
mock.should_expect do |r|
|
99
99
|
r.f { :result }.once
|
@@ -105,7 +105,7 @@ class TestRecordMode < Test::Unit::TestCase
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def test_strict_record_mode_requires_exact_argument_matches
|
108
|
-
|
108
|
+
assert_mock_failure(:deep => true, :line => __LINE__+6) do
|
109
109
|
FlexMock.use("mock") do |mock|
|
110
110
|
mock.should_expect do |rec|
|
111
111
|
rec.should_be_strict
|
@@ -117,7 +117,7 @@ class TestRecordMode < Test::Unit::TestCase
|
|
117
117
|
end
|
118
118
|
|
119
119
|
def test_strict_record_mode_requires_exact_ordering
|
120
|
-
|
120
|
+
assert_mock_failure(:deep => true, :line => __LINE__+8) do
|
121
121
|
FlexMock.use("mock") do |mock|
|
122
122
|
mock.should_expect do |rec|
|
123
123
|
rec.should_be_strict
|
@@ -131,7 +131,7 @@ class TestRecordMode < Test::Unit::TestCase
|
|
131
131
|
end
|
132
132
|
|
133
133
|
def test_strict_record_mode_requires_once
|
134
|
-
|
134
|
+
assert_mock_failure(:deep => true, :line => __LINE__+4) do
|
135
135
|
FlexMock.use("mock") do |mock|
|
136
136
|
mock.should_expect do |rec|
|
137
137
|
rec.should_be_strict
|