1# ========================================== 2# Unity Project - A Test Framework for C 3# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams 4# [Released under MIT License. Please refer to license.txt for details] 5# ========================================== 6 7# !/usr/bin/ruby 8# 9# unity_test_summary.rb 10# 11require 'fileutils' 12require 'set' 13 14class UnityTestSummary 15 include FileUtils::Verbose 16 17 attr_reader :report, :total_tests, :failures, :ignored 18 attr_writer :targets, :root 19 20 def initialize(_opts = {}) 21 @report = '' 22 @total_tests = 0 23 @failures = 0 24 @ignored = 0 25 end 26 27 def run 28 # Clean up result file names 29 results = @targets.map { |target| target.tr('\\', '/') } 30 31 # Dig through each result file, looking for details on pass/fail: 32 failure_output = [] 33 ignore_output = [] 34 35 results.each do |result_file| 36 lines = File.readlines(result_file).map(&:chomp) 37 38 raise "Empty test result file: #{result_file}" if lines.empty? 39 40 output = get_details(result_file, lines) 41 failure_output << output[:failures] unless output[:failures].empty? 42 ignore_output << output[:ignores] unless output[:ignores].empty? 43 tests, failures, ignored = parse_test_summary(lines) 44 @total_tests += tests 45 @failures += failures 46 @ignored += ignored 47 end 48 49 if @ignored > 0 50 @report += "\n" 51 @report += "--------------------------\n" 52 @report += "UNITY IGNORED TEST SUMMARY\n" 53 @report += "--------------------------\n" 54 @report += ignore_output.flatten.join("\n") 55 end 56 57 if @failures > 0 58 @report += "\n" 59 @report += "--------------------------\n" 60 @report += "UNITY FAILED TEST SUMMARY\n" 61 @report += "--------------------------\n" 62 @report += failure_output.flatten.join("\n") 63 end 64 65 @report += "\n" 66 @report += "--------------------------\n" 67 @report += "OVERALL UNITY TEST SUMMARY\n" 68 @report += "--------------------------\n" 69 @report += "#{@total_tests} TOTAL TESTS #{@failures} TOTAL FAILURES #{@ignored} IGNORED\n" 70 @report += "\n" 71 end 72 73 def usage(err_msg = nil) 74 puts "\nERROR: " 75 puts err_msg if err_msg 76 puts "\nUsage: unity_test_summary.rb result_file_directory/ root_path/" 77 puts ' result_file_directory - The location of your results files.' 78 puts ' Defaults to current directory if not specified.' 79 puts ' Should end in / if specified.' 80 puts ' root_path - Helpful for producing more verbose output if using relative paths.' 81 exit 1 82 end 83 84 protected 85 86 def get_details(_result_file, lines) 87 results = { failures: [], ignores: [], successes: [] } 88 lines.each do |line| 89 _src_file, _src_line, _test_name, status, _msg = line.split(/:/) 90 line_out = (@root && (@root != 0) ? "#{@root}#{line}" : line).gsub(/\//, '\\') 91 case status 92 when 'IGNORE' then results[:ignores] << line_out 93 when 'FAIL' then results[:failures] << line_out 94 when 'PASS' then results[:successes] << line_out 95 end 96 end 97 results 98 end 99 100 def parse_test_summary(summary) 101 raise "Couldn't parse test results: #{summary}" unless summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ } 102 103 [Regexp.last_match(1).to_i, Regexp.last_match(2).to_i, Regexp.last_match(3).to_i] 104 end 105end 106 107if $0 == __FILE__ 108 109 # parse out the command options 110 opts, args = ARGV.partition { |v| v =~ /^--\w+/ } 111 opts.map! { |v| v[2..-1].to_sym } 112 113 # create an instance to work with 114 uts = UnityTestSummary.new(opts) 115 116 begin 117 # look in the specified or current directory for result files 118 args[0] ||= './' 119 targets = "#{ARGV[0].tr('\\', '/')}**/*.test*" 120 results = Dir[targets] 121 122 raise "No *.testpass, *.testfail, or *.testresults files found in '#{targets}'" if results.empty? 123 124 uts.targets = results 125 126 # set the root path 127 args[1] ||= Dir.pwd + '/' 128 uts.root = ARGV[1] 129 130 # run the summarizer 131 puts uts.run 132 rescue StandardError => e 133 uts.usage e.message 134 end 135end 136