muack 1.5.1 → 1.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77dfffce2bb5df1930472ff39a8280bd9a1a69f6e81d1f0173d02099b5cdeaf9
4
- data.tar.gz: aabb83e37e3ae995c02ad1ba1e938866cd3e036fa8a3f7682273a80255c60f90
3
+ metadata.gz: 87b3de29deb805feea133c6e8fc7b3fc2720334df701a59452acc3141fd63509
4
+ data.tar.gz: aeb2e74419effc23ca0d1b51de935308242fd0fa12e9dae6be064dc11cc7e8ea
5
5
  SHA512:
6
- metadata.gz: 01e57727b0e41455e69a5c4f0f6552b14d1efc192b08435d4b154abe68d86bf62e058cc54196ca05fb1519a301ae7c4fd3bc9924e25a2036c44d1b5a3c3a7843
7
- data.tar.gz: 2324f6b087b7d79c46c5727078fce53a2f178ff8474bbed48af3750e447ad6e16168b788d148ca3c3a347a6a11ac578b923aa5effeb81013a9ab5e159d5508e3
6
+ metadata.gz: 0d67d586cb7005f3ec8fae297cf6e9bc7f669cc1853dc5c293b28858fb3b7f6134c7e373399f5135fb88ab3879122e8f6c61a653925a456bab3a53715549a3de
7
+ data.tar.gz: a6387f685b6db8c25e447027698de5f47cc8aea2abef864552bc2d3010e5c5f92e637df9dd08ab6bdb3692e40c598ad6c01b1c7fae4d4e59672e9f66eae6fcf9
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,40 @@
1
+
2
+ stages:
3
+ - test
4
+
5
+ .test:
6
+ stage: test
7
+ image: ruby:${RUBY_VERSION}-bullseye
8
+ variables:
9
+ GIT_DEPTH: "1"
10
+ GIT_SUBMODULE_STRATEGY: recursive
11
+ GIT_SUBMODULE_PATHS: task
12
+ RUBYOPT: --enable-frozen-string-literal
13
+ before_script:
14
+ - bundle install --retry=3
15
+ - unset CI # Coverage doesn't work well with frozen literal
16
+ script:
17
+ - ruby -vr bundler/setup -S rake test
18
+
19
+ ruby:3.0:
20
+ extends:
21
+ - .test
22
+ variables:
23
+ RUBY_VERSION: '3.0'
24
+
25
+ ruby:3.1:
26
+ extends:
27
+ - .test
28
+ variables:
29
+ RUBY_VERSION: '3.1'
30
+
31
+ ruby:3.2:
32
+ extends:
33
+ - .test
34
+ variables:
35
+ RUBY_VERSION: '3.2'
36
+
37
+ jruby:latest:
38
+ extends:
39
+ - .test
40
+ image: jruby:latest
data/.gitmodules CHANGED
@@ -1,3 +1,3 @@
1
1
  [submodule "task"]
2
2
  path = task
3
- url = git://github.com/godfat/gemgem.git
3
+ url = https://github.com/godfat/gemgem.git
data/CHANGES.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # CHANGES
2
2
 
3
+ ## Muack 1.7.0 -- 2022-12-29
4
+
5
+ ### Incompatible changes
6
+
7
+ * Drop support for Ruby 2.6-
8
+
9
+ ### Bugs fixed
10
+
11
+ * Fixed stubbed instance method not following the original visibility.
12
+ It's always public before this fix.
13
+ * Worked around a few JRuby 9.4 compatibility issues. Note that there are
14
+ still some issues due to JRuby bugs. Those tests are currently skipped.
15
+
16
+ ## Muack 1.6.0 -- 2020-12-06
17
+
18
+ ### Enhancement
19
+
20
+ * Fix a few cases for mocking against modules/classes with prepended modules,
21
+ especially when `any_instance_of` is also used in combination. Previously,
22
+ it's either not mocking correctly or it may affect modules/classes which
23
+ also use the same prepended modules. For mocking prepended methods, an
24
+ internal `MuackPrepended` module will be prepended into the modules/classes
25
+ to properly override the prepended methods. This module cannot be removed
26
+ between tests because there's no way to do that with current Rubies.
27
+ * Performance could be potentially slightly improved with Ruby 2.6+
28
+
3
29
  ## Muack 1.5.1 -- 2020-12-06
4
30
 
5
31
  ### Bugs fixed
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Muack [![Build Status](https://secure.travis-ci.org/godfat/muack.png?branch=master)](http://travis-ci.org/godfat/muack) [![Coverage Status](https://coveralls.io/repos/github/godfat/muack/badge.png)](https://coveralls.io/github/godfat/muack) [![Join the chat at https://gitter.im/godfat/muack](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/godfat/muack)
1
+ # Muack [![Pipeline status](https://gitlab.com/godfat/muack/badges/master/pipeline.svg)](https://gitlab.com/godfat/muack/-/pipelines)
2
2
 
3
3
  by Lin Jen-Shin ([godfat](http://godfat.org))
4
4
 
@@ -1221,7 +1221,7 @@ Or, I am happy to break legacy.
1221
1221
 
1222
1222
  Apache License 2.0 (Apache-2.0)
1223
1223
 
1224
- Copyright (c) 2013-2020, Lin Jen-Shin (godfat)
1224
+ Copyright (c) 2013-2022, Lin Jen-Shin (godfat)
1225
1225
 
1226
1226
  Licensed under the Apache License, Version 2.0 (the "License");
1227
1227
  you may not use this file except in compliance with the License.
data/lib/muack/block.rb CHANGED
@@ -1,6 +1,16 @@
1
1
 
2
- if RUBY_VERSION < '2.7'
3
- require 'muack/block_26'
4
- else
5
- require 'muack/block_27'
2
+ module Muack
3
+ class Block < Struct.new(:block, :context)
4
+ def initialize block, context=nil
5
+ super
6
+ end
7
+
8
+ def call(...)
9
+ if context
10
+ context.instance_exec(...)
11
+ else
12
+ block.call(...)
13
+ end
14
+ end
15
+ end
6
16
  end
@@ -2,7 +2,7 @@
2
2
  module Muack
3
3
  Definition = Struct.new(:msg, :args, :returns,
4
4
  :peek_args, :peek_return,
5
- :original_method, :visibility)
5
+ :target, :original_method, :visibility)
6
6
  ActualCall = Struct.new(:msg, :args, :block)
7
7
  WithAnyArgs = Object.new
8
8
  end
data/lib/muack/mock.rb CHANGED
@@ -112,22 +112,18 @@ module Muack
112
112
  private
113
113
  def __mock_inject_method defi
114
114
  __mock_injected[defi.msg] = defi
115
- # a) ancestors.first is the first module in the method chain.
116
- # it's just the singleton_class when nothing was prepended,
117
- # otherwise the last prepended module.
118
- # b) would be the class in AnyInstanceOf.
119
- target = object.singleton_class.ancestors.first
115
+ target = Mock.prepare_target(object.singleton_class, defi.msg)
116
+ defi.target = target
120
117
  Mock.store_original_method(target, defi)
121
118
  __mock_inject_mock_method(target, defi)
122
119
  end
123
120
 
124
121
  def __mock_reset_method defi
125
- object.singleton_class.ancestors.first.module_eval do
122
+ defi.target.module_eval do
126
123
  remove_method(defi.msg)
127
124
  # restore original method
128
- if public_instance_methods(false).include?(defi.original_method) ||
129
- protected_instance_methods(false).include?(defi.original_method) ||
130
- private_instance_methods(false).include?(defi.original_method)
125
+ if defi.original_method &&
126
+ Mock.direct_method_defined?(self, defi.original_method)
131
127
  alias_method(defi.msg, defi.original_method)
132
128
  __send__(defi.visibility, defi.msg)
133
129
  remove_method(defi.original_method)
@@ -135,33 +131,69 @@ module Muack
135
131
  end
136
132
  end
137
133
 
138
- def self.store_original_method klass, defi
139
- visibility = if klass.public_instance_methods(false).include?(defi.msg)
134
+ def self.direct_method_defined? mod, msg
135
+ mod.method_defined?(msg, false) || # this doesn't cover private method
136
+ mod.private_method_defined?(msg, false)
137
+ end
138
+
139
+ def self.method_visibility mod, msg, inherit=false
140
+ if mod.public_method_defined?(msg, inherit)
140
141
  :public
141
- elsif klass.protected_instance_methods(false).include?(defi.msg)
142
+ elsif mod.protected_method_defined?(msg, inherit)
142
143
  :protected
143
- elsif klass.private_instance_methods(false).include?(defi.msg)
144
+ elsif mod.private_method_defined?(msg, inherit)
144
145
  :private
145
146
  end
147
+ end
146
148
 
147
- if visibility # store original method
148
- original_method = find_new_name(klass, defi.msg)
149
- klass.__send__(:alias_method, original_method, defi.msg)
149
+ def self.prepare_target singleton_class, msg
150
+ if singleton_class == singleton_class.ancestors.first # no prepended mod
151
+ singleton_class
152
+ else # check if we need to prepend an internal module to override
153
+ index = singleton_class.ancestors.index(singleton_class)
154
+ prepended_modules = singleton_class.ancestors[0...index]
155
+
156
+ if prepended_modules.find{ |m| direct_method_defined?(m, msg) }
157
+ # prepend an internal module to override the prepended module(s)
158
+ name = :MuackPrepended
159
+ if singleton_class.const_defined?(name)
160
+ singleton_class.const_get(name)
161
+ else
162
+ prepended = ::Module.new
163
+ singleton_class.const_set(name, prepended)
164
+ singleton_class.private_constant(name)
165
+ singleton_class.prepend(prepended)
166
+ prepended
167
+ end
168
+ else # we don't need to override so singleton class is enough
169
+ singleton_class
170
+ end
171
+ end
172
+ end
173
+
174
+ def self.store_original_method mod, defi
175
+ if visibility = method_visibility(mod, defi.msg)
176
+ # Defined in itself, we need to make alias
177
+ original_method = find_new_name(mod, defi.msg)
178
+ mod.__send__(:alias_method, original_method, defi.msg)
150
179
  defi.original_method = original_method
151
180
  defi.visibility = visibility
152
- else
181
+ elsif visibility = method_visibility(mod, defi.msg, true)
182
+ # Defined in parent, we can just override
183
+ defi.visibility = visibility
184
+ else # Not defined, pick a reasonable default
153
185
  defi.visibility = :public
154
186
  end
155
187
  end
156
188
 
157
- def self.find_new_name klass, message, level=0
189
+ def self.find_new_name mod, message, level=0
158
190
  if level >= (::ENV['MUACK_RECURSION_LEVEL'] || 9).to_i
159
191
  raise CannotFindInjectionName.new(level+1, message)
160
192
  end
161
193
 
162
194
  new_name = "__muack_#{name}_#{level}_#{message}".to_sym
163
- if klass.instance_methods(false).include?(new_name)
164
- find_new_name(klass, message, level+1)
195
+ if direct_method_defined?(mod, new_name)
196
+ find_new_name(mod, message, level+1)
165
197
  else
166
198
  new_name
167
199
  end
@@ -246,12 +278,12 @@ module Muack
246
278
  ::Kernel.instance_method(:method).bind(object).call(method_name).
247
279
  super_method
248
280
 
249
- if super_method.owner == ::Class && super_method.name == :new
281
+ if super_method.owner.kind_of?(::Class) && super_method.name == :new
250
282
  initialize_method = ::Class.instance_method(:instance_method).
251
283
  bind(object).call(:initialize)
252
284
  __mock_block_with_kargs?(initialize_method)
253
285
  else
254
- super_method && __mock_block_with_kargs?(super_method)
286
+ __mock_block_with_kargs?(super_method)
255
287
  end
256
288
  end
257
289
 
data/lib/muack/session.rb CHANGED
@@ -22,6 +22,10 @@ module Muack
22
22
  def verify obj=nil
23
23
  if obj
24
24
  with(obj, :[]).all?(&:__mock_verify)
25
+ elsif RUBY_ENGINE == 'jruby'
26
+ # Workaround weird error:
27
+ # TypeError: Muack::Stub#to_ary should return Array
28
+ data.each_value.all?{ |v| v.__mock_verify }
25
29
  else
26
30
  data.each_value.all?(&:__mock_verify)
27
31
  end
data/lib/muack/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
 
2
2
  module Muack
3
- VERSION = '1.5.1'
3
+ VERSION = '1.7.0'
4
4
  end
data/muack.gemspec CHANGED
@@ -1,20 +1,20 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: muack 1.5.1 ruby lib
2
+ # stub: muack 1.7.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "muack".freeze
6
- s.version = "1.5.1"
6
+ s.version = "1.7.0"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Lin Jen-Shin (godfat)".freeze]
11
- s.date = "2020-12-06"
11
+ s.date = "2022-12-29"
12
12
  s.description = "Muack -- A fast, small, yet powerful mocking library.\n\nInspired by [RR][], and it's 32x times faster (750s vs 23s) than RR\nfor running [Rib][] tests.\n\n[RR]: https://github.com/rr/rr\n[Rib]: https://github.com/godfat/rib".freeze
13
13
  s.email = ["godfat (XD) godfat.org".freeze]
14
14
  s.files = [
15
15
  ".gitignore".freeze,
16
+ ".gitlab-ci.yml".freeze,
16
17
  ".gitmodules".freeze,
17
- ".travis.yml".freeze,
18
18
  "CHANGES.md".freeze,
19
19
  "Gemfile".freeze,
20
20
  "LICENSE".freeze,
@@ -23,8 +23,6 @@ Gem::Specification.new do |s|
23
23
  "lib/muack.rb".freeze,
24
24
  "lib/muack/any_instance_of.rb".freeze,
25
25
  "lib/muack/block.rb".freeze,
26
- "lib/muack/block_26.rb".freeze,
27
- "lib/muack/block_27.rb".freeze,
28
26
  "lib/muack/coat.rb".freeze,
29
27
  "lib/muack/definition.rb".freeze,
30
28
  "lib/muack/error.rb".freeze,
@@ -54,7 +52,7 @@ Gem::Specification.new do |s|
54
52
  "test/test_visibility.rb".freeze]
55
53
  s.homepage = "https://github.com/godfat/muack".freeze
56
54
  s.licenses = ["Apache-2.0".freeze]
57
- s.rubygems_version = "3.1.4".freeze
55
+ s.rubygems_version = "3.4.1".freeze
58
56
  s.summary = "Muack -- A fast, small, yet powerful mocking library.".freeze
59
57
  s.test_files = [
60
58
  "test/test_any_instance_of.rb".freeze,
data/task/README.md CHANGED
@@ -39,7 +39,7 @@ end
39
39
 
40
40
  Apache License 2.0 (Apache-2.0)
41
41
 
42
- Copyright (c) 2011-2019, Lin Jen-Shin (godfat)
42
+ Copyright (c) 2011-2021, Lin Jen-Shin (godfat)
43
43
 
44
44
  Licensed under the Apache License, Version 2.0 (the "License");
45
45
  you may not use this file except in compliance with the License.
data/task/gemgem.rb CHANGED
@@ -42,6 +42,7 @@ module Gemgem
42
42
 
43
43
  def gem_install
44
44
  require 'rubygems/commands/install_command'
45
+ require 'rubygems/package'
45
46
  # read ~/.gemrc
46
47
  Gem.use_paths(Gem.configuration[:gemhome], Gem.configuration[:gempath])
47
48
  Gem::Command.extra_args = Gem.configuration[:gem]
@@ -51,7 +52,8 @@ module Gemgem
51
52
  cmd.handle_options([])
52
53
 
53
54
  # install
54
- install = Gem::Installer.new(gem_path, cmd.options)
55
+ gem_package = Gem::Package.new(gem_path)
56
+ install = Gem::Installer.new(gem_package, cmd.options)
55
57
  install.install
56
58
  puts "\e[35mGem installed: \e[33m#{strip_path(install.gem_dir)}\e[0m"
57
59
  end
@@ -113,6 +113,17 @@ describe Muack::AnyInstanceOf do
113
113
  obj.f.should.eq 0
114
114
  end
115
115
 
116
+ describe 'mock any_instance_of on a method defined higher up' do
117
+ methods_count = klass.instance_methods.size
118
+
119
+ would 'not store a backup method' do
120
+ any_instance_of(klass){ |inst| mock(inst).to_s{ 'to_s' } }
121
+
122
+ expect(klass.new.to_s).eq 'to_s'
123
+ expect(klass.instance_methods.size).eq methods_count
124
+ end
125
+ end
126
+
116
127
  # Brought from rspec-mocks and it's currently failing on rspec-mocks
117
128
  would 'stub any_instance_of on module extending it self' do
118
129
  mod = Module.new {
data/test/test_keyargs.rb CHANGED
@@ -50,6 +50,9 @@ describe Muack::Mock do
50
50
  end
51
51
 
52
52
  would 'instance method' do
53
+ # https://github.com/jruby/jruby/issues/7545
54
+ skip if RUBY_ENGINE == 'jruby' && obj.kind_of?(Muack::AnyInstanceOf)
55
+
53
56
  mock(obj).bonjour(a: 0, b: 1)
54
57
 
55
58
  expect(instance.bonjour(a: 0, b: 1)).eq([0, 1])
data/test/test_mock.rb CHANGED
@@ -104,10 +104,73 @@ describe Muack::Mock do
104
104
  end
105
105
 
106
106
  describe 'not affect the original module' do
107
- would 'with include' do
108
- m = Module.new{ def f; :f; end }
109
- c0 = Class.new{ include m }.new
110
- c1 = Class.new{ include m }.new
107
+ def mod
108
+ @mod ||= Module.new{ def f; :f; end }
109
+ end
110
+
111
+ def setup type
112
+ m = mod
113
+ Array.new(2).map{ Class.new{ public_send(type, m) }.new }
114
+ end
115
+
116
+ would 'with include and mock' do
117
+ c0, c1 = setup(:include)
118
+
119
+ mock(c0).f{:g}
120
+
121
+ expect(c0.f).eq :g
122
+ expect(c1.f).eq :f
123
+ end
124
+
125
+ would 'with prepend and mock' do
126
+ c0, c1 = setup(:prepend)
127
+
128
+ mock(c0).f{:g}
129
+
130
+ expect(c0.f).eq :g
131
+ expect(c1.f).eq :f
132
+ end
133
+
134
+ would 'with include and mock any_instance_of C0' do
135
+ c0, c1 = setup(:include)
136
+
137
+ mock(any_instance_of(c0.class)).f{:g}
138
+
139
+ expect(c0.f).eq :g
140
+ expect(c1.f).eq :f
141
+ end
142
+
143
+ would 'with prepend and mock any_instance_of C0' do
144
+ c0, c1 = setup(:prepend)
145
+
146
+ mock(any_instance_of(c0.class)).f{:g}
147
+
148
+ expect(c0.f).eq :g
149
+ expect(c1.f).eq :f
150
+ end
151
+
152
+ would 'with include and mock any_instance_of M' do
153
+ c0, c1 = setup(:include)
154
+
155
+ mock(any_instance_of(mod)).f{:g}.times(2)
156
+
157
+ expect(c0.f).eq :g
158
+ expect(c1.f).eq :g
159
+ end
160
+
161
+ would 'with prepend and mock any_instance_of M' do
162
+ c0, c1 = setup(:prepend)
163
+
164
+ mock(any_instance_of(mod)).f{:g}.times(2)
165
+
166
+ expect(c0.f).eq :g
167
+ expect(c1.f).eq :g
168
+ end
169
+
170
+ would 'with extend on the instance' do
171
+ m = mod
172
+ c0 = Class.new.new.extend(m)
173
+ c1 = Class.new{ prepend m }.new
111
174
 
112
175
  mock(c0).f{:g}
113
176
 
@@ -115,9 +178,10 @@ describe Muack::Mock do
115
178
  expect(c1.f).eq :f
116
179
  end
117
180
 
118
- would 'with prepend' do
119
- m = Module.new{ def f; :f; end }
120
- c0 = Class.new{ prepend m }.new
181
+ would 'with prepend on the singleton class of instance' do
182
+ m = mod
183
+ c0 = Class.new.new
184
+ c0.singleton_class.prepend m
121
185
  c1 = Class.new{ prepend m }.new
122
186
 
123
187
  mock(c0).f{:g}
@@ -125,6 +189,83 @@ describe Muack::Mock do
125
189
  expect(c0.f).eq :g
126
190
  expect(c1.f).eq :f
127
191
  end
192
+
193
+ describe 'with prepend on any_instance_of' do
194
+ describe 'on prepended method' do
195
+ would 'have a muack prepended module' do
196
+ m = mod
197
+ c = Class.new{ prepend m }
198
+ ancestors_size = c.ancestors.size
199
+
200
+ mock(any_instance_of(c)).f{:g}
201
+
202
+ expect(c.new.f).eq :g
203
+ expect(c).const_defined?(:MuackPrepended)
204
+ expect(c.ancestors.size).eq ancestors_size + 1
205
+
206
+ expect(Muack.verify).eq true
207
+
208
+ # Make sure there's only one MuackPrepended
209
+ mock(any_instance_of(c)).f{:h}
210
+ expect(c.ancestors.size).eq ancestors_size + 1
211
+ expect(c.new.f).eq :h
212
+ end
213
+ end
214
+
215
+ describe 'on non-prepended method' do
216
+ would 'not have a muack prepended module' do
217
+ m = mod
218
+ c = Class.new{ def g; :g; end; prepend m }
219
+ ancestors_size = c.ancestors.size
220
+
221
+ mock(any_instance_of(c)).g{:m}
222
+
223
+ expect(c.new.f).eq :f
224
+ expect(c.new.g).eq :m
225
+ expect(c).not.const_defined?(:MuackPrepended)
226
+ expect(c.ancestors.size).eq ancestors_size
227
+ end
228
+ end
229
+ end
230
+
231
+ describe 'any_instance_of on a module which has a prepended module' do
232
+ before do
233
+ @m0 = m0 = Module.new{ def f; :m0; end }
234
+ @m1 = m1 = Module.new{ def f; :m1; end; prepend m0 }
235
+ @c0 = Class.new{ prepend m0 }.new
236
+ @c1 = Class.new{ prepend m1 }.new
237
+ end
238
+
239
+ would 'any_instance_of m0' do
240
+ mock(any_instance_of(@m0)).f{:g}.times(2)
241
+
242
+ expect(@c0.f).eq :g
243
+ expect(@c1.f).eq :g
244
+ end
245
+
246
+ would 'any_instance_of m1' do
247
+ skip if RUBY_ENGINE == 'jruby'
248
+
249
+ mock(any_instance_of(@m1)).f{:g}
250
+
251
+ expect(@c0.f).eq :m0
252
+ expect(@c1.f).eq :g
253
+ end
254
+
255
+ would 'any_instance_of c0.class' do
256
+ mock(any_instance_of(@c0.class)).f{:g}
257
+
258
+ expect(@c0.f).eq :g
259
+ expect(@c1.f).eq :m0
260
+ end
261
+
262
+ would 'any_instance_of c1.class' do
263
+ mock(any_instance_of(@c1.class)).f{:g}
264
+
265
+ expect(@c0.f).eq :m0
266
+ expect(@c1.f).eq :g
267
+ end
268
+ end
128
269
  end
129
270
  end
130
271
 
data/test/test_prepend.rb CHANGED
@@ -94,6 +94,35 @@ describe 'mock with prepend' do
94
94
  paste :test
95
95
  end
96
96
 
97
+ describe 'class with a chain of prepended modules' do
98
+ would 'not affect other modules' do
99
+ mod0 = Module.new{ def f; :m0; end }
100
+ mod1 = Module.new{ def f; :m1; end }
101
+ klass0 = Class.new{ prepend mod0 }
102
+ klass1 = Class.new{ prepend mod1 }
103
+ klass = Class.new{ prepend mod1; prepend mod0 }
104
+
105
+ mock(any_instance_of(klass)).f{:f}
106
+
107
+ expect(klass.new.f).eq :f
108
+ expect(klass0.new.f).eq :m0
109
+ expect(klass1.new.f).eq :m1
110
+ end
111
+ end
112
+
113
+ describe 'class and subclass' do
114
+ would 'work for prepended superclass' do
115
+ mod = Module.new{ def f; :f; end }
116
+ base = Class.new{ prepend mod }
117
+ sub = Class.new(base)
118
+
119
+ mock(any_instance_of(base)).f{:g}.times(2)
120
+
121
+ expect(base.new.f).eq :g
122
+ expect(sub.new.f).eq :g
123
+ end
124
+ end
125
+
97
126
  # Brought from rspec-mocks and it's currently failing on rspec-mocks
98
127
  # See https://github.com/rspec/rspec-mocks/pull/1218
99
128
  would "handle stubbing prepending methods that were only defined on the prepended module" do
@@ -18,17 +18,9 @@ describe 'retain visibility' do
18
18
  end
19
19
 
20
20
  def generate visibility
21
- klass = Class.new do
22
- def greet
23
- 'hi'
24
- end
25
- end
21
+ klass = Class.new
26
22
 
27
23
  mod = Module.new do
28
- def greet
29
- hello
30
- end
31
-
32
24
  def hello
33
25
  'hello'
34
26
  end
@@ -97,8 +89,54 @@ describe 'retain visibility' do
97
89
  paste :test
98
90
  end
99
91
 
92
+ describe 'set the same visibility from the original method' do
93
+ copy :test do
94
+ def find_visibilities
95
+ %i[public protected private].map do |v|
96
+ object.send("#{v}_methods").include?(:hello)
97
+ end
98
+ end
99
+
100
+ would do
101
+ current_visibilities = find_visibilities
102
+
103
+ stub(object).hello{ :stub }
104
+
105
+ expect(find_visibilities).eq current_visibilities
106
+ end
107
+ end
108
+
109
+ describe 'for instance method' do
110
+ def object
111
+ @object ||= Class.new do
112
+ private
113
+ def hello; :hello; end
114
+ end.new
115
+ end
116
+
117
+ paste :test
118
+ end
119
+
120
+ describe 'for singleton method' do
121
+ def object
122
+ @object ||= begin
123
+ ret = Object.new
124
+ def ret.hello; :hello; end
125
+ ret
126
+ end
127
+ end
128
+
129
+ paste :test
130
+ end
131
+ end
132
+
100
133
  # Brought from rspec-mocks
101
134
  would "correctly restore the visibility of methods whose visibility has been tweaked on the singleton class" do
135
+ # JRuby didn't store the visibility change on the singleton class,
136
+ # therefore it cannot be properly detected and visibility change
137
+ # will be lost upon reset.
138
+ skip if RUBY_ENGINE == 'jruby'
139
+
102
140
  # hello is a private method when mixed in, but public on the module
103
141
  # itself
104
142
  mod = Module.new do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: muack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lin Jen-Shin (godfat)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-06 00:00:00.000000000 Z
11
+ date: 2022-12-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |-
14
14
  Muack -- A fast, small, yet powerful mocking library.
@@ -25,8 +25,8 @@ extensions: []
25
25
  extra_rdoc_files: []
26
26
  files:
27
27
  - ".gitignore"
28
+ - ".gitlab-ci.yml"
28
29
  - ".gitmodules"
29
- - ".travis.yml"
30
30
  - CHANGES.md
31
31
  - Gemfile
32
32
  - LICENSE
@@ -35,8 +35,6 @@ files:
35
35
  - lib/muack.rb
36
36
  - lib/muack/any_instance_of.rb
37
37
  - lib/muack/block.rb
38
- - lib/muack/block_26.rb
39
- - lib/muack/block_27.rb
40
38
  - lib/muack/coat.rb
41
39
  - lib/muack/definition.rb
42
40
  - lib/muack/error.rb
@@ -83,7 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
81
  - !ruby/object:Gem::Version
84
82
  version: '0'
85
83
  requirements: []
86
- rubygems_version: 3.1.4
84
+ rubygems_version: 3.4.1
87
85
  signing_key:
88
86
  specification_version: 4
89
87
  summary: Muack -- A fast, small, yet powerful mocking library.
data/.travis.yml DELETED
@@ -1,21 +0,0 @@
1
- sudo: false
2
- language: ruby
3
-
4
- install: 'gem update --system; gem install bundler; bundle install --retry=3'
5
- before_script: unset CI
6
- script: 'ruby -vwr bundler/setup -S rake test'
7
-
8
- matrix:
9
- include:
10
- - rvm: 2.4
11
- env: RUBYOPT=--enable-frozen-string-literal
12
- - rvm: 2.5
13
- env: RUBYOPT=--enable-frozen-string-literal
14
- - rvm: 2.6
15
- env: RUBYOPT=--enable-frozen-string-literal
16
- - rvm: 2.7
17
- env: RUBYOPT=--enable-frozen-string-literal
18
- - rvm: ruby-head
19
- env: RUBYOPT=--enable-frozen-string-literal
20
- - rvm: jruby
21
- env: RUBYOPT=--enable-frozen-string-literal
@@ -1,16 +0,0 @@
1
-
2
- module Muack
3
- class Block < Struct.new(:block, :context)
4
- def initialize block, context=nil
5
- super
6
- end
7
-
8
- def call(*args, &block)
9
- if context
10
- context.instance_exec(*args, &block)
11
- else
12
- block.call(*args, &block)
13
- end
14
- end
15
- end
16
- end
@@ -1,16 +0,0 @@
1
-
2
- module Muack
3
- class Block < Struct.new(:block, :context)
4
- def initialize block, context=nil
5
- super
6
- end
7
-
8
- def call(...)
9
- if context
10
- context.instance_exec(...)
11
- else
12
- block.call(...)
13
- end
14
- end
15
- end
16
- end