daily pastebin goal
33%
SHARE
TWEET

Untitled

a guest Apr 17th, 2018 46 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env ruby
  2. # vim: encoding=utf-8 filetype=ruby
  3.  
  4. require 'rubygems'
  5. require 'optparse'
  6. require 'yaml'
  7.  
  8. options = YAML.load(<<CONF)
  9. color:      true
  10. verbose:    false
  11. target:     'UnitTest'
  12. config:     'Release'
  13. sdkversion: '3.0'
  14. format:     'simple'
  15. CONF
  16.  
  17. if FileTest.exist?('.rocurc')
  18.   options.merge!(YAML.load_file('.rocurc'))
  19. end
  20.  
  21. OptionParser.new { |opt|
  22.   opt.on('-o','--options=FILE')   { |f| options.merge!(YAML.load_file(f)) }
  23.   opt.on('--[no-]color')          { |c| options['color'] = c }
  24.   opt.on('--[no-]verbose')        { |v| options['verbose'] = v }
  25.   opt.on('-t','--target=TARGET')  { |t| options['target'] = t }
  26.   opt.on('--sdk-version=VERSION') { |v| options['sdkversion'] = v }
  27.   opt.on('-f','--format=FORMAT')  { |f| options['format'] = v }
  28.  
  29.   opt.parse!(ARGV)
  30. }
  31.  
  32. TESTCMD = "xcodebuild -target #{options['target']} -configuration #{options['config']} -sdk iphonesimulator#{options['sdkversion']} 2>&1"
  33.  
  34. module DummyANSIColor
  35.   def bold; self; end
  36.   def negative; self; end
  37.   def red; self; end
  38.   def green; self; end
  39.   def yellow; self; end
  40.   def blue; self; end
  41. end
  42.  
  43. if options['color']
  44.   begin
  45.     require 'term/ansicolor'
  46.     class String
  47.       include Term::ANSIColor
  48.     end
  49.   rescue LoadError
  50.     warn "#{$0} depends on Term::ANSIColor!"
  51.   end
  52. end
  53.  
  54. unless String.instance_methods.include?(:bold)
  55.   class String
  56.     include DummyANSIColor
  57.   end
  58. end
  59.  
  60. module XBTools
  61.   class Filter
  62.     Terminator = /\A\*\* BUILD/
  63.  
  64.     def self.process(io, opts={})
  65.       new(io, opts).process
  66.     end
  67.  
  68.     def initialize(io,opts={})
  69.       @input = io
  70.       @log   = []
  71.       @opts  = opts
  72.     end
  73.  
  74.     def parse
  75.       line = @input.gets
  76.       case line
  77.       when Terminator
  78.         false
  79.       else
  80.         @log.push({ :message => line, :type => :unknown })
  81.       end
  82.     end
  83.  
  84.     def fold
  85.       @log.map{ |l|
  86.         line = l[:position] ? "#{l[:message]} (#{l[:position]})" : l[:message]
  87.         line = case l[:type]
  88.                when :header then line.bold
  89.                when :passed then line.green
  90.                when :failed then line.red
  91.                else line end
  92.         line = case l[:level]
  93.                when :error   then line.red.bold
  94.                when :warning then line.yellow
  95.                else line end
  96.         l[:negative] ? line.negative : line
  97.       }.join("\n")
  98.     end
  99.  
  100.     def process
  101.       while parse; end
  102.       fold
  103.     end
  104.   end
  105.  
  106.   class BuildFilter < XBTools::Filter
  107.     Terminator = /\APhaseScriptExecution/
  108.  
  109.     def initialize(io,opts={})
  110.       super
  111.       @in_submsg = false
  112.     end
  113.  
  114.     def parse
  115.       return false unless super
  116.       line = @log.pop
  117.       return false unless line
  118.       case line[:message]
  119.       when /\A(?:#{Dir.pwd}\/)?(.+); In function (.+)/
  120.         @log.push( :message => $2, :position => $1, :type => :info )
  121.       when /\A(?:#{Dir.pwd}\/)?(.+[0-9]+): (warning|error): (.+)/
  122.         pos   = $1
  123.         level = $2.intern
  124.         msg   = $3
  125.         if @in_submsg
  126.           @log.last[:message] << msg
  127.           @in_submsg = false if msg =~ /\)(\n|\z)/
  128.         elsif msg =~ /\A\(/
  129.           @log.last[:message] << ' ' << msg
  130.           @in_submsg = true
  131.         else
  132.           @log.push( :message => msg, :position => pos, :level => level )
  133.         end
  134.       when Terminator
  135.         return false
  136.       end
  137.       true
  138.     end
  139.   end
  140.  
  141.   class OCUnitFilter < Filter
  142.     def initialize(io,opts={})
  143.       super
  144.       @in_subtest = false
  145.       @failures   = []
  146.       @opts[:format] ||= 'simple'
  147.     end
  148.  
  149.     def fold
  150.       if @opts[:format] == 'specdoc'
  151.         super
  152.       else
  153.         log     = {}
  154.         current = ''
  155.         result  = nil
  156.         if (@log.last)[:message] =~ /Executed/
  157.           result = @log.pop
  158.         end
  159.         @log.each do |l|
  160.           if l[:type] == :header
  161.             current = l[:message]
  162.             log[current] = {
  163.               :results => [],
  164.               :errors  => []
  165.             }
  166.           else
  167.             section = log[current]
  168.             if !!section
  169.               msg = l[:position] ? "#{l[:message]} (#{l[:position]})" : l[:message]
  170.               msg.gsub!(/\t/,'') unless msg.nil?
  171.               case l[:type]
  172.               when :passed
  173.                 section[:results] << '.'.green
  174.               when :failed
  175.                 section[:results] << 'E'.red
  176.                 section[:errors]  << msg.red.bold
  177.               else
  178.                 case l[:level]
  179.                 when :error
  180.                   section[:errors] << msg.red.bold
  181.                 when :warning
  182.                   section[:errors] << msg.yellow
  183.                 end
  184.               end
  185.             end
  186.           end
  187.         end
  188.         output = ""
  189.         errors = []
  190.         log.each_pair do |key,val|
  191.           output << val[:results].join('')
  192.           unless val[:errors].empty?
  193.             errors << [key.bold, *val[:errors]].join("\n")
  194.           end
  195.         end
  196.         output = "#{output}\n\n#{errors.join("\n\n")}"
  197.         output << "\n\n#{(result[:type] == :passed ? result[:message].green : result[:message].red).negative}" if !!result
  198.         output
  199.       end
  200.     end
  201.  
  202.     def parse
  203.       return false unless super
  204.       line = @log.pop
  205.       return false unless line
  206.       case line[:message]
  207.       when /\A(?:#{Dir.pwd}\/)?(.+[0-9]+): error: -\[.+\] : (.+)/
  208.         pos = $1
  209.         msg = $2
  210.         if @failures.last && @failures.last[:type] == 'assert' && !@failures.last[:message]
  211.           @failures.last[:message] = "Assertion failure. #{msg} (#{@failures.last[:position]})"
  212.         elsif pos =~ /Unknown.m:0/
  213.           @failures << { :type => 'runtime', :message => msg }
  214.         else
  215.           @failures << { :type => 'test', :message => "#{msg} (#{pos})" }
  216.         end
  217.       when /\*\*\* Assertion failure in (?:-|\+)\[.+\], (?:#{Dir.pwd}\/)?(.+)/
  218.         @failures.push( :type => 'assert', :position => $1 )
  219.       when /\AExecuted/
  220.         if @in_subtest
  221.           @in_subtest = false
  222.         else
  223.           msg = line[:message]
  224.           @log.push(
  225.             :message  => msg,
  226.             :type     => msg =~ /with 0 failure/ ? :passed : :failed,
  227.             :negative => true
  228.           )
  229.         end
  230.       when /\ATest Suite '([a-zA-Z0-9]+)' started/
  231.         @log.push( :message => "#{$1}:", :type => :header )
  232.         @in_subtest = true
  233.       when /\ATest Suite '(.+)' started/
  234.         @log.push( :message => "#{$1}:", :type => :header )
  235.       when /\ATest Case '(-\[.+\])' passed/
  236.         @log.push( :message => "\t#{$1}", :type => :passed )
  237.       when /\ATest Case '(-\[.+\])' failed/
  238.         @log.push( :message => "\t#{$1}", :type => :failed )
  239.         @failures.each do |assert|
  240.           case assert[:type]
  241.           when 'test'
  242.             @log.push( :message => "\t\t#{assert[:message]}", :type => :failed )
  243.           when 'assert'
  244.             @log.push( :message => "\t\t#{assert[:message]}", :level => :warning )
  245.           when 'runtime'
  246.             @log.push( :message => "\t\t#{assert[:message]}", :level => :error )
  247.           end
  248.         end
  249.         @failures = []
  250.       when /\ATest Suite '.+' finished/
  251.         @log.push( :message => 'All test finished.' ) unless @in_subtest
  252.       end
  253.       true
  254.     end
  255.  
  256.     def message(m)
  257.     end
  258.     private :message
  259.   end
  260. end
  261.  
  262. if $0 == __FILE__
  263.   IO.popen(TESTCMD) { |io|
  264.     puts '=== BUILD PHASE ==='
  265.     puts XBTools::BuildFilter.process(io)
  266.     puts '=== TEST PHASE ==='
  267.     puts XBTools::OCUnitFilter.process(io, :format => options['format'])
  268.   }
  269. end
RAW Paste Data
Top