net-ping 2.0.8 → 2.1.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.
@@ -0,0 +1,71 @@
1
+ # Platform-specific gem dependencies
2
+
3
+ ## Goal
4
+
5
+ Resolve issue #31 by publishing platform-specific `net-ping` gems whose
6
+ runtime dependencies accurately describe the requirements for ICMP support.
7
+ The solution also corrects the equivalent Linux `cap2` metadata omission.
8
+
9
+ ## Scope
10
+
11
+ The release produces three gems with the same name and version:
12
+
13
+ | Gem platform | Additional runtime dependency |
14
+ | --- | --- |
15
+ | `ruby` | None |
16
+ | `universal-linux` | `cap2 (>= 0.2.2)` |
17
+ | `universal-mingw-ucrt` | `win32-security (>= 0.2.0)` |
18
+
19
+ Only the current RubyInstaller `mingw-ucrt` platform is supported for Windows.
20
+ Legacy `mingw32` is out of scope.
21
+
22
+ The CI workflow builds and validates these gems, but does not publish them.
23
+ The existing release process remains responsible for pushing all three files
24
+ to RubyGems.
25
+
26
+ ## Design
27
+
28
+ `net-ping.gemspec` becomes the OS-independent Ruby gemspec. It must not
29
+ inspect the host OS or add OS-specific runtime dependencies.
30
+
31
+ `net-ping-universal-linux.gemspec` loads the base specification, changes its
32
+ platform to `universal-linux`, and adds `cap2`. The platform is intentionally
33
+ CPU-independent so RubyGems can select it for supported Linux CPU variants.
34
+
35
+ `net-ping-universal-mingw-ucrt.gemspec` loads the same base specification,
36
+ changes its platform to `universal-mingw-ucrt`, and adds `win32-security`.
37
+
38
+ The Rake gem namespace explicitly enumerates the three gemspecs. `gem:create`
39
+ cleans old gem artifacts and builds all three. `gem:install` selects the
40
+ specific generated specification compatible with the local platform, falling
41
+ back to the Ruby specification when no platform-specific specification
42
+ matches, then installs its artifact.
43
+
44
+ ## Verification
45
+
46
+ Add `gem:check`, which reads each generated gem through RubyGems and fails
47
+ when its platform or runtime dependencies differ from this specification:
48
+
49
+ - Ruby gem: platform `ruby`; neither `cap2` nor `win32-security`.
50
+ - Linux gem: platform `universal-linux`; includes `cap2`.
51
+ - Windows gem: platform `universal-mingw-ucrt`; includes `win32-security`.
52
+
53
+ The existing GitHub Actions matrix continues to run the test suite. It also
54
+ runs `gem:create` and `gem:check` on both Ubuntu and Windows. A missing,
55
+ malformed, or incorrectly attributed dependency causes the job to fail.
56
+
57
+ ## Documentation
58
+
59
+ Update the prerequisite/install documentation to state that RubyGems chooses
60
+ the platform-specific package and installs the Linux or Windows ICMP
61
+ dependency automatically.
62
+
63
+ Add a `CHANGES` entry describing the corrected platform-specific dependency
64
+ metadata.
65
+
66
+ ## Non-goals
67
+
68
+ - Publishing gems from CI.
69
+ - Supporting legacy `mingw32`.
70
+ - Changing ICMP runtime behavior.
71
+ - Altering non-ICMP protocol implementations or tests.
@@ -66,7 +66,7 @@ module Net
66
66
  bool = true # Success, at least one response.
67
67
  end
68
68
 
69
- if err & (err =~ /warning/i)
69
+ if err && (err =~ /warning/i)
70
70
  @warning = err.chomp
71
71
  end
72
72
  when 2
@@ -116,8 +116,10 @@ module Net
116
116
  pcmd += ['-i', interval.to_s] unless RbConfig::CONFIG['busybox']
117
117
  when /aix/i
118
118
  pcmd += ['-c', count.to_s, '-w', timeout.to_s, host]
119
+ when /freebsd/i
120
+ pcmd += ['-c', count.to_s, '-x', timeout.to_s, host]
119
121
  when /bsd|osx|mach|darwin/i
120
- pcmd += ['-c', count.to_s, '-t', timeout.to_s, host]
122
+ pcmd += ['-c', count.to_s, '-i', interval.to_s, host]
121
123
  when /solaris|sunos/i
122
124
  pcmd += [host, timeout.to_s]
123
125
  when /hpux/i
@@ -147,7 +149,7 @@ module Net
147
149
  bool = true # Success, at least one response.
148
150
  end
149
151
 
150
- if err & err =~ /warning/i
152
+ if err && (err =~ /warning/i)
151
153
  @warning = err.chomp
152
154
  end
153
155
  when 2
data/lib/net/ping/ping.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'socket'
2
2
  require 'timeout'
3
3
 
4
+ require_relative 'version'
5
+
4
6
  # The Net module serves as a namespace only.
5
7
  #
6
8
  module Net
@@ -9,9 +11,6 @@ module Net
9
11
  # types. You should not instantiate this class directly.
10
12
  #
11
13
  class Ping
12
- # The version of the net-ping library.
13
- VERSION = '1.7.6'
14
-
15
14
  # The host to ping. In the case of Ping::HTTP, this is the URI.
16
15
  attr_accessor :host
17
16
 
@@ -0,0 +1,6 @@
1
+ module Net
2
+ class Ping
3
+ # The version of the net-ping library.
4
+ VERSION = '2.1.0'
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ spec = Gem::Specification.load('net-ping.gemspec').dup
2
+ spec.platform = Gem::Platform.new(['universal', 'linux'])
3
+ spec.add_dependency('cap2', '>= 0.2.2')
4
+ spec
@@ -0,0 +1,7 @@
1
+ spec = Gem::Specification.load('net-ping.gemspec').dup
2
+ spec.platform = Gem::Platform.new(['universal', 'mingw-ucrt'])
3
+ spec.add_dependency('win32-security', '>= 0.2.0')
4
+
5
+ # No longer a default gem as of Ruby 4.0. Used by the WMI ping class.
6
+ spec.add_dependency('win32ole', '>= 1.8.8')
7
+ spec
data/net-ping.gemspec CHANGED
@@ -1,16 +1,15 @@
1
- require 'rubygems'
2
- require 'rbconfig'
1
+ require_relative "lib/net/ping/version"
3
2
 
4
3
  Gem::Specification.new do |spec|
5
4
  spec.name = 'net-ping'
6
- spec.version = '2.0.8'
5
+ spec.version = Net::Ping::VERSION
7
6
  spec.license = 'Artistic 2.0'
8
7
  spec.author = 'Chris Chernesky'
9
8
  spec.email = 'chris.netping@tinderglow.com'
10
9
  spec.homepage = 'https://github.com/chernesk/net-ping'
11
10
  spec.summary = 'A ping interface for Ruby.'
12
11
  spec.test_file = 'test/test_net_ping.rb'
13
- spec.files = Dir['**/*'].reject{ |f| f.include?('git') }
12
+ spec.files = Dir['**/*'].reject { |f| f.include?('git') || File.extname(f) == '.gem' }
14
13
  spec.metadata = {
15
14
  'bug_tracker_uri' => "#{spec.homepage}/issues",
16
15
  'changelog_uri' => "#{spec.homepage}/blob/master/CHANGES",
@@ -25,21 +24,10 @@ Gem::Specification.new do |spec|
25
24
  spec.required_ruby_version = ">= 1.9.3"
26
25
 
27
26
  spec.add_development_dependency('test-unit', '>= 0')
28
- spec.add_development_dependency('fakeweb', '>= 0')
27
+ spec.add_development_dependency('webmock', '>= 0')
29
28
  spec.add_development_dependency('rake', '>= 0')
30
29
  spec.add_development_dependency('pry-byebug', '>= 0')
31
30
 
32
- if File::ALT_SEPARATOR
33
- require 'rbconfig'
34
- arch = RbConfig::CONFIG['build_os'] || 'mingw32' # JRuby
35
- spec.platform = Gem::Platform.new(['universal', arch])
36
- spec.platform.version = nil
37
-
38
- # Used for icmp pings.
39
- spec.add_dependency('win32-security', '>= 0.2.0')
40
- spec.add_dependency('cap2', '>= 0.2.2')
41
- end
42
-
43
31
  spec.description = <<-EOF
44
32
  The net-ping library provides a ping interface for Ruby. It includes
45
33
  separate TCP, HTTP, LDAP, ICMP, UDP, WMI (for Windows) and external ping
@@ -5,10 +5,10 @@
5
5
  # class test won't be run unless this is run as a privileged process.
6
6
  ######################################################################
7
7
  require 'test_net_ping_external'
8
+ require 'test_net_ping_gem_packaging'
8
9
  require 'test_net_ping_http'
9
10
  require 'test_net_ping_tcp'
10
11
  require 'test_net_ping_udp'
11
- require 'fakeweb'
12
12
 
13
13
  if File::ALT_SEPARATOR
14
14
  require 'win32/security'
@@ -39,8 +39,6 @@ end
39
39
 
40
40
  class TC_Net_Ping < Test::Unit::TestCase
41
41
  def test_net_ping_version
42
- assert_equal('1.7.6', Net::Ping::VERSION)
42
+ assert_equal(Gem::Specification.load('net-ping.gemspec').version.to_s, Net::Ping::VERSION)
43
43
  end
44
44
  end
45
-
46
- FakeWeb.allow_net_connect = false
@@ -10,6 +10,8 @@
10
10
  #########################################################################
11
11
  require 'test-unit'
12
12
  require 'net/ping/external'
13
+ require 'mkmf'
14
+ require 'stringio'
13
15
 
14
16
  class TC_Net_Ping_External < Test::Unit::TestCase
15
17
  def setup
@@ -47,6 +49,7 @@ class TC_Net_Ping_External < Test::Unit::TestCase
47
49
  end
48
50
 
49
51
  test "pinging a good host returns true" do
52
+ omit_if(find_executable0('ping').nil?)
50
53
  assert_true(@pe.ping?)
51
54
  end
52
55
 
@@ -55,12 +58,14 @@ class TC_Net_Ping_External < Test::Unit::TestCase
55
58
  end
56
59
 
57
60
  test "duration basic functionality" do
61
+ omit_if(find_executable0('ping').nil?)
58
62
  assert_nothing_raised{ @pe.ping }
59
63
  assert_respond_to(@pe, :duration)
60
64
  assert_kind_of(Float, @pe.duration)
61
65
  end
62
66
 
63
67
  test "duration is unset if a bad ping follows a good ping" do
68
+ omit_if(find_executable0('ping').nil?)
64
69
  assert_nothing_raised{ @pe.ping }
65
70
  assert_not_nil(@pe.duration)
66
71
  assert_false(@pe.ping?(@bogus))
@@ -111,6 +116,7 @@ class TC_Net_Ping_External < Test::Unit::TestCase
111
116
  end
112
117
 
113
118
  test "pinging a good host results in no exception data" do
119
+ omit_if(find_executable0('ping').nil?)
114
120
  assert_nothing_raised{ @pe.ping }
115
121
  assert_nil(@pe.exception)
116
122
  end
@@ -134,6 +140,89 @@ class TC_Net_Ping_External < Test::Unit::TestCase
134
140
  assert_false(@bad.ping?)
135
141
  end
136
142
 
143
+ test "ping6 uses timeout for FreeBSD" do
144
+ command = nil
145
+ original_os = RbConfig::CONFIG['host_os']
146
+ original_popen3 = Open3.method(:popen3)
147
+
148
+ RbConfig::CONFIG['host_os'] = 'freebsd'
149
+ Open3.define_singleton_method(:popen3) do |*args, &block|
150
+ command = args
151
+ stdin = StringIO.new
152
+ stdout = StringIO.new
153
+ stderr = StringIO.new
154
+ status = Struct.new(:exitstatus).new(0)
155
+ thread = Struct.new(:value).new(status)
156
+ block.call(stdin, stdout, stderr, thread)
157
+ end
158
+
159
+ @pe.ping6('example.test', 2, 3, 4)
160
+
161
+ assert_equal(['ping6', '-c', '2', '-x', '4', 'example.test'], command)
162
+ ensure
163
+ RbConfig::CONFIG['host_os'] = original_os
164
+ Open3.define_singleton_method(:popen3, original_popen3)
165
+ end
166
+
167
+ test "ping6 uses interval for macOS" do
168
+ command = nil
169
+ original_os = RbConfig::CONFIG['host_os']
170
+ original_popen3 = Open3.method(:popen3)
171
+
172
+ RbConfig::CONFIG['host_os'] = 'darwin'
173
+ Open3.define_singleton_method(:popen3) do |*args, &block|
174
+ command = args
175
+ stdin = StringIO.new
176
+ stdout = StringIO.new
177
+ stderr = StringIO.new
178
+ status = Struct.new(:exitstatus).new(0)
179
+ thread = Struct.new(:value).new(status)
180
+ block.call(stdin, stdout, stderr, thread)
181
+ end
182
+
183
+ @pe.ping6('example.test', 2, 3, 4)
184
+
185
+ assert_equal(['ping6', '-c', '2', '-i', '3', 'example.test'], command)
186
+ ensure
187
+ RbConfig::CONFIG['host_os'] = original_os
188
+ Open3.define_singleton_method(:popen3, original_popen3)
189
+ end
190
+
191
+ test "ping6 succeeds without an exception when stderr is empty" do
192
+ stdin = StringIO.new
193
+ stdout = StringIO.new('64 bytes from ::1')
194
+ stderr = StringIO.new
195
+ status = Struct.new(:exitstatus).new(0)
196
+ thread = Struct.new(:value).new(status)
197
+ popen3 = Open3.method(:popen3)
198
+ nil_match = NilClass.instance_method(:=~) if NilClass.instance_methods(false).include?(:=~)
199
+ false_match = FalseClass.instance_method(:=~) if FalseClass.instance_methods(false).include?(:=~)
200
+
201
+ Open3.singleton_class.send(:define_method, :popen3) do |*args, &block|
202
+ block.call(stdin, stdout, stderr, thread)
203
+ end
204
+ [NilClass, FalseClass].each do |klass|
205
+ klass.send(:define_method, :=~) do |*args|
206
+ raise NoMethodError, "undefined method '=~' for #{self.inspect}"
207
+ end
208
+ end
209
+
210
+ assert_true(@pe.ping6('::1'))
211
+ assert_nil(@pe.exception)
212
+ ensure
213
+ Open3.singleton_class.send(:define_method, :popen3, popen3) if popen3
214
+ if nil_match
215
+ NilClass.send(:define_method, :=~, nil_match)
216
+ else
217
+ NilClass.send(:remove_method, :=~)
218
+ end
219
+ if false_match
220
+ FalseClass.send(:define_method, :=~, false_match)
221
+ else
222
+ FalseClass.send(:remove_method, :=~)
223
+ end
224
+ end
225
+
137
226
  def teardown
138
227
  @host = nil
139
228
  @bogus = nil
@@ -0,0 +1,333 @@
1
+ require 'open3'
2
+ require 'rake'
3
+ require 'rubygems/package'
4
+ require 'test/unit'
5
+
6
+ class TestNetPingGemPackaging < Test::Unit::TestCase
7
+ GemfileRecorder = Struct.new(:dependencies) do
8
+ def initialize
9
+ super({})
10
+ end
11
+
12
+ def source(*); end
13
+ def gemspec(*); end
14
+
15
+ def gem(name, *requirements)
16
+ dependencies[name] = requirements
17
+ end
18
+ end
19
+
20
+ EXPECTATIONS = {
21
+ 'net-ping.gemspec' => ['ruby', {}],
22
+ 'net-ping-universal-linux.gemspec' => ['universal-linux', {'cap2' => '>= 0.2.2'}],
23
+ 'net-ping-universal-mingw-ucrt.gemspec' => [
24
+ 'universal-mingw-ucrt',
25
+ {'win32-security' => '>= 0.2.0', 'win32ole' => '>= 1.8.8'}
26
+ ]
27
+ }.freeze
28
+ ROOT = File.expand_path('..', __dir__)
29
+
30
+ def test_platforms_and_runtime_dependencies
31
+ gem_files = nil
32
+ specifications = load_specifications
33
+
34
+ Dir.chdir(ROOT) do
35
+ gem_files = specifications.map { |_, spec| Gem::Package.build(spec) }
36
+ end
37
+
38
+ specifications.each do |path, spec|
39
+ expected_platform, expected_dependencies = EXPECTATIONS.fetch(path)
40
+ packaged_spec = Gem::Package.new(File.join(ROOT, spec.file_name)).spec
41
+ dependencies = packaged_spec.runtime_dependencies.each_with_object({}) do |dependency, memo|
42
+ memo[dependency.name] = dependency.requirement.to_s
43
+ end
44
+
45
+ assert_equal(expected_dependencies, dependencies, path)
46
+
47
+ if platform_round_trips_for_test?(expected_platform)
48
+ assert_equal(expected_platform, packaged_spec.platform.to_s, path)
49
+ else
50
+ omit("this RubyGems (#{Gem::VERSION}) cannot round-trip the #{expected_platform.inspect} platform string")
51
+ end
52
+ end
53
+ ensure
54
+ delete_files(gem_files)
55
+ end
56
+
57
+ def test_rake_create_builds_all_expected_artifacts_and_validates_them
58
+ stdout, stderr, status = run_rake('clean', 'gem:create', 'gem:check')
59
+
60
+ assert(status.success?, [stdout, stderr].join)
61
+ assert_equal(expected_gem_files, built_gem_files)
62
+ ensure
63
+ delete_files(built_gem_files)
64
+ end
65
+
66
+ def test_gem_create_excludes_generated_artifacts_from_spec_files_and_keeps_bundle_exec_usable
67
+ stdout, stderr, status = run_rake('clean', 'gem:create')
68
+
69
+ assert(status.success?, [stdout, stderr].join)
70
+ load_specifications.each do |path, spec|
71
+ assert_equal([], spec.files.grep(/\.gem$/).sort, path)
72
+ end
73
+
74
+ stdout, stderr, status = run_bundle_exec('ruby', '-e', 'puts :bundle_exec_after_gem_create')
75
+ assert(status.success?, [stdout, stderr].join)
76
+ assert_equal("bundle_exec_after_gem_create\n", stdout)
77
+ ensure
78
+ delete_files(built_gem_files)
79
+ end
80
+
81
+ def test_gem_check_uses_fixed_expectations_instead_of_loaded_specifications
82
+ stdout, stderr, status = run_rake('clean', 'gem:create')
83
+
84
+ assert(status.success?, [stdout, stderr].join)
85
+
86
+ specifications = load_specifications.map do |path, spec|
87
+ if path == 'net-ping-universal-linux.gemspec'
88
+ [path, specification_with_reported_platform(spec, Gem::Platform::RUBY)]
89
+ else
90
+ [path, spec]
91
+ end
92
+ end
93
+
94
+ with_rakefile do |application|
95
+ with_stubbed_load_gem_specifications(specifications.map(&:last)) do
96
+ assert_nothing_raised { application['gem:check'].invoke }
97
+ end
98
+ end
99
+ ensure
100
+ delete_files(built_gem_files)
101
+ end
102
+
103
+ def test_gem_install_selects_local_compatible_specification
104
+ with_rakefile do
105
+ assert_equal(expected_install_platform, select_install_specification.platform.to_s)
106
+ end
107
+ end
108
+
109
+ def test_gemfile_adds_win32_security_only_for_windows_development
110
+ assert_nil(gemfile_dependencies_for(win_platform: false)['win32-security'])
111
+ assert_equal(
112
+ ['>= 0.2.0'],
113
+ gemfile_dependencies_for(win_platform: true)['win32-security']
114
+ )
115
+ end
116
+
117
+ def test_with_unbundled_env_prefers_with_unbundled_env_when_available
118
+ calls = []
119
+
120
+ with_rakefile do
121
+ with_stubbed_bundler_methods(
122
+ :with_unbundled_env => proc do |&block|
123
+ calls << :with_unbundled_env
124
+ block.call
125
+ end,
126
+ :with_clean_env => proc do |&block|
127
+ calls << :with_clean_env
128
+ block.call
129
+ end
130
+ ) do
131
+ assert_equal(:ran, with_unbundled_env { calls << :block; :ran })
132
+ end
133
+ end
134
+
135
+ assert_equal([:with_unbundled_env, :block], calls)
136
+ end
137
+
138
+ def test_with_unbundled_env_falls_back_to_with_clean_env
139
+ calls = []
140
+
141
+ with_rakefile do
142
+ with_stubbed_bundler_methods(
143
+ :with_clean_env => proc do |&block|
144
+ calls << :with_clean_env
145
+ block.call
146
+ end
147
+ ) do
148
+ assert_equal(:ran, with_unbundled_env { calls << :block; :ran })
149
+ end
150
+ end
151
+
152
+ assert_equal([:with_clean_env, :block], calls)
153
+ end
154
+
155
+ def test_platform_installable_prefers_installable_when_available
156
+ spec = Struct.new(:platform).new(:preferred_platform)
157
+ calls = []
158
+
159
+ with_rakefile do
160
+ with_stubbed_platform_methods(
161
+ :installable? => proc do |candidate|
162
+ calls << [:installable?, candidate.platform]
163
+ true
164
+ end,
165
+ :match => proc do |platform|
166
+ calls << [:match, platform]
167
+ false
168
+ end
169
+ ) do
170
+ assert_equal(true, platform_installable?(spec))
171
+ end
172
+ end
173
+
174
+ assert_equal([[:installable?, :preferred_platform]], calls)
175
+ end
176
+
177
+ def test_platform_installable_falls_back_to_match
178
+ spec = Struct.new(:platform).new(:fallback_platform)
179
+ calls = []
180
+
181
+ with_rakefile do
182
+ with_stubbed_platform_methods(
183
+ :match => proc do |platform|
184
+ calls << [:match, platform]
185
+ true
186
+ end
187
+ ) do
188
+ assert_equal(true, platform_installable?(spec))
189
+ end
190
+ end
191
+
192
+ assert_equal([[:match, :fallback_platform]], calls)
193
+ end
194
+
195
+ private
196
+
197
+ def load_specifications
198
+ Dir.chdir(ROOT) do
199
+ EXPECTATIONS.keys.map do |path|
200
+ assert(File.exist?(path), "#{path} does not exist")
201
+
202
+ loaded_spec = Gem::Specification.load(path)
203
+ spec = loaded_spec ? loaded_spec.dup : nil
204
+ assert_not_nil(spec, "expected #{path} to load")
205
+
206
+ [path, spec]
207
+ end
208
+ end
209
+ end
210
+
211
+ def expected_gem_files
212
+ load_specifications.map { |_, spec| spec.file_name }.sort
213
+ end
214
+
215
+ def built_gem_files
216
+ Dir.chdir(ROOT) { Dir['net-ping-*.gem'].sort }
217
+ end
218
+
219
+ def expected_install_platform
220
+ specifications = load_specifications.map(&:last)
221
+ specific = specifications.find do |spec|
222
+ spec.platform != Gem::Platform::RUBY && platform_installable_for_test?(spec)
223
+ end
224
+ (specific || specifications.find { |spec| spec.platform == Gem::Platform::RUBY }).platform.to_s
225
+ end
226
+
227
+ def run_rake(*tasks, env: {})
228
+ Open3.capture3(env, Gem.ruby, '-S', 'bundle', 'exec', 'rake', *tasks, chdir: ROOT)
229
+ end
230
+
231
+ def run_bundle_exec(*command, env: {})
232
+ Open3.capture3(env, Gem.ruby, '-S', 'bundle', 'exec', *command, chdir: ROOT)
233
+ end
234
+
235
+ def with_rakefile
236
+ original = Rake.application
237
+ application = Rake::Application.new
238
+ Rake.application = application
239
+
240
+ Dir.chdir(ROOT) do
241
+ load File.join(ROOT, 'Rakefile')
242
+ yield(application)
243
+ end
244
+ ensure
245
+ Rake.application = original
246
+ end
247
+
248
+ def gemfile_dependencies_for(win_platform:)
249
+ recorder = GemfileRecorder.new
250
+ singleton_class = class << Gem; self; end
251
+ original = singleton_class.instance_method(:win_platform?)
252
+ singleton_class.send(:define_method, :win_platform?) { win_platform }
253
+ recorder.instance_eval(File.read(File.join(ROOT, 'Gemfile')), File.join(ROOT, 'Gemfile'))
254
+
255
+ recorder.dependencies
256
+ ensure
257
+ singleton_class.send(:define_method, :win_platform?, original) if singleton_class && original
258
+ end
259
+
260
+ def delete_files(paths)
261
+ Array(paths).each do |path|
262
+ file = File.join(ROOT, path)
263
+ File.delete(file) if File.exist?(file)
264
+ end
265
+ end
266
+
267
+ def specification_with_reported_platform(spec, platform)
268
+ file_name = spec.file_name
269
+ mutated = spec.dup
270
+ mutated.platform = platform
271
+ mutated.define_singleton_method(:file_name) { file_name }
272
+ mutated
273
+ end
274
+
275
+ def with_stubbed_load_gem_specifications(specifications)
276
+ original = Object.instance_method(:load_gem_specifications)
277
+ Object.send(:remove_method, :load_gem_specifications)
278
+ Object.send(:define_method, :load_gem_specifications) { specifications }
279
+ Object.send(:private, :load_gem_specifications)
280
+ yield
281
+ ensure
282
+ Object.send(:remove_method, :load_gem_specifications)
283
+ Object.send(:define_method, :load_gem_specifications, original)
284
+ Object.send(:private, :load_gem_specifications)
285
+ end
286
+
287
+ def with_stubbed_bundler_methods(methods)
288
+ bundler = Module.new
289
+ methods.each do |name, implementation|
290
+ bundler.define_singleton_method(name, &implementation)
291
+ end
292
+
293
+ with_replaced_constant(Object, :Bundler, bundler) do
294
+ yield
295
+ end
296
+ end
297
+
298
+ def with_stubbed_platform_methods(methods)
299
+ platform = Module.new
300
+ methods.each do |name, implementation|
301
+ platform.define_singleton_method(name, &implementation)
302
+ end
303
+ platform.const_set(:RUBY, Gem::Platform::RUBY)
304
+
305
+ with_replaced_constant(Gem, :Platform, platform) do
306
+ yield
307
+ end
308
+ end
309
+
310
+ def with_replaced_constant(container, name, replacement)
311
+ original = container.const_get(name) if container.const_defined?(name, false)
312
+ container.send(:remove_const, name) if container.const_defined?(name, false)
313
+ container.const_set(name, replacement)
314
+ yield
315
+ ensure
316
+ container.send(:remove_const, name) if container.const_defined?(name, false)
317
+ if original
318
+ container.const_set(name, original)
319
+ end
320
+ end
321
+
322
+ def platform_round_trips_for_test?(platform_string)
323
+ Gem::Platform.new(platform_string).to_s == platform_string
324
+ end
325
+
326
+ def platform_installable_for_test?(spec)
327
+ if Gem::Platform.respond_to?(:installable?)
328
+ Gem::Platform.installable?(spec)
329
+ else
330
+ Gem::Platform.match(spec.platform)
331
+ end
332
+ end
333
+ end