bogus 0.0.4 → 0.1.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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile.lock +19 -1
  3. data/Guardfile +0 -7
  4. data/Guardfile.cucumber +9 -0
  5. data/README.md +42 -6
  6. data/bogus.gemspec +3 -0
  7. data/features/.nav +5 -2
  8. data/features/authors.md +10 -2
  9. data/features/changelog.md +11 -0
  10. data/features/configuration/fake_ar_attributes.feature +51 -0
  11. data/features/configuration/readme.md +7 -0
  12. data/features/{configuration_options.feature → configuration/search_modules.feature} +2 -2
  13. data/features/fakes/anonymous_doubles.feature +11 -7
  14. data/features/fakes/fake_objects.feature +0 -16
  15. data/lib/bogus/active_record_accessors.rb +41 -0
  16. data/lib/bogus/class_methods.rb +1 -1
  17. data/lib/bogus/configuration.rb +1 -0
  18. data/lib/bogus/constructor_methods.rb +18 -0
  19. data/lib/bogus/copies_methods.rb +7 -5
  20. data/lib/bogus/creates_fakes.rb +1 -1
  21. data/lib/bogus/creates_fakes_with_stubbed_methods.rb +1 -1
  22. data/lib/bogus/ensures_all_interactions_satisfied.rb +0 -2
  23. data/lib/bogus/fake.rb +8 -0
  24. data/lib/bogus/injector.rb +10 -0
  25. data/lib/bogus/instance_methods.rb +1 -1
  26. data/lib/bogus/interaction.rb +22 -3
  27. data/lib/bogus/interaction_presenter.rb +1 -1
  28. data/lib/bogus/makes_ducks.rb +5 -6
  29. data/lib/bogus/makes_subtypes.rb +1 -1
  30. data/lib/bogus/method_stringifier.rb +16 -8
  31. data/lib/bogus/record_interactions.rb +1 -1
  32. data/lib/bogus/records_double_interactions.rb +8 -7
  33. data/lib/bogus/registers_created_fakes.rb +10 -8
  34. data/lib/bogus/responds_to_everything.rb +8 -1
  35. data/lib/bogus/shadow.rb +3 -2
  36. data/lib/bogus/undefined_return_value.rb +11 -0
  37. data/lib/bogus/verifies_contracts.rb +12 -10
  38. data/lib/bogus/verifies_stub_definition.rb +37 -41
  39. data/lib/bogus/version.rb +1 -1
  40. data/spec/bogus/copies_classes_spec.rb +13 -6
  41. data/spec/bogus/creates_fakes_spec.rb +1 -1
  42. data/spec/bogus/fake_ar_attributes_spec.rb +72 -0
  43. data/spec/bogus/faking_factories_spec.rb +83 -0
  44. data/spec/bogus/frozen_fakes_spec.rb +59 -0
  45. data/spec/bogus/interaction_spec.rb +4 -0
  46. data/spec/bogus/method_copiers_spec.rb +26 -0
  47. data/spec/bogus/mocking_dsl_spec.rb +7 -3
  48. data/spec/bogus/overwrites_methods_spec.rb +2 -2
  49. data/spec/bogus/record_interactions_spec.rb +1 -1
  50. data/spec/bogus/ruby_2_support_spec.rb +96 -0
  51. data/spec/bogus/shadow_spec.rb +10 -8
  52. data/spec/bogus/verifies_stub_definition_spec.rb +1 -1
  53. data/spec/spec_helper.rb +1 -1
  54. data/spec/support/matchers.rb +3 -0
  55. 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
@@ -1,14 +1,16 @@
1
1
  module Bogus
2
2
  class CopiesMethods
3
- extend Bogus::Takes
3
+ extend Takes
4
4
 
5
5
  takes :makes_substitute_methods,
6
- :instance_methods,
7
- :class_methods
6
+ :method_copiers,
7
+ :copies_constructor
8
8
 
9
9
  def copy(from, into)
10
- copy_methods(from, into, instance_methods)
11
- copy_methods(from, into, class_methods)
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
@@ -15,7 +15,7 @@ module Bogus
15
15
 
16
16
  case mode
17
17
  when :instance
18
- return klass_copy.new
18
+ return klass_copy.__create__
19
19
  when :class
20
20
  return klass_copy
21
21
  else
@@ -1,6 +1,6 @@
1
1
  module Bogus
2
2
  class CreatesFakesWithStubbedMethods
3
- extend Bogus::Takes
3
+ extend Takes
4
4
 
5
5
  takes :multi_stubber, :creates_fakes,
6
6
  :responds_to_everything, :fake_configuration
@@ -1,7 +1,5 @@
1
1
  module Bogus
2
2
  class EnsuresAllInteractionsSatisfied
3
- extend Bogus::Takes
4
-
5
3
  def ensure_satisfied!(objects)
6
4
  unsatisfied = unsatisfied_interactions(objects)
7
5
  return if unsatisfied.empty?
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
@@ -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
@@ -1,6 +1,6 @@
1
1
  module Bogus
2
2
  class InstanceMethods
3
- extend Bogus::Takes
3
+ extend Takes
4
4
  takes :klass
5
5
 
6
6
  def all
@@ -19,15 +19,26 @@ module Bogus
19
19
  end
20
20
 
21
21
  def args
22
- super.reject { |arg| arg.eql?(Bogus::DefaultValue) }
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
- return false unless args.size == other.args.size
30
- args.zip(other.args).all?{|a1, a2| a1 == a2 || a2 == a1}
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
@@ -1,6 +1,6 @@
1
1
  module Bogus
2
2
  class InteractionPresenter
3
- extend Bogus::Takes
3
+ extend Takes
4
4
 
5
5
  takes :interaction
6
6
 
@@ -1,16 +1,15 @@
1
1
  module Bogus
2
2
  class MakesDucks
3
- extend Bogus::Takes
3
+ extend Takes
4
4
 
5
- takes :class_methods, :instance_methods, :makes_subtypes
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
- remove_methods(class_methods.call(duck),
11
- class_methods.call(klass))
12
- remove_methods(instance_methods.call(duck),
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
@@ -1,6 +1,6 @@
1
1
  module Bogus
2
2
  class MakesSubtypes
3
- extend Bogus::Takes
3
+ extend Takes
4
4
 
5
5
  takes :copies_methods
6
6
 
@@ -10,21 +10,29 @@ module Bogus
10
10
  end
11
11
 
12
12
  def arguments_as_string(arguments)
13
- arguments = fill_in_missing_names(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
- arguments_as_string(arguments).gsub(" = Bogus::DefaultValue", '')
17
+ stringify_arguments(arguments)
19
18
  end
20
19
 
21
- def argument_to_string(name, type)
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 then "#{name}: #{name}"
25
- when :opt then "#{name} = Bogus::DefaultValue"
26
- when :req then name
27
- when :rest then "*#{name}"
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,7 +1,7 @@
1
1
  module Bogus
2
2
  module RecordInteractions
3
3
  def __shadow__
4
- @__shadow__ ||= Shadow.new{ self }
4
+ @__shadow__ ||= Shadow.new
5
5
  end
6
6
 
7
7
  def __record__(method, *args, &block)
@@ -1,11 +1,12 @@
1
- class Bogus::RecordsDoubleInteractions
2
- extend Bogus::Takes
1
+ module Bogus
2
+ class RecordsDoubleInteractions
3
+ extend Takes
3
4
 
4
- takes :doubled_interactions, :fake_registry
5
+ takes :doubled_interactions, :fake_registry
5
6
 
6
- def record(object, method_name, args, &block)
7
- fake_name = fake_registry.name(object)
8
- doubled_interactions.record(fake_name, method_name, *args, &block) if fake_name
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
- class Bogus::RegistersCreatedFakes
2
- extend Bogus::Takes
1
+ module Bogus
2
+ class RegistersCreatedFakes
3
+ extend Takes
3
4
 
4
- takes :creates_fakes, :fake_registry, :double_tracker
5
+ takes :creates_fakes, :fake_registry, :double_tracker
5
6
 
6
- def create(name, opts = {}, &block)
7
- fake = creates_fakes.create(name, opts, &block)
8
- fake_registry.store(name, fake)
9
- double_tracker.track(fake)
10
- fake
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
- self
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(&default_return_value)
5
+ def initialize
6
6
  @calls = []
7
7
  @stubs = []
8
- @defaults = Hash.new(default_return_value)
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
@@ -0,0 +1,11 @@
1
+ module Bogus
2
+ class UndefinedReturnValue
3
+ def initialize(interaction)
4
+ @interaction = InteractionPresenter.new(interaction)
5
+ end
6
+
7
+ def to_s
8
+ "#<UndefinedReturnValue for #{@interaction}>"
9
+ end
10
+ end
11
+ end
@@ -1,16 +1,18 @@
1
- class Bogus::VerifiesContracts
2
- extend Bogus::Takes
1
+ module Bogus
2
+ class VerifiesContracts
3
+ extend Takes
3
4
 
4
- takes :doubled_interactions, :real_interactions
5
+ takes :doubled_interactions, :real_interactions
5
6
 
6
- def verify(fake_name)
7
- missed = doubled_interactions.for_fake(fake_name).reject do |interaction|
8
- real_interactions.recorded?(fake_name, interaction)
9
- end
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
- unless missed.empty?
12
- actual = real_interactions.for_fake(fake_name)
13
- raise Bogus::ContractNotFulfilled.new(fake_name, missed: missed, actual: actual)
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
- class Bogus::VerifiesStubDefinition
2
- extend Bogus::Takes
3
-
4
- takes :method_stringifier
5
-
6
- def verify!(object, method_name, args)
7
- stubbing_non_existent_method!(object, method_name) unless object.respond_to?(method_name)
8
- return unless object.methods.include?(method_name)
9
- return if any_args?(args)
10
- method = object.method(method_name)
11
- wrong_number_of_arguments!(method, args) if under_number_of_required_arguments?(method, args.size)
12
- wrong_number_of_arguments!(method, args) if over_number_of_allowed_arguments?(method, args.size)
13
- end
14
-
15
- private
16
-
17
- def wrong_number_of_arguments!(method, args)
18
- args_string = method_stringifier.arguments_as_string(method.parameters)
19
- raise ArgumentError, "tried to stub #{method.name}(#{args_string}) with #{args.size} arguments"
20
- end
21
-
22
- def stubbing_non_existent_method!(object, method_name)
23
- raise NameError, "#{object.inspect} does not respond to #{method_name}"
24
- end
25
-
26
- def under_number_of_required_arguments?(method, args_count)
27
- number_of_arguments = method.arity
28
- number_of_arguments = -number_of_arguments - 1 if number_of_arguments < 0
29
-
30
- args_count < number_of_arguments
31
- end
32
-
33
- def over_number_of_allowed_arguments?(method, args_count)
34
- return false if method.parameters.find{|type, name| type == :rest}
35
- number_of_arguments = method.parameters.count{|type, name| [:key, :opt, :req].include?(type) }
36
-
37
- args_count > number_of_arguments
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