bogus 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile.lock +19 -1
- data/Guardfile +0 -7
- data/Guardfile.cucumber +9 -0
- data/README.md +42 -6
- data/bogus.gemspec +3 -0
- data/features/.nav +5 -2
- data/features/authors.md +10 -2
- data/features/changelog.md +11 -0
- data/features/configuration/fake_ar_attributes.feature +51 -0
- data/features/configuration/readme.md +7 -0
- data/features/{configuration_options.feature → configuration/search_modules.feature} +2 -2
- data/features/fakes/anonymous_doubles.feature +11 -7
- data/features/fakes/fake_objects.feature +0 -16
- data/lib/bogus/active_record_accessors.rb +41 -0
- data/lib/bogus/class_methods.rb +1 -1
- data/lib/bogus/configuration.rb +1 -0
- data/lib/bogus/constructor_methods.rb +18 -0
- data/lib/bogus/copies_methods.rb +7 -5
- data/lib/bogus/creates_fakes.rb +1 -1
- data/lib/bogus/creates_fakes_with_stubbed_methods.rb +1 -1
- data/lib/bogus/ensures_all_interactions_satisfied.rb +0 -2
- data/lib/bogus/fake.rb +8 -0
- data/lib/bogus/injector.rb +10 -0
- data/lib/bogus/instance_methods.rb +1 -1
- data/lib/bogus/interaction.rb +22 -3
- data/lib/bogus/interaction_presenter.rb +1 -1
- data/lib/bogus/makes_ducks.rb +5 -6
- data/lib/bogus/makes_subtypes.rb +1 -1
- data/lib/bogus/method_stringifier.rb +16 -8
- data/lib/bogus/record_interactions.rb +1 -1
- data/lib/bogus/records_double_interactions.rb +8 -7
- data/lib/bogus/registers_created_fakes.rb +10 -8
- data/lib/bogus/responds_to_everything.rb +8 -1
- data/lib/bogus/shadow.rb +3 -2
- data/lib/bogus/undefined_return_value.rb +11 -0
- data/lib/bogus/verifies_contracts.rb +12 -10
- data/lib/bogus/verifies_stub_definition.rb +37 -41
- data/lib/bogus/version.rb +1 -1
- data/spec/bogus/copies_classes_spec.rb +13 -6
- data/spec/bogus/creates_fakes_spec.rb +1 -1
- data/spec/bogus/fake_ar_attributes_spec.rb +72 -0
- data/spec/bogus/faking_factories_spec.rb +83 -0
- data/spec/bogus/frozen_fakes_spec.rb +59 -0
- data/spec/bogus/interaction_spec.rb +4 -0
- data/spec/bogus/method_copiers_spec.rb +26 -0
- data/spec/bogus/mocking_dsl_spec.rb +7 -3
- data/spec/bogus/overwrites_methods_spec.rb +2 -2
- data/spec/bogus/record_interactions_spec.rb +1 -1
- data/spec/bogus/ruby_2_support_spec.rb +96 -0
- data/spec/bogus/shadow_spec.rb +10 -8
- data/spec/bogus/verifies_stub_definition_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/support/matchers.rb +3 -0
- metadata +76 -66
@@ -0,0 +1,18 @@
|
|
1
|
+
module Bogus
|
2
|
+
class CopiesConstructor
|
3
|
+
extend Takes
|
4
|
+
takes :method_stringifier, :instance_methods, :class_methods
|
5
|
+
|
6
|
+
def copy(from, into)
|
7
|
+
return unless from.is_a?(Class)
|
8
|
+
initializer = instance_methods.call(from).get(:initialize)
|
9
|
+
body = body(initializer)
|
10
|
+
class_methods.call(into).define(body)
|
11
|
+
end
|
12
|
+
|
13
|
+
def body(initializer)
|
14
|
+
body = method_stringifier.stringify(initializer, "super")
|
15
|
+
body.gsub("initialize", "new")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/bogus/copies_methods.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
module Bogus
|
2
2
|
class CopiesMethods
|
3
|
-
extend
|
3
|
+
extend Takes
|
4
4
|
|
5
5
|
takes :makes_substitute_methods,
|
6
|
-
:
|
7
|
-
:
|
6
|
+
:method_copiers,
|
7
|
+
:copies_constructor
|
8
8
|
|
9
9
|
def copy(from, into)
|
10
|
-
|
11
|
-
|
10
|
+
method_copiers.each do |copier|
|
11
|
+
copy_methods(from, into, copier)
|
12
|
+
end
|
13
|
+
copies_constructor.copy(from, into)
|
12
14
|
end
|
13
15
|
|
14
16
|
private
|
data/lib/bogus/creates_fakes.rb
CHANGED
data/lib/bogus/fake.rb
CHANGED
@@ -10,6 +10,7 @@ module Bogus
|
|
10
10
|
extend FakeObject
|
11
11
|
|
12
12
|
def initialize(*args)
|
13
|
+
__shadow__
|
13
14
|
end
|
14
15
|
|
15
16
|
def to_s
|
@@ -27,6 +28,13 @@ module Bogus
|
|
27
28
|
class << self
|
28
29
|
attr_accessor :__copied_class__
|
29
30
|
|
31
|
+
alias :__create__ :new
|
32
|
+
|
33
|
+
def new(*args, &block)
|
34
|
+
__record__(:new, *args, &block)
|
35
|
+
__create__
|
36
|
+
end
|
37
|
+
|
30
38
|
def name
|
31
39
|
__copied_class__.name
|
32
40
|
end
|
data/lib/bogus/injector.rb
CHANGED
@@ -44,6 +44,16 @@ module Bogus
|
|
44
44
|
inject(ClassMethods, klass: klass)
|
45
45
|
end
|
46
46
|
|
47
|
+
def active_record_accessors(klass)
|
48
|
+
inject(ActiveRecordAccessors, klass: klass)
|
49
|
+
end
|
50
|
+
|
51
|
+
def method_copiers
|
52
|
+
copiers = [method(:class_methods), method(:instance_methods)]
|
53
|
+
copiers << method(:active_record_accessors) if configuration.fake_ar_attributes
|
54
|
+
copiers
|
55
|
+
end
|
56
|
+
|
47
57
|
def have_received_matcher
|
48
58
|
inject(HaveReceivedMatcher)
|
49
59
|
end
|
data/lib/bogus/interaction.rb
CHANGED
@@ -19,15 +19,26 @@ module Bogus
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def args
|
22
|
-
super.
|
22
|
+
args = super.map { |arg| remove_default_values_from_hash(arg) }
|
23
|
+
args.reject { |arg| arg.eql?(DefaultValue) }
|
23
24
|
end
|
24
25
|
|
25
26
|
private
|
26
27
|
|
27
28
|
def same_args?(other)
|
28
29
|
return true if any_args? || other.any_args?
|
29
|
-
|
30
|
-
args
|
30
|
+
|
31
|
+
other_args = normalize_other_args(args, other.args)
|
32
|
+
return false unless args.size == other_args.size
|
33
|
+
args.zip(other_args).all?{|a1, a2| a1 == a2 || a2 == a1}
|
34
|
+
end
|
35
|
+
|
36
|
+
def normalize_other_args(args, other_args)
|
37
|
+
if args.last.is_a?(Hash) && !other_args.last.is_a?(Hash)
|
38
|
+
other_args + [{}]
|
39
|
+
else
|
40
|
+
other_args
|
41
|
+
end
|
31
42
|
end
|
32
43
|
|
33
44
|
def same_result?(other)
|
@@ -40,5 +51,13 @@ module Bogus
|
|
40
51
|
rescue => e
|
41
52
|
self.error = e.class
|
42
53
|
end
|
54
|
+
|
55
|
+
def remove_default_values_from_hash(arg)
|
56
|
+
if arg.is_a?(Hash)
|
57
|
+
arg.reject { |_, val| val.eql?(DefaultValue) }
|
58
|
+
else
|
59
|
+
arg
|
60
|
+
end
|
61
|
+
end
|
43
62
|
end
|
44
63
|
end
|
data/lib/bogus/makes_ducks.rb
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
module Bogus
|
2
2
|
class MakesDucks
|
3
|
-
extend
|
3
|
+
extend Takes
|
4
4
|
|
5
|
-
takes :
|
5
|
+
takes :method_copiers, :makes_subtypes
|
6
6
|
|
7
7
|
def make(first_class, *classes)
|
8
8
|
duck = makes_subtypes.make(first_class)
|
9
9
|
classes.each do |klass|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
instance_methods.call(klass))
|
10
|
+
method_copiers.each do |copier|
|
11
|
+
remove_methods(copier.call(duck), copier.call(klass))
|
12
|
+
end
|
14
13
|
end
|
15
14
|
duck
|
16
15
|
end
|
data/lib/bogus/makes_subtypes.rb
CHANGED
@@ -10,21 +10,29 @@ module Bogus
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def arguments_as_string(arguments)
|
13
|
-
arguments
|
14
|
-
arguments.map{|type, name| argument_to_string(name, type) }.compact.join(', ')
|
13
|
+
stringify_arguments(arguments, DefaultValue)
|
15
14
|
end
|
16
15
|
|
17
16
|
def argument_values(arguments)
|
18
|
-
|
17
|
+
stringify_arguments(arguments)
|
19
18
|
end
|
20
19
|
|
21
|
-
|
20
|
+
private
|
21
|
+
|
22
|
+
def stringify_arguments(arguments, default = nil)
|
23
|
+
fill_in_missing_names(arguments).map do |type, name|
|
24
|
+
argument_to_string(name, type, default)
|
25
|
+
end.join(', ')
|
26
|
+
end
|
27
|
+
|
28
|
+
def argument_to_string(name, type, default)
|
22
29
|
case type
|
23
30
|
when :block then "&#{name}"
|
24
|
-
when :key
|
25
|
-
when :opt
|
26
|
-
when :req
|
27
|
-
when :rest
|
31
|
+
when :key then default ? "#{name}: #{default}" : "#{name}: #{name}"
|
32
|
+
when :opt then default ? "#{name} = #{default}" : name
|
33
|
+
when :req then name
|
34
|
+
when :rest then "*#{name}"
|
35
|
+
when :keyrest then "**#{name}"
|
28
36
|
else raise "unknown argument type: #{type}"
|
29
37
|
end
|
30
38
|
end
|
@@ -1,11 +1,12 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module Bogus
|
2
|
+
class RecordsDoubleInteractions
|
3
|
+
extend Takes
|
3
4
|
|
4
|
-
|
5
|
+
takes :doubled_interactions, :fake_registry
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
def record(object, method_name, args, &block)
|
8
|
+
fake_name = fake_registry.name(object)
|
9
|
+
doubled_interactions.record(fake_name, method_name, *args, &block) if fake_name
|
10
|
+
end
|
9
11
|
end
|
10
|
-
|
11
12
|
end
|
@@ -1,12 +1,14 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module Bogus
|
2
|
+
class RegistersCreatedFakes
|
3
|
+
extend Takes
|
3
4
|
|
4
|
-
|
5
|
+
takes :creates_fakes, :fake_registry, :double_tracker
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
def create(name, opts = {}, &block)
|
8
|
+
fake = creates_fakes.create(name, opts, &block)
|
9
|
+
fake_registry.store(name, fake)
|
10
|
+
double_tracker.track(fake)
|
11
|
+
fake
|
12
|
+
end
|
11
13
|
end
|
12
14
|
end
|
@@ -1,11 +1,18 @@
|
|
1
1
|
module Bogus
|
2
2
|
class RespondsToEverything
|
3
|
+
include FakeObject
|
4
|
+
include RecordInteractions
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
__shadow__
|
8
|
+
end
|
9
|
+
|
3
10
|
def respond_to?(method)
|
4
11
|
true
|
5
12
|
end
|
6
13
|
|
7
14
|
def method_missing(name, *args, &block)
|
8
|
-
|
15
|
+
__record__(name, *args, &block)
|
9
16
|
end
|
10
17
|
end
|
11
18
|
end
|
data/lib/bogus/shadow.rb
CHANGED
@@ -2,10 +2,10 @@ module Bogus
|
|
2
2
|
class Shadow
|
3
3
|
attr_reader :calls
|
4
4
|
|
5
|
-
def initialize
|
5
|
+
def initialize
|
6
6
|
@calls = []
|
7
7
|
@stubs = []
|
8
|
-
@defaults =
|
8
|
+
@defaults = {}
|
9
9
|
@required = Set.new
|
10
10
|
end
|
11
11
|
|
@@ -54,6 +54,7 @@ module Bogus
|
|
54
54
|
def return_value(interaction)
|
55
55
|
_, return_value = @stubs.reverse.find{|i, v| i == interaction}
|
56
56
|
return_value ||= @defaults[interaction.method]
|
57
|
+
return_value ||= proc{ UndefinedReturnValue.new(interaction) }
|
57
58
|
return_value.call
|
58
59
|
end
|
59
60
|
end
|
@@ -1,16 +1,18 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module Bogus
|
2
|
+
class VerifiesContracts
|
3
|
+
extend Takes
|
3
4
|
|
4
|
-
|
5
|
+
takes :doubled_interactions, :real_interactions
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
def verify(fake_name)
|
8
|
+
missed = doubled_interactions.for_fake(fake_name).reject do |interaction|
|
9
|
+
real_interactions.recorded?(fake_name, interaction)
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
unless missed.empty?
|
13
|
+
actual = real_interactions.for_fake(fake_name)
|
14
|
+
raise Bogus::ContractNotFulfilled.new(fake_name, missed: missed, actual: actual)
|
15
|
+
end
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
@@ -1,43 +1,39 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
def any_args?(args)
|
41
|
-
[Bogus::AnyArgs] == args
|
1
|
+
module Bogus
|
2
|
+
class VerifiesStubDefinition
|
3
|
+
extend Takes
|
4
|
+
|
5
|
+
takes :method_stringifier
|
6
|
+
|
7
|
+
def verify!(object, method_name, args)
|
8
|
+
stubbing_non_existent_method!(object, method_name) unless object.respond_to?(method_name)
|
9
|
+
return unless object.methods.include?(method_name)
|
10
|
+
return if any_args?(args)
|
11
|
+
method = object.method(method_name)
|
12
|
+
verify_call!(method, args)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def verify_call!(method, args)
|
18
|
+
object = Object.new
|
19
|
+
fake_method = method_stringifier.stringify(method, "")
|
20
|
+
object.instance_eval(fake_method)
|
21
|
+
object.send(method.name, *args)
|
22
|
+
rescue ArgumentError
|
23
|
+
wrong_arguments!(method, args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def wrong_arguments!(method, args)
|
27
|
+
args_string = method_stringifier.arguments_as_string(method.parameters)
|
28
|
+
raise ArgumentError, "tried to stub #{method.name}(#{args_string}) with arguments: #{args.map(&:inspect).join(",")}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def stubbing_non_existent_method!(object, method_name)
|
32
|
+
raise NameError, "#{object.inspect} does not respond to #{method_name}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def any_args?(args)
|
36
|
+
[Bogus::AnyArgs] == args
|
37
|
+
end
|
42
38
|
end
|
43
39
|
end
|