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.
- data/.gitignore +7 -0
- data/.pelusa.yml +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +75 -0
- data/Guardfile +15 -0
- data/README.md +272 -0
- data/Rakefile +1 -0
- data/bogus.gemspec +34 -0
- data/features/configuration_options.feature +43 -0
- data/features/contract_tests_mocks.feature +100 -0
- data/features/contract_tests_spies.feature +72 -0
- data/features/contract_tests_stubs.feature +101 -0
- data/features/fake_objects.feature +94 -0
- data/features/return_value_contracts.feature +90 -0
- data/features/safe_mocking.feature +59 -0
- data/features/safe_stubbing.feature +62 -0
- data/features/spies.feature +78 -0
- data/features/step_definitions/rspec_steps.rb +68 -0
- data/features/support/env.rb +1 -0
- data/lib/bogus.rb +35 -0
- data/lib/bogus/adds_recording.rb +11 -0
- data/lib/bogus/configuration.rb +9 -0
- data/lib/bogus/contract_not_fulfilled.rb +24 -0
- data/lib/bogus/converts_name_to_class.rb +31 -0
- data/lib/bogus/copies_classes.rb +44 -0
- data/lib/bogus/creates_fakes.rb +32 -0
- data/lib/bogus/double.rb +10 -0
- data/lib/bogus/fake.rb +33 -0
- data/lib/bogus/fake_registry.rb +13 -0
- data/lib/bogus/injector.rb +64 -0
- data/lib/bogus/interaction.rb +24 -0
- data/lib/bogus/interaction_presenter.rb +29 -0
- data/lib/bogus/interactions_repository.rb +19 -0
- data/lib/bogus/invocation_matcher.rb +27 -0
- data/lib/bogus/method_stringifier.rb +31 -0
- data/lib/bogus/overwrites_classes.rb +9 -0
- data/lib/bogus/proxy_class.rb +22 -0
- data/lib/bogus/public_methods.rb +46 -0
- data/lib/bogus/record_interactions.rb +17 -0
- data/lib/bogus/recording_proxy.rb +18 -0
- data/lib/bogus/records_double_interactions.rb +11 -0
- data/lib/bogus/registers_created_fakes.rb +11 -0
- data/lib/bogus/rr_proxy.rb +5 -0
- data/lib/bogus/rspec.rb +4 -0
- data/lib/bogus/rspec_extensions.rb +32 -0
- data/lib/bogus/takes.rb +8 -0
- data/lib/bogus/verifies_contracts.rb +12 -0
- data/lib/bogus/verifies_stub_definition.rb +37 -0
- data/lib/bogus/version.rb +3 -0
- data/pelusa.sh +3 -0
- data/rbs.sh +3 -0
- data/spec/bogus/adds_recording_spec.rb +33 -0
- data/spec/bogus/configuration_spec.rb +17 -0
- data/spec/bogus/converts_name_to_class_spec.rb +40 -0
- data/spec/bogus/copies_classes_spec.rb +175 -0
- data/spec/bogus/creates_fakes_spec.rb +59 -0
- data/spec/bogus/double_spec.rb +31 -0
- data/spec/bogus/fake_registry_spec.rb +24 -0
- data/spec/bogus/interaction_spec.rb +68 -0
- data/spec/bogus/interactions_repository_spec.rb +50 -0
- data/spec/bogus/invocation_matcher_spec.rb +26 -0
- data/spec/bogus/mocking_dsl_spec.rb +76 -0
- data/spec/bogus/overwrites_classes_spec.rb +26 -0
- data/spec/bogus/proxy_class_spec.rb +95 -0
- data/spec/bogus/record_interactions_spec.rb +27 -0
- data/spec/bogus/records_double_interactions_spec.rb +25 -0
- data/spec/bogus/registers_created_fakes_spec.rb +25 -0
- data/spec/bogus/verifies_contracts_spec.rb +42 -0
- data/spec/bogus/verifies_stub_definition_spec.rb +71 -0
- data/spec/spec_helper.rb +14 -0
- metadata +299 -0
data/lib/bogus/double.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
class Bogus::Double < BasicObject
|
2
|
+
extend ::Bogus::Takes
|
3
|
+
takes :object, :double, :verifies_stub_definition, :records_double_interactions
|
4
|
+
|
5
|
+
def method_missing(name, *args, &block)
|
6
|
+
@verifies_stub_definition.verify!(@object, name, args)
|
7
|
+
@records_double_interactions.record(@object, name, args, &block)
|
8
|
+
@double.__send__(name, *args, &block)
|
9
|
+
end
|
10
|
+
end
|
data/lib/bogus/fake.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Bogus
|
2
|
+
class Fake
|
3
|
+
include RecordInteractions
|
4
|
+
extend RecordInteractions
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
"#<#{self.class}:0x#{object_id.to_s(16)}>"
|
11
|
+
end
|
12
|
+
|
13
|
+
def kind_of?(klass)
|
14
|
+
klass == self.class.__copied_class__
|
15
|
+
end
|
16
|
+
|
17
|
+
def instance_of?(klass)
|
18
|
+
klass == self.class.__copied_class__
|
19
|
+
end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
attr_accessor :__copied_class__
|
23
|
+
|
24
|
+
def name
|
25
|
+
__copied_class__.name
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Bogus
|
2
|
+
class Injector
|
3
|
+
include Dependor::AutoInject
|
4
|
+
look_in_modules Bogus
|
5
|
+
|
6
|
+
def configuration
|
7
|
+
@configuration ||= Bogus::Configuration.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def search_modules
|
11
|
+
configuration.search_modules
|
12
|
+
end
|
13
|
+
|
14
|
+
def rr_proxy
|
15
|
+
Bogus::RRProxy
|
16
|
+
end
|
17
|
+
|
18
|
+
def fake_registry
|
19
|
+
@fake_registry ||= inject(Bogus::FakeRegistry)
|
20
|
+
end
|
21
|
+
|
22
|
+
def creates_fakes
|
23
|
+
creates_fakes = inject(Bogus::CreatesFakes)
|
24
|
+
inject(Bogus::RegistersCreatedFakes, creates_fakes: creates_fakes)
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_stub(object)
|
28
|
+
stub = rr_proxy.stub(object)
|
29
|
+
inject(Bogus::Double, object: object, double: stub)
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_mock(object)
|
33
|
+
mock = rr_proxy.mock(object)
|
34
|
+
inject(Bogus::Double, object: object, double: mock)
|
35
|
+
end
|
36
|
+
|
37
|
+
def invocation_matcher(method = nil)
|
38
|
+
inject(Bogus::InvocationMatcher, method: method)
|
39
|
+
end
|
40
|
+
|
41
|
+
def interactions_repository
|
42
|
+
raise "Specify either real_interactions or stubbed_interactions"
|
43
|
+
end
|
44
|
+
|
45
|
+
def real_interactions
|
46
|
+
@real_interactions ||= inject(Bogus::InteractionsRepository)
|
47
|
+
end
|
48
|
+
|
49
|
+
def doubled_interactions
|
50
|
+
@doubled_interactions ||= inject(Bogus::InteractionsRepository)
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_proxy_class(fake_name, klass)
|
54
|
+
inject(Bogus::ProxyClass, fake_name: fake_name, klass: klass)
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_recording_proxy(instance, fake_name)
|
58
|
+
inject(Bogus::RecordingProxy,
|
59
|
+
instance: instance,
|
60
|
+
fake_name: fake_name,
|
61
|
+
interactions_repository: real_interactions)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,24 @@
|
|
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
|
5
|
+
|
6
|
+
if block_given?
|
7
|
+
evaluate_return_value(block)
|
8
|
+
self.has_result = true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def ==(other)
|
13
|
+
return super(other) if has_result && other.has_result
|
14
|
+
method == other.method && args == other.args
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def evaluate_return_value(block)
|
20
|
+
self.return_value = block.call
|
21
|
+
rescue => e
|
22
|
+
self.error = e.class
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Bogus
|
2
|
+
class InteractionPresenter
|
3
|
+
extend Bogus::Takes
|
4
|
+
|
5
|
+
takes :interaction
|
6
|
+
|
7
|
+
def to_s
|
8
|
+
"##{interaction.method}(#{args})#{result}"
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def args
|
14
|
+
interaction.args.map(&:inspect).join(', ')
|
15
|
+
end
|
16
|
+
|
17
|
+
def result
|
18
|
+
error || return_value
|
19
|
+
end
|
20
|
+
|
21
|
+
def return_value
|
22
|
+
" => #{interaction.return_value.inspect}" if interaction.has_result
|
23
|
+
end
|
24
|
+
|
25
|
+
def error
|
26
|
+
" !! #{interaction.error}" if interaction.error
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Bogus
|
2
|
+
class InteractionsRepository
|
3
|
+
def initialize
|
4
|
+
@interactions = Hash.new { |hash, fake_name| hash[fake_name] = [] }
|
5
|
+
end
|
6
|
+
|
7
|
+
def record(fake_name, method, *args, &block)
|
8
|
+
@interactions[fake_name] << Interaction.new(method, args, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def recorded?(fake_name, interaction)
|
12
|
+
@interactions[fake_name].include?(interaction)
|
13
|
+
end
|
14
|
+
|
15
|
+
def for_fake(fake_name)
|
16
|
+
@interactions[fake_name]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rr'
|
2
|
+
|
3
|
+
module Bogus
|
4
|
+
class InvocationMatcher < RR::Adapters::Rspec::InvocationMatcher
|
5
|
+
def initialize(method, verifies_stub_definition, records_double_interactions)
|
6
|
+
super(method)
|
7
|
+
@verifies_stub_definition = verifies_stub_definition
|
8
|
+
@records_double_interactions = records_double_interactions
|
9
|
+
@stubbed_method_calls = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def matches?(subject)
|
13
|
+
@stubbed_method_calls.each do |name, args|
|
14
|
+
@verifies_stub_definition.verify!(subject, name, args)
|
15
|
+
@records_double_interactions.record(subject, name, args)
|
16
|
+
end
|
17
|
+
|
18
|
+
return super(subject.__inner_object__) if subject.respond_to?(:__inner_object__)
|
19
|
+
return super(subject)
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(name, *args, &block)
|
23
|
+
@stubbed_method_calls << [name, args]
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Bogus
|
2
|
+
class MethodStringifier
|
3
|
+
|
4
|
+
def stringify(method, body)
|
5
|
+
<<-RUBY
|
6
|
+
def #{method.name}(#{arguments_as_string(method.parameters)})
|
7
|
+
#{body}
|
8
|
+
end
|
9
|
+
RUBY
|
10
|
+
end
|
11
|
+
|
12
|
+
def arguments_as_string(arguments)
|
13
|
+
arguments.map{|type, name| argument_to_string(name, type) }.compact.join(', ')
|
14
|
+
end
|
15
|
+
|
16
|
+
def argument_to_string(name, type)
|
17
|
+
if type == :req
|
18
|
+
name
|
19
|
+
elsif type == :rest
|
20
|
+
"*#{name}"
|
21
|
+
elsif type == :block
|
22
|
+
"&#{name}"
|
23
|
+
elsif type == :opt
|
24
|
+
"#{name} = {}"
|
25
|
+
else
|
26
|
+
raise "unknown argument type: #{type}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class Bogus::OverwritesClasses
|
2
|
+
def overwrite(klass, new_klass)
|
3
|
+
modules = klass.name.split('::')
|
4
|
+
klass_name = modules.pop
|
5
|
+
parent_module = modules.reduce(Object) { |mod, name| mod.const_get(name) }
|
6
|
+
parent_module.send(:remove_const, klass_name)
|
7
|
+
parent_module.const_set(klass_name, new_klass)
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,22 @@
|
|
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
|
6
|
+
|
7
|
+
@recording_proxy = @create_recording_proxy.call(@klass, @fake_name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def new(*args, &block)
|
11
|
+
instance = @klass.new(*args, &block)
|
12
|
+
@create_recording_proxy.call(instance, @fake_name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(name, *args, &block)
|
16
|
+
@recording_proxy.__send__(name, *args, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def respond_to?(name)
|
20
|
+
@recording_proxy.respond_to?(name)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Bogus
|
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)
|
10
|
+
end
|
11
|
+
|
12
|
+
def verify_contract!(fake_name)
|
13
|
+
inject.verifies_contracts.verify(fake_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def configure(&block)
|
17
|
+
config.tap(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def config
|
21
|
+
inject.configuration
|
22
|
+
end
|
23
|
+
|
24
|
+
def reset!
|
25
|
+
@injector = Bogus::Injector.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_stub(object)
|
29
|
+
inject.create_stub(object)
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_mock(object)
|
33
|
+
inject.create_mock(object)
|
34
|
+
end
|
35
|
+
|
36
|
+
def have_received(method = nil)
|
37
|
+
inject.invocation_matcher(method)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def inject
|
43
|
+
@injector ||= Bogus::Injector.new
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Bogus
|
2
|
+
module RecordInteractions
|
3
|
+
def __inner_object__
|
4
|
+
@__inner_object__ ||= Object.new
|
5
|
+
end
|
6
|
+
|
7
|
+
def __stub__
|
8
|
+
@__stub__ ||= RRProxy.stub(__inner_object__)
|
9
|
+
end
|
10
|
+
|
11
|
+
def __record__(method, *args, &block)
|
12
|
+
__stub__.__send__(method, *args)
|
13
|
+
__inner_object__.__send__(method, *args, &block)
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Bogus::RecordingProxy < BasicObject
|
2
|
+
extend ::Bogus::Takes
|
3
|
+
takes :instance, :fake_name, :interactions_repository
|
4
|
+
|
5
|
+
def method_missing(name, *args, &block)
|
6
|
+
returned_value = @instance.__send__(name, *args, &block)
|
7
|
+
@interactions_repository.record(@fake_name, name, *args) { returned_value }
|
8
|
+
returned_value
|
9
|
+
rescue => e
|
10
|
+
@interactions_repository.record(@fake_name, name, *args) { ::Kernel.raise(e) }
|
11
|
+
::Kernel.raise
|
12
|
+
end
|
13
|
+
|
14
|
+
def respond_to?(name)
|
15
|
+
@instance.respond_to?(name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Bogus::RecordsDoubleInteractions
|
2
|
+
extend Bogus::Takes
|
3
|
+
|
4
|
+
takes :doubled_interactions, :fake_registry
|
5
|
+
|
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
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
data/lib/bogus/rspec.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Bogus
|
2
|
+
module RSpecExtensions
|
3
|
+
def fake(name, opts = {}, &block)
|
4
|
+
let(name) { Bogus.fake_for(name, opts, &block) }
|
5
|
+
end
|
6
|
+
|
7
|
+
def verify_contract(name)
|
8
|
+
before do
|
9
|
+
Bogus.record_calls_for(name)
|
10
|
+
end
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.after(:suite) { Bogus.verify_contract!(name) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module MockingDSL
|
19
|
+
def stub(object)
|
20
|
+
Bogus.create_stub(object)
|
21
|
+
end
|
22
|
+
|
23
|
+
def have_received(method = nil)
|
24
|
+
Bogus.have_received(method)
|
25
|
+
end
|
26
|
+
|
27
|
+
def mock(object)
|
28
|
+
Bogus.create_mock(object)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|