bogus 0.0.2 → 0.0.3.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile.lock +14 -2
  3. data/Guardfile +5 -0
  4. data/README.md +7 -249
  5. data/bogus.gemspec +3 -1
  6. data/features/.nav +21 -0
  7. data/features/authors.md +42 -0
  8. data/{CHANGELOG.md → features/changelog.md} +9 -2
  9. data/features/configuration_options.feature +1 -2
  10. data/features/{contract_tests_mocks.feature → contract_tests/contract_tests_mocks.feature} +4 -1
  11. data/features/{contract_tests_spies.feature → contract_tests/contract_tests_spies.feature} +2 -0
  12. data/features/{contract_tests_stubs.feature → contract_tests/contract_tests_stubs.feature} +14 -0
  13. data/features/contract_tests/readme.md +26 -0
  14. data/features/{return_value_contracts.feature → contract_tests/return_value_contracts.feature} +6 -2
  15. data/features/{anonymous_doubles.feature → fakes/anonymous_doubles.feature} +24 -8
  16. data/features/{fake_objects.feature → fakes/fake_objects.feature} +39 -4
  17. data/features/fakes/global_fake_configuration.feature +88 -0
  18. data/features/fakes/readme.md +11 -0
  19. data/features/fakes/replacing_classes.feature +148 -0
  20. data/features/getting_started.md +36 -0
  21. data/features/license.md +9 -0
  22. data/features/readme.md +173 -0
  23. data/features/safe_stubbing/argument_matchers.feature +30 -0
  24. data/features/safe_stubbing/readme.md +35 -0
  25. data/features/{safe_mocking.feature → safe_stubbing/safe_mocking.feature} +14 -0
  26. data/features/{safe_stubbing.feature → safe_stubbing/safe_stubbing.feature} +18 -4
  27. data/features/{spies.feature → safe_stubbing/spies.feature} +19 -4
  28. data/features/step_definitions/rspec_steps.rb +14 -5
  29. data/features/support/env.rb +4 -0
  30. data/lib/bogus.rb +2 -0
  31. data/lib/bogus/adds_recording.rb +11 -7
  32. data/lib/bogus/any_args.rb +7 -0
  33. data/lib/bogus/anything.rb +11 -0
  34. data/lib/bogus/contract_not_fulfilled.rb +17 -10
  35. data/lib/bogus/copies_classes.rb +2 -6
  36. data/lib/bogus/creates_fakes_with_stubbed_methods.rb +40 -0
  37. data/lib/bogus/double.rb +28 -8
  38. data/lib/bogus/ensures_all_interactions_satisfied.rb +36 -0
  39. data/lib/bogus/fake.rb +6 -0
  40. data/lib/bogus/fake_configuration.rb +69 -0
  41. data/lib/bogus/fakes_classes.rb +21 -0
  42. data/lib/bogus/has_overwritten_methods.rb +24 -0
  43. data/lib/bogus/have_received_matcher.rb +63 -0
  44. data/lib/bogus/injector.rb +36 -14
  45. data/lib/bogus/interaction.rb +33 -17
  46. data/lib/bogus/makes_substitute_methods.rb +15 -0
  47. data/lib/bogus/mocking_dsl.rb +31 -0
  48. data/lib/bogus/multi_stubber.rb +15 -0
  49. data/lib/bogus/not_all_expectations_satisfied.rb +27 -0
  50. data/lib/bogus/overwriten_classes.rb +15 -0
  51. data/lib/bogus/overwrites_classes.rb +2 -2
  52. data/lib/bogus/overwrites_methods.rb +42 -0
  53. data/lib/bogus/proxies_method_calls.rb +23 -0
  54. data/lib/bogus/proxy_class.rb +25 -16
  55. data/lib/bogus/public_methods.rb +36 -11
  56. data/lib/bogus/record_interactions.rb +3 -9
  57. data/lib/bogus/recording_proxy.rb +5 -0
  58. data/lib/bogus/registers_created_fakes.rb +2 -1
  59. data/lib/bogus/resets_overwritten_classes.rb +14 -0
  60. data/lib/bogus/resets_stubbed_methods.rb +12 -0
  61. data/lib/bogus/responds_to_everything.rb +11 -0
  62. data/lib/bogus/rspec.rb +7 -0
  63. data/lib/bogus/rspec_adapter.rb +17 -0
  64. data/lib/bogus/rspec_extensions.rb +8 -20
  65. data/lib/bogus/shadow.rb +60 -0
  66. data/lib/bogus/verifies_contracts.rb +5 -1
  67. data/lib/bogus/verifies_stub_definition.rb +5 -0
  68. data/lib/bogus/version.rb +1 -1
  69. data/lib/tracks_existence_of_test_doubles.rb +11 -0
  70. data/spec/bogus/adds_recording_spec.rb +46 -10
  71. data/spec/bogus/anything_spec.rb +13 -0
  72. data/spec/bogus/copies_classes_spec.rb +4 -3
  73. data/spec/bogus/creates_fakes_with_stubbed_methods_spec.rb +121 -0
  74. data/spec/bogus/double_spec.rb +63 -20
  75. data/spec/bogus/ensures_all_interactions_satisfied_spec.rb +43 -0
  76. data/spec/bogus/fake_configuration_spec.rb +99 -0
  77. data/spec/bogus/fakes_classes_spec.rb +46 -0
  78. data/spec/bogus/have_received_matcher_spec.rb +56 -0
  79. data/spec/bogus/interaction_spec.rb +18 -7
  80. data/spec/bogus/interactions_repository_spec.rb +42 -0
  81. data/spec/bogus/makes_substitute_methods_spec.rb +24 -0
  82. data/spec/bogus/mocking_dsl_spec.rb +234 -7
  83. data/spec/bogus/multi_stubber_spec.rb +31 -0
  84. data/spec/bogus/overwriten_classes_spec.rb +27 -0
  85. data/spec/bogus/overwrites_classes_spec.rb +2 -2
  86. data/spec/bogus/overwrites_methods_spec.rb +107 -0
  87. data/spec/bogus/proxy_class_spec.rb +6 -0
  88. data/spec/bogus/record_interactions_spec.rb +3 -4
  89. data/spec/bogus/registers_created_fakes_spec.rb +8 -0
  90. data/spec/bogus/resets_overwritten_classes_spec.rb +26 -0
  91. data/spec/bogus/resets_stubbed_methods_spec.rb +16 -0
  92. data/spec/bogus/shadow_spec.rb +182 -0
  93. data/spec/bogus/verifies_contracts_spec.rb +9 -3
  94. data/spec/bogus/verifies_stub_definition_spec.rb +4 -0
  95. data/spec/spec_helper.rb +3 -0
  96. data/spec/support/fake_creator_of_fakes.rb +15 -0
  97. data/spec/support/sample_fake.rb +13 -0
  98. data/spec/tracks_existence_of_test_doubles_spec.rb +26 -0
  99. metadata +105 -32
  100. data/lib/bogus/creates_anonymous_stubs.rb +0 -27
  101. data/lib/bogus/invocation_matcher.rb +0 -27
  102. data/lib/bogus/rr_proxy.rb +0 -5
  103. data/spec/bogus/invocation_matcher_spec.rb +0 -26
@@ -1,24 +1,40 @@
1
- class Bogus::Interaction < Struct.new(:method, :args, :return_value, :error, :has_result)
2
- def initialize(method, args, &block)
3
- self.method = method
4
- self.args = args
1
+ module Bogus
2
+ class Interaction < Struct.new(:method, :args, :return_value, :error, :has_result)
3
+ def initialize(method, args, &block)
4
+ self.method = method
5
+ self.args = args
5
6
 
6
- if block_given?
7
- evaluate_return_value(block)
8
- self.has_result = true
7
+ if block_given?
8
+ evaluate_return_value(block)
9
+ self.has_result = true
10
+ end
9
11
  end
10
- end
11
12
 
12
- def ==(other)
13
- return super(other) if has_result && other.has_result
14
- method == other.method && args == other.args
15
- end
13
+ def ==(other)
14
+ method == other.method && same_args?(other) && same_result?(other)
15
+ end
16
+
17
+ def any_args?
18
+ args == [AnyArgs]
19
+ end
16
20
 
17
- private
21
+ private
18
22
 
19
- def evaluate_return_value(block)
20
- self.return_value = block.call
21
- rescue => e
22
- self.error = e.class
23
+ def same_args?(other)
24
+ return true if any_args? || other.any_args?
25
+ return false unless args.size == other.args.size
26
+ args.zip(other.args).all?{|a1, a2| a1 == a2 || a2 == a1}
27
+ end
28
+
29
+ def same_result?(other)
30
+ return true unless has_result && other.has_result
31
+ return_value == other.return_value && error == other.error
32
+ end
33
+
34
+ def evaluate_return_value(block)
35
+ self.return_value = block.call
36
+ rescue => e
37
+ self.error = e.class
38
+ end
23
39
  end
24
40
  end
@@ -0,0 +1,15 @@
1
+ module Bogus
2
+ class MakesSubstituteMethods
3
+ extend Takes
4
+
5
+ takes :method_stringifier
6
+
7
+ def stringify(method)
8
+ args = method_stringifier.arguments_as_string(method.parameters)
9
+ args_no_defaults = args.gsub(' = {}', '')
10
+
11
+ method_stringifier.stringify(method,
12
+ "__record__(:#{method.name}, #{args_no_defaults})")
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ module Bogus
2
+ module MockingDSL
3
+ def fake(*args, &block)
4
+ Bogus.fake_for(*args, &block)
5
+ end
6
+
7
+ def fake_class(name, opts = {})
8
+ Bogus.fake_class(name, opts)
9
+ end
10
+
11
+ def stub(*args)
12
+ Bogus.create_stub(*args)
13
+ end
14
+
15
+ def have_received(*args)
16
+ Bogus.have_received(*args)
17
+ end
18
+
19
+ def mock(*args)
20
+ Bogus.create_mock(*args)
21
+ end
22
+
23
+ def any_args
24
+ Bogus::AnyArgs
25
+ end
26
+
27
+ def anything
28
+ Bogus::Anything
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ module Bogus
2
+ class MultiStubber
3
+ extend Takes
4
+ takes :create_double
5
+
6
+ def stub_all(object, methods = {})
7
+ double = create_double.call(object)
8
+ methods.each do |name, result|
9
+ block = result.is_a?(Proc) ? result : proc{ result }
10
+ double.stubs(name, Bogus::AnyArgs, &block)
11
+ end
12
+ object
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ module Bogus
2
+ class NotAllExpectationsSatisfied < StandardError
3
+ def self.create(unsatisfied_interactions, calls)
4
+ str = <<-EOF
5
+ Some of the mocked interactions were not satisfied:
6
+
7
+ <% unsatisfied_interactions.each do |o, i| %>
8
+ - <%= render_interaction(o, i) %>
9
+ <% end %>
10
+
11
+ The following calls were recorded:
12
+
13
+ <% calls.each do |o, i| %>
14
+ - <%= render_interaction(o, i) %>
15
+ <% end %>
16
+ EOF
17
+ str = str.gsub(/ {6}/, '')
18
+ template = ERB.new(str, nil, "<>")
19
+ new(template.result(binding))
20
+ end
21
+
22
+ def self.render_interaction(object, interaction)
23
+ args = interaction.args.map(&:inspect).join(", ")
24
+ "#{object.inspect}.#{interaction.method}(#{args})"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ module Bogus
2
+ class OverwrittenClasses
3
+ def add(name, klass)
4
+ classes << [name, klass]
5
+ end
6
+
7
+ def clear
8
+ @classes = []
9
+ end
10
+
11
+ def classes
12
+ @classes ||= []
13
+ end
14
+ end
15
+ end
@@ -1,6 +1,6 @@
1
1
  class Bogus::OverwritesClasses
2
- def overwrite(klass, new_klass)
3
- modules = klass.name.split('::')
2
+ def overwrite(full_name, new_klass)
3
+ modules = full_name.split('::')
4
4
  klass_name = modules.pop
5
5
  parent_module = modules.reduce(Object) { |mod, name| mod.const_get(name) }
6
6
  parent_module.send(:remove_const, klass_name)
@@ -0,0 +1,42 @@
1
+ module Bogus
2
+ class OverwritesMethods
3
+ extend Takes
4
+
5
+ takes :makes_substitute_methods
6
+
7
+ def overwrite(object, name)
8
+ raise "wut?" if name == :__shadow__
9
+ return if object.is_a?(FakeObject)
10
+
11
+ object.extend RecordInteractions
12
+ object.extend HasOverwritenMethods
13
+
14
+ method = method_by_name(object, name)
15
+ copy = copy(object, name)
16
+
17
+ object.__overwrite__(name, method, copy)
18
+ end
19
+
20
+ def reset(object)
21
+ return if object.is_a?(FakeObject)
22
+
23
+ object.__reset__
24
+ end
25
+
26
+ private
27
+
28
+ def method_by_name(object, name)
29
+ object.method(name) if object.methods.include?(name)
30
+ end
31
+
32
+ def copy(object, name)
33
+ method = method_by_name(object, name)
34
+ return default_method(name) unless method
35
+ makes_substitute_methods.stringify(method)
36
+ end
37
+
38
+ def default_method(name)
39
+ "def #{name}(*args, &block); __record__(:#{name}, *args, &block); end"
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,23 @@
1
+ module Bogus
2
+ module ProxiesMethodCalls
3
+ def proxy(method_name)
4
+ MethodCallProxy.new do |name, *args, &return_value|
5
+ __send__(method_name, name, *args, &return_value)
6
+ end
7
+ end
8
+ end
9
+
10
+ class MethodCallProxy < BasicObject
11
+ def initialize(&on_called)
12
+ @on_called = on_called
13
+ end
14
+
15
+ def raise(*args)
16
+ ::Kernel.raise(*args)
17
+ end
18
+
19
+ def method_missing(name, *args, &block)
20
+ @on_called.call(name, *args, &block)
21
+ end
22
+ end
23
+ end
@@ -1,22 +1,31 @@
1
- class Bogus::ProxyClass
2
- def initialize(fake_name, klass, create_recording_proxy)
3
- @fake_name = fake_name
4
- @klass = klass
5
- @create_recording_proxy = create_recording_proxy
1
+ module Bogus
2
+ class ProxyClass < Module
3
+ def initialize(fake_name, klass, create_recording_proxy)
4
+ @fake_name = fake_name
5
+ @klass = klass
6
+ @create_recording_proxy = create_recording_proxy
6
7
 
7
- @recording_proxy = @create_recording_proxy.call(@klass, @fake_name)
8
- end
8
+ @recording_proxy = @create_recording_proxy.call(@klass, @fake_name)
9
+ end
9
10
 
10
- def new(*args, &block)
11
- instance = @klass.new(*args, &block)
12
- @create_recording_proxy.call(instance, @fake_name)
13
- end
11
+ def self.create(fake_name, klass, create_recording_proxy)
12
+ end
14
13
 
15
- def method_missing(name, *args, &block)
16
- @recording_proxy.__send__(name, *args, &block)
17
- end
14
+ def new(*args, &block)
15
+ instance = @klass.new(*args, &block)
16
+ @create_recording_proxy.call(instance, @fake_name)
17
+ end
18
+
19
+ def method_missing(name, *args, &block)
20
+ @recording_proxy.__send__(name, *args, &block)
21
+ end
22
+
23
+ def const_missing(name)
24
+ @recording_proxy.__send__(:const_get, name)
25
+ end
18
26
 
19
- def respond_to?(name)
20
- @recording_proxy.respond_to?(name)
27
+ def respond_to?(name)
28
+ @recording_proxy.respond_to?(name)
29
+ end
21
30
  end
22
31
  end
@@ -1,12 +1,7 @@
1
1
  module Bogus
2
2
  module PublicMethods
3
-
4
- def fake_for(*args, &block)
5
- inject.creates_fakes.create(*args, &block)
6
- end
7
-
8
- def record_calls_for(name)
9
- inject.adds_recording.add(name)
3
+ def record_calls_for(name, klass = nil)
4
+ inject.adds_recording.add(name, klass)
10
5
  end
11
6
 
12
7
  def verify_contract!(fake_name)
@@ -34,14 +29,44 @@ module Bogus
34
29
  end
35
30
 
36
31
  def have_received(*args)
37
- inject.invocation_matcher(*args)
32
+ inject.have_received_matcher(*args).method_call
33
+ end
34
+
35
+ def fake_for(*args, &block)
36
+ inject.creates_fakes_with_stubbed_methods.create(*args, &block)
37
+ end
38
+
39
+ def fake_class(*args)
40
+ inject.fakes_classes.fake(*args)
38
41
  end
39
42
 
40
- def create_anonymous_stub(*args)
41
- inject.creates_anonymous_stubs.create(*args)
43
+ def after_each_test
44
+ ensure_all_expectations_satisfied!
45
+ reset_stubbed_methods
46
+ clear_expectations
47
+ reset_overwritten_classes
42
48
  end
43
49
 
44
- private
50
+ def ensure_all_expectations_satisfied!
51
+ doubles = inject.double_tracker.doubles
52
+ inject.ensures_all_interactions_satisfied.ensure_satisfied!(doubles)
53
+ end
54
+
55
+ def clear_expectations
56
+ inject.clear_tracked_doubles
57
+ end
58
+
59
+ def reset_stubbed_methods
60
+ inject.resets_stubbed_methods.reset_all_doubles
61
+ end
62
+
63
+ def reset_overwritten_classes
64
+ inject.resets_overwritten_classes.reset
65
+ end
66
+
67
+ def fakes(&block)
68
+ inject.fake_configuration.evaluate(&block)
69
+ end
45
70
 
46
71
  def inject
47
72
  @injector ||= Bogus::Injector.new
@@ -1,17 +1,11 @@
1
1
  module Bogus
2
2
  module RecordInteractions
3
- def __inner_object__
4
- @__inner_object__ ||= Object.new
5
- end
6
-
7
- def __stub__
8
- @__stub__ ||= RRProxy.stub(__inner_object__)
3
+ def __shadow__
4
+ @__shadow__ ||= Shadow.new{ self }
9
5
  end
10
6
 
11
7
  def __record__(method, *args, &block)
12
- __stub__.__send__(method, *args)
13
- __inner_object__.__send__(method, *args, &block)
14
- self
8
+ __shadow__.run(method, *args, &block)
15
9
  end
16
10
  end
17
11
  end
@@ -11,6 +11,11 @@ class Bogus::RecordingProxy < BasicObject
11
11
  ::Kernel.raise
12
12
  end
13
13
 
14
+ # apparently even BasicObject has an equality operator
15
+ def ==(other)
16
+ method_missing(:==, other)
17
+ end
18
+
14
19
  def respond_to?(name)
15
20
  @instance.respond_to?(name)
16
21
  end
@@ -1,11 +1,12 @@
1
1
  class Bogus::RegistersCreatedFakes
2
2
  extend Bogus::Takes
3
3
 
4
- takes :creates_fakes, :fake_registry
4
+ takes :creates_fakes, :fake_registry, :double_tracker
5
5
 
6
6
  def create(name, opts = {}, &block)
7
7
  fake = creates_fakes.create(name, opts, &block)
8
8
  fake_registry.store(name, fake)
9
+ double_tracker.track(fake)
9
10
  fake
10
11
  end
11
12
  end
@@ -0,0 +1,14 @@
1
+ module Bogus
2
+ class ResetsOverwrittenClasses
3
+ extend Takes
4
+
5
+ takes :overwritten_classes, :overwrites_classes
6
+
7
+ def reset
8
+ overwritten_classes.classes.each do |name, klass|
9
+ overwrites_classes.overwrite(name, klass)
10
+ end
11
+ overwritten_classes.clear
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ module Bogus
2
+ class ResetsStubbedMethods
3
+ extend Takes
4
+
5
+ takes :double_tracker, :overwrites_methods
6
+
7
+ def reset_all_doubles
8
+ doubles = double_tracker.doubles
9
+ doubles.each { |double| overwrites_methods.reset(double) }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module Bogus
2
+ class RespondsToEverything
3
+ def respond_to?(method)
4
+ true
5
+ end
6
+
7
+ def method_missing(name, *args, &block)
8
+ self
9
+ end
10
+ end
11
+ end