Class Gem::TestCase
In: lib/rubygems/test_case.rb
Parent: MiniTest::Unit::TestCase

RubyGemTestCase provides a variety of methods for testing rubygems and gem-related behavior in a sandbox. Through RubyGemTestCase you can install and uninstall gems, fetch remote gems through a stub fetcher and be assured your normal set of gems is not affected.

Tests are always run at a safe level of 1.

Methods

Included Modules

Gem::DefaultUserInteraction

Public Class methods

Returns the make command for the current platform. For versions of Ruby built on MS Windows with VC++ or Borland it will return ‘nmake’. On all other platforms, including Cygwin, it will return ‘make’.

[Source]

     # File lib/rubygems/test_case.rb, line 613
613:   def self.make_command
614:     ENV["make"] || (vc_windows? ? 'nmake' : 'make')
615:   end

Allows tests to use a random (but controlled) port number instead of a hardcoded one. This helps CI tools when running parallels builds on the same builder slave.

[Source]

     # File lib/rubygems/test_case.rb, line 638
638:   def self.process_based_port
639:     @@process_based_port ||= 8000 + $$ % 1000
640:   end

Finds the path to the ruby executable

[Source]

     # File lib/rubygems/test_case.rb, line 670
670:   def self.rubybin
671:     ruby = ENV["RUBY"]
672:     return ruby if ruby
673:     ruby = "ruby"
674:     rubyexe = "#{ruby}.exe"
675: 
676:     3.times do
677:       if File.exist? ruby and File.executable? ruby and !File.directory? ruby
678:         return File.expand_path(ruby)
679:       end
680:       if File.exist? rubyexe and File.executable? rubyexe
681:         return File.expand_path(rubyexe)
682:       end
683:       ruby = File.join("..", ruby)
684:     end
685: 
686:     begin
687:       require "rbconfig"
688:       File.join(RbConfig::CONFIG["bindir"],
689:                 RbConfig::CONFIG["ruby_install_name"] +
690:                 RbConfig::CONFIG["EXEEXT"])
691:     rescue LoadError
692:       "ruby"
693:     end
694:   end

Returns whether or not we‘re on a version of Ruby built with VC++ (or Borland) versus Cygwin, Mingw, etc.

[Source]

     # File lib/rubygems/test_case.rb, line 596
596:   def self.vc_windows?
597:     RUBY_PLATFORM.match('mswin')
598:   end

Is this test being run on a Windows platform?

[Source]

     # File lib/rubygems/test_case.rb, line 581
581:   def self.win_platform?
582:     Gem.win_platform?
583:   end

Public Instance methods

Allows the proper version of rake to be used for the test.

[Source]

     # File lib/rubygems/test_case.rb, line 652
652:   def build_rake_in
653:     gem_ruby = Gem.ruby
654:     Gem.ruby = @@ruby
655:     env_rake = ENV["rake"]
656:     ENV["rake"] = @@rake
657:     yield @@rake
658:   ensure
659:     Gem.ruby = gem_ruby
660:     if env_rake
661:       ENV["rake"] = env_rake
662:     else
663:       ENV.delete("rake")
664:     end
665:   end

Construct a new Gem::Dependency.

[Source]

     # File lib/rubygems/test_case.rb, line 710
710:   def dep name, *requirements
711:     Gem::Dependency.new name, *requirements
712:   end

Builds and installs the Gem::Specification spec

[Source]

     # File lib/rubygems/test_case.rb, line 231
231:   def install_gem spec
232:     require 'rubygems/installer'
233: 
234:     use_ui Gem::MockGemUi.new do
235:       Dir.chdir @tempdir do
236:         Gem::Builder.new(spec).build
237:       end
238:     end
239: 
240:     gem = File.join(@tempdir, spec.file_name).untaint
241: 
242:     Gem::Installer.new(gem, :wrappers => true).install
243:   end

Returns the make command for the current platform. For versions of Ruby built on MS Windows with VC++ or Borland it will return ‘nmake’. On all other platforms, including Cygwin, it will return ‘make’.

[Source]

     # File lib/rubygems/test_case.rb, line 622
622:   def make_command
623:     ENV["make"] || (vc_windows? ? 'nmake' : 'make')
624:   end

Enables pretty-print for all tests

[Source]

     # File lib/rubygems/test_case.rb, line 258
258:   def mu_pp(obj)
259:     s = ''
260:     s = PP.pp obj, s
261:     s = s.force_encoding(Encoding.default_external) if defined? Encoding
262:     s.chomp
263:   end

Returns whether or not the nmake command could be found.

[Source]

     # File lib/rubygems/test_case.rb, line 629
629:   def nmake_found?
630:     system('nmake /? 1>NUL 2>&1')
631:   end

See ::process_based_port

[Source]

     # File lib/rubygems/test_case.rb, line 645
645:   def process_based_port
646:     self.class.process_based_port
647:   end

Creates a Gem::Specification with a minimum of extra work. name and version are the gem‘s name and version, platform, author, email, homepage, summary and description are defaulted. The specification is yielded for customization.

The gem is added to the installed gems in +@gemhome+ and to the current source_index.

Use this with write_file to build an installed gem.

[Source]

     # File lib/rubygems/test_case.rb, line 307
307:   def quick_gem(name, version='2')
308:     require 'rubygems/specification'
309: 
310:     spec = Gem::Specification.new do |s|
311:       s.platform = Gem::Platform::RUBY
312:       s.name = name
313:       s.version = version
314:       s.author = 'A User'
315:       s.email = 'example@example.com'
316:       s.homepage = 'http://example.com'
317:       s.has_rdoc = true
318:       s.summary = "this is a summary"
319:       s.description = "This is a test description"
320: 
321:       yield(s) if block_given?
322:     end
323: 
324:     path = File.join "specifications", spec.spec_name
325:     written_path = write_file path do |io|
326:       io.write(spec.to_ruby)
327:     end
328: 
329:     spec.loaded_from = written_path
330: 
331:     Gem.source_index.add_spec spec
332: 
333:     return spec
334:   end

Reads a binary file at path

[Source]

     # File lib/rubygems/test_case.rb, line 277
277:   def read_binary(path)
278:     Gem.read_binary path
279:   end

Reads a Marshal file at path

[Source]

     # File lib/rubygems/test_case.rb, line 268
268:   def read_cache(path)
269:     open path.dup.untaint, 'rb' do |io|
270:       Marshal.load io.read
271:     end
272:   end

Constructs a new Gem::Requirement.

[Source]

     # File lib/rubygems/test_case.rb, line 717
717:   def req *requirements
718:     return requirements.first if Gem::Requirement === requirements.first
719:     Gem::Requirement.create requirements
720:   end

setup prepares a sandboxed location to install gems. All installs are directed to a temporary directory. All install plugins are removed.

If the RUBY environment variable is set the given path is used for Gem::ruby. The local platform is set to i386-mswin32 for Windows or i686-darwin8.10.1 otherwise.

If the KEEP_FILES environment variable is set the files will not be removed from /tmp/test_rubygems_#{$$}.#{Time.now.to_i}.

[Source]

     # File lib/rubygems/test_case.rb, line 102
102:   def setup
103:     super
104: 
105:     @orig_gem_home = ENV['GEM_HOME']
106:     @orig_gem_path = ENV['GEM_PATH']
107: 
108:     @ui = Gem::MockGemUi.new
109:     tmpdir = nil
110:     Dir.chdir Dir.tmpdir do tmpdir = Dir.pwd end # HACK OSX /private/tmp
111:     if ENV['KEEP_FILES'] then
112:       @tempdir = File.join tmpdir, "test_rubygems_#{$$}.#{Time.now.to_i}"
113:     else
114:       @tempdir = File.join tmpdir, "test_rubygems_#{$$}"
115:     end
116:     @tempdir.untaint
117:     @gemhome  = File.join @tempdir, 'gemhome'
118:     @userhome = File.join @tempdir, 'userhome'
119: 
120:     Gem.ensure_gem_subdirectories @gemhome
121: 
122:     @orig_ruby = if ruby = ENV['RUBY'] then
123:                    Gem.class_eval { ruby, @ruby = @ruby, ruby }
124:                    ruby
125:                  end
126: 
127:     Gem.ensure_gem_subdirectories @gemhome
128: 
129:     @orig_ENV_HOME = ENV['HOME']
130:     ENV['HOME'] = @userhome
131:     Gem.instance_variable_set :@user_home, nil
132: 
133:     FileUtils.mkdir_p @gemhome
134:     FileUtils.mkdir_p @userhome
135: 
136:     Gem.use_paths(@gemhome)
137:     Gem.loaded_specs.clear
138: 
139:     Gem.configuration.verbose = true
140:     Gem.configuration.update_sources = true
141: 
142:     @gem_repo = "http://gems.example.com/"
143:     @uri = URI.parse @gem_repo
144:     Gem.sources.replace [@gem_repo]
145: 
146:     Gem::SpecFetcher.fetcher = nil
147: 
148:     @orig_BASERUBY = Gem::ConfigMap[:BASERUBY]
149:     Gem::ConfigMap[:BASERUBY] = Gem::ConfigMap[:ruby_install_name]
150: 
151:     @orig_arch = Gem::ConfigMap[:arch]
152: 
153:     if win_platform?
154:       util_set_arch 'i386-mswin32'
155:     else
156:       util_set_arch 'i686-darwin8.10.1'
157:     end
158: 
159:     @marshal_version = "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
160: 
161:     @private_key = File.expand_path('../../../test/rubygems/private_key.pem',
162:                                     __FILE__)
163:     @public_cert = File.expand_path('../../../test/rubygems/public_cert.pem',
164:                                     __FILE__)
165: 
166:     Gem.post_build_hooks.clear
167:     Gem.post_install_hooks.clear
168:     Gem.post_uninstall_hooks.clear
169:     Gem.pre_install_hooks.clear
170:     Gem.pre_uninstall_hooks.clear
171: 
172:     Gem.post_build do |installer|
173:       @post_build_hook_arg = installer
174:       true
175:     end
176: 
177:     Gem.post_install do |installer|
178:       @post_install_hook_arg = installer
179:     end
180: 
181:     Gem.post_uninstall do |uninstaller|
182:       @post_uninstall_hook_arg = uninstaller
183:     end
184: 
185:     Gem.pre_install do |installer|
186:       @pre_install_hook_arg = installer
187:       true
188:     end
189: 
190:     Gem.pre_uninstall do |uninstaller|
191:       @pre_uninstall_hook_arg = uninstaller
192:     end
193: 
194:     @orig_LOAD_PATH = $LOAD_PATH.dup
195:   end

Constructs a new Gem::Specification.

[Source]

     # File lib/rubygems/test_case.rb, line 725
725:   def spec name, version, &block
726:     Gem::Specification.new name, v(version), &block
727:   end

teardown restores the process to its original state and removes the tempdir unless the KEEP_FILES environment variable was set.

[Source]

     # File lib/rubygems/test_case.rb, line 201
201:   def teardown
202:     $LOAD_PATH.replace @orig_LOAD_PATH
203: 
204:     Gem::ConfigMap[:BASERUBY] = @orig_BASERUBY
205:     Gem::ConfigMap[:arch] = @orig_arch
206: 
207:     if defined? Gem::RemoteFetcher then
208:       Gem::RemoteFetcher.fetcher = nil
209:     end
210: 
211:     FileUtils.rm_rf @tempdir unless ENV['KEEP_FILES']
212: 
213:     ENV['GEM_HOME'] = @orig_gem_home
214:     ENV['GEM_PATH'] = @orig_gem_path
215: 
216:     Gem.clear_paths
217: 
218:     _ = @orig_ruby
219:     Gem.class_eval { @ruby = _ } if _
220: 
221:     if @orig_ENV_HOME then
222:       ENV['HOME'] = @orig_ENV_HOME
223:     else
224:       ENV.delete 'HOME'
225:     end
226:   end

Uninstalls the Gem::Specification spec

[Source]

     # File lib/rubygems/test_case.rb, line 247
247:   def uninstall_gem spec
248:     require 'rubygems/uninstaller'
249: 
250:     uninstaller = Gem::Uninstaller.new spec.name, :executables => true,
251:                  :user_install => true
252:     uninstaller.uninstall
253:   end

Builds a gem from spec and places it in File.join @gemhome, ‘cache‘. Automatically creates files based on +spec.files+

[Source]

     # File lib/rubygems/test_case.rb, line 340
340:   def util_build_gem(spec)
341:     dir = File.join(@gemhome, 'gems', spec.full_name)
342:     FileUtils.mkdir_p dir
343: 
344:     Dir.chdir dir do
345:       spec.files.each do |file|
346:         next if File.exist? file
347:         FileUtils.mkdir_p File.dirname(file)
348:         File.open file, 'w' do |fp| fp.puts "# #{file}" end
349:       end
350: 
351:       use_ui Gem::MockGemUi.new do
352:         Gem::Builder.new(spec).build
353:       end
354: 
355:       FileUtils.mv spec.file_name,
356:                    File.join(@gemhome, 'cache', "#{spec.original_name}.gem")
357:     end
358:   end

Removes all installed gems from +@gemhome+.

[Source]

     # File lib/rubygems/test_case.rb, line 363
363:   def util_clear_gems
364:     FileUtils.rm_r File.join(@gemhome, 'gems')
365:     FileUtils.rm_r File.join(@gemhome, 'specifications')
366:     Gem.source_index.refresh!
367:   end

Creates a gem with name, version and deps. The specification will be yielded before gem creation for customization. The gem will be placed in File.join @tempdir, ‘gems‘. The specification and .gem file location are returned.

[Source]

     # File lib/rubygems/test_case.rb, line 375
375:   def util_gem(name, version, deps = nil, &block)
376:     if deps then
377:       block = proc do |s|
378:         deps.each do |n, req|
379:           s.add_dependency n, (req || '>= 0')
380:         end
381:       end
382:     end
383: 
384:     spec = quick_gem(name, version, &block)
385: 
386:     util_build_gem spec
387: 
388:     cache_file = File.join @tempdir, 'gems', "#{spec.original_name}.gem"
389:     FileUtils.mv File.join(@gemhome, 'cache', "#{spec.original_name}.gem"),
390:                  cache_file
391:     FileUtils.rm File.join(@gemhome, 'specifications', spec.spec_name)
392: 
393:     spec.loaded_from = nil
394:     spec.loaded = false
395: 
396:     [spec, cache_file]
397:   end

Gzips data.

[Source]

     # File lib/rubygems/test_case.rb, line 402
402:   def util_gzip(data)
403:     out = StringIO.new
404: 
405:     Zlib::GzipWriter.wrap out do |io|
406:       io.write data
407:     end
408: 
409:     out.string
410:   end

Creates several default gems which all have a lib/code.rb file. The gems are not installed but are available in the cache dir.

+@a1+:gem a version 1, this is the best-described gem.
+@a2+:gem a version 2
+@a3a:gem a version 3.a
+@a_evil9+:gem a_evil version 9, use this to ensure similarly-named gems don‘t collide with a.
+@b2+:gem b version 2
+@c1_2+:gem c version 1.2
+@pl1+:gem pl version 1, this gem has a legacy platform of i386-linux.

Additional prerelease gems may also be created:

+@a2_pre+:gem a version 2.a

TODO: nuke this and fix tests. this should speed up a lot

[Source]

     # File lib/rubygems/test_case.rb, line 430
430:   def util_make_gems(prerelease = false)
431:     @a1 = quick_gem 'a', '1' do |s|
432:       s.files = %w[lib/code.rb]
433:       s.require_paths = %w[lib]
434:       s.date = Gem::Specification::TODAY - 86400
435:       s.homepage = 'http://a.example.com'
436:       s.email = %w[example@example.com example2@example.com]
437:       s.authors = %w[Example Example2]
438:       s.description = "This line is really, really long.  So long, in fact, that it is more than eighty characters long!  The purpose of this line is for testing wrapping behavior because sometimes people don't wrap their text to eighty characters.  Without the wrapping, the text might not look good in the RSS feed.\n\nAlso, a list:\n* An entry that's actually kind of sort\n* an entry that's really long, which will probably get wrapped funny.  That's ok, somebody wasn't thinking straight when they made it more than eighty characters.\n"
439:     end
440: 
441:     init = proc do |s|
442:       s.files = %w[lib/code.rb]
443:       s.require_paths = %w[lib]
444:     end
445: 
446:     @a2      = quick_gem('a', '2',      &init)
447:     @a3a     = quick_gem('a', '3.a',    &init)
448:     @a_evil9 = quick_gem('a_evil', '9', &init)
449:     @b2      = quick_gem('b', '2',      &init)
450:     @c1_2    = quick_gem('c', '1.2',    &init)
451: 
452:     @pl1     = quick_gem 'pl', '1' do |s| # l for legacy
453:       s.files = %w[lib/code.rb]
454:       s.require_paths = %w[lib]
455:       s.platform = Gem::Platform.new 'i386-linux'
456:       s.instance_variable_set :@original_platform, 'i386-linux'
457:     end
458: 
459:     if prerelease
460:       @a2_pre = quick_gem('a', '2.a', &init)
461:       write_file File.join(*??[gems #{@a2_pre.original_name} lib code.rb])
462:       util_build_gem @a2_pre
463:     end
464: 
465:     write_file File.join(*??[gems #{@a1.original_name}   lib code.rb])
466:     write_file File.join(*??[gems #{@a2.original_name}   lib code.rb])
467:     write_file File.join(*??[gems #{@a3a.original_name}  lib code.rb])
468:     write_file File.join(*??[gems #{@b2.original_name}   lib code.rb])
469:     write_file File.join(*??[gems #{@c1_2.original_name} lib code.rb])
470:     write_file File.join(*??[gems #{@pl1.original_name}  lib code.rb])
471: 
472:     [@a1, @a2, @a3a, @a_evil9, @b2, @c1_2, @pl1].each do |spec|
473:       util_build_gem spec
474:     end
475: 
476:     FileUtils.rm_r File.join(@gemhome, 'gems', @pl1.original_name)
477: 
478:     Gem.source_index = nil
479:   end

Set the platform to arch

[Source]

     # File lib/rubygems/test_case.rb, line 491
491:   def util_set_arch(arch)
492:     Gem::ConfigMap[:arch] = arch
493:     platform = Gem::Platform.new arch
494: 
495:     Gem.instance_variable_set :@platforms, nil
496:     Gem::Platform.instance_variable_set :@local, nil
497: 
498:     platform
499:   end

Sets up a fake fetcher using the gems from util_make_gems. Optionally additional prerelease gems may be included.

Gems created by this method may be fetched using Gem::RemoteFetcher.

[Source]

     # File lib/rubygems/test_case.rb, line 507
507:   def util_setup_fake_fetcher(prerelease = false)
508:     require 'zlib'
509:     require 'socket'
510:     require 'rubygems/remote_fetcher'
511: 
512:     @fetcher = Gem::FakeFetcher.new
513: 
514:     util_make_gems(prerelease)
515: 
516:     @all_gems = [@a1, @a2, @a3a, @a_evil9, @b2, @c1_2].sort
517:     @all_gem_names = @all_gems.map { |gem| gem.full_name }
518: 
519:     gem_names = [@a1.full_name, @a2.full_name, @a3a.full_name, @b2.full_name]
520:     @gem_names = gem_names.sort.join("\n")
521: 
522:     @source_index = Gem::SourceIndex.new
523:     @source_index.add_spec @a1
524:     @source_index.add_spec @a2
525:     @source_index.add_spec @a3a
526:     @source_index.add_spec @a_evil9
527:     @source_index.add_spec @c1_2
528:     @source_index.add_spec @a2_pre if prerelease
529: 
530:     Gem::RemoteFetcher.fetcher = @fetcher
531:   end

Sets up Gem::SpecFetcher to return information from the gems in specs. Best used with +@all_gems+ from util_setup_fake_fetcher.

[Source]

     # File lib/rubygems/test_case.rb, line 537
537:   def util_setup_spec_fetcher(*specs)
538:     specs = Hash[*specs.map { |spec| [spec.full_name, spec] }.flatten]
539:     si = Gem::SourceIndex.new specs
540: 
541:     spec_fetcher = Gem::SpecFetcher.fetcher
542: 
543:     spec_fetcher.specs[@uri] = []
544:     si.gems.sort_by { |_, spec| spec }.each do |_, spec|
545:       spec_tuple = [spec.name, spec.version, spec.original_platform]
546:       spec_fetcher.specs[@uri] << spec_tuple
547:     end
548: 
549:     spec_fetcher.latest_specs[@uri] = []
550:     si.latest_specs.sort.each do |spec|
551:       spec_tuple = [spec.name, spec.version, spec.original_platform]
552:       spec_fetcher.latest_specs[@uri] << spec_tuple
553:     end
554: 
555:     spec_fetcher.prerelease_specs[@uri] = []
556:     si.prerelease_specs.sort.each do |spec|
557:       spec_tuple = [spec.name, spec.version, spec.original_platform]
558:       spec_fetcher.prerelease_specs[@uri] << spec_tuple
559:     end
560: 
561:     (si.gems.merge si.prerelease_gems).sort_by { |_,spec| spec }.each do |_, spec|
562:       path = "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{spec.original_name}.gemspec.rz"
563:       data = Marshal.dump spec
564:       data_deflate = Zlib::Deflate.deflate data
565:       @fetcher.data[path] = data_deflate
566:     end
567: 
568:     si
569:   end

Deflates data

[Source]

     # File lib/rubygems/test_case.rb, line 574
574:   def util_zip(data)
575:     Zlib::Deflate.deflate data
576:   end

Construct a new Gem::Version.

[Source]

     # File lib/rubygems/test_case.rb, line 732
732:   def v string
733:     Gem::Version.create string
734:   end

Returns whether or not we‘re on a version of Ruby built with VC++ (or Borland) versus Cygwin, Mingw, etc.

[Source]

     # File lib/rubygems/test_case.rb, line 604
604:   def vc_windows?
605:     RUBY_PLATFORM.match('mswin')
606:   end

Is this test being run on a Windows platform?

[Source]

     # File lib/rubygems/test_case.rb, line 588
588:   def win_platform?
589:     Gem.win_platform?
590:   end

Writes a binary file to path which is relative to +@gemhome+

[Source]

     # File lib/rubygems/test_case.rb, line 284
284:   def write_file(path)
285:     path = File.join @gemhome, path
286:     dir = File.dirname path
287:     FileUtils.mkdir_p dir
288: 
289:     open path, 'wb' do |io|
290:       yield io if block_given?
291:     end
292: 
293:     path
294:   end

[Validate]