surrogate 0.6.1 → 0.6.2
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/Changelog.md +7 -0
- data/Readme.md +15 -20
- data/Readme.md.mountain_berry_fields +15 -20
- data/lib/surrogate/api_comparer.rb +64 -7
- data/lib/surrogate/argument_errorizer.rb +7 -0
- data/lib/surrogate/hatchling.rb +7 -2
- data/lib/surrogate/method_definition.rb +7 -1
- data/lib/surrogate/rspec/substitute_for.rb +14 -3
- data/lib/surrogate/version.rb +1 -1
- data/spec/acceptance_spec.rb +8 -8
- data/spec/defining_api_methods_spec.rb +2 -0
- data/spec/rspec/initialization_matcher_spec.rb +14 -14
- data/spec/rspec/substitute_for_spec.rb +144 -42
- data/spec/unit/api_comparer_spec.rb +9 -9
- data/spec/unit/argument_errorizer_spec.rb +9 -0
- data/todo +2 -5
- metadata +12 -12
data/Changelog.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
### 0.6.2
|
2
|
+
|
3
|
+
* Make substitutability matcher go either way (you should now do `RealClass.should substitute_for SurrogateClass` eventually, doing it in the other direction will not be supported)
|
4
|
+
* Bug fix: checks arity on invocations, even when default value is overridden
|
5
|
+
* Substitutability can check argument names
|
6
|
+
* Fix error message when there are no api methods. Used to say "Doesn't know initialize, only knows "
|
7
|
+
|
1
8
|
### 0.6.1
|
2
9
|
|
3
10
|
* bang methods map to ivars suffixed with `_b`, because you can't have a bang in an ivar name
|
data/Readme.md
CHANGED
@@ -327,7 +327,7 @@ Assert that your mock has the **same interface** as your real class.
|
|
327
327
|
This will fail if the mock inherits methods which are not on the real class. It will also fail
|
328
328
|
if the real class has any methods which have not been defined on the mock or inherited by the mock.
|
329
329
|
|
330
|
-
Presently, it will ignore methods defined directly in the mock (as it
|
330
|
+
Presently, it will ignore methods defined directly in the mock (as it considers them to be helpers).
|
331
331
|
In a future version, you will be able to tell it to treat other methods
|
332
332
|
as part of the API (will fail if they don't match, and maybe record their values).
|
333
333
|
|
@@ -344,30 +344,25 @@ class MockUser
|
|
344
344
|
end
|
345
345
|
|
346
346
|
# they are the same
|
347
|
-
|
347
|
+
User.should substitute_for MockUser
|
348
348
|
|
349
|
-
#
|
349
|
+
# they differ
|
350
350
|
MockUser.define :name
|
351
|
-
|
351
|
+
User.should_not substitute_for MockUser
|
352
352
|
|
353
|
-
#
|
354
|
-
class UserWithName < User
|
355
|
-
def name()end
|
356
|
-
end
|
357
|
-
MockUser.should substitute_for UserWithName
|
358
|
-
|
359
|
-
# real class has extra methods
|
360
|
-
class UserWithNameAndAddress < UserWithName
|
361
|
-
def address()end
|
362
|
-
end
|
363
|
-
MockUser.should_not substitute_for UserWithNameAndAddress
|
364
|
-
|
365
|
-
# signatures don't match
|
353
|
+
# signatures don't match (you can turn this off by passing `types: false` to substitute_for)
|
366
354
|
class UserWithWrongSignature
|
367
355
|
def initialize()end # no id
|
368
356
|
def id()end
|
369
357
|
end
|
370
|
-
|
358
|
+
UserWithWrongSignature.should_not substitute_for MockUser
|
359
|
+
|
360
|
+
# parameter names don't match
|
361
|
+
class UserWithWrongParamNames
|
362
|
+
def initialize(name)end # real one takes an id
|
363
|
+
def id()end
|
364
|
+
end
|
365
|
+
UserWithWrongParamNames.should_not substitute_for MockUser, names: true
|
371
366
|
```
|
372
367
|
|
373
368
|
Sometimes you don't want to have to implement the entire interface.
|
@@ -388,11 +383,11 @@ class MockUser
|
|
388
383
|
end
|
389
384
|
|
390
385
|
# doesn't matter that real user has a name as long as it has initialize and id
|
391
|
-
|
386
|
+
User.should substitute_for MockUser, subset: true
|
392
387
|
|
393
388
|
# but now it fails b/c it has no address
|
394
389
|
MockUser.define :address
|
395
|
-
|
390
|
+
User.should_not substitute_for MockUser, subset: true
|
396
391
|
```
|
397
392
|
|
398
393
|
|
@@ -411,7 +411,7 @@ Assert that your mock has the **same interface** as your real class.
|
|
411
411
|
This will fail if the mock inherits methods which are not on the real class. It will also fail
|
412
412
|
if the real class has any methods which have not been defined on the mock or inherited by the mock.
|
413
413
|
|
414
|
-
Presently, it will ignore methods defined directly in the mock (as it
|
414
|
+
Presently, it will ignore methods defined directly in the mock (as it considers them to be helpers).
|
415
415
|
In a future version, you will be able to tell it to treat other methods
|
416
416
|
as part of the API (will fail if they don't match, and maybe record their values).
|
417
417
|
|
@@ -429,30 +429,25 @@ class MockUser
|
|
429
429
|
end
|
430
430
|
|
431
431
|
# they are the same
|
432
|
-
|
432
|
+
User.should substitute_for MockUser
|
433
433
|
|
434
|
-
#
|
434
|
+
# they differ
|
435
435
|
MockUser.define :name
|
436
|
-
|
436
|
+
User.should_not substitute_for MockUser
|
437
437
|
|
438
|
-
#
|
439
|
-
class UserWithName < User
|
440
|
-
def name()end
|
441
|
-
end
|
442
|
-
MockUser.should substitute_for UserWithName
|
443
|
-
|
444
|
-
# real class has extra methods
|
445
|
-
class UserWithNameAndAddress < UserWithName
|
446
|
-
def address()end
|
447
|
-
end
|
448
|
-
MockUser.should_not substitute_for UserWithNameAndAddress
|
449
|
-
|
450
|
-
# signatures don't match
|
438
|
+
# signatures don't match (you can turn this off by passing `types: false` to substitute_for)
|
451
439
|
class UserWithWrongSignature
|
452
440
|
def initialize()end # no id
|
453
441
|
def id()end
|
454
442
|
end
|
455
|
-
|
443
|
+
UserWithWrongSignature.should_not substitute_for MockUser
|
444
|
+
|
445
|
+
# parameter names don't match
|
446
|
+
class UserWithWrongParamNames
|
447
|
+
def initialize(name)end # real one takes an id
|
448
|
+
def id()end
|
449
|
+
end
|
450
|
+
UserWithWrongParamNames.should_not substitute_for MockUser, names: true
|
456
451
|
<% end %>
|
457
452
|
```
|
458
453
|
|
@@ -475,11 +470,11 @@ class MockUser
|
|
475
470
|
end
|
476
471
|
|
477
472
|
# doesn't matter that real user has a name as long as it has initialize and id
|
478
|
-
|
473
|
+
User.should substitute_for MockUser, subset: true
|
479
474
|
|
480
475
|
# but now it fails b/c it has no address
|
481
476
|
MockUser.define :address
|
482
|
-
|
477
|
+
User.should_not substitute_for MockUser, subset: true
|
483
478
|
<% end %>
|
484
479
|
```
|
485
480
|
|
@@ -8,7 +8,11 @@ class Surrogate
|
|
8
8
|
class ApiComparer
|
9
9
|
attr_accessor :surrogate, :actual
|
10
10
|
|
11
|
-
def initialize(
|
11
|
+
def initialize(actual, surrogate)
|
12
|
+
unless surrogate.instance_variable_get(:@hatchery).kind_of?(Hatchery) && surrogate.instance_variable_get(:@hatchling).kind_of?(Hatchling)
|
13
|
+
Kernel.warn "You said #{actual} should substitute for #{surrogate}`, but as of 0.6.2, this should be asserted in the other direction."
|
14
|
+
surrogate, actual = actual, surrogate
|
15
|
+
end
|
12
16
|
self.surrogate, self.actual = surrogate, actual
|
13
17
|
end
|
14
18
|
|
@@ -26,11 +30,13 @@ class Surrogate
|
|
26
30
|
not_on_surrogate: instance_not_on_surrogate,
|
27
31
|
not_on_actual: instance_not_on_actual,
|
28
32
|
types: instance_types,
|
33
|
+
names: instance_names,
|
29
34
|
},
|
30
35
|
class: {
|
31
36
|
not_on_surrogate: class_not_on_surrogate,
|
32
37
|
not_on_actual: class_not_on_actual,
|
33
38
|
types: class_types,
|
39
|
+
names: class_names,
|
34
40
|
},
|
35
41
|
}
|
36
42
|
end
|
@@ -53,11 +59,12 @@ class Surrogate
|
|
53
59
|
surrogate_methods[:class][:api] - actual_methods[:class][:inherited] - actual_methods[:class][:other]
|
54
60
|
end
|
55
61
|
|
62
|
+
|
63
|
+
# there is a lot of duplication in these next four methods -.-
|
64
|
+
# idk if there is something we can do about it.
|
65
|
+
|
56
66
|
# types are only shown for methods on both objects
|
57
67
|
def class_types
|
58
|
-
surrogate_class_methods = surrogate_methods[:class][:api] + surrogate_methods[:class][:inherited]
|
59
|
-
actual_class_methods = actual_methods[:class][:inherited] + actual_methods[:class][:other]
|
60
|
-
class_methods_that_should_match = (surrogate_class_methods & actual_class_methods) - surrogate_methods[:class][:without_bodies] - actual_methods[:class][:without_bodies]
|
61
68
|
class_methods_that_should_match.each_with_object Hash.new do |name, hash|
|
62
69
|
surrogate_type, actual_type = class_types_for name
|
63
70
|
next if surrogate_type == actual_type
|
@@ -67,9 +74,6 @@ class Surrogate
|
|
67
74
|
|
68
75
|
# types are only shown for methods on both objects
|
69
76
|
def instance_types
|
70
|
-
surrogate_instance_methods = surrogate_methods[:instance][:api] + surrogate_methods[:instance][:inherited]
|
71
|
-
actual_instance_methods = actual_methods[:instance][:inherited] + actual_methods[:instance][:other]
|
72
|
-
instance_methods_that_should_match = (surrogate_instance_methods & actual_instance_methods) - surrogate_methods[:instance][:without_bodies] - actual_methods[:instance][:without_bodies]
|
73
77
|
instance_methods_that_should_match.each_with_object Hash.new do |name, hash|
|
74
78
|
surrogate_type, actual_type = instance_types_for name
|
75
79
|
next if surrogate_type == actual_type
|
@@ -77,8 +81,41 @@ class Surrogate
|
|
77
81
|
end
|
78
82
|
end
|
79
83
|
|
84
|
+
# names are only shown for methods on both objects
|
85
|
+
def class_names
|
86
|
+
class_methods_that_should_match.each_with_object Hash.new do |method_name, hash|
|
87
|
+
surrogate_name, actual_name = class_parameter_names_for method_name
|
88
|
+
next if surrogate_name == actual_name
|
89
|
+
hash[method_name] = { surrogate: surrogate_name, actual: actual_name }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# names are only shown for methods on both objects
|
94
|
+
def instance_names
|
95
|
+
instance_methods_that_should_match.each_with_object Hash.new do |method_name, hash|
|
96
|
+
surrogate_name, actual_name = instance_parameter_names_for method_name
|
97
|
+
next if surrogate_name == actual_name
|
98
|
+
hash[method_name] = { surrogate: surrogate_name, actual: actual_name }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
80
102
|
private
|
81
103
|
|
104
|
+
def instance_methods_that_should_match
|
105
|
+
surrogate_instance_methods = surrogate_methods[:instance][:api] + surrogate_methods[:instance][:inherited]
|
106
|
+
actual_instance_methods = actual_methods[:instance][:inherited] + actual_methods[:instance][:other]
|
107
|
+
instance_methods_that_should_match = (surrogate_instance_methods & actual_instance_methods) - surrogate_methods[:instance][:without_bodies] - actual_methods[:instance][:without_bodies]
|
108
|
+
end
|
109
|
+
|
110
|
+
def class_methods_that_should_match
|
111
|
+
surrogate_class_methods = surrogate_methods[:class][:api] + surrogate_methods[:class][:inherited]
|
112
|
+
actual_class_methods = actual_methods[:class][:inherited] + actual_methods[:class][:other]
|
113
|
+
(surrogate_class_methods & actual_class_methods) - surrogate_methods[:class][:without_bodies] - actual_methods[:class][:without_bodies]
|
114
|
+
end
|
115
|
+
|
116
|
+
# there is a lot of duplication in these next four methods -.-
|
117
|
+
# also, it seems like a lot of this shit could move into the reflectors
|
118
|
+
|
82
119
|
def class_types_for(name)
|
83
120
|
surrogate_method = class_api_method_for name
|
84
121
|
surrogate_method &&= to_lambda surrogate_method
|
@@ -95,10 +132,30 @@ class Surrogate
|
|
95
132
|
return type_for(surrogate_method), type_for(actual_method)
|
96
133
|
end
|
97
134
|
|
135
|
+
def class_parameter_names_for(name)
|
136
|
+
surrogate_method = class_api_method_for name
|
137
|
+
surrogate_method &&= to_lambda surrogate_method
|
138
|
+
surrogate_method ||= surrogate.method name
|
139
|
+
actual_method = actual.method name
|
140
|
+
return parameter_names_for(surrogate_method), parameter_names_for(actual_method)
|
141
|
+
end
|
142
|
+
|
143
|
+
def instance_parameter_names_for(name)
|
144
|
+
surrogate_method = instance_api_method_for name
|
145
|
+
surrogate_method &&= to_lambda surrogate_method
|
146
|
+
surrogate_method ||= surrogate.instance_method name
|
147
|
+
actual_method = actual.instance_method name
|
148
|
+
return parameter_names_for(surrogate_method), parameter_names_for(actual_method)
|
149
|
+
end
|
150
|
+
|
98
151
|
def type_for(method)
|
99
152
|
method.parameters.map(&:first)
|
100
153
|
end
|
101
154
|
|
155
|
+
def parameter_names_for(method)
|
156
|
+
method.parameters.map(&:last)
|
157
|
+
end
|
158
|
+
|
102
159
|
def to_lambda(proc)
|
103
160
|
obj = Object.new
|
104
161
|
obj.singleton_class.send :define_method, :abc123, &proc
|
@@ -6,6 +6,7 @@ class Surrogate
|
|
6
6
|
attr_accessor :name, :empty_lambda
|
7
7
|
|
8
8
|
def initialize(name, lambda_or_method)
|
9
|
+
must_be_lambda_or_method lambda_or_method
|
9
10
|
self.name, self.empty_lambda = name.to_s, lambda_with_same_params_as(lambda_or_method)
|
10
11
|
end
|
11
12
|
|
@@ -39,5 +40,11 @@ class Surrogate
|
|
39
40
|
raise "forgot to account for #{type.inspect}"
|
40
41
|
end
|
41
42
|
end
|
43
|
+
|
44
|
+
def must_be_lambda_or_method(lambda_or_method)
|
45
|
+
return if lambda_or_method.kind_of? ::Method
|
46
|
+
return if lambda_or_method.kind_of?(Proc) && lambda_or_method.lambda?
|
47
|
+
raise ArgumentError, "Expected a lambda or method, got a #{lambda_or_method.class}"
|
48
|
+
end
|
42
49
|
end
|
43
50
|
end
|
data/lib/surrogate/hatchling.rb
CHANGED
@@ -54,8 +54,13 @@ class Surrogate
|
|
54
54
|
|
55
55
|
def must_know(method_name)
|
56
56
|
return if api_methods.has_key? method_name
|
57
|
-
|
58
|
-
|
57
|
+
if api_methods.empty?
|
58
|
+
message = "doesn't know \"#{method_name}\", doesn't know anything! It's an epistemological conundrum, go define #{method_name}."
|
59
|
+
else
|
60
|
+
known_methods = api_methods.keys.map(&:to_s).map(&:inspect).join ', '
|
61
|
+
message = "doesn't know \"#{method_name}\", only knows #{known_methods}"
|
62
|
+
end
|
63
|
+
raise UnknownMethod, message
|
59
64
|
end
|
60
65
|
|
61
66
|
# maybe these ivar methods should be extracted into their own class
|
@@ -39,7 +39,7 @@ class Surrogate
|
|
39
39
|
private
|
40
40
|
|
41
41
|
def errorizer
|
42
|
-
@errorizer ||= ArgumentErrorizer.new name, default_proc
|
42
|
+
@errorizer ||= ArgumentErrorizer.new name, to_method_definition(default_proc)
|
43
43
|
end
|
44
44
|
|
45
45
|
def default_proc_as_method_on(instance)
|
@@ -50,6 +50,12 @@ class Surrogate
|
|
50
50
|
klass.__send__ :remove_method, unique_name
|
51
51
|
as_method.bind instance
|
52
52
|
end
|
53
|
+
|
54
|
+
def to_method_definition(default_proc)
|
55
|
+
object = Object.new
|
56
|
+
object.define_singleton_method(:temp_method, &default_proc)
|
57
|
+
object.method(:temp_method)
|
58
|
+
end
|
53
59
|
end
|
54
60
|
end
|
55
61
|
|
@@ -1,11 +1,13 @@
|
|
1
1
|
class Surrogate
|
2
|
+
# turn this into a real class
|
2
3
|
::RSpec::Matchers.define :substitute_for do |original_class, options={}|
|
3
4
|
|
4
5
|
comparison = nil
|
5
6
|
subset_only = options[:subset]
|
6
7
|
types = options.fetch :types, true
|
8
|
+
names = options.fetch :names, false
|
7
9
|
|
8
|
-
def comparing_fields(comparison, subset_only, types)
|
10
|
+
def comparing_fields(comparison, subset_only, types, names)
|
9
11
|
fields = {}
|
10
12
|
fields[:instance_not_on_actual ] = comparison[:instance][:not_on_actual]
|
11
13
|
fields[:class_not_on_actual ] = comparison[:class ][:not_on_actual]
|
@@ -13,21 +15,25 @@ class Surrogate
|
|
13
15
|
fields[:class_not_on_surrogate ] = comparison[:class ][:not_on_surrogate] unless subset_only
|
14
16
|
fields[:instance_types ] = comparison[:instance][:types] if types
|
15
17
|
fields[:class_types ] = comparison[:class ][:types] if types
|
18
|
+
fields[:instance_names ] = comparison[:instance][:names] if names
|
19
|
+
fields[:class_names ] = comparison[:class ][:names] if names
|
16
20
|
fields
|
17
21
|
end
|
18
22
|
|
19
23
|
match do |mocked_class|
|
20
24
|
comparison = ApiComparer.new(mocked_class, original_class).compare
|
21
|
-
comparing_fields(comparison, subset_only, types).values.inject(:+).empty?
|
25
|
+
comparing_fields(comparison, subset_only, types, names).values.inject(:+).empty?
|
22
26
|
end
|
23
27
|
|
24
28
|
failure_message_for_should do
|
25
|
-
extra_instance_methods = comparison[:instance][:not_on_actual ].to_a
|
29
|
+
extra_instance_methods = comparison[:instance][:not_on_actual ].to_a # these come in as sets
|
26
30
|
extra_class_methods = comparison[:class ][:not_on_actual ].to_a
|
27
31
|
missing_instance_methods = comparison[:instance][:not_on_surrogate].to_a
|
28
32
|
missing_class_methods = comparison[:class ][:not_on_surrogate].to_a
|
29
33
|
instance_type_mismatch = comparison[:instance][:types ]
|
30
34
|
class_type_mismatch = comparison[:class ][:types ]
|
35
|
+
instance_name_mismatch = comparison[:instance][:names ]
|
36
|
+
class_name_mismatch = comparison[:class ][:names ]
|
31
37
|
|
32
38
|
|
33
39
|
differences = []
|
@@ -40,6 +46,11 @@ class Surrogate
|
|
40
46
|
instance_type_mismatch.each { |name, types| differences << "##{name} had types #{types.inspect}" }
|
41
47
|
class_type_mismatch.each { |name, types| differences << ".#{name} had types #{types.inspect}" }
|
42
48
|
end
|
49
|
+
|
50
|
+
if names # this conditional is not tested, nor are these error messages
|
51
|
+
instance_name_mismatch.each { |method_name, param_names| differences << "##{method_name} had parameter names #{param_names.inspect}" }
|
52
|
+
class_type_mismatch.each { |method_name, param_names| differences << ".#{method_name} had parameter names #{param_names.inspect}" }
|
53
|
+
end
|
43
54
|
"Was not substitutable because surrogate " << differences.join("\n")
|
44
55
|
end
|
45
56
|
|
data/lib/surrogate/version.rb
CHANGED
data/spec/acceptance_spec.rb
CHANGED
@@ -107,12 +107,12 @@ describe Surrogate do
|
|
107
107
|
# pass the error as the return value, it will be raised when method is invoked
|
108
108
|
error = StandardError.new("some message")
|
109
109
|
user.will_add_phone_number error
|
110
|
-
expect { user.add_phone_number }.to raise_error StandardError, "some message"
|
110
|
+
expect { user.add_phone_number '312', '123-4567' }.to raise_error StandardError, "some message"
|
111
111
|
|
112
112
|
# ===== Substitutability =====
|
113
113
|
|
114
114
|
# real user is not a suitable substitute if missing methods that mock user has
|
115
|
-
|
115
|
+
Class.new.should_not substitute_for user_class
|
116
116
|
|
117
117
|
# real user must have all of mock user's methods to be substitutable
|
118
118
|
substitutable_real_user_class = Class.new do
|
@@ -124,22 +124,22 @@ describe Surrogate do
|
|
124
124
|
def phone_numbers() end
|
125
125
|
def add_phone_number(area_code, number) end
|
126
126
|
end
|
127
|
-
|
128
|
-
|
127
|
+
substitutable_real_user_class.should substitute_for user_class
|
128
|
+
substitutable_real_user_class.should substitute_for user_class, subset: true
|
129
129
|
|
130
130
|
# when real user class has extra methods, it is only substitutable as a subset
|
131
131
|
real_user_class = substitutable_real_user_class.clone
|
132
132
|
def real_user_class.some_class_meth() end
|
133
|
-
|
133
|
+
real_user_class.should_not substitute_for user_class
|
134
134
|
|
135
135
|
real_user_class = substitutable_real_user_class.dup
|
136
136
|
real_user_class.send(:define_method, :some_instance_method) {}
|
137
|
-
|
138
|
-
|
137
|
+
real_user_class.should_not substitute_for user_class
|
138
|
+
real_user_class.should substitute_for user_class, subset: true
|
139
139
|
|
140
140
|
# subset substitutability does not work for superset
|
141
141
|
real_user_class = substitutable_real_user_class.dup
|
142
142
|
real_user_class.send :undef_method, :address
|
143
|
-
|
143
|
+
real_user_class.should_not substitute_for user_class, subset: true
|
144
144
|
end
|
145
145
|
end
|
@@ -99,6 +99,8 @@ describe 'define' do
|
|
99
99
|
it 'raises an error if you try to override a nonexistent method' do
|
100
100
|
expect { instance.will_override :whateva, 123 }
|
101
101
|
.to raise_error Surrogate::UnknownMethod, %(doesn't know "whateva", only knows "wink")
|
102
|
+
expect { Surrogate.endow(Class.new).new.will_override :whateva, 123 }
|
103
|
+
.to raise_error Surrogate::UnknownMethod, %[doesn't know "whateva", doesn't know anything! It's an epistemological conundrum, go define whateva.]
|
102
104
|
end
|
103
105
|
end
|
104
106
|
|
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe '
|
3
|
+
describe 'was initialized_with' do
|
4
4
|
let(:mocked_class) { Surrogate.endow(Class.new).define(:initialize) { |*| } }
|
5
5
|
|
6
|
-
it 'is the same as
|
7
|
-
mocked_class.new.
|
8
|
-
mocked_class.new.
|
9
|
-
mocked_class.new(1).
|
10
|
-
mocked_class.new(1, '2').
|
6
|
+
it 'is the same as told_to(:initialize).with(...)' do
|
7
|
+
mocked_class.new.was initialized_with no_args
|
8
|
+
mocked_class.new.was_not initialized_with(1)
|
9
|
+
mocked_class.new(1).was initialized_with 1
|
10
|
+
mocked_class.new(1, '2').was initialized_with 1, '2'
|
11
11
|
end
|
12
12
|
|
13
13
|
def failure_message_for
|
@@ -17,17 +17,17 @@ describe 'should/should_not have_been_initialized_with' do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
example 'failure message for should' do
|
20
|
-
failure_message_for { mocked_class.new("1").
|
21
|
-
failure_message_for { mocked_class.new("1").
|
20
|
+
failure_message_for { mocked_class.new("1").was initialized_with 2 }.should ==
|
21
|
+
failure_message_for { mocked_class.new("1").was told_to(:initialize).with(2) }
|
22
22
|
end
|
23
23
|
|
24
24
|
example 'failure message for should not' do
|
25
|
-
failure_message_for { mocked_class.new("1").
|
26
|
-
failure_message_for { mocked_class.new("1").
|
25
|
+
failure_message_for { mocked_class.new("1").was_not initialized_with('1') }.should ==
|
26
|
+
failure_message_for { mocked_class.new("1").was_not told_to(:initialize).with('1') }
|
27
27
|
end
|
28
28
|
|
29
29
|
example "informs you when it wasn't defined" do
|
30
|
-
expect { Surrogate.endow(Class.new).new.
|
30
|
+
expect { Surrogate.endow(Class.new).new.was initialized_with no_args }
|
31
31
|
.to raise_error Surrogate::UnknownMethod
|
32
32
|
end
|
33
33
|
end
|
@@ -35,7 +35,7 @@ end
|
|
35
35
|
describe 'was/was_not initialized_with' do
|
36
36
|
let(:mocked_class) { Surrogate.endow(Class.new).define(:initialize) { |*| } }
|
37
37
|
|
38
|
-
it 'is the same as
|
38
|
+
it 'is the same as told_to(:initialize).with(...)' do
|
39
39
|
mocked_class.new.was initialized_with no_args
|
40
40
|
mocked_class.new.was_not initialized_with 1
|
41
41
|
mocked_class.new(1).was initialized_with 1
|
@@ -54,8 +54,8 @@ describe 'was/was_not initialized_with' do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
example 'failure message for should not' do
|
57
|
-
failure_message_for { mocked_class.new("1").was_not initialized_with
|
58
|
-
failure_message_for { mocked_class.new("1").was_not told_to(:initialize).with
|
57
|
+
failure_message_for { mocked_class.new("1").was_not initialized_with '1' }.should ==
|
58
|
+
failure_message_for { mocked_class.new("1").was_not told_to(:initialize).with '1' }
|
59
59
|
end
|
60
60
|
|
61
61
|
example "informs you when it wasn't defined" do
|
@@ -1,31 +1,47 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'substitute_for' do
|
4
|
+
context 'understands that the non-surrogate class should substitute for the surrogate class when' do
|
5
|
+
specify 'the surrogate class comes first (but it does emit a warning)' do
|
6
|
+
Kernel.should_receive(:warn).twice.with kind_of String
|
7
|
+
surrogate = Surrogate.endow(Class.new).define(:some_meth)
|
8
|
+
surrogate.should_not substitute_for Class.new
|
9
|
+
surrogate.should substitute_for Class.new { def some_meth() end }
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'the non-surrogate class comes first (and it does not emit a warning)' do
|
13
|
+
Kernel.should_not_receive :warn
|
14
|
+
surrogate = Surrogate.endow(Class.new).define(:some_meth)
|
15
|
+
Class.new.should_not substitute_for surrogate
|
16
|
+
Class.new { def some_meth() end }.should substitute_for surrogate
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
4
20
|
context 'exact substitutability' do
|
5
21
|
context "returns true iff api methods and inherited methods match exactly to the other object's methods. Examples:" do
|
6
22
|
context "a surrogate with no api methods" do
|
7
23
|
let(:surrogate) { Surrogate.endow Class.new }
|
8
24
|
|
9
25
|
example "is substitutable for a class with no methods" do
|
10
|
-
|
26
|
+
Class.new.should substitute_for surrogate
|
11
27
|
end
|
12
28
|
|
13
29
|
example "is not substitutable for a class with instance methods" do
|
14
|
-
|
30
|
+
Class.new { def foo()end }.should_not substitute_for surrogate
|
15
31
|
end
|
16
32
|
|
17
33
|
example "is not substitutable for a class with class methods" do
|
18
|
-
|
34
|
+
Class.new { def self.foo()end }.should_not substitute_for surrogate
|
19
35
|
end
|
20
36
|
|
21
37
|
example "is not substitutable for a class with inherited instance methods" do
|
22
38
|
parent = Class.new { def foo()end }
|
23
|
-
|
39
|
+
Class.new(parent).should_not substitute_for surrogate
|
24
40
|
end
|
25
41
|
|
26
42
|
example "is not substitutable for a class with inherited class methods" do
|
27
43
|
parent = Class.new { def self.foo()end }
|
28
|
-
|
44
|
+
Class.new(parent).should_not substitute_for surrogate
|
29
45
|
end
|
30
46
|
end
|
31
47
|
|
@@ -34,39 +50,39 @@ describe 'substitute_for' do
|
|
34
50
|
let(:surrogate) { Class.new { Surrogate.endow self; define :foo } }
|
35
51
|
|
36
52
|
example "is substitutable for a class with the same method" do
|
37
|
-
|
53
|
+
Class.new { def foo()end }.should substitute_for surrogate
|
38
54
|
end
|
39
55
|
|
40
56
|
example "is substitutable for a class that inherits the method" do
|
41
57
|
parent = Class.new { def foo()end }
|
42
|
-
|
58
|
+
Class.new(parent).should substitute_for surrogate
|
43
59
|
end
|
44
60
|
|
45
61
|
example "is not substitutable for a class without the method" do
|
46
|
-
|
62
|
+
Class.new.should_not substitute_for surrogate
|
47
63
|
end
|
48
64
|
|
49
65
|
example "is not substitutable for a class with a different method" do
|
50
|
-
|
66
|
+
Class.new { def bar()end }.should_not substitute_for surrogate
|
51
67
|
end
|
52
68
|
|
53
69
|
example "is not substitutable for a class with additional methods" do
|
54
70
|
other = Class.new { def foo()end; def bar()end }
|
55
|
-
|
71
|
+
other.should_not substitute_for surrogate
|
56
72
|
end
|
57
73
|
|
58
74
|
example "is not substitutable for a class with the method and inerited additional methods" do
|
59
75
|
parent = Class.new { def bar()end }
|
60
|
-
|
76
|
+
Class.new(parent) { def foo()end }.should_not substitute_for surrogate
|
61
77
|
end
|
62
78
|
|
63
79
|
example "is not substitutable for a class with the method and additional class methods" do
|
64
|
-
|
80
|
+
Class.new { def foo()end; def self.bar()end }.should_not substitute_for surrogate
|
65
81
|
end
|
66
82
|
|
67
83
|
example "is not substitutable for a class with the method and inherited additional class methods" do
|
68
84
|
parent = Class.new { def self.bar()end }
|
69
|
-
|
85
|
+
Class.new(parent) { def foo()end }.should_not substitute_for surrogate
|
70
86
|
end
|
71
87
|
end
|
72
88
|
|
@@ -76,32 +92,32 @@ describe 'substitute_for' do
|
|
76
92
|
|
77
93
|
specify 'when klass is missing an instance method' do
|
78
94
|
surrogate.define :meth
|
79
|
-
expect {
|
95
|
+
expect { Class.new.should substitute_for surrogate }.to \
|
80
96
|
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate has extra instance methods: [:meth]")
|
81
97
|
end
|
82
98
|
|
83
99
|
specify 'when klass is missing a class method' do
|
84
100
|
surrogate = Surrogate.endow(Class.new) { define :meth }
|
85
|
-
expect {
|
101
|
+
expect { Class.new.should substitute_for surrogate }.to \
|
86
102
|
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate has extra class methods: [:meth]")
|
87
103
|
end
|
88
104
|
|
89
105
|
specify 'when surrogate is missing an instance method' do
|
90
106
|
klass = Class.new { def meth() end }
|
91
|
-
expect {
|
107
|
+
expect { klass.should substitute_for surrogate }.to \
|
92
108
|
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate is missing instance methods: [:meth]")
|
93
109
|
end
|
94
110
|
|
95
111
|
specify 'when surrogate is missing a class method' do
|
96
112
|
klass = Class.new { def self.meth() end }
|
97
|
-
expect {
|
113
|
+
expect { klass.should substitute_for surrogate }.to \
|
98
114
|
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate is missing class methods: [:meth]")
|
99
115
|
end
|
100
116
|
|
101
117
|
specify 'when combined' do
|
102
118
|
surrogate = Surrogate.endow(Class.new) { define :surrogate_class_meth }.define :surrogate_instance_meth
|
103
119
|
klass = Class.new { def self.api_class_meth()end; def api_instance_meth() end }
|
104
|
-
expect {
|
120
|
+
expect { klass.should substitute_for surrogate }.to \
|
105
121
|
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate has extra instance methods: [:surrogate_instance_meth]\n"\
|
106
122
|
"has extra class methods: [:surrogate_class_meth]\n"\
|
107
123
|
"is missing instance methods: [:api_instance_meth]\n"\
|
@@ -109,7 +125,7 @@ describe 'substitute_for' do
|
|
109
125
|
end
|
110
126
|
|
111
127
|
specify "when negated (idk why you'd ever want this, though)" do
|
112
|
-
expect {
|
128
|
+
expect { Class.new.should_not substitute_for surrogate }.to \
|
113
129
|
raise_error(RSpec::Expectations::ExpectationNotMetError, "Should not have been substitute, but was")
|
114
130
|
end
|
115
131
|
end
|
@@ -121,29 +137,32 @@ describe 'substitute_for' do
|
|
121
137
|
context 'subset substitutability -- specified with subset: true option' do
|
122
138
|
context "returns true if api methods and inherited methods match are all implemented by other class. Examples:" do
|
123
139
|
example 'true when exact match' do
|
124
|
-
|
140
|
+
Class.new.should substitute_for Surrogate.endow(Class.new), subset: true
|
125
141
|
end
|
126
142
|
|
127
143
|
example 'true when other has additional instance methods and class methods' do
|
128
144
|
klass = Class.new { def self.class_meth()end; def instance_meth()end }
|
129
|
-
Surrogate.endow(Class.new)
|
145
|
+
klass.should substitute_for Surrogate.endow(Class.new), subset: true
|
130
146
|
end
|
131
147
|
|
132
148
|
example 'false when other is missing instance methods' do
|
133
|
-
klass
|
134
|
-
|
149
|
+
klass = Class.new { def self.extra_method()end; def extra_method()end }
|
150
|
+
surrogate = Surrogate.endow(Class.new).define(:meth)
|
151
|
+
expect { klass.should substitute_for surrogate, subset:true }.to \
|
135
152
|
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate has extra instance methods: [:meth]")
|
136
153
|
end
|
137
154
|
|
138
155
|
example 'false when other is missing class methods' do
|
139
|
-
klass
|
140
|
-
|
156
|
+
klass = Class.new { def self.extra_method()end; def extra_method()end }
|
157
|
+
surrogate = Surrogate.endow(Class.new) { define :meth }
|
158
|
+
expect { klass.should substitute_for surrogate, subset:true }.to \
|
141
159
|
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate has extra class methods: [:meth]")
|
142
160
|
end
|
143
161
|
|
144
162
|
example 'false when other is missing instance and class methods' do
|
145
163
|
klass = Class.new { def self.extra_method()end; def extra_method()end }
|
146
|
-
|
164
|
+
surrogate = Surrogate.endow(Class.new) { define :class_meth }.define(:instance_meth)
|
165
|
+
expect { klass.should substitute_for surrogate, subset: true }.to \
|
147
166
|
raise_error(RSpec::Expectations::ExpectationNotMetError,
|
148
167
|
"Was not substitutable because surrogate has extra instance methods: [:instance_meth]\nhas extra class methods: [:class_meth]")
|
149
168
|
end
|
@@ -156,82 +175,165 @@ describe 'substitute_for' do
|
|
156
175
|
it 'is turned on by default' do
|
157
176
|
klass = Class.new { def instance_meth(a) end }
|
158
177
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { }
|
159
|
-
|
160
|
-
|
178
|
+
klass.should_not substitute_for surrogate
|
179
|
+
klass.should substitute_for surrogate, types: false
|
161
180
|
end
|
162
181
|
|
163
182
|
it 'disregards when argument names differ' do
|
164
183
|
klass = Class.new { def instance_meth(a) end }
|
165
184
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |b| }
|
166
|
-
|
185
|
+
klass.should substitute_for surrogate, names: false, types: true
|
167
186
|
end
|
168
187
|
|
169
188
|
it 'disregards when surrogate has no body for an api method' do
|
170
189
|
klass = Class.new { def instance_meth(a) end }
|
171
190
|
surrogate = Surrogate.endow(Class.new).define :instance_meth
|
172
|
-
|
191
|
+
klass.should substitute_for surrogate, types: true
|
173
192
|
end
|
174
193
|
|
175
194
|
it 'disregards when real object has natively implemented methods that cannot be reflected on' do
|
176
195
|
Array.method(:[]).parameters.should == [[:rest]] # make sure Array signatures aren't changing across versions or something
|
177
196
|
Array.instance_method(:insert).parameters.should == [[:rest]]
|
178
197
|
surrogate = Surrogate.endow(Class.new) { define(:[]) { |a,b,c| } }.define(:insert) { |a,b,c| }
|
179
|
-
|
198
|
+
Array.should substitute_for surrogate, subset: true, types: true
|
180
199
|
end
|
181
200
|
|
182
201
|
context 'returns true if argument types match exactly. Examples:' do
|
183
202
|
example 'true when exact match' do
|
184
203
|
klass = Class.new { def instance_meth(a, b=1, *c, d, &e) end }
|
185
204
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |a, b=1, *c, d, &e| }
|
186
|
-
|
205
|
+
klass.should substitute_for surrogate, types: true
|
187
206
|
end
|
188
207
|
|
189
208
|
example 'false when missing block' do
|
190
209
|
klass = Class.new { def instance_meth(a, b=1, *c, d) end }
|
191
210
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |a, b=1, *c, d, &e| }
|
192
|
-
|
211
|
+
klass.should_not substitute_for surrogate, types: true
|
193
212
|
|
194
213
|
klass = Class.new { def instance_meth(a, b=1, *c, d, &e) end }
|
195
214
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |a, b=1, *c, d| }
|
196
|
-
|
215
|
+
klass.should_not substitute_for surrogate, types: true
|
197
216
|
end
|
198
217
|
|
199
218
|
example 'false when missing splatted args' do
|
200
219
|
klass = Class.new { def instance_meth(a, b=1, d, &e) end }
|
201
220
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |a, b=1, *c, d, &e| }
|
202
|
-
|
221
|
+
klass.should_not substitute_for surrogate, types: true
|
203
222
|
|
204
223
|
klass = Class.new { def instance_meth(a, b=1, *c, d, &e) end }
|
205
224
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |a, b=1, d, &e| }
|
206
|
-
|
225
|
+
klass.should_not substitute_for surrogate
|
207
226
|
end
|
208
227
|
|
209
228
|
example 'false when missing optional args' do
|
210
229
|
klass = Class.new { def instance_meth(a, *c, d, &e) end }
|
211
230
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |a, b=1, *c, d, &e| }
|
212
|
-
|
231
|
+
klass.should_not substitute_for surrogate
|
213
232
|
|
214
233
|
klass = Class.new { def instance_meth(a, b=1, *c, d, &e) end }
|
215
234
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |a, *c, d, &e| }
|
216
|
-
|
235
|
+
klass.should_not substitute_for surrogate, types: true
|
217
236
|
end
|
218
237
|
|
219
238
|
example 'false when missing required args' do
|
220
239
|
klass = Class.new { def instance_meth(b=1, *c, d, &e) end }
|
221
240
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |a, b=1, *c, d, &e| }
|
222
|
-
|
241
|
+
klass.should_not substitute_for surrogate, types: true
|
223
242
|
|
224
243
|
klass = Class.new { def instance_meth(a, b=1, *c, d, &e) end }
|
225
244
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |b=1, *c, d, &e| }
|
226
|
-
|
245
|
+
klass.should_not substitute_for surrogate, types: true
|
227
246
|
|
228
247
|
klass = Class.new { def instance_meth(a, b=1, *c, &e) end }
|
229
248
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |a, b=1, *c, d, &e| }
|
230
|
-
|
249
|
+
klass.should_not substitute_for surrogate, types: true
|
231
250
|
|
232
251
|
klass = Class.new { def instance_meth(a, b=1, *c, d, &e) end }
|
233
252
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |a, b=1, *c, &e| }
|
234
|
-
|
253
|
+
klass.should_not substitute_for surrogate, types: true
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
context 'name substitutability -- specified with names: true/false option (DEFAULTS TO FALSE)' do
|
260
|
+
it 'is turned off by default' do
|
261
|
+
# instance
|
262
|
+
klass = Class.new { def instance_meth(a) end }
|
263
|
+
surrogate = Surrogate.endow(Class.new).define(:instance_meth) {|b|}
|
264
|
+
klass.should substitute_for surrogate
|
265
|
+
klass.should_not substitute_for surrogate, names: true
|
266
|
+
|
267
|
+
# class
|
268
|
+
klass = Class.new { def self.class_meth(a) end }
|
269
|
+
surrogate = Surrogate.endow(Class.new) { define(:class_meth) {|b|} }
|
270
|
+
klass.should substitute_for surrogate
|
271
|
+
klass.should_not substitute_for surrogate, names: true
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'disregards when argument types differ' do
|
275
|
+
# instance
|
276
|
+
klass = Class.new { def instance_meth(a=1) end }
|
277
|
+
surrogate = Surrogate.endow(Class.new).define(:instance_meth) {|a|}
|
278
|
+
klass.should substitute_for surrogate, types: false, names: true
|
279
|
+
|
280
|
+
# class
|
281
|
+
klass = Class.new { def self.class_meth(a=1) end }
|
282
|
+
surrogate = Surrogate.endow(Class.new) { define(:class_meth) {|a|} }
|
283
|
+
klass.should substitute_for surrogate, types: false, names: true
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'disregards when surrogate has no body for an api method' do
|
287
|
+
# instance
|
288
|
+
klass = Class.new { def instance_meth(a) end }
|
289
|
+
surrogate = Surrogate.endow(Class.new).define(:instance_meth)
|
290
|
+
klass.should substitute_for surrogate, names: true
|
291
|
+
|
292
|
+
# class
|
293
|
+
klass = Class.new { def self.class_meth(a) end }
|
294
|
+
surrogate = Surrogate.endow(Class.new) { define :class_meth }
|
295
|
+
klass.should substitute_for surrogate, names: true
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'disregards when real object has natively implemented methods that cannot be reflected on' do
|
299
|
+
Array.method(:[]).parameters.should == [[:rest]] # make sure Array signatures aren't changing across versions or something
|
300
|
+
Array.instance_method(:insert).parameters.should == [[:rest]]
|
301
|
+
surrogate = Surrogate.endow(Class.new) { define(:[]) { |a,b,c| } }.define(:insert) { |a,b,c| }
|
302
|
+
Array.should substitute_for surrogate, subset: true, names: true
|
303
|
+
end
|
304
|
+
|
305
|
+
context 'returns true if argument names match exactly. Examples:' do
|
306
|
+
specify 'true when exact match' do
|
307
|
+
klass = Class.new do
|
308
|
+
def self.class_meth(a) end
|
309
|
+
def instance_meth(b) end
|
310
|
+
end
|
311
|
+
surrogate = Surrogate.endow(Class.new) { define(:class_meth) {|a|} }.define(:instance_meth) {|b|}
|
312
|
+
klass.should substitute_for surrogate, names: true
|
313
|
+
end
|
314
|
+
|
315
|
+
specify 'false when different number of args' do
|
316
|
+
# instance
|
317
|
+
klass = Class.new { def instance_meth(a, b=1, *c, d, &e) end }
|
318
|
+
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |a, b=1, *c, d| }
|
319
|
+
klass.should_not substitute_for surrogate, names: true
|
320
|
+
|
321
|
+
# class
|
322
|
+
klass = Class.new { def self.class_meth(a, b=1, *c, d, &e) end }
|
323
|
+
surrogate = Surrogate.endow(Class.new) { define(:class_meth) { |a, b=1, *c, d| } }
|
324
|
+
klass.should_not substitute_for surrogate, names: true
|
325
|
+
end
|
326
|
+
|
327
|
+
specify 'false when different names' do
|
328
|
+
# instance
|
329
|
+
klass = Class.new { def instance_meth(a, b=1, *c, d, &e) end }
|
330
|
+
surrogate = Surrogate.endow(Class.new).define(:instance_meth) { |a, b=1, *c, d, ¬_e| }
|
331
|
+
klass.should_not substitute_for surrogate, names: true
|
332
|
+
|
333
|
+
# class
|
334
|
+
klass = Class.new { def instance_meth(a, b=1, *c, d, &e) end }
|
335
|
+
surrogate = Surrogate.endow(Class.new) { define(:class_meth) { |a, b=1, *c, d, ¬_e| } }
|
336
|
+
klass.should_not substitute_for surrogate, names: true
|
235
337
|
end
|
236
338
|
end
|
237
339
|
end
|
@@ -10,7 +10,7 @@ describe Surrogate::ApiComparer do
|
|
10
10
|
context 'when identifying types' do
|
11
11
|
it 'uses :req, :opt, :rest, and :block' do
|
12
12
|
surrogate = Surrogate.endow(Class.new).define(:to_s) { |a, b, c, d=1, e=2, *f, g, &h| }
|
13
|
-
comparer = described_class.new(
|
13
|
+
comparer = described_class.new(Class.new, surrogate)
|
14
14
|
comparer.compare[:instance][:types][:to_s][:surrogate].should ==
|
15
15
|
[:req, :req, :req, :opt, :opt, :rest, :req, :block]
|
16
16
|
end
|
@@ -40,7 +40,7 @@ describe Surrogate::ApiComparer do
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
let(:comparer) { described_class.new
|
43
|
+
let(:comparer) { described_class.new Class.new, surrogate }
|
44
44
|
|
45
45
|
it "knows the surrogate's instance level api methods" do
|
46
46
|
comparer.surrogate_methods[:instance][:api].should == Set[:api_instance_meth, :api_instance_meth_with_signature]
|
@@ -86,7 +86,7 @@ describe Surrogate::ApiComparer do
|
|
86
86
|
Class.new(parent) { def self.class_meth()end; def instance_meth()end }
|
87
87
|
end
|
88
88
|
|
89
|
-
let(:comparer) { described_class.new
|
89
|
+
let(:comparer) { described_class.new actual, surrogate }
|
90
90
|
|
91
91
|
it "knows the object's inherited instance methods" do
|
92
92
|
set_assertion comparer.actual_methods[:instance][:inherited],
|
@@ -131,7 +131,7 @@ describe Surrogate::ApiComparer do
|
|
131
131
|
end
|
132
132
|
end
|
133
133
|
|
134
|
-
let(:comparer) { described_class.new
|
134
|
+
let(:comparer) { described_class.new actual, surrogate }
|
135
135
|
|
136
136
|
it 'tells me about instance methods on actual that are not on surrogate' do
|
137
137
|
comparer.compare[:instance][:not_on_surrogate].should == Set[:instance_not_on_surrogate, :inherited_instance_not_on_surrogate, :instance_meth_on_both]
|
@@ -175,7 +175,7 @@ describe Surrogate::ApiComparer do
|
|
175
175
|
def instance_meth3(e3, f3=1, *c3, &d3)end
|
176
176
|
end
|
177
177
|
|
178
|
-
comparer = described_class.new
|
178
|
+
comparer = described_class.new klass, surrogate
|
179
179
|
comparer.compare[:instance][:types].should == {}
|
180
180
|
comparer.compare[:class][:types].should == {}
|
181
181
|
end
|
@@ -192,7 +192,7 @@ describe Surrogate::ApiComparer do
|
|
192
192
|
define(:instance_meth2) { |a, b, c, d| }
|
193
193
|
end
|
194
194
|
|
195
|
-
described_class.new(
|
195
|
+
described_class.new(klass, surrogate).compare
|
196
196
|
comparer.compare[:class][:types].should == {}
|
197
197
|
comparer.compare[:instance][:types].should == {}
|
198
198
|
end
|
@@ -200,7 +200,7 @@ describe Surrogate::ApiComparer do
|
|
200
200
|
it 'ignores methods with no default block' do
|
201
201
|
klass = Class.new { def instance_meth(a)end }
|
202
202
|
surrogate = Surrogate.endow(Class.new).define(:instance_meth)
|
203
|
-
described_class.new(
|
203
|
+
described_class.new(klass, surrogate).compare
|
204
204
|
comparer.compare[:class][:types].should == {}
|
205
205
|
comparer.compare[:instance][:types].should == {}
|
206
206
|
end
|
@@ -217,7 +217,7 @@ describe Surrogate::ApiComparer do
|
|
217
217
|
end
|
218
218
|
end
|
219
219
|
|
220
|
-
comparer = described_class.new
|
220
|
+
comparer = described_class.new klass, surrogate
|
221
221
|
comparer.compare[:class][:types].should == {
|
222
222
|
class_meth1: { actual: [:req, :opt, :rest, :block],
|
223
223
|
surrogate: [ :opt, :rest, :block],
|
@@ -239,7 +239,7 @@ describe Surrogate::ApiComparer do
|
|
239
239
|
define(:instance_meth2) { |a, *c, &d| }
|
240
240
|
end
|
241
241
|
|
242
|
-
comparer = described_class.new
|
242
|
+
comparer = described_class.new klass, surrogate
|
243
243
|
comparer.compare[:instance][:types].should == {
|
244
244
|
instance_meth1: { actual: [:req, :opt, :rest, :block],
|
245
245
|
surrogate: [ :opt, :rest, :block],
|
@@ -6,6 +6,7 @@ describe Surrogate::ArgumentErrorizer do
|
|
6
6
|
describe 'match!' do
|
7
7
|
it 'raises an argument error if the arguments do not match' do
|
8
8
|
expect { described_class.new(meth_name, ->(){}).match! 1 }.to raise_error ArgumentError
|
9
|
+
expect { described_class.new(meth_name, ->(a){}).match! }.to raise_error ArgumentError
|
9
10
|
end
|
10
11
|
|
11
12
|
it 'does not raise any errors if the arguments do match' do
|
@@ -47,4 +48,12 @@ describe Surrogate::ArgumentErrorizer do
|
|
47
48
|
assert_message ->(a, *b, &c){}, [], "wrong number of arguments (0 for 1) in #{meth_name}(a, *b, &c)"
|
48
49
|
assert_message ->(a, b, c=1, d=1, *e, f, &g){}, [], "wrong number of arguments (0 for 3) in #{meth_name}(a, b, c='?', d='?', *e, f, &g)"
|
49
50
|
end
|
51
|
+
|
52
|
+
it 'raises an ArgumentError if initialized with a non lambda/method' do
|
53
|
+
def self.some_method() end
|
54
|
+
described_class.new 'some_name', method(:some_method)
|
55
|
+
described_class.new 'some_name', lambda {}
|
56
|
+
expect { described_class.new 'some_name', Proc.new {} }.to raise_error ArgumentError, 'Expected a lambda or method, got a Proc'
|
57
|
+
expect { described_class.new 'some_name', 'abc' }.to raise_error ArgumentError, 'Expected a lambda or method, got a String'
|
58
|
+
end
|
50
59
|
end
|
data/todo
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
Urgent (things I want to do immediately, formatted as the git commits I will use)
|
2
2
|
---------------------------------------------------------------------------------
|
3
3
|
|
4
|
+
* refactor the stupid interface code, api comparer is fucking gross
|
4
5
|
* be smart enough to handle method missing
|
5
|
-
* tests around the error messages of types
|
6
|
-
* Substitutability can check argument names
|
6
|
+
* tests around the error messages of types and names
|
7
7
|
* substitute_for should not depend on rspec-expectations
|
8
8
|
* Error messages on blocks are actually useful
|
9
|
-
* error message
|
10
|
-
"Doesn't know initialize, only knows " <-- fix that shit
|
11
9
|
|
12
10
|
TODO (next up after urgent, these will happen whenever I get around to it)
|
13
11
|
--------------------------------------------------------------------------
|
@@ -18,7 +16,6 @@ TODO (next up after urgent, these will happen whenever I get around to it)
|
|
18
16
|
* Figure out whether I'm supposed to be using clone or dup for the object -.^ (looks like there may also be an `initialize_copy` method I can take advantage of instead of crazy stupid shit I'm doing now)
|
19
17
|
* config: rspec_mocks loaded, whether unprepared blocks should raise or just return nil
|
20
18
|
* extract surrogate/rspec into its own gem
|
21
|
-
* make substitutability matcher go either way
|
22
19
|
* make substitutability matcher not care whether either are surrogates
|
23
20
|
|
24
21
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: surrogate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement: &
|
16
|
+
requirement: &70208657501360 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70208657501360
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &70208657500800 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '2.4'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70208657500800
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: mountain_berry_fields
|
38
|
-
requirement: &
|
38
|
+
requirement: &70208657500220 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 1.0.3
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70208657500220
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: mountain_berry_fields-rspec
|
49
|
-
requirement: &
|
49
|
+
requirement: &70208657499660 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.0.3
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70208657499660
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: mountain_berry_fields-magic_comments
|
60
|
-
requirement: &
|
60
|
+
requirement: &70208657499120 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
version: 1.0.1
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70208657499120
|
69
69
|
description: Framework to aid in handrolling mock/spy objects.
|
70
70
|
email:
|
71
71
|
- josh.cheek@gmail.com
|