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.
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’.
# 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.
# 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
# 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.
# 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?
# File lib/rubygems/test_case.rb, line 581 581: def self.win_platform? 582: Gem.win_platform? 583: end
Allows the proper version of rake to be used for the test.
# 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.
# 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
# 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’.
# 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
# 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.
# 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
# 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.
# 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
# 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
# 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.
# 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}.
# 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.
# 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.
# 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
# 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+
# 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+.
# 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.
# 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.
# 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
# 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
# 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.
# 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.
# 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
# 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.
# 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.
# 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?
# 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+
# 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