aboutsummaryrefslogtreecommitdiff
path: root/tests/unity/auto/parse_output.rb
blob: 8e88fff044230b4e86bf8ce5d3fbf1b9fe349900 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
#============================================================
#  Author:   John Theofanopoulos
#  A simple parser.   Takes the output files generated during the build process and
# extracts information relating to the tests.
#
#  Notes:
#    To capture an output file under VS builds use the following:
#      devenv [build instructions]  > Output.txt & type Output.txt
#
#    To capture an output file under GCC/Linux builds use the following:
#      make | tee Output.txt
#
#    To use this parser use the following command
#    ruby parseOutput.rb [options] [file]
#        options:  -xml  : produce a JUnit compatible XML file
#        file      :  file to scan for results
#============================================================

class ParseOutput
  def initialize
    @test_flag = false
    @xml_out = false
    @array_list = false
    @total_tests = false
    @class_index = false
  end

  #   Set the flag to indicate if there will be an XML output file or not
  def set_xml_output
    @xml_out = true
  end

  #  if write our output to XML
  def write_xml_output
    output = File.open('report.xml', 'w')
    output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
    @array_list.each do |item|
      output << item << "\n"
    end
    output << "</testsuite>\n"
  end

  #  This function will try and determine when the suite is changed.   This is
  # is the name that gets added to the classname parameter.
  def test_suite_verify(test_suite_name)
    return if @test_flag

    @test_flag = true
    # Split the path name
    test_name = test_suite_name.split('/')
    # Remove the extension
    base_name = test_name[test_name.size - 1].split('.')
    @test_suite = 'test.' + base_name[0]
    printf "New Test: %s\n", @test_suite
  end

  # Test was flagged as having passed so format the output
  def test_passed(array)
    last_item = array.length - 1
    test_name = array[last_item - 1]
    test_suite_verify(array[@class_name])
    printf "%-40s PASS\n", test_name

    return unless @xml_out

    @array_list.push '     <testcase classname="' + @test_suite + '" name="' + test_name + '"/>'
  end

  # Test was flagged as having passed so format the output.
  # This is using the Unity fixture output and not the original Unity output.
  def test_passed_unity_fixture(array)
    test_suite = array[0].sub('TEST(', '')
    test_suite = test_suite.sub(',', '')
    test_name = array[1].sub(')', '')

    return unless @xml_out

    @array_list.push '     <testcase classname="' + test_suite + '" name="' + test_name + '"/>'
  end

  # Test was flagged as being ignored so format the output
  def test_ignored(array)
    last_item = array.length - 1
    test_name = array[last_item - 2]
    reason = array[last_item].chomp
    test_suite_verify(array[@class_name])
    printf "%-40s IGNORED\n", test_name

    if test_name.start_with? 'TEST('
      array2 = test_name.split(' ')
      @test_suite = array2[0].sub('TEST(', '')
      @test_suite = @test_suite.sub(',', '')
      test_name = array2[1].sub(')', '')
    end

    return unless @xml_out

    @array_list.push '     <testcase classname="' + @test_suite + '" name="' + test_name + '">'
    @array_list.push '            <skipped type="TEST IGNORED"> ' + reason + ' </skipped>'
    @array_list.push '     </testcase>'
  end

  # Test was flagged as having failed  so format the line
  def test_failed(array)
    last_item = array.length - 1
    test_name = array[last_item - 2]
    reason = array[last_item].chomp + ' at line: ' + array[last_item - 3]
    test_suite_verify(array[@class_name])
    printf "%-40s FAILED\n", test_name

    if test_name.start_with? 'TEST('
      array2 = test_name.split(' ')
      @test_suite = array2[0].sub('TEST(', '')
      @test_suite = @test_suite.sub(',', '')
      test_name = array2[1].sub(')', '')
    end

    return unless @xml_out

    @array_list.push '     <testcase classname="' + @test_suite + '" name="' + test_name + '">'
    @array_list.push '            <failure type="ASSERT FAILED"> ' + reason + ' </failure>'
    @array_list.push '     </testcase>'
  end

  # Figure out what OS we are running on.   For now we are assuming if it's not Windows it must
  # be Unix based.
  def detect_os
    os = RUBY_PLATFORM.split('-')
    @class_name = if os.size == 2
                    if os[1] == 'mingw32'
                      1
                    else
                      0
                    end
                  else
                    0
                  end
  end

  # Main function used to parse the file that was captured.
  def process(name)
    @test_flag = false
    @array_list = []

    detect_os

    puts 'Parsing file: ' + name

    test_pass = 0
    test_fail = 0
    test_ignore = 0
    puts ''
    puts '=================== RESULTS ====================='
    puts ''
    File.open(name).each do |line|
      # Typical test lines look like this:
      # <path>/<test_file>.c:36:test_tc1000_opsys:FAIL: Expected 1 Was 0
      # <path>/<test_file>.c:112:test_tc5004_initCanChannel:IGNORE: Not Yet Implemented
      # <path>/<test_file>.c:115:test_tc5100_initCanVoidPtrs:PASS
      #
      # where path is different on Unix vs Windows devices (Windows leads with a drive letter)
      line_array = line.split(':')

      # If we were able to split the line then we can look to see if any of our target words
      # were found.  Case is important.
      if (line_array.size >= 4) || (line.start_with? 'TEST(')
        # Determine if this test passed
        if line.include? ':PASS'
          test_passed(line_array)
          test_pass += 1
        elsif line.include? ':FAIL:'
          test_failed(line_array)
          test_fail += 1
        elsif line.include? ':IGNORE:'
          test_ignored(line_array)
          test_ignore += 1
        elsif line.start_with? 'TEST('
          if line.include? ' PASS'
            line_array = line.split(' ')
            test_passed_unity_fixture(line_array)
            test_pass += 1
          end
        # If none of the keywords are found there are no more tests for this suite so clear
        # the test flag
        else
          @test_flag = false
        end
      else
        @test_flag = false
      end
    end
    puts ''
    puts '=================== SUMMARY ====================='
    puts ''
    puts 'Tests Passed  : ' + test_pass.to_s
    puts 'Tests Failed  : ' + test_fail.to_s
    puts 'Tests Ignored : ' + test_ignore.to_s
    @total_tests = test_pass + test_fail + test_ignore

    return unless @xml_out

    heading = '<testsuite tests="' + @total_tests.to_s + '" failures="' + test_fail.to_s + '"' + ' skips="' + test_ignore.to_s + '">'
    @array_list.insert(0, heading)
    write_xml_output
  end
end

# If the command line has no values in, used a default value of Output.txt
parse_my_file = ParseOutput.new

if ARGV.size >= 1
  ARGV.each do |a|
    if a == '-xml'
      parse_my_file.set_xml_output
    else
      parse_my_file.process(a)
      break
    end
  end
end