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 683
683:   def self.make_command
684:     ENV["make"] || (vc_windows? ? 'nmake' : 'make')
685:   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 708
708:   def self.process_based_port
709:     @@process_based_port ||= 8000 + $$ % 1000
710:   end

Finds the path to the ruby executable

[Source]

     # File lib/rubygems/test_case.rb, line 740
740:   def self.rubybin
741:     ruby = ENV["RUBY"]
742:     return ruby if ruby
743:     ruby = "ruby"
744:     rubyexe = "#{ruby}.exe"
745: 
746:     3.times do
747:       if File.exist? ruby and File.executable? ruby and !File.directory? ruby
748:         return File.expand_path(ruby)
749:       end
750:       if File.exist? rubyexe and File.executable? rubyexe
751:         return File.expand_path(rubyexe)
752:       end
753:       ruby = File.join("..", ruby)
754:     end
755: 
756:     begin
757:       require "rbconfig"
758:       File.join(RbConfig::CONFIG["bindir"],
759:                 RbConfig::CONFIG["ruby_install_name"] +
760:                 RbConfig::CONFIG["EXEEXT"])
761:     rescue LoadError
762:       "ruby"
763:     end
764:   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 666
666:   def self.vc_windows?
667:     RUBY_PLATFORM.match('mswin')
668:   end

Is this test being run on a Windows platform?

[Source]

     # File lib/rubygems/test_case.rb, line 651
651:   def self.win_platform?
652:     Gem.win_platform?
653:   end

Public Instance methods

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

[Source]

     # File lib/rubygems/test_case.rb, line 722
722:   def build_rake_in
723:     gem_ruby = Gem.ruby
724:     Gem.ruby = @@ruby
725:     env_rake = ENV["rake"]
726:     ENV["rake"] = @@rake
727:     yield @@rake
728:   ensure
729:     Gem.ruby = gem_ruby
730:     if env_rake
731:       ENV["rake"] = env_rake
732:     else
733:       ENV.delete("rake")
734:     end
735:   end

Construct a new Gem::Dependency.

[Source]

     # File lib/rubygems/test_case.rb, line 780
780:   def dep name, *requirements
781:     Gem::Dependency.new name, *requirements
782:   end

Builds and installs the Gem::Specification spec

[Source]

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

Install the provided specs

[Source]

     # File lib/rubygems/test_case.rb, line 391
391:   def install_specs(*specs)
392:     specs.each do |spec|
393:       # TODO: inverted responsibility
394:       Gem.source_index.add_spec spec
395:     end
396:     Gem.searcher = nil
397:   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 692
692:   def make_command
693:     ENV["make"] || (vc_windows? ? 'nmake' : 'make')
694:   end

Enables pretty-print for all tests

[Source]

     # File lib/rubygems/test_case.rb, line 254
254:   def mu_pp(obj)
255:     s = ''
256:     s = PP.pp obj, s
257:     s = s.force_encoding(Encoding.default_external) if defined? Encoding
258:     s.chomp
259:   end

Create a new spec (or gem if passed an array of files) and set it up properly. Use this instead of util_spec and util_gem.

[Source]

     # File lib/rubygems/test_case.rb, line 403
403:   def new_spec name, version, deps = nil, *files
404:     # TODO: unfactor and deprecate util_gem and util_spec
405:     spec, = unless files.empty? then
406:               util_gem name, version do |s|
407:                 Array(deps).each do |n,v|
408:                   s.add_dependency n, v
409:                 end
410:                 s.files.push(*files)
411:               end
412:             else
413:               util_spec name, version, deps
414:             end
415:     spec.loaded_from = File.join @gemhome, 'specifications', spec.spec_name
416:     spec.loaded = false
417:     spec
418:   end

Returns whether or not the nmake command could be found.

[Source]

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

See ::process_based_port

[Source]

     # File lib/rubygems/test_case.rb, line 715
715:   def process_based_port
716:     self.class.process_based_port
717:   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 303
303:   def quick_gem(name, version='2')
304:     require 'rubygems/specification'
305: 
306:     spec = Gem::Specification.new do |s|
307:       s.platform    = Gem::Platform::RUBY
308:       s.name        = name
309:       s.version     = version
310:       s.author      = 'A User'
311:       s.email       = 'example@example.com'
312:       s.homepage    = 'http://example.com'
313:       s.summary     = "this is a summary"
314:       s.description = "This is a test description"
315: 
316:       yield(s) if block_given?
317:     end
318: 
319:     path = File.join "specifications", spec.spec_name
320:     written_path = write_file path do |io|
321:       io.write spec.to_ruby_for_cache
322:     end
323: 
324:     spec.loaded_from = spec.loaded_from = written_path
325: 
326:     Gem.source_index.add_spec spec.for_cache
327: 
328:     return spec
329:   end

[Source]

     # File lib/rubygems/test_case.rb, line 331
331:   def quick_spec name, version = '2'
332:     require 'rubygems/specification'
333: 
334:     spec = Gem::Specification.new do |s|
335:       s.platform    = Gem::Platform::RUBY
336:       s.name        = name
337:       s.version     = version
338:       s.author      = 'A User'
339:       s.email       = 'example@example.com'
340:       s.homepage    = 'http://example.com'
341:       s.summary     = "this is a summary"
342:       s.description = "This is a test description"
343: 
344:       yield(s) if block_given?
345:     end
346: 
347:     path = File.join @gemhome, "specifications", spec.spec_name
348:     spec.loaded_from = path
349: 
350:     Gem.source_index.add_spec spec
351: 
352:     return spec
353:   end

Reads a binary file at path

[Source]

     # File lib/rubygems/test_case.rb, line 273
273:   def read_binary(path)
274:     Gem.read_binary path
275:   end

Reads a Marshal file at path

[Source]

     # File lib/rubygems/test_case.rb, line 264
264:   def read_cache(path)
265:     open path.dup.untaint, 'rb' do |io|
266:       Marshal.load io.read
267:     end
268:   end

Constructs a new Gem::Requirement.

[Source]

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

Constructs a new Gem::Specification.

[Source]

     # File lib/rubygems/test_case.rb, line 795
795:   def spec name, version, &block
796:     Gem::Specification.new name, v(version), &block
797:   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 195
195:   def teardown
196:     $LOAD_PATH.replace @orig_LOAD_PATH
197: 
198:     Gem::ConfigMap[:BASERUBY] = @orig_BASERUBY
199:     Gem::ConfigMap[:arch] = @orig_arch
200: 
201:     if defined? Gem::RemoteFetcher then
202:       Gem::RemoteFetcher.fetcher = nil
203:     end
204: 
205:     Dir.chdir @@project_dir
206: 
207:     FileUtils.rm_rf @tempdir unless ENV['KEEP_FILES']
208: 
209:     ENV['GEM_HOME'] = @orig_gem_home
210:     ENV['GEM_PATH'] = @orig_gem_path
211: 
212:     Gem.clear_paths
213: 
214:     _ = @orig_ruby
215:     Gem.class_eval { @ruby = _ } if _
216: 
217:     if @orig_ENV_HOME then
218:       ENV['HOME'] = @orig_ENV_HOME
219:     else
220:       ENV.delete 'HOME'
221:     end
222:   end

Uninstalls the Gem::Specification spec

[Source]

     # File lib/rubygems/test_case.rb, line 243
243:   def uninstall_gem spec
244:     require 'rubygems/uninstaller'
245: 
246:     uninstaller = Gem::Uninstaller.new spec.name, :executables => true,
247:                  :user_install => true
248:     uninstaller.uninstall
249:   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 359
359:   def util_build_gem(spec)
360:     dir = File.join(@gemhome, 'gems', spec.full_name)
361:     FileUtils.mkdir_p dir
362: 
363:     Dir.chdir dir do
364:       spec.files.each do |file|
365:         next if File.exist? file
366:         FileUtils.mkdir_p File.dirname(file)
367:         File.open file, 'w' do |fp| fp.puts "# #{file}" end
368:       end
369: 
370:       use_ui Gem::MockGemUi.new do
371:         Gem::Builder.new(spec).build
372:       end
373: 
374:       FileUtils.mv spec.file_name,
375:                    Gem.cache_gem("#{spec.original_name}.gem")
376:     end
377:   end

Removes all installed gems from +@gemhome+.

[Source]

     # File lib/rubygems/test_case.rb, line 382
382:   def util_clear_gems
383:     FileUtils.rm_rf File.join(@gemhome, 'gems')
384:     FileUtils.rm_rf File.join(@gemhome, 'specifications')
385:     Gem.source_index.refresh!
386:   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 443
443:   def util_gem(name, version, deps = nil, &block)
444:     raise "deps or block, not both" if deps and block
445: 
446:     if deps then
447:       block = proc do |s|
448:         deps.each do |n, req|
449:           s.add_dependency n, (req || '>= 0')
450:         end
451:       end
452:     end
453: 
454:     spec = quick_gem(name, version, &block)
455: 
456:     util_build_gem spec
457: 
458:     cache_file = File.join @tempdir, 'gems', "#{spec.original_name}.gem"
459:     FileUtils.mkdir_p File.dirname cache_file
460:     FileUtils.mv Gem.cache_gem("#{spec.original_name}.gem"), cache_file
461:     FileUtils.rm File.join(@gemhome, 'specifications', spec.spec_name)
462: 
463:     spec.loaded_from = nil
464:     spec.loaded = false
465: 
466:     [spec, cache_file]
467:   end

Gzips data.

[Source]

     # File lib/rubygems/test_case.rb, line 472
472:   def util_gzip(data)
473:     out = StringIO.new
474: 
475:     Zlib::GzipWriter.wrap out do |io|
476:       io.write data
477:     end
478: 
479:     out.string
480:   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 500
500:   def util_make_gems(prerelease = false)
501:     @a1 = quick_gem 'a', '1' do |s|
502:       s.files = %w[lib/code.rb]
503:       s.require_paths = %w[lib]
504:       s.date = Gem::Specification::TODAY - 86400
505:       s.homepage = 'http://a.example.com'
506:       s.email = %w[example@example.com example2@example.com]
507:       s.authors = %w[Example Example2]
508:       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"
509:     end
510: 
511:     init = proc do |s|
512:       s.files = %w[lib/code.rb]
513:       s.require_paths = %w[lib]
514:     end
515: 
516:     @a2      = quick_gem('a', '2',      &init)
517:     @a3a     = quick_gem('a', '3.a',    &init)
518:     @a_evil9 = quick_gem('a_evil', '9', &init)
519:     @b2      = quick_gem('b', '2',      &init)
520:     @c1_2    = quick_gem('c', '1.2',    &init)
521: 
522:     @pl1     = quick_gem 'pl', '1' do |s| # l for legacy
523:       s.files = %w[lib/code.rb]
524:       s.require_paths = %w[lib]
525:       s.platform = Gem::Platform.new 'i386-linux'
526:       s.instance_variable_set :@original_platform, 'i386-linux'
527:     end
528: 
529:     if prerelease
530:       @a2_pre = quick_gem('a', '2.a', &init)
531:       write_file File.join(*??[gems #{@a2_pre.original_name} lib code.rb])
532:       util_build_gem @a2_pre
533:     end
534: 
535:     write_file File.join(*??[gems #{@a1.original_name}   lib code.rb])
536:     write_file File.join(*??[gems #{@a2.original_name}   lib code.rb])
537:     write_file File.join(*??[gems #{@a3a.original_name}  lib code.rb])
538:     write_file File.join(*??[gems #{@b2.original_name}   lib code.rb])
539:     write_file File.join(*??[gems #{@c1_2.original_name} lib code.rb])
540:     write_file File.join(*??[gems #{@pl1.original_name}  lib code.rb])
541: 
542:     [@a1, @a2, @a3a, @a_evil9, @b2, @c1_2, @pl1].each do |spec|
543:       util_build_gem spec
544:     end
545: 
546:     FileUtils.rm_r File.join(@gemhome, 'gems', @pl1.original_name)
547: 
548:     Gem.source_index = nil
549:   end

Set the platform to arch

[Source]

     # File lib/rubygems/test_case.rb, line 561
561:   def util_set_arch(arch)
562:     Gem::ConfigMap[:arch] = arch
563:     platform = Gem::Platform.new arch
564: 
565:     Gem.instance_variable_set :@platforms, nil
566:     Gem::Platform.instance_variable_set :@local, nil
567: 
568:     platform
569:   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 577
577:   def util_setup_fake_fetcher(prerelease = false)
578:     require 'zlib'
579:     require 'socket'
580:     require 'rubygems/remote_fetcher'
581: 
582:     @fetcher = Gem::FakeFetcher.new
583: 
584:     util_make_gems(prerelease)
585: 
586:     @all_gems = [@a1, @a2, @a3a, @a_evil9, @b2, @c1_2].sort
587:     @all_gem_names = @all_gems.map { |gem| gem.full_name }
588: 
589:     gem_names = [@a1.full_name, @a2.full_name, @a3a.full_name, @b2.full_name]
590:     @gem_names = gem_names.sort.join("\n")
591: 
592:     @source_index = Gem::SourceIndex.new
593:     @source_index.add_spec @a1
594:     @source_index.add_spec @a2
595:     @source_index.add_spec @a3a
596:     @source_index.add_spec @a_evil9
597:     @source_index.add_spec @c1_2
598:     @source_index.add_spec @a2_pre if prerelease
599: 
600:     Gem::RemoteFetcher.fetcher = @fetcher
601:   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 607
607:   def util_setup_spec_fetcher(*specs)
608:     si = Gem::SourceIndex.new
609:     si.add_specs(*specs)
610: 
611:     spec_fetcher = Gem::SpecFetcher.fetcher
612: 
613:     spec_fetcher.specs[@uri] = []
614:     si.gems.sort_by { |_, spec| spec }.each do |_, spec|
615:       spec_tuple = [spec.name, spec.version, spec.original_platform]
616:       spec_fetcher.specs[@uri] << spec_tuple
617:     end
618: 
619:     spec_fetcher.latest_specs[@uri] = []
620:     si.latest_specs.sort.each do |spec|
621:       spec_tuple = [spec.name, spec.version, spec.original_platform]
622:       spec_fetcher.latest_specs[@uri] << spec_tuple
623:     end
624: 
625:     spec_fetcher.prerelease_specs[@uri] = []
626:     si.prerelease_specs.sort.each do |spec|
627:       spec_tuple = [spec.name, spec.version, spec.original_platform]
628:       spec_fetcher.prerelease_specs[@uri] << spec_tuple
629:     end
630: 
631:     (si.gems.merge si.prerelease_gems).sort_by { |_,spec| spec }.each do |_, spec|
632:       path = "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{spec.original_name}.gemspec.rz"
633:       data = Marshal.dump spec
634:       data_deflate = Zlib::Deflate.deflate data
635:       @fetcher.data[path] = data_deflate
636:     end
637: 
638:     si
639:   end

Creates a spec with name, version and deps.

[Source]

     # File lib/rubygems/test_case.rb, line 423
423:   def util_spec(name, version, deps = nil, &block)
424:     raise "deps or block, not both" if deps and block
425: 
426:     if deps then
427:       block = proc do |s|
428:         deps.each do |n, req|
429:           s.add_dependency n, (req || '>= 0')
430:         end
431:       end
432:     end
433: 
434:     quick_spec(name, version, &block)
435:   end

Deflates data

[Source]

     # File lib/rubygems/test_case.rb, line 644
644:   def util_zip(data)
645:     Zlib::Deflate.deflate data
646:   end

Construct a new Gem::Version.

[Source]

     # File lib/rubygems/test_case.rb, line 802
802:   def v string
803:     Gem::Version.create string
804:   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 674
674:   def vc_windows?
675:     RUBY_PLATFORM.match('mswin')
676:   end

Is this test being run on a Windows platform?

[Source]

     # File lib/rubygems/test_case.rb, line 658
658:   def win_platform?
659:     Gem.win_platform?
660:   end

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

[Source]

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

[Validate]