bogus 0.0.1

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 (72) hide show
  1. data/.gitignore +7 -0
  2. data/.pelusa.yml +1 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +75 -0
  6. data/Guardfile +15 -0
  7. data/README.md +272 -0
  8. data/Rakefile +1 -0
  9. data/bogus.gemspec +34 -0
  10. data/features/configuration_options.feature +43 -0
  11. data/features/contract_tests_mocks.feature +100 -0
  12. data/features/contract_tests_spies.feature +72 -0
  13. data/features/contract_tests_stubs.feature +101 -0
  14. data/features/fake_objects.feature +94 -0
  15. data/features/return_value_contracts.feature +90 -0
  16. data/features/safe_mocking.feature +59 -0
  17. data/features/safe_stubbing.feature +62 -0
  18. data/features/spies.feature +78 -0
  19. data/features/step_definitions/rspec_steps.rb +68 -0
  20. data/features/support/env.rb +1 -0
  21. data/lib/bogus.rb +35 -0
  22. data/lib/bogus/adds_recording.rb +11 -0
  23. data/lib/bogus/configuration.rb +9 -0
  24. data/lib/bogus/contract_not_fulfilled.rb +24 -0
  25. data/lib/bogus/converts_name_to_class.rb +31 -0
  26. data/lib/bogus/copies_classes.rb +44 -0
  27. data/lib/bogus/creates_fakes.rb +32 -0
  28. data/lib/bogus/double.rb +10 -0
  29. data/lib/bogus/fake.rb +33 -0
  30. data/lib/bogus/fake_registry.rb +13 -0
  31. data/lib/bogus/injector.rb +64 -0
  32. data/lib/bogus/interaction.rb +24 -0
  33. data/lib/bogus/interaction_presenter.rb +29 -0
  34. data/lib/bogus/interactions_repository.rb +19 -0
  35. data/lib/bogus/invocation_matcher.rb +27 -0
  36. data/lib/bogus/method_stringifier.rb +31 -0
  37. data/lib/bogus/overwrites_classes.rb +9 -0
  38. data/lib/bogus/proxy_class.rb +22 -0
  39. data/lib/bogus/public_methods.rb +46 -0
  40. data/lib/bogus/record_interactions.rb +17 -0
  41. data/lib/bogus/recording_proxy.rb +18 -0
  42. data/lib/bogus/records_double_interactions.rb +11 -0
  43. data/lib/bogus/registers_created_fakes.rb +11 -0
  44. data/lib/bogus/rr_proxy.rb +5 -0
  45. data/lib/bogus/rspec.rb +4 -0
  46. data/lib/bogus/rspec_extensions.rb +32 -0
  47. data/lib/bogus/takes.rb +8 -0
  48. data/lib/bogus/verifies_contracts.rb +12 -0
  49. data/lib/bogus/verifies_stub_definition.rb +37 -0
  50. data/lib/bogus/version.rb +3 -0
  51. data/pelusa.sh +3 -0
  52. data/rbs.sh +3 -0
  53. data/spec/bogus/adds_recording_spec.rb +33 -0
  54. data/spec/bogus/configuration_spec.rb +17 -0
  55. data/spec/bogus/converts_name_to_class_spec.rb +40 -0
  56. data/spec/bogus/copies_classes_spec.rb +175 -0
  57. data/spec/bogus/creates_fakes_spec.rb +59 -0
  58. data/spec/bogus/double_spec.rb +31 -0
  59. data/spec/bogus/fake_registry_spec.rb +24 -0
  60. data/spec/bogus/interaction_spec.rb +68 -0
  61. data/spec/bogus/interactions_repository_spec.rb +50 -0
  62. data/spec/bogus/invocation_matcher_spec.rb +26 -0
  63. data/spec/bogus/mocking_dsl_spec.rb +76 -0
  64. data/spec/bogus/overwrites_classes_spec.rb +26 -0
  65. data/spec/bogus/proxy_class_spec.rb +95 -0
  66. data/spec/bogus/record_interactions_spec.rb +27 -0
  67. data/spec/bogus/records_double_interactions_spec.rb +25 -0
  68. data/spec/bogus/registers_created_fakes_spec.rb +25 -0
  69. data/spec/bogus/verifies_contracts_spec.rb +42 -0
  70. data/spec/bogus/verifies_stub_definition_spec.rb +71 -0
  71. data/spec/spec_helper.rb +14 -0
  72. metadata +299 -0
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::Interaction do
4
+ class SomeError < StandardError; end
5
+
6
+ same = [
7
+ [[:foo, [:bar], "value"], [:foo, [:bar], "value"]],
8
+ [[:foo, [:bar]], [:foo, [:bar], "value"]],
9
+ [[:foo, [:bar], "value"], [:foo, [:bar]]],
10
+ [[:foo, [:bar]], [:foo, [:bar]]]
11
+ ]
12
+
13
+ different = [
14
+ [[:foo, [:bar], "value"], [:foo, [:bar], "value2"]],
15
+ [[:foo, [:bar], "value"], [:baz, [:bar], "value"]],
16
+ [[:foo, [:baz], "value"], [:foo, [:bar], "value"]],
17
+ [[:foo, [:bar]], [:foo, [:baz]]],
18
+ [[:baz, [:bar]], [:foo, [:bar]]]
19
+ ]
20
+
21
+ def create_interaction(interaction)
22
+ method_name, args, return_value = interaction
23
+ if return_value
24
+ Bogus::Interaction.new(method_name, args) { return_value }
25
+ else
26
+ Bogus::Interaction.new(method_name, args)
27
+ end
28
+ end
29
+
30
+ same.each do |first_interaction, second_interaction|
31
+ it "returns true for #{first_interaction.inspect} and #{second_interaction.inspect}" do
32
+ first = create_interaction(first_interaction)
33
+ second = create_interaction(second_interaction)
34
+
35
+ first.should == second
36
+ end
37
+ end
38
+
39
+ different.each do |first_interaction, second_interaction|
40
+ it "returns false for #{first_interaction.inspect} and #{second_interaction.inspect}" do
41
+ first = create_interaction(first_interaction)
42
+ second = create_interaction(second_interaction)
43
+
44
+ first.should_not == second
45
+ end
46
+ end
47
+
48
+ it "differs exceptions from empty return values" do
49
+ first = Bogus::Interaction.new(:foo, :bar) { raise SomeError }
50
+ second = Bogus::Interaction.new(:foo, :bar) { nil }
51
+
52
+ first.should_not == second
53
+ end
54
+
55
+ it "differs raised exceptions from ones just returned from the block" do
56
+ first = Bogus::Interaction.new(:foo, :bar) { raise SomeError }
57
+ second = Bogus::Interaction.new(:foo, :bar) { SomeError }
58
+
59
+ first.should_not == second
60
+ end
61
+
62
+ it "considers exceptions of the same type as equal" do
63
+ first = Bogus::Interaction.new(:foo, :bar) { raise SomeError }
64
+ second = Bogus::Interaction.new(:foo, :bar) { raise SomeError }
65
+
66
+ first.should == second
67
+ end
68
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::InteractionsRepository do
4
+ let(:interactions_repository) { Bogus::InteractionsRepository.new }
5
+
6
+ def recorded?(fake_name, method, *args)
7
+ interactions_repository.recorded?(fake_name, Bogus::Interaction.new(method, args))
8
+ end
9
+
10
+ it "considers the interaction recorded if it was recorded previously" do
11
+ interactions_repository.record(:foo, :bar, 1, 2, 3)
12
+
13
+ recorded?(:foo, :bar, 1, 2, 3).should be_true
14
+ end
15
+
16
+ it "considers the interaction recorded if it returned the same value as passed block" do
17
+ interactions_repository.record(:foo, :bar) { "a result" }
18
+ interaction = Bogus::Interaction.new(:bar, []) { "a result" }
19
+
20
+ interactions_repository.recorded?(:foo, interaction).should be_true
21
+ end
22
+
23
+ it "does not consider any interactions recorded prior to any recordings" do
24
+ recorded?(:foo, :bar, 1).should be_false
25
+ end
26
+
27
+ it "does not consider the interaction recorded with a different fake name" do
28
+ interactions_repository.record(:baz, :bar, 1)
29
+
30
+ recorded?(:foo, :bar, 1).should be_false
31
+ end
32
+
33
+ it "does not consider the interaction recorded with a different method name" do
34
+ interactions_repository.record(:foo, :baz, 1)
35
+
36
+ recorded?(:foo, :bar, 1).should be_false
37
+ end
38
+
39
+ it "does not consider the interaction recorded with different method arguments" do
40
+ interactions_repository.record(:foo, :bar, 1, 2)
41
+
42
+ recorded?(:foo, :bar, 1).should be_false
43
+ end
44
+
45
+ it "returns a list of interactions for given fake" do
46
+ interactions_repository.record(:foo, :bar, 1, 2)
47
+
48
+ interactions_repository.for_fake(:foo).should == [Bogus::Interaction.new(:bar, [1, 2])]
49
+ end
50
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::InvocationMatcher do
4
+ let(:object) { stub }
5
+ let(:method) { nil }
6
+ let(:records_double_interactions) { stub }
7
+ let(:verifies_stub_definition) { stub }
8
+
9
+ let(:invocation_matcher) { isolate(Bogus::InvocationMatcher) }
10
+
11
+ before do
12
+ stub(verifies_stub_definition).verify!
13
+ stub(records_double_interactions).record
14
+
15
+ invocation_matcher.the_method(:foo, :bar)
16
+ invocation_matcher.matches?(object)
17
+ end
18
+
19
+ it "verifies stub definition" do
20
+ verifies_stub_definition.should have_received.verify!(object, :the_method, [:foo, :bar])
21
+ end
22
+
23
+ it "records double interacions" do
24
+ records_double_interactions.should have_received.record(object, :the_method, [:foo, :bar])
25
+ end
26
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::MockingDSL do
4
+ class ExampleFoo
5
+ def foo(bar)
6
+ end
7
+ end
8
+
9
+ class Stubber
10
+ extend Bogus::MockingDSL
11
+ end
12
+
13
+ describe "#stub" do
14
+ it "allows stubbing the existing methods" do
15
+ baz = ExampleFoo.new
16
+
17
+ Stubber.stub(baz).foo("bar") { :return_value }
18
+
19
+ baz.foo("bar").should == :return_value
20
+ end
21
+
22
+ it "does not allow stubbing non-existent methods" do
23
+ baz = ExampleFoo.new
24
+ expect do
25
+ Stubber.stub(baz).does_not_exist("bar") { :return_value }
26
+ end.to raise_error(NameError)
27
+ end
28
+ end
29
+
30
+ describe "#have_received" do
31
+ context "with a fake object" do
32
+ let(:the_fake) { Bogus.fake_for(:example_foo) }
33
+
34
+ it "allows verifying that fakes have correct interfaces" do
35
+ the_fake.foo("test")
36
+
37
+ the_fake.should Stubber.have_received.foo("test")
38
+ end
39
+
40
+ it "does not allow verifying on non-existent methods" do
41
+ expect {
42
+ the_fake.should Stubber.have_received.bar("test")
43
+ }.to raise_error(NameError)
44
+ end
45
+
46
+ it "does not allow verifying on methods with a wrong argument count" do
47
+ expect {
48
+ the_fake.should Stubber.have_received.foo("test", "test 2")
49
+ }.to raise_error(ArgumentError)
50
+ end
51
+ end
52
+
53
+ it "can be used with plain old Ruby objects" do
54
+ object = ExampleFoo.new
55
+ stub(object).foo
56
+
57
+ object.foo('test')
58
+
59
+ object.should Stubber.have_received.foo("test")
60
+ end
61
+ end
62
+
63
+ class Mocker
64
+ extend Bogus::MockingDSL
65
+ end
66
+
67
+ describe "#mock" do
68
+ it "allows mocking the existing methods" do
69
+ baz = ExampleFoo.new
70
+
71
+ Mocker.mock(baz).foo("bar") { :return_value }
72
+
73
+ baz.foo("bar").should == :return_value
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::OverwritesClasses do
4
+ module SampleOuterModule
5
+ module SampleModule
6
+ class SampleClass
7
+ end
8
+ end
9
+ end
10
+
11
+ let(:new_class) { Class.new }
12
+ let(:overwrites_classes) { Bogus::OverwritesClasses.new }
13
+
14
+ it "overwrites nested classes" do
15
+ overwrites_classes.overwrite(SampleOuterModule::SampleModule::SampleClass, new_class)
16
+
17
+ SampleOuterModule::SampleModule::SampleClass.should equal(new_class)
18
+ end
19
+
20
+ it "overwrites top level classes" do
21
+ overwrites_classes.overwrite(SampleOuterModule, new_class)
22
+
23
+ SampleOuterModule.should equal(new_class)
24
+ end
25
+ end
26
+
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::ProxyClass do
4
+ module SampleModule
5
+ class GrandLibrary
6
+ def checkout(book, user)
7
+ :checkouted
8
+ end
9
+
10
+ def self.find_by_address(address)
11
+ :the_library
12
+ end
13
+
14
+ def self.find_by_isbn(isbn)
15
+ raise StandardError
16
+ end
17
+ end
18
+ end
19
+
20
+ let(:proxy_class) { Bogus::ProxyClass.new(:fake_name, SampleModule::GrandLibrary, create_recording_proxy) }
21
+
22
+ let(:create_recording_proxy) do
23
+ lambda {|instance, fake_name| Bogus::RecordingProxy.new(instance, fake_name, interactions_repository) }
24
+ end
25
+
26
+ let(:interactions_repository) { FakeRepository.new }
27
+
28
+ it "returns the proxy" do
29
+ proxy_class.new.checkout("Moby Dick", "Bob").should == :checkouted
30
+ end
31
+
32
+ it "records interactions with created objects" do
33
+ proxy_class.new.checkout("Moby Dick", "Bob")
34
+
35
+ interactions_repository.should have_recorded(:fake_name, :checkout, "Moby Dick", "Bob")
36
+ end
37
+
38
+ it "responds to every method that the original class responds to" do
39
+ proxy_class.should respond_to(:find_by_address)
40
+ end
41
+
42
+ it "delegates interactions with the proxy class to wrapped class" do
43
+ proxy_class.find_by_address("some address").should == :the_library
44
+ end
45
+
46
+ it "records interactions with the proxy class" do
47
+ proxy_class.find_by_address("some address")
48
+
49
+ interactions_repository.should have_recorded(:fake_name, :find_by_address, "some address")
50
+ end
51
+
52
+ it "records return values" do
53
+ proxy_class.find_by_address("some address")
54
+
55
+ interactions_repository.return_value(:fake_name, :find_by_address, "some address").should == :the_library
56
+ end
57
+
58
+ it "re-raises exceptions" do
59
+ expect {
60
+ proxy_class.find_by_isbn("some isbn")
61
+ }.to raise_error(StandardError)
62
+ end
63
+
64
+ it "records raised exceptions" do
65
+ proxy_class.find_by_isbn("some isbn") rescue nil
66
+
67
+ expect {
68
+ interactions_repository.return_value(:fake_name, :find_by_isbn, "some isbn")
69
+ }.to raise_error(StandardError)
70
+ end
71
+
72
+ class FakeRepository
73
+ def initialize
74
+ @recordings = []
75
+ end
76
+
77
+ def record(fake_name, method, *args, &block)
78
+ @recordings << [fake_name, method, args, block]
79
+ end
80
+
81
+ def has_recorded?(fake_name, method, *args)
82
+ !!find(fake_name, method, *args)
83
+ end
84
+
85
+ def return_value(fake_name, method, *args)
86
+ find(fake_name, method, *args).last.call
87
+ end
88
+
89
+ def find(fake_name, method, *args)
90
+ @recordings.find do |f, m, a, b|
91
+ [f, m, a] == [fake_name, method, args]
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::RecordInteractions do
4
+
5
+ class SampleRecordsInteractions
6
+ include Bogus::RecordInteractions
7
+ end
8
+
9
+ let(:sample) { SampleRecordsInteractions.new }
10
+ let!(:rr) { Bogus::RRProxy }
11
+
12
+ it "allows verifying that interactions happened" do
13
+ sample.__record__(:foo, 1, 2, 3)
14
+
15
+ sample.__inner_object__.should have_received.foo(1, 2, 3)
16
+ end
17
+
18
+ it "allows verifying that interactions didn't happen" do
19
+ sample.__record__(:bar)
20
+
21
+ sample.__inner_object__.should_not have_received.foo
22
+ end
23
+
24
+ it "returns self from record" do
25
+ sample.__record__(:foo).should == sample
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::RecordsDoubleInteractions do
4
+ let(:fake_registry) { stub }
5
+ let(:doubled_interactions) { stub }
6
+ let(:object) { Object.new }
7
+
8
+ let(:records_double_interactions) { isolate(Bogus::RecordsDoubleInteractions) }
9
+
10
+ it "records the call in double interaction repository" do
11
+ stub(fake_registry).name(object) { :object_name }
12
+ stub(doubled_interactions).record
13
+
14
+ records_double_interactions.record(object, :method_name, [:foo, 1])
15
+
16
+ doubled_interactions.should have_received.record(:object_name, :method_name, :foo, 1)
17
+ end
18
+
19
+ it "does not record the interaction if object is not a fake" do
20
+ stub(fake_registry).name(object) { nil }
21
+ dont_allow(doubled_interactions).record
22
+
23
+ records_double_interactions.record(object, :method_name, [:foo, 1])
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::RegistersCreatedFakes do
4
+ let(:fake_registry) { stub }
5
+ let(:creates_fakes) { stub }
6
+
7
+ let(:registers_created_fakes) { isolate(Bogus::RegistersCreatedFakes) }
8
+
9
+ before do
10
+ stub(fake_registry).store
11
+ stub(creates_fakes).create { :the_fake }
12
+ end
13
+
14
+ it "registers the fakes created by creates_fakes" do
15
+ registers_created_fakes.create(:foo, as: :instance) { Object }
16
+
17
+ fake_registry.should have_received.store(:foo, :the_fake)
18
+ end
19
+
20
+ it "returns the created fake" do
21
+ fake = registers_created_fakes.create(:foo, as: :instance) { Object }
22
+
23
+ fake.should == :the_fake
24
+ end
25
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::VerifiesContracts do
4
+ let(:real_interactions) { stub }
5
+ let(:doubled_interactions) { stub }
6
+ let(:verifies_contracts) { isolate(Bogus::VerifiesContracts) }
7
+
8
+ let(:matched_interaction) { interaction("matched") }
9
+
10
+ it "fails unmatched calls" do
11
+ first_interaction = interaction("first")
12
+ second_interaction = interaction("second")
13
+
14
+ stub(doubled_interactions).for_fake(:fake_name){[first_interaction, matched_interaction, second_interaction]}
15
+
16
+ stub(real_interactions).recorded?(:fake_name, first_interaction) { false }
17
+ stub(real_interactions).recorded?(:fake_name, second_interaction) { false }
18
+ stub(real_interactions).recorded?(:fake_name, matched_interaction) { true }
19
+
20
+ expect_verify_to_raise_error_with_interactions(:fake_name, [first_interaction, second_interaction])
21
+ end
22
+
23
+ it "passes with all calls matched" do
24
+ stub(doubled_interactions).for_fake(:fake_name) { [matched_interaction] }
25
+ stub(real_interactions).recorded?(:fake_name, matched_interaction) { true }
26
+
27
+ expect {
28
+ verifies_contracts.verify(:fake_name)
29
+ }.not_to raise_error
30
+ end
31
+
32
+ def expect_verify_to_raise_error_with_interactions(name, interactions)
33
+ verifies_contracts.verify(name)
34
+ fail
35
+ rescue Bogus::ContractNotFulfilled => contract_error
36
+ contract_error.interactions.should == { name => interactions }
37
+ end
38
+
39
+ def interaction(method)
40
+ Bogus::Interaction.new(method, [:foo, :bar]) { "return value" }
41
+ end
42
+ end