muack 1.5.1 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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