PageRenderTime 40ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/jruby-1.7.3/lib/ruby/1.9/test/unit.rb

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Ruby | 640 lines | 595 code | 44 blank | 1 comment | 22 complexity | 7d54de8896357ff24041e7a0adf8f17b MD5 | raw file
  1. # test/unit compatibility layer using minitest.
  2. require 'minitest/unit'
  3. require 'test/unit/assertions'
  4. require 'test/unit/testcase'
  5. require 'optparse'
  6. module Test
  7. module Unit
  8. TEST_UNIT_IMPLEMENTATION = 'test/unit compatibility layer using minitest'
  9. module RunCount
  10. @@run_count = 0
  11. def self.have_run?
  12. @@run_count.nonzero?
  13. end
  14. def run(*)
  15. @@run_count += 1
  16. super
  17. end
  18. def run_once
  19. return if have_run?
  20. return if $! # don't run if there was an exception
  21. yield
  22. end
  23. module_function :run_once
  24. end
  25. module Options
  26. def initialize(*, &block)
  27. @init_hook = block
  28. @options = nil
  29. super(&nil)
  30. end
  31. def option_parser
  32. @option_parser ||= OptionParser.new
  33. end
  34. def process_args(args = [])
  35. return @options if @options
  36. orig_args = args.dup
  37. options = {}
  38. opts = option_parser
  39. setup_options(opts, options)
  40. opts.parse!(args)
  41. orig_args -= args
  42. args = @init_hook.call(args, options) if @init_hook
  43. non_options(args, options)
  44. @help = orig_args.map { |s| s =~ /[\s|&<>$()]/ ? s.inspect : s }.join " "
  45. @options = options
  46. if @options[:parallel]
  47. @files = args
  48. @args = orig_args
  49. end
  50. options
  51. end
  52. private
  53. def setup_options(opts, options)
  54. opts.separator 'minitest options:'
  55. opts.version = MiniTest::Unit::VERSION
  56. opts.on '-h', '--help', 'Display this help.' do
  57. puts opts
  58. exit
  59. end
  60. opts.on '-s', '--seed SEED', Integer, "Sets random seed" do |m|
  61. options[:seed] = m
  62. end
  63. opts.on '-v', '--verbose', "Verbose. Show progress processing files." do
  64. options[:verbose] = true
  65. self.verbose = options[:verbose]
  66. end
  67. opts.on '-n', '--name PATTERN', "Filter test names on pattern." do |a|
  68. options[:filter] = a
  69. end
  70. opts.on '--jobs-status [TYPE]', [:normal, :replace],
  71. "Show status of jobs every file; Disabled when --jobs isn't specified." do |type|
  72. options[:job_status] = type || :normal
  73. end
  74. opts.on '-j N', '--jobs N', "Allow run tests with N jobs at once" do |a|
  75. if /^t/ =~ a
  76. options[:testing] = true # For testing
  77. options[:parallel] = a[1..-1].to_i
  78. else
  79. options[:parallel] = a.to_i
  80. end
  81. end
  82. opts.on '--no-retry', "Don't retry running testcase when --jobs specified" do
  83. options[:no_retry] = true
  84. end
  85. opts.on '--ruby VAL', "Path to ruby; It'll have used at -j option" do |a|
  86. options[:ruby] = a.split(/ /).reject(&:empty?)
  87. end
  88. opts.on '-q', '--hide-skip', 'Hide skipped tests' do
  89. options[:hide_skip] = true
  90. end
  91. end
  92. def non_options(files, options)
  93. begin
  94. require "rbconfig"
  95. rescue LoadError
  96. warn "#{caller(1)[0]}: warning: Parallel running disabled because can't get path to ruby; run specify with --ruby argument"
  97. options[:parallel] = nil
  98. else
  99. options[:ruby] ||= RbConfig.ruby
  100. end
  101. true
  102. end
  103. end
  104. module GlobOption
  105. include Options
  106. @@testfile_prefix = "test"
  107. def setup_options(parser, options)
  108. super
  109. parser.on '-b', '--basedir=DIR', 'Base directory of test suites.' do |dir|
  110. options[:base_directory] = dir
  111. end
  112. parser.on '-x', '--exclude PATTERN', 'Exclude test files on pattern.' do |pattern|
  113. (options[:reject] ||= []) << pattern
  114. end
  115. end
  116. def non_options(files, options)
  117. paths = [options.delete(:base_directory), nil].uniq
  118. if reject = options.delete(:reject)
  119. reject_pat = Regexp.union(reject.map {|r| /#{r}/ })
  120. end
  121. files.map! {|f|
  122. f = f.tr(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
  123. ((paths if /\A\.\.?(?:\z|\/)/ !~ f) || [nil]).any? do |prefix|
  124. if prefix
  125. path = f.empty? ? prefix : "#{prefix}/#{f}"
  126. else
  127. next if f.empty?
  128. path = f
  129. end
  130. if !(match = Dir["#{path}/**/#{@@testfile_prefix}_*.rb"]).empty?
  131. if reject
  132. match.reject! {|n|
  133. n[(prefix.length+1)..-1] if prefix
  134. reject_pat =~ n
  135. }
  136. end
  137. break match
  138. elsif !reject or reject_pat !~ f and File.exist? path
  139. break path
  140. end
  141. end or
  142. raise ArgumentError, "file not found: #{f}"
  143. }
  144. files.flatten!
  145. super(files, options)
  146. end
  147. end
  148. module LoadPathOption
  149. include Options
  150. def setup_options(parser, options)
  151. super
  152. parser.on '-Idirectory', 'Add library load path' do |dirs|
  153. dirs.split(':').each { |d| $LOAD_PATH.unshift d }
  154. end
  155. end
  156. end
  157. module GCStressOption
  158. def setup_options(parser, options)
  159. super
  160. parser.on '--[no-]gc-stress', 'Set GC.stress as true' do |flag|
  161. options[:gc_stress] = flag
  162. end
  163. end
  164. def non_options(files, options)
  165. if options.delete(:gc_stress)
  166. MiniTest::Unit::TestCase.class_eval do
  167. oldrun = instance_method(:run)
  168. define_method(:run) do |runner|
  169. begin
  170. gc_stress, GC.stress = GC.stress, true
  171. oldrun.bind(self).call(runner)
  172. ensure
  173. GC.stress = gc_stress
  174. end
  175. end
  176. end
  177. end
  178. super
  179. end
  180. end
  181. module RequireFiles
  182. def non_options(files, options)
  183. return false if !super
  184. result = false
  185. files.each {|f|
  186. d = File.dirname(path = File.expand_path(f))
  187. unless $:.include? d
  188. $: << d
  189. end
  190. begin
  191. require path unless options[:parallel]
  192. result = true
  193. rescue LoadError
  194. puts "#{f}: #{$!}"
  195. end
  196. }
  197. result
  198. end
  199. end
  200. class Runner < MiniTest::Unit
  201. include Test::Unit::Options
  202. include Test::Unit::GlobOption
  203. include Test::Unit::LoadPathOption
  204. include Test::Unit::GCStressOption
  205. include Test::Unit::RunCount
  206. class Worker
  207. def self.launch(ruby,args=[])
  208. io = IO.popen([*ruby,
  209. "#{File.dirname(__FILE__)}/unit/parallel.rb",
  210. *args], "rb+")
  211. new(io, io.pid, :waiting)
  212. end
  213. def initialize(io, pid, status)
  214. @io = io
  215. @pid = pid
  216. @status = status
  217. @file = nil
  218. @real_file = nil
  219. @loadpath = []
  220. @hooks = {}
  221. end
  222. def puts(*args)
  223. @io.puts(*args)
  224. end
  225. def run(task,type)
  226. @file = File.basename(task).gsub(/\.rb/,"")
  227. @real_file = task
  228. begin
  229. puts "loadpath #{[Marshal.dump($:-@loadpath)].pack("m").gsub("\n","")}"
  230. @loadpath = $:.dup
  231. puts "run #{task} #{type}"
  232. @status = :prepare
  233. rescue Errno::EPIPE
  234. died
  235. rescue IOError
  236. raise unless ["stream closed","closed stream"].include? $!.message
  237. died
  238. end
  239. end
  240. def hook(id,&block)
  241. @hooks[id] ||= []
  242. @hooks[id] << block
  243. self
  244. end
  245. def read
  246. res = (@status == :quit) ? @io.read : @io.gets
  247. res && res.chomp
  248. end
  249. def close
  250. @io.close
  251. self
  252. end
  253. def died(*additional)
  254. @status = :quit
  255. @io.close
  256. call_hook(:dead,*additional)
  257. end
  258. def to_s
  259. if @file
  260. "#{@pid}=#{@file}"
  261. else
  262. "#{@pid}:#{@status.to_s.ljust(7)}"
  263. end
  264. end
  265. attr_reader :io, :pid
  266. attr_accessor :status, :file, :real_file, :loadpath
  267. private
  268. def call_hook(id,*additional)
  269. @hooks[id] ||= []
  270. @hooks[id].each{|hook| hook[self,additional] }
  271. self
  272. end
  273. end
  274. class << self; undef autorun; end
  275. @@stop_auto_run = false
  276. def self.autorun
  277. at_exit {
  278. Test::Unit::RunCount.run_once {
  279. exit(Test::Unit::Runner.new.run(ARGV) || true)
  280. } unless @@stop_auto_run
  281. } unless @@installed_at_exit
  282. @@installed_at_exit = true
  283. end
  284. def after_worker_down(worker, e=nil, c=false)
  285. return unless @options[:parallel]
  286. return if @interrupt
  287. if e
  288. b = e.backtrace
  289. warn "#{b.shift}: #{e.message} (#{e.class})"
  290. STDERR.print b.map{|s| "\tfrom #{s}"}.join("\n")
  291. end
  292. @need_quit = true
  293. warn ""
  294. warn "Some worker was crashed. It seems ruby interpreter's bug"
  295. warn "or, a bug of test/unit/parallel.rb. try again without -j"
  296. warn "option."
  297. warn ""
  298. STDERR.flush
  299. exit c
  300. end
  301. def jobs_status
  302. return unless @options[:job_status]
  303. puts "" unless @options[:verbose]
  304. status_line = @workers.map(&:to_s).join(" ")
  305. if @options[:job_status] == :replace and $stdout.tty?
  306. @terminal_width ||=
  307. begin
  308. require 'io/console'
  309. $stdout.winsize[1]
  310. rescue LoadError, NoMethodError
  311. ENV["COLUMNS"].to_i.nonzero? || 80
  312. end
  313. @jstr_size ||= 0
  314. del_jobs_status
  315. $stdout.flush
  316. print status_line[0...@terminal_width]
  317. $stdout.flush
  318. @jstr_size = [status_line.size, @terminal_width].min
  319. else
  320. puts status_line
  321. end
  322. end
  323. def del_jobs_status
  324. return unless @options[:job_status] == :replace && @jstr_size.nonzero?
  325. print "\r"+" "*@jstr_size+"\r"
  326. end
  327. def after_worker_quit(worker)
  328. return unless @options[:parallel]
  329. return if @interrupt
  330. @workers.delete(worker)
  331. @dead_workers << worker
  332. @ios = @workers.map(&:io)
  333. end
  334. def _run_parallel suites, type, result
  335. if @options[:parallel] < 1
  336. warn "Error: parameter of -j option should be greater than 0."
  337. return
  338. end
  339. begin
  340. # Require needed things for parallel running
  341. require 'thread'
  342. require 'timeout'
  343. @tasks = @files.dup # Array of filenames.
  344. @need_quit = false
  345. @dead_workers = [] # Array of dead workers.
  346. @warnings = []
  347. shutting_down = false
  348. rep = [] # FIXME: more good naming
  349. # Array of workers.
  350. @workers = @options[:parallel].times.map {
  351. worker = Worker.launch(@options[:ruby],@args)
  352. worker.hook(:dead) do |w,info|
  353. after_worker_quit w
  354. after_worker_down w, *info unless info.empty?
  355. end
  356. worker
  357. }
  358. # Thread: watchdog
  359. watchdog = Thread.new do
  360. while stat = Process.wait2
  361. break if @interrupt # Break when interrupt
  362. pid, stat = stat
  363. w = (@workers + @dead_workers).find{|x| pid == x.pid }.dup
  364. next unless w
  365. unless w.status == :quit
  366. # Worker down
  367. w.died(nil, !stat.signaled? && stat.exitstatus)
  368. end
  369. end
  370. end
  371. @workers_hash = Hash[@workers.map {|w| [w.io,w] }] # out-IO => worker
  372. @ios = @workers.map{|w| w.io } # Array of worker IOs
  373. while _io = IO.select(@ios)[0]
  374. break unless _io.each do |io|
  375. break if @need_quit
  376. worker = @workers_hash[io]
  377. case worker.read
  378. when /^okay$/
  379. worker.status = :running
  380. jobs_status
  381. when /^ready$/
  382. worker.status = :ready
  383. if @tasks.empty?
  384. break unless @workers.find{|x| x.status == :running }
  385. else
  386. worker.run(@tasks.shift, type)
  387. end
  388. jobs_status
  389. when /^done (.+?)$/
  390. r = Marshal.load($1.unpack("m")[0])
  391. result << r[0..1] unless r[0..1] == [nil,nil]
  392. rep << {file: worker.real_file,
  393. report: r[2], result: r[3], testcase: r[5]}
  394. $:.push(*r[4]).uniq!
  395. when /^p (.+?)$/
  396. del_jobs_status
  397. print $1.unpack("m")[0]
  398. jobs_status if @options[:job_status] == :replace
  399. when /^after (.+?)$/
  400. @warnings << Marshal.load($1.unpack("m")[0])
  401. when /^bye (.+?)$/
  402. after_worker_down worker, Marshal.load($1.unpack("m")[0])
  403. when /^bye$/
  404. if shutting_down
  405. after_worker_quit worker
  406. else
  407. after_worker_down worker
  408. end
  409. end
  410. break if @need_quit
  411. end
  412. end
  413. rescue Interrupt => e
  414. @interrupt = e
  415. return result
  416. ensure
  417. shutting_down = true
  418. watchdog.kill if watchdog
  419. if @interrupt
  420. @ios.select!{|x| @workers_hash[x].status == :running }
  421. while !@ios.empty? && (__io = IO.select(@ios,[],[],10))
  422. _io = __io[0]
  423. _io.each do |io|
  424. worker = @workers_hash[io]
  425. case worker.read
  426. when /^done (.+?)$/
  427. r = Marshal.load($1.unpack("m")[0])
  428. result << r[0..1] unless r[0..1] == [nil,nil]
  429. rep << {file: worker.real_file,
  430. report: r[2], result: r[3], testcase: r[5]}
  431. $:.push(*r[4]).uniq!
  432. @ios.delete(io)
  433. end
  434. end
  435. end
  436. end
  437. @workers.each do |worker|
  438. begin
  439. timeout(1) do
  440. worker.puts "quit"
  441. end
  442. rescue Errno::EPIPE
  443. rescue Timeout::Error
  444. end
  445. worker.close
  446. end
  447. begin
  448. timeout(0.2*@workers.size) do
  449. Process.waitall
  450. end
  451. rescue Timeout::Error
  452. @workers.each do |worker|
  453. begin
  454. Process.kill(:KILL,worker.pid)
  455. rescue Errno::ESRCH; end
  456. end
  457. end
  458. if @interrupt || @options[:no_retry] || @need_quit
  459. rep.each do |r|
  460. report.push(*r[:report])
  461. end
  462. @errors += rep.map{|x| x[:result][0] }.inject(:+)
  463. @failures += rep.map{|x| x[:result][1] }.inject(:+)
  464. @skips += rep.map{|x| x[:result][2] }.inject(:+)
  465. else
  466. puts ""
  467. puts "Retrying..."
  468. puts ""
  469. rep.each do |r|
  470. if r[:testcase] && r[:file] && !r[:report].empty?
  471. require r[:file]
  472. _run_suite(eval(r[:testcase]),type)
  473. else
  474. report.push(*r[:report])
  475. @errors += r[:result][0]
  476. @failures += r[:result][1]
  477. @skips += r[:result][2]
  478. end
  479. end
  480. end
  481. if @warnings
  482. warn ""
  483. ary = []
  484. @warnings.reject! do |w|
  485. r = ary.include?(w[1].message)
  486. ary << w[1].message
  487. r
  488. end
  489. @warnings.each do |w|
  490. warn "#{w[0]}: #{w[1].message} (#{w[1].class})"
  491. end
  492. warn ""
  493. end
  494. end
  495. end
  496. def _run_suites suites, type
  497. @interrupt = nil
  498. result = []
  499. if @options[:parallel]
  500. _run_parallel suites, type, result
  501. else
  502. suites.each {|suite|
  503. begin
  504. result << _run_suite(suite, type)
  505. rescue Interrupt => e
  506. @interrupt = e
  507. break
  508. end
  509. }
  510. end
  511. report.reject!{|r| r.start_with? "Skipped:" } if @options[:hide_skip]
  512. result
  513. end
  514. # Overriding of MiniTest::Unit#puke
  515. def puke klass, meth, e
  516. # TODO:
  517. # this overriding is for minitest feature that skip messages are
  518. # hidden when not verbose (-v), note this is temporally.
  519. e = case e
  520. when MiniTest::Skip then
  521. @skips += 1
  522. "Skipped:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
  523. when MiniTest::Assertion then
  524. @failures += 1
  525. "Failure:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
  526. else
  527. @errors += 1
  528. bt = MiniTest::filter_backtrace(e.backtrace).join "\n "
  529. "Error:\n#{meth}(#{klass}):\n#{e.class}: #{e.message}\n #{bt}\n"
  530. end
  531. @report << e
  532. e[0, 1]
  533. end
  534. def status(*args)
  535. result = super
  536. raise @interrupt if @interrupt
  537. result
  538. end
  539. end
  540. class AutoRunner
  541. class Runner < Test::Unit::Runner
  542. include Test::Unit::RequireFiles
  543. end
  544. attr_accessor :to_run, :options
  545. def initialize(force_standalone = false, default_dir = nil, argv = ARGV)
  546. @runner = Runner.new do |files, options|
  547. options[:base_directory] ||= default_dir
  548. files << default_dir if files.empty? and default_dir
  549. @to_run = files
  550. yield self if block_given?
  551. files
  552. end
  553. Runner.runner = @runner
  554. @options = @runner.option_parser
  555. @argv = argv
  556. end
  557. def process_args(*args)
  558. @runner.process_args(*args)
  559. !@to_run.empty?
  560. end
  561. def run
  562. @runner.run(@argv) || true
  563. end
  564. def self.run(*args)
  565. new(*args).run
  566. end
  567. end
  568. end
  569. end
  570. Test::Unit::Runner.autorun