Ram Gandikota
/
ABCD
A metronome using the FRDM K64F board
pal/Test/Unity/auto/stylize_as_junit.rb@0:a7a43371b306, 2017-05-14 (annotated)
- Committer:
- ram54288
- Date:
- Sun May 14 18:40:18 2017 +0000
- Revision:
- 0:a7a43371b306
Initial commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ram54288 | 0:a7a43371b306 | 1 | #!/usr/bin/ruby |
ram54288 | 0:a7a43371b306 | 2 | # |
ram54288 | 0:a7a43371b306 | 3 | # unity_to_junit.rb |
ram54288 | 0:a7a43371b306 | 4 | # |
ram54288 | 0:a7a43371b306 | 5 | require 'fileutils' |
ram54288 | 0:a7a43371b306 | 6 | require 'optparse' |
ram54288 | 0:a7a43371b306 | 7 | require 'ostruct' |
ram54288 | 0:a7a43371b306 | 8 | require 'set' |
ram54288 | 0:a7a43371b306 | 9 | |
ram54288 | 0:a7a43371b306 | 10 | require 'pp' |
ram54288 | 0:a7a43371b306 | 11 | |
ram54288 | 0:a7a43371b306 | 12 | VERSION = 1.0 |
ram54288 | 0:a7a43371b306 | 13 | |
ram54288 | 0:a7a43371b306 | 14 | class ArgvParser |
ram54288 | 0:a7a43371b306 | 15 | |
ram54288 | 0:a7a43371b306 | 16 | # |
ram54288 | 0:a7a43371b306 | 17 | # Return a structure describing the options. |
ram54288 | 0:a7a43371b306 | 18 | # |
ram54288 | 0:a7a43371b306 | 19 | def self.parse(args) |
ram54288 | 0:a7a43371b306 | 20 | # The options specified on the command line will be collected in *options*. |
ram54288 | 0:a7a43371b306 | 21 | # We set default values here. |
ram54288 | 0:a7a43371b306 | 22 | options = OpenStruct.new |
ram54288 | 0:a7a43371b306 | 23 | options.results_dir = "." |
ram54288 | 0:a7a43371b306 | 24 | options.root_path = "." |
ram54288 | 0:a7a43371b306 | 25 | options.out_file = "results.xml" |
ram54288 | 0:a7a43371b306 | 26 | |
ram54288 | 0:a7a43371b306 | 27 | opts = OptionParser.new do |opts| |
ram54288 | 0:a7a43371b306 | 28 | opts.banner = "Usage: unity_to_junit.rb [options]" |
ram54288 | 0:a7a43371b306 | 29 | |
ram54288 | 0:a7a43371b306 | 30 | opts.separator "" |
ram54288 | 0:a7a43371b306 | 31 | opts.separator "Specific options:" |
ram54288 | 0:a7a43371b306 | 32 | |
ram54288 | 0:a7a43371b306 | 33 | opts.on("-r", "--results <dir>", "Look for Unity Results files here.") do |results| |
ram54288 | 0:a7a43371b306 | 34 | #puts "results #{results}" |
ram54288 | 0:a7a43371b306 | 35 | options.results_dir = results |
ram54288 | 0:a7a43371b306 | 36 | end |
ram54288 | 0:a7a43371b306 | 37 | |
ram54288 | 0:a7a43371b306 | 38 | opts.on("-p", "--root_path <path>", "Prepend this path to files in results.") do |root_path| |
ram54288 | 0:a7a43371b306 | 39 | options.root_path = root_path |
ram54288 | 0:a7a43371b306 | 40 | end |
ram54288 | 0:a7a43371b306 | 41 | |
ram54288 | 0:a7a43371b306 | 42 | opts.on("-o", "--output <filename>", "XML file to generate.") do |out_file| |
ram54288 | 0:a7a43371b306 | 43 | #puts "out_file: #{out_file}" |
ram54288 | 0:a7a43371b306 | 44 | options.out_file = out_file |
ram54288 | 0:a7a43371b306 | 45 | end |
ram54288 | 0:a7a43371b306 | 46 | |
ram54288 | 0:a7a43371b306 | 47 | opts.separator "" |
ram54288 | 0:a7a43371b306 | 48 | opts.separator "Common options:" |
ram54288 | 0:a7a43371b306 | 49 | |
ram54288 | 0:a7a43371b306 | 50 | # No argument, shows at tail. This will print an options summary. |
ram54288 | 0:a7a43371b306 | 51 | opts.on_tail("-h", "--help", "Show this message") do |
ram54288 | 0:a7a43371b306 | 52 | puts opts |
ram54288 | 0:a7a43371b306 | 53 | exit |
ram54288 | 0:a7a43371b306 | 54 | end |
ram54288 | 0:a7a43371b306 | 55 | |
ram54288 | 0:a7a43371b306 | 56 | # Another typical switch to print the version. |
ram54288 | 0:a7a43371b306 | 57 | opts.on_tail("--version", "Show version") do |
ram54288 | 0:a7a43371b306 | 58 | puts "unity_to_junit.rb version #{VERSION}" |
ram54288 | 0:a7a43371b306 | 59 | exit |
ram54288 | 0:a7a43371b306 | 60 | end |
ram54288 | 0:a7a43371b306 | 61 | end |
ram54288 | 0:a7a43371b306 | 62 | |
ram54288 | 0:a7a43371b306 | 63 | opts.parse!(args) |
ram54288 | 0:a7a43371b306 | 64 | options |
ram54288 | 0:a7a43371b306 | 65 | end # parse() |
ram54288 | 0:a7a43371b306 | 66 | |
ram54288 | 0:a7a43371b306 | 67 | end # class OptparseExample |
ram54288 | 0:a7a43371b306 | 68 | |
ram54288 | 0:a7a43371b306 | 69 | class UnityToJUnit |
ram54288 | 0:a7a43371b306 | 70 | include FileUtils::Verbose |
ram54288 | 0:a7a43371b306 | 71 | attr_reader :report, :total_tests, :failures, :ignored |
ram54288 | 0:a7a43371b306 | 72 | |
ram54288 | 0:a7a43371b306 | 73 | def initialize |
ram54288 | 0:a7a43371b306 | 74 | @report = '' |
ram54288 | 0:a7a43371b306 | 75 | @unit_name = '' |
ram54288 | 0:a7a43371b306 | 76 | end |
ram54288 | 0:a7a43371b306 | 77 | |
ram54288 | 0:a7a43371b306 | 78 | def run |
ram54288 | 0:a7a43371b306 | 79 | # Clean up result file names |
ram54288 | 0:a7a43371b306 | 80 | results = @targets.map {|target| target.gsub(/\\/,"/")} |
ram54288 | 0:a7a43371b306 | 81 | #puts "Output File: #{@out_file}" |
ram54288 | 0:a7a43371b306 | 82 | f = File.new(@out_file, "w") |
ram54288 | 0:a7a43371b306 | 83 | write_xml_header(f) |
ram54288 | 0:a7a43371b306 | 84 | write_suites_header( f ) |
ram54288 | 0:a7a43371b306 | 85 | results.each do |result_file| |
ram54288 | 0:a7a43371b306 | 86 | lines = File.readlines(result_file).map { |line| line.chomp } |
ram54288 | 0:a7a43371b306 | 87 | if lines.length == 0 |
ram54288 | 0:a7a43371b306 | 88 | raise "Empty test result file: #{result_file}" |
ram54288 | 0:a7a43371b306 | 89 | else |
ram54288 | 0:a7a43371b306 | 90 | result_output = get_details(result_file, lines) |
ram54288 | 0:a7a43371b306 | 91 | tests,failures,ignored = parse_test_summary(lines) |
ram54288 | 0:a7a43371b306 | 92 | result_output[:counts][:total] = tests |
ram54288 | 0:a7a43371b306 | 93 | result_output[:counts][:failed] = failures |
ram54288 | 0:a7a43371b306 | 94 | result_output[:counts][:ignored] = ignored |
ram54288 | 0:a7a43371b306 | 95 | result_output[:counts][:passed] = (result_output[:counts][:total] - result_output[:counts][:failed] - result_output[:counts][:ignored]) |
ram54288 | 0:a7a43371b306 | 96 | end |
ram54288 | 0:a7a43371b306 | 97 | #use line[0] from the test output to get the test_file path and name |
ram54288 | 0:a7a43371b306 | 98 | test_file_str = lines[0].gsub("\\","/") |
ram54288 | 0:a7a43371b306 | 99 | test_file_str = test_file_str.split(":") |
ram54288 | 0:a7a43371b306 | 100 | test_file = if (test_file_str.length < 2) |
ram54288 | 0:a7a43371b306 | 101 | result_file |
ram54288 | 0:a7a43371b306 | 102 | else |
ram54288 | 0:a7a43371b306 | 103 | test_file_str[0] + ':' + test_file_str[1] |
ram54288 | 0:a7a43371b306 | 104 | end |
ram54288 | 0:a7a43371b306 | 105 | result_output[:source][:path] = File.dirname(test_file) |
ram54288 | 0:a7a43371b306 | 106 | result_output[:source][:file] = File.basename(test_file) |
ram54288 | 0:a7a43371b306 | 107 | |
ram54288 | 0:a7a43371b306 | 108 | # save result_output |
ram54288 | 0:a7a43371b306 | 109 | @unit_name = File.basename(test_file, ".*") |
ram54288 | 0:a7a43371b306 | 110 | |
ram54288 | 0:a7a43371b306 | 111 | write_suite_header( result_output[:counts], f) |
ram54288 | 0:a7a43371b306 | 112 | write_failures( result_output, f ) |
ram54288 | 0:a7a43371b306 | 113 | write_tests( result_output, f ) |
ram54288 | 0:a7a43371b306 | 114 | write_ignored( result_output, f ) |
ram54288 | 0:a7a43371b306 | 115 | write_suite_footer( f ) |
ram54288 | 0:a7a43371b306 | 116 | end |
ram54288 | 0:a7a43371b306 | 117 | write_suites_footer( f ) |
ram54288 | 0:a7a43371b306 | 118 | f.close |
ram54288 | 0:a7a43371b306 | 119 | end |
ram54288 | 0:a7a43371b306 | 120 | |
ram54288 | 0:a7a43371b306 | 121 | def set_targets(target_array) |
ram54288 | 0:a7a43371b306 | 122 | @targets = target_array |
ram54288 | 0:a7a43371b306 | 123 | end |
ram54288 | 0:a7a43371b306 | 124 | |
ram54288 | 0:a7a43371b306 | 125 | def set_root_path(path) |
ram54288 | 0:a7a43371b306 | 126 | @root = path |
ram54288 | 0:a7a43371b306 | 127 | end |
ram54288 | 0:a7a43371b306 | 128 | def set_out_file(filename) |
ram54288 | 0:a7a43371b306 | 129 | @out_file = filename |
ram54288 | 0:a7a43371b306 | 130 | end |
ram54288 | 0:a7a43371b306 | 131 | def usage(err_msg=nil) |
ram54288 | 0:a7a43371b306 | 132 | puts "\nERROR: " |
ram54288 | 0:a7a43371b306 | 133 | puts err_msg if err_msg |
ram54288 | 0:a7a43371b306 | 134 | puts "Usage: unity_to_junit.rb [options]" |
ram54288 | 0:a7a43371b306 | 135 | puts "" |
ram54288 | 0:a7a43371b306 | 136 | puts "Specific options:" |
ram54288 | 0:a7a43371b306 | 137 | puts " -r, --results <dir> Look for Unity Results files here." |
ram54288 | 0:a7a43371b306 | 138 | puts " -p, --root_path <path> Prepend this path to files in results." |
ram54288 | 0:a7a43371b306 | 139 | puts " -o, --output <filename> XML file to generate." |
ram54288 | 0:a7a43371b306 | 140 | puts "" |
ram54288 | 0:a7a43371b306 | 141 | puts "Common options:" |
ram54288 | 0:a7a43371b306 | 142 | puts " -h, --help Show this message" |
ram54288 | 0:a7a43371b306 | 143 | puts " --version Show version" |
ram54288 | 0:a7a43371b306 | 144 | |
ram54288 | 0:a7a43371b306 | 145 | exit 1 |
ram54288 | 0:a7a43371b306 | 146 | end |
ram54288 | 0:a7a43371b306 | 147 | |
ram54288 | 0:a7a43371b306 | 148 | protected |
ram54288 | 0:a7a43371b306 | 149 | def get_details(result_file, lines) |
ram54288 | 0:a7a43371b306 | 150 | results = get_results_structure |
ram54288 | 0:a7a43371b306 | 151 | lines.each do |line| |
ram54288 | 0:a7a43371b306 | 152 | line = line.gsub("\\","/") |
ram54288 | 0:a7a43371b306 | 153 | src_file,src_line,test_name,status,msg = line.split(/:/) |
ram54288 | 0:a7a43371b306 | 154 | line_out = ((@root and (@root != 0)) ? "#{@root}#{line}" : line ).gsub(/\//, "\\") |
ram54288 | 0:a7a43371b306 | 155 | case(status) |
ram54288 | 0:a7a43371b306 | 156 | when 'IGNORE' then results[:ignores] << {:test => test_name, :line => src_line, :message => msg} |
ram54288 | 0:a7a43371b306 | 157 | when 'FAIL' then results[:failures] << {:test => test_name, :line => src_line, :message => msg} |
ram54288 | 0:a7a43371b306 | 158 | when 'PASS' then results[:successes] << {:test => test_name, :line => src_line, :message => msg} |
ram54288 | 0:a7a43371b306 | 159 | end |
ram54288 | 0:a7a43371b306 | 160 | end |
ram54288 | 0:a7a43371b306 | 161 | return results |
ram54288 | 0:a7a43371b306 | 162 | end |
ram54288 | 0:a7a43371b306 | 163 | |
ram54288 | 0:a7a43371b306 | 164 | def parse_test_summary(summary) |
ram54288 | 0:a7a43371b306 | 165 | if summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ } |
ram54288 | 0:a7a43371b306 | 166 | [$1.to_i,$2.to_i,$3.to_i] |
ram54288 | 0:a7a43371b306 | 167 | else |
ram54288 | 0:a7a43371b306 | 168 | raise "Couldn't parse test results: #{summary}" |
ram54288 | 0:a7a43371b306 | 169 | end |
ram54288 | 0:a7a43371b306 | 170 | end |
ram54288 | 0:a7a43371b306 | 171 | def here; File.expand_path(File.dirname(__FILE__)); end |
ram54288 | 0:a7a43371b306 | 172 | |
ram54288 | 0:a7a43371b306 | 173 | private |
ram54288 | 0:a7a43371b306 | 174 | |
ram54288 | 0:a7a43371b306 | 175 | def get_results_structure |
ram54288 | 0:a7a43371b306 | 176 | return { |
ram54288 | 0:a7a43371b306 | 177 | :source => {:path => '', :file => ''}, |
ram54288 | 0:a7a43371b306 | 178 | :successes => [], |
ram54288 | 0:a7a43371b306 | 179 | :failures => [], |
ram54288 | 0:a7a43371b306 | 180 | :ignores => [], |
ram54288 | 0:a7a43371b306 | 181 | :counts => {:total => 0, :passed => 0, :failed => 0, :ignored => 0}, |
ram54288 | 0:a7a43371b306 | 182 | :stdout => [], |
ram54288 | 0:a7a43371b306 | 183 | } |
ram54288 | 0:a7a43371b306 | 184 | end |
ram54288 | 0:a7a43371b306 | 185 | |
ram54288 | 0:a7a43371b306 | 186 | def write_xml_header( stream ) |
ram54288 | 0:a7a43371b306 | 187 | stream.puts "<?xml version='1.0' encoding='utf-8' ?>" |
ram54288 | 0:a7a43371b306 | 188 | end |
ram54288 | 0:a7a43371b306 | 189 | |
ram54288 | 0:a7a43371b306 | 190 | def write_suites_header( stream ) |
ram54288 | 0:a7a43371b306 | 191 | stream.puts "<testsuites>" |
ram54288 | 0:a7a43371b306 | 192 | end |
ram54288 | 0:a7a43371b306 | 193 | |
ram54288 | 0:a7a43371b306 | 194 | def write_suite_header( counts, stream ) |
ram54288 | 0:a7a43371b306 | 195 | stream.puts "\t<testsuite errors=\"0\" skipped=\"#{counts[:ignored]}\" failures=\"#{counts[:failed]}\" tests=\"#{counts[:total]}\" name=\"unity\">" |
ram54288 | 0:a7a43371b306 | 196 | end |
ram54288 | 0:a7a43371b306 | 197 | |
ram54288 | 0:a7a43371b306 | 198 | def write_failures( results, stream ) |
ram54288 | 0:a7a43371b306 | 199 | result = results[:failures] |
ram54288 | 0:a7a43371b306 | 200 | result.each do |item| |
ram54288 | 0:a7a43371b306 | 201 | filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*')) |
ram54288 | 0:a7a43371b306 | 202 | stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\">" |
ram54288 | 0:a7a43371b306 | 203 | stream.puts "\t\t\t<failure message=\"#{item[:message]}\" type=\"Assertion\"/>" |
ram54288 | 0:a7a43371b306 | 204 | stream.puts "\t\t\t<system-err>
[File] #{filename}
[Line] #{item[:line]}
</system-err>" |
ram54288 | 0:a7a43371b306 | 205 | stream.puts "\t\t</testcase>" |
ram54288 | 0:a7a43371b306 | 206 | end |
ram54288 | 0:a7a43371b306 | 207 | end |
ram54288 | 0:a7a43371b306 | 208 | |
ram54288 | 0:a7a43371b306 | 209 | def write_tests( results, stream ) |
ram54288 | 0:a7a43371b306 | 210 | result = results[:successes] |
ram54288 | 0:a7a43371b306 | 211 | result.each do |item| |
ram54288 | 0:a7a43371b306 | 212 | filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*')) |
ram54288 | 0:a7a43371b306 | 213 | stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\" />" |
ram54288 | 0:a7a43371b306 | 214 | end |
ram54288 | 0:a7a43371b306 | 215 | end |
ram54288 | 0:a7a43371b306 | 216 | |
ram54288 | 0:a7a43371b306 | 217 | def write_ignored( results, stream ) |
ram54288 | 0:a7a43371b306 | 218 | result = results[:ignores] |
ram54288 | 0:a7a43371b306 | 219 | result.each do |item| |
ram54288 | 0:a7a43371b306 | 220 | filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*')) |
ram54288 | 0:a7a43371b306 | 221 | puts "Writing ignored tests for test harness: #{filename}" |
ram54288 | 0:a7a43371b306 | 222 | stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\">" |
ram54288 | 0:a7a43371b306 | 223 | stream.puts "\t\t\t<skipped message=\"#{item[:message]}\" type=\"Assertion\"/>" |
ram54288 | 0:a7a43371b306 | 224 | stream.puts "\t\t\t<system-err>
[File] #{filename}
[Line] #{item[:line]}
</system-err>" |
ram54288 | 0:a7a43371b306 | 225 | stream.puts "\t\t</testcase>" |
ram54288 | 0:a7a43371b306 | 226 | end |
ram54288 | 0:a7a43371b306 | 227 | end |
ram54288 | 0:a7a43371b306 | 228 | |
ram54288 | 0:a7a43371b306 | 229 | def write_suite_footer( stream ) |
ram54288 | 0:a7a43371b306 | 230 | stream.puts "\t</testsuite>" |
ram54288 | 0:a7a43371b306 | 231 | end |
ram54288 | 0:a7a43371b306 | 232 | |
ram54288 | 0:a7a43371b306 | 233 | def write_suites_footer( stream ) |
ram54288 | 0:a7a43371b306 | 234 | stream.puts "</testsuites>" |
ram54288 | 0:a7a43371b306 | 235 | end |
ram54288 | 0:a7a43371b306 | 236 | end #UnityToJUnit |
ram54288 | 0:a7a43371b306 | 237 | |
ram54288 | 0:a7a43371b306 | 238 | if __FILE__ == $0 |
ram54288 | 0:a7a43371b306 | 239 | #parse out the command options |
ram54288 | 0:a7a43371b306 | 240 | options = ArgvParser.parse(ARGV) |
ram54288 | 0:a7a43371b306 | 241 | |
ram54288 | 0:a7a43371b306 | 242 | #create an instance to work with |
ram54288 | 0:a7a43371b306 | 243 | utj = UnityToJUnit.new |
ram54288 | 0:a7a43371b306 | 244 | begin |
ram54288 | 0:a7a43371b306 | 245 | #look in the specified or current directory for result files |
ram54288 | 0:a7a43371b306 | 246 | targets = "#{options.results_dir.gsub(/\\/, '/')}**/*.test*" |
ram54288 | 0:a7a43371b306 | 247 | |
ram54288 | 0:a7a43371b306 | 248 | results = Dir[targets] |
ram54288 | 0:a7a43371b306 | 249 | raise "No *.testpass, *.testfail, or *.testresults files found in '#{targets}'" if results.empty? |
ram54288 | 0:a7a43371b306 | 250 | utj.set_targets(results) |
ram54288 | 0:a7a43371b306 | 251 | |
ram54288 | 0:a7a43371b306 | 252 | #set the root path |
ram54288 | 0:a7a43371b306 | 253 | utj.set_root_path(options.root_path) |
ram54288 | 0:a7a43371b306 | 254 | |
ram54288 | 0:a7a43371b306 | 255 | #set the output XML file name |
ram54288 | 0:a7a43371b306 | 256 | #puts "Output File from options: #{options.out_file}" |
ram54288 | 0:a7a43371b306 | 257 | utj.set_out_file(options.out_file) |
ram54288 | 0:a7a43371b306 | 258 | |
ram54288 | 0:a7a43371b306 | 259 | #run the summarizer |
ram54288 | 0:a7a43371b306 | 260 | puts utj.run |
ram54288 | 0:a7a43371b306 | 261 | rescue Exception => e |
ram54288 | 0:a7a43371b306 | 262 | utj.usage e.message |
ram54288 | 0:a7a43371b306 | 263 | end |
ram54288 | 0:a7a43371b306 | 264 | end |