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