mocktail 0.0.1 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +9 -3
  3. data/CHANGELOG.md +38 -0
  4. data/Gemfile.lock +2 -1
  5. data/README.md +242 -65
  6. data/bin/console +47 -1
  7. data/lib/mocktail/explains_thing.rb +132 -0
  8. data/lib/mocktail/handles_dry_call/fulfills_stubbing/describes_unsatisfied_stubbing.rb +13 -0
  9. data/lib/mocktail/handles_dry_call/fulfills_stubbing.rb +4 -0
  10. data/lib/mocktail/handles_dry_call/validates_arguments.rb +2 -23
  11. data/lib/mocktail/imitates_type/makes_double/declares_dry_class.rb +29 -23
  12. data/lib/mocktail/imitates_type/makes_double/gathers_fakeable_instance_methods.rb +21 -0
  13. data/lib/mocktail/imitates_type/makes_double.rb +8 -4
  14. data/lib/mocktail/raises_neato_no_method_error.rb +81 -0
  15. data/lib/mocktail/share/creates_identifier.rb +28 -0
  16. data/lib/mocktail/{verifies_call/raises_verification_error → share}/stringifies_call.rb +16 -7
  17. data/lib/mocktail/share/stringifies_method_name.rb +11 -0
  18. data/lib/mocktail/simulates_argument_error/cleans_backtrace.rb +15 -0
  19. data/lib/mocktail/simulates_argument_error/reconciles_args_with_params.rb +20 -0
  20. data/lib/mocktail/simulates_argument_error/recreates_message.rb +29 -0
  21. data/lib/mocktail/simulates_argument_error/transforms_params.rb +32 -0
  22. data/lib/mocktail/simulates_argument_error.rb +30 -0
  23. data/lib/mocktail/value/cabinet.rb +12 -0
  24. data/lib/mocktail/value/double.rb +7 -8
  25. data/lib/mocktail/value/double_data.rb +10 -0
  26. data/lib/mocktail/value/explanation.rb +26 -0
  27. data/lib/mocktail/value/signature.rb +36 -0
  28. data/lib/mocktail/value/stub_returned_nil.rb +26 -0
  29. data/lib/mocktail/value/top_shelf.rb +24 -25
  30. data/lib/mocktail/value/type_replacement_data.rb +13 -0
  31. data/lib/mocktail/value/unsatisfied_stubbing.rb +8 -0
  32. data/lib/mocktail/value.rb +6 -0
  33. data/lib/mocktail/verifies_call/raises_verification_error.rb +4 -2
  34. data/lib/mocktail/version.rb +1 -1
  35. data/lib/mocktail.rb +9 -0
  36. data/mocktail.gemspec +2 -2
  37. metadata +22 -6
  38. data/lib/mocktail/share/simulates_argument_error.rb +0 -28
@@ -1,61 +1,60 @@
1
- # The top shelf stores all cross-thread & thread-aware state, so anything that
2
- # goes here is on its own when it comes to ensuring thread safety.
3
1
  module Mocktail
4
2
  class TopShelf
5
3
  def self.instance
6
- @self ||= new
4
+ Thread.current[:mocktail_top_shelf] ||= new
7
5
  end
8
6
 
7
+ @@type_replacements = {}
8
+ @@type_replacements_mutex = Mutex.new
9
+
9
10
  def initialize
10
- @type_replacements = {}
11
- @new_registrations = {}
12
- @of_next_registrations = {}
13
- @singleton_method_registrations = {}
11
+ @new_registrations = []
12
+ @of_next_registrations = []
13
+ @singleton_method_registrations = []
14
14
  end
15
15
 
16
16
  def type_replacement_for(type)
17
- @type_replacements[type] ||= TypeReplacement.new(type: type)
17
+ @@type_replacements_mutex.synchronize {
18
+ @@type_replacements[type] ||= TypeReplacement.new(type: type)
19
+ }
20
+ end
21
+
22
+ def type_replacement_if_exists_for(type)
23
+ @@type_replacements_mutex.synchronize {
24
+ @@type_replacements[type]
25
+ }
18
26
  end
19
27
 
20
28
  def reset_current_thread!
21
- @new_registrations[Thread.current] = []
22
- @of_next_registrations[Thread.current] = []
23
- @singleton_method_registrations[Thread.current] = []
29
+ Thread.current[:mocktail_top_shelf] = self.class.new
24
30
  end
25
31
 
26
32
  def register_new_replacement!(type)
27
- @new_registrations[Thread.current] ||= []
28
- @new_registrations[Thread.current] |= [type]
33
+ @new_registrations |= [type]
29
34
  end
30
35
 
31
36
  def new_replaced?(type)
32
- @new_registrations[Thread.current] ||= []
33
- @new_registrations[Thread.current].include?(type)
37
+ @new_registrations.include?(type)
34
38
  end
35
39
 
36
40
  def register_of_next_replacement!(type)
37
- @of_next_registrations[Thread.current] ||= []
38
- @of_next_registrations[Thread.current] |= [type]
41
+ @of_next_registrations |= [type]
39
42
  end
40
43
 
41
44
  def of_next_registered?(type)
42
- @of_next_registrations[Thread.current] ||= []
43
- @of_next_registrations[Thread.current].include?(type)
45
+ @of_next_registrations.include?(type)
44
46
  end
45
47
 
46
48
  def unregister_of_next_replacement!(type)
47
- @of_next_registrations[Thread.current] ||= []
48
- @of_next_registrations[Thread.current] -= [type]
49
+ @of_next_registrations -= [type]
49
50
  end
50
51
 
51
52
  def register_singleton_method_replacement!(type)
52
- @singleton_method_registrations[Thread.current] ||= []
53
- @singleton_method_registrations[Thread.current] |= [type]
53
+ @singleton_method_registrations |= [type]
54
54
  end
55
55
 
56
56
  def singleton_methods_replaced?(type)
57
- @singleton_method_registrations[Thread.current] ||= []
58
- @singleton_method_registrations[Thread.current].include?(type)
57
+ @singleton_method_registrations.include?(type)
59
58
  end
60
59
  end
61
60
  end
@@ -0,0 +1,13 @@
1
+ module Mocktail
2
+ class TypeReplacementData < Struct.new(
3
+ :type,
4
+ :replaced_method_names,
5
+ :calls,
6
+ :stubbings,
7
+ keyword_init: true
8
+ )
9
+ def double
10
+ type
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ module Mocktail
2
+ class UnsatisfiedStubbing < Struct.new(
3
+ :call,
4
+ :other_stubbings,
5
+ keyword_init: true
6
+ )
7
+ end
8
+ end
@@ -2,7 +2,13 @@ require_relative "value/cabinet"
2
2
  require_relative "value/call"
3
3
  require_relative "value/demo_config"
4
4
  require_relative "value/double"
5
+ require_relative "value/double_data"
6
+ require_relative "value/explanation"
5
7
  require_relative "value/matcher_registry"
8
+ require_relative "value/signature"
6
9
  require_relative "value/stubbing"
10
+ require_relative "value/stub_returned_nil"
7
11
  require_relative "value/top_shelf"
8
12
  require_relative "value/type_replacement"
13
+ require_relative "value/type_replacement_data"
14
+ require_relative "value/unsatisfied_stubbing"
@@ -1,16 +1,18 @@
1
1
  require_relative "raises_verification_error/gathers_calls_of_method"
2
- require_relative "raises_verification_error/stringifies_call"
2
+ require_relative "../share/stringifies_method_name"
3
+ require_relative "../share/stringifies_call"
3
4
 
4
5
  module Mocktail
5
6
  class RaisesVerificationError
6
7
  def initialize
7
8
  @gathers_calls_of_method = GathersCallsOfMethod.new
9
+ @stringifies_method_name = StringifiesMethodName.new
8
10
  @stringifies_call = StringifiesCall.new
9
11
  end
10
12
 
11
13
  def raise(recording, verifiable_calls, demo_config)
12
14
  Kernel.raise VerificationError.new <<~MSG
13
- Expected mocktail of #{recording.original_type.name}##{recording.method} to be called like:
15
+ Expected mocktail of `#{@stringifies_method_name.stringify(recording)}' to be called like:
14
16
 
15
17
  #{@stringifies_call.stringify(recording)}#{[
16
18
  (" [#{demo_config.times} #{pl("time", demo_config.times)}]" unless demo_config.times.nil?),
@@ -1,3 +1,3 @@
1
1
  module Mocktail
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.5"
3
3
  end
data/lib/mocktail.rb CHANGED
@@ -1,16 +1,19 @@
1
1
  require_relative "mocktail/dsl"
2
2
  require_relative "mocktail/errors"
3
+ require_relative "mocktail/explains_thing"
3
4
  require_relative "mocktail/handles_dry_call"
4
5
  require_relative "mocktail/handles_dry_new_call"
5
6
  require_relative "mocktail/imitates_type"
6
7
  require_relative "mocktail/initializes_mocktail"
7
8
  require_relative "mocktail/matcher_presentation"
8
9
  require_relative "mocktail/matchers"
10
+ require_relative "mocktail/raises_neato_no_method_error"
9
11
  require_relative "mocktail/registers_matcher"
10
12
  require_relative "mocktail/registers_stubbing"
11
13
  require_relative "mocktail/replaces_next"
12
14
  require_relative "mocktail/replaces_type"
13
15
  require_relative "mocktail/resets_state"
16
+ require_relative "mocktail/simulates_argument_error"
14
17
  require_relative "mocktail/value"
15
18
  require_relative "mocktail/verifies_call"
16
19
  require_relative "mocktail/version"
@@ -54,7 +57,13 @@ module Mocktail
54
57
  ResetsState.new.reset
55
58
  end
56
59
 
60
+ def self.explain(thing)
61
+ ExplainsThing.new.explain(thing)
62
+ end
63
+
57
64
  # Stores most transactional state about calls & stubbing configurations
65
+ # Anything returned by this is undocumented and could change at any time, so
66
+ # don't commit code that relies on it!
58
67
  def self.cabinet
59
68
  Thread.current[:mocktail_store] ||= Cabinet.new
60
69
  end
data/mocktail.gemspec CHANGED
@@ -6,9 +6,9 @@ Gem::Specification.new do |spec|
6
6
  spec.authors = ["Justin Searls"]
7
7
  spec.email = ["searls@gmail.com"]
8
8
 
9
- spec.summary = "your objects, less potency"
9
+ spec.summary = "Take your objects, and make them a double"
10
10
  spec.homepage = "https://github.com/testdouble/mocktail"
11
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
11
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0")
12
12
 
13
13
  spec.metadata["homepage_uri"] = spec.homepage
14
14
  spec.metadata["source_code_uri"] = spec.homepage
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mocktail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Searls
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-22 00:00:00.000000000 Z
11
+ date: 2021-10-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -31,8 +31,10 @@ files:
31
31
  - lib/mocktail.rb
32
32
  - lib/mocktail/dsl.rb
33
33
  - lib/mocktail/errors.rb
34
+ - lib/mocktail/explains_thing.rb
34
35
  - lib/mocktail/handles_dry_call.rb
35
36
  - lib/mocktail/handles_dry_call/fulfills_stubbing.rb
37
+ - lib/mocktail/handles_dry_call/fulfills_stubbing/describes_unsatisfied_stubbing.rb
36
38
  - lib/mocktail/handles_dry_call/fulfills_stubbing/finds_satisfaction.rb
37
39
  - lib/mocktail/handles_dry_call/logs_call.rb
38
40
  - lib/mocktail/handles_dry_call/validates_arguments.rb
@@ -41,6 +43,7 @@ files:
41
43
  - lib/mocktail/imitates_type/ensures_imitation_support.rb
42
44
  - lib/mocktail/imitates_type/makes_double.rb
43
45
  - lib/mocktail/imitates_type/makes_double/declares_dry_class.rb
46
+ - lib/mocktail/imitates_type/makes_double/gathers_fakeable_instance_methods.rb
44
47
  - lib/mocktail/initializes_mocktail.rb
45
48
  - lib/mocktail/matcher_presentation.rb
46
49
  - lib/mocktail/matchers.rb
@@ -53,6 +56,7 @@ files:
53
56
  - lib/mocktail/matchers/not.rb
54
57
  - lib/mocktail/matchers/numeric.rb
55
58
  - lib/mocktail/matchers/that.rb
59
+ - lib/mocktail/raises_neato_no_method_error.rb
56
60
  - lib/mocktail/records_demonstration.rb
57
61
  - lib/mocktail/registers_matcher.rb
58
62
  - lib/mocktail/registers_stubbing.rb
@@ -61,22 +65,34 @@ files:
61
65
  - lib/mocktail/replaces_type/redefines_new.rb
62
66
  - lib/mocktail/replaces_type/redefines_singleton_methods.rb
63
67
  - lib/mocktail/resets_state.rb
68
+ - lib/mocktail/share/creates_identifier.rb
64
69
  - lib/mocktail/share/determines_matching_calls.rb
65
- - lib/mocktail/share/simulates_argument_error.rb
70
+ - lib/mocktail/share/stringifies_call.rb
71
+ - lib/mocktail/share/stringifies_method_name.rb
72
+ - lib/mocktail/simulates_argument_error.rb
73
+ - lib/mocktail/simulates_argument_error/cleans_backtrace.rb
74
+ - lib/mocktail/simulates_argument_error/reconciles_args_with_params.rb
75
+ - lib/mocktail/simulates_argument_error/recreates_message.rb
76
+ - lib/mocktail/simulates_argument_error/transforms_params.rb
66
77
  - lib/mocktail/value.rb
67
78
  - lib/mocktail/value/cabinet.rb
68
79
  - lib/mocktail/value/call.rb
69
80
  - lib/mocktail/value/demo_config.rb
70
81
  - lib/mocktail/value/double.rb
82
+ - lib/mocktail/value/double_data.rb
83
+ - lib/mocktail/value/explanation.rb
71
84
  - lib/mocktail/value/matcher_registry.rb
85
+ - lib/mocktail/value/signature.rb
86
+ - lib/mocktail/value/stub_returned_nil.rb
72
87
  - lib/mocktail/value/stubbing.rb
73
88
  - lib/mocktail/value/top_shelf.rb
74
89
  - lib/mocktail/value/type_replacement.rb
90
+ - lib/mocktail/value/type_replacement_data.rb
91
+ - lib/mocktail/value/unsatisfied_stubbing.rb
75
92
  - lib/mocktail/verifies_call.rb
76
93
  - lib/mocktail/verifies_call/finds_verifiable_calls.rb
77
94
  - lib/mocktail/verifies_call/raises_verification_error.rb
78
95
  - lib/mocktail/verifies_call/raises_verification_error/gathers_calls_of_method.rb
79
- - lib/mocktail/verifies_call/raises_verification_error/stringifies_call.rb
80
96
  - lib/mocktail/version.rb
81
97
  - mocktail.gemspec
82
98
  homepage: https://github.com/testdouble/mocktail
@@ -93,7 +109,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
109
  requirements:
94
110
  - - ">="
95
111
  - !ruby/object:Gem::Version
96
- version: 2.7.0
112
+ version: 3.0.0
97
113
  required_rubygems_version: !ruby/object:Gem::Requirement
98
114
  requirements:
99
115
  - - ">="
@@ -103,5 +119,5 @@ requirements: []
103
119
  rubygems_version: 3.2.15
104
120
  signing_key:
105
121
  specification_version: 4
106
- summary: your objects, less potency
122
+ summary: Take your objects, and make them a double
107
123
  test_files: []
@@ -1,28 +0,0 @@
1
- module Mocktail
2
- class SimulatesArgumentError
3
- def simulate(arg_params, args, kwarg_params, kwargs)
4
- req_args = arg_params.count { |type, _| type == :req }
5
- opt_args = arg_params.count { |type, _| type == :opt }
6
- rest_args = arg_params.any? { |type, _| type == :rest }
7
- req_kwargs = kwarg_params.select { |type, _| type == :keyreq }
8
-
9
- allowed_args = req_args + opt_args
10
- msg = if args.size < req_args || (!rest_args && args.size > allowed_args)
11
- expected_desc = if rest_args
12
- "#{req_args}+"
13
- elsif allowed_args != req_args
14
- "#{req_args}..#{allowed_args}"
15
- else
16
- req_args.to_s
17
- end
18
-
19
- "wrong number of arguments (given #{args.size}, expected #{expected_desc}#{"; required keyword#{"s" if req_kwargs.size > 1}: #{req_kwargs.map { |_, name| name }.join(", ")}" unless req_kwargs.empty?})"
20
-
21
- elsif !(missing_kwargs = req_kwargs.reject { |_, name| kwargs.key?(name) }).empty?
22
- "missing keyword#{"s" if missing_kwargs.size > 1}: #{missing_kwargs.map { |_, name| name.inspect }.join(", ")}"
23
- end
24
-
25
- ArgumentError.new(msg)
26
- end
27
- end
28
- end