Module: JunitParser

Defined in:
lib/assets/junit_parser.rb

Constant Summary collapse

SKIP_STR_IN_MATCH =
['*', '\n', '\\', '//']

Class Method Summary collapse

Class Method Details

.add_code(codefragment) ⇒ Object



87
88
89
# File 'lib/assets/junit_parser.rb', line 87

def self.add_code(codefragment)
  "<![CDATA[#{codefragment}]]>"
end

.add_failed_testcase(name, failures) ⇒ Object



37
38
39
40
# File 'lib/assets/junit_parser.rb', line 37

def self.add_failed_testcase(name, failures)
  "#{xml_level(2)}<testcase name='#{name}'>" \
  "#{failures}#{xml_level(2)}</testcase>"
end

.add_failure(message, type, text) ⇒ Object



52
53
54
55
56
57
# File 'lib/assets/junit_parser.rb', line 52

def self.add_failure(message, type, text)
  "#{xml_level(3)}<failure #{insert_attribute('type', type)} status='failed' " \
  "#{insert_attribute('message', message)}>" \
	"#{text}" \
	"#{xml_level(3)}</failure>"
end

.add_properties(property_array, value_array) ⇒ Object



63
64
65
66
67
68
69
70
71
72
# File 'lib/assets/junit_parser.rb', line 63

def self.add_properties(property_array, value_array)
  properties = "#{xml_level(2)}<properties>"
  property_array.each_with_index do |property, index|
    value = value_array[index]
    unless value.nil?
      properties += "#{xml_level(3)}<property name='#{property}' value='#{value}' />"
    end
  end
  properties += "#{xml_level(2)}</properties>"
end

.add_skipped_testcase(name, assertions, message) ⇒ Object



46
47
48
49
50
# File 'lib/assets/junit_parser.rb', line 46

def self.add_skipped_testcase(name, assertions, message)
  out = message == '' ? '' : add_system_output(message)
  "#{xml_level(2)}<testcase #{insert_attribute('name', name)} #{insert_attribute('assertions', assertions)}>" \
  "#{out}#{xml_level(3)}<skipped/>#{xml_level(2)}</testcase>"
end

.add_success_testcase(name, assertions) ⇒ Object



42
43
44
# File 'lib/assets/junit_parser.rb', line 42

def self.add_success_testcase(name, assertions)
  "#{xml_level(2)}<testcase name='#{name}' #{insert_attribute('assertions', assertions)} status='success'/>"
end

.add_system_output(text) ⇒ Object



59
60
61
# File 'lib/assets/junit_parser.rb', line 59

def self.add_system_output(text)
  "#{xml_level(3)}<system-out>#{text}#{xml_level(3)}</system-out>"
end

.add_testsuite(name, testcases) ⇒ Object



31
32
33
34
35
# File 'lib/assets/junit_parser.rb', line 31

def self.add_testsuite(name, testcases)
  "#{xml_level(1)}<testsuite name='#{name}'>" \
  "#{testcases}" \
  "#{xml_level(1)}</testsuite>"
end

.check_for_file_info(text_list) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/assets/junit_parser.rb', line 152

def self.check_for_file_info(text_list)
  result = []
  text_list.each_with_index do |text, i|
    file = %r{([a-zA-Z0-9\.]*)?(/[a-zA-Z0-9\._-]+)*(\.){1}[a-zA-Z0-9\._-]+}.match(text)
    file = nil if file.to_s =~ /\.{2,}/
    next if file.nil?
    next_value = text_list.to_a[i.to_i + 1].nil? ? '' : text_list.to_a[i.to_i + 1]
    line = /[0-9]+/.match(next_value)
    if line.nil?
      result = [file]
    else
      result = [file, line]
    end
    break
  end
  result
end

.construct_failure_mes(attributes, values) ⇒ Object



74
75
76
77
78
79
80
81
# File 'lib/assets/junit_parser.rb', line 74

def self.construct_failure_mes(attributes, values)
  properties = ''
  attributes.each_with_index do |property, index|
    value = values[index]
    properties += format("#{xml_level(4)}%-18s: %s", property, value) unless value.nil?
  end
  properties
end

.create_clang_xml(file_replacements, skipped) ⇒ Object



306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/assets/junit_parser.rb', line 306

def self.create_clang_xml(file_replacements, skipped)
  xml = ''
  file_replacements.each do |i_hash|
    if skipped
      new_code_fragment = read_lines_in_file(i_hash[:file], i_hash[:code_lines][0], i_hash[:code_lines][1], true)
      error_text = construct_failure_mes(
        ['Code fragment with formatting issue', "#{xml_level(4)}Clang fix", "#{xml_level(4)}Code fragment after clang fix"],
        [i_hash[:old_code], i_hash[:fix_code], new_code_fragment]
      )
      xml += add_skipped_testcase("F#{i_hash[:file_id]}:#{i_hash[:file]}:#{i_hash[:code_lines][0] + 1}", '', error_text)
    else
      error_text = construct_failure_mes(
        ['Code fragment with formatting issue', "#{xml_level(4)}Clang fix"],
        [i_hash[:old_code], i_hash[:fix_code]]
      )
      failure = add_failure('', '', error_text)
      xml += add_failed_testcase("F#{i_hash[:file_id]}:#{i_hash[:file]}:#{i_hash[:code_lines][0] + 1}", failure)
    end
  end
  xml
end

.create_junit_xml(testsuite, result_file_name) ⇒ Object

create root xml content



108
109
110
111
# File 'lib/assets/junit_parser.rb', line 108

def self.create_junit_xml(testsuite, result_file_name)
  full_data = create_testsuites(testsuite)
  create_xml(full_data, result_file_name)
end

.create_testsuites(testsuites) ⇒ Object



27
28
29
# File 'lib/assets/junit_parser.rb', line 27

def self.create_testsuites(testsuites)
  "#{xml_level(0)}<testsuites>#{testsuites}#{xml_level(0)}</testsuites>"
end

.create_xml(xml_data_custom, result_file_name) ⇒ Object

For all parsers =================


19
20
21
22
23
24
25
# File 'lib/assets/junit_parser.rb', line 19

def self.create_xml(xml_data_custom, result_file_name)
  xml_data = '<?xml version="1.0" encoding="UTF-8"?>'
  xml_data += xml_data_custom
  File.open(result_file_name, 'w') do |f|
    f.write(xml_data)
  end
end

.get_code_lines(value, value_end, file_lines) ⇒ Object



360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
# File 'lib/assets/junit_parser.rb', line 360

def self.get_code_lines(value, value_end, file_lines)
  s_line = file_lines[:start]
  e_line = file_lines[:finish]
  value = value.to_i
  start_flag = false
  finish_flag = false
  start = 0
  finish = 0
  s_line.each_with_index do |line, index|
    if value >= line and value < e_line[index] and !start_flag
      start = file_lines[:line][index]
      start_flag = true
    end
    if value_end > line and value_end <= e_line[index] and !finish_flag
      finish = file_lines[:line][index]
      finish_flag = true
    end
    break if start_flag and finish_flag
  end
  [start, finish]
end

.get_failure_type(str) ⇒ Object



91
92
93
94
95
# File 'lib/assets/junit_parser.rb', line 91

def self.get_failure_type(str)
  failure_type = str[/\[(.*?)\]/, 1]
  failure_type = '-W' if failure_type.nil?
  failure_type
end

.insert_attribute(attribute, value) ⇒ Object



83
84
85
# File 'lib/assets/junit_parser.rb', line 83

def self.insert_attribute(attribute, value)
  (value == '' or value.nil?) ? '' : "#{attribute}='#{value}'"
end

.parse_clang(clang_changes, inspected_file, file_id, file_lines) ⇒ Object

Clang Parser ==================


265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/assets/junit_parser.rb', line 265

def self.parse_clang(clang_changes, inspected_file, file_id, file_lines)
  count = 0
  file_replacements = []
  clang_changes.each_line do |line|
    next unless line =~ %r{</replacement>}
    hash = parse_str(line)
    offset = hash[:offset]
    offset_long = hash[:length]
    offset_end = offset.to_i + offset_long.to_i
    code_lines = get_code_lines(offset, offset_end, file_lines)
    # read current code fragment that include clang format issue
    current_code_fragment = read_lines_in_file(inspected_file, code_lines[0], code_lines[1], false)

    # make clang format replacement more understandable
    replacements = hash[:replacements]
    fixed_code_fragment = replacements
    fixed_code_fragment = replacements.sub("&#10;", '') if replacements =~ /(&#10;){2,}./
    fixed_code_fragment.gsub!("&#10;", "\n")
    replace_in(fixed_code_fragment)
    fixed_code_fragment = "\n'#{add_code(fixed_code_fragment)}'"

    # if replacements.match(/^([a-zA-Z0-9])[\n&#10;]*(\ )*$/)
    #   if offset_long.to_i == 1
    #     fixed_code_fragment = "change one character (remove/add space/tab/new line). Replacement: #{fixed_code_fragment.sub("\n", '')}"
    #   else
    #     fixed_code_fragment = "generally needed to remove/add space/tab/new line. Replacement: #{fixed_code_fragment.sub("\n", '')}"
    #   end
    # end

    hash_info = { old_code: current_code_fragment,
    fix_code: fixed_code_fragment,
    code_lines: code_lines,
    file: inspected_file,
    file_id: file_id }
    file_replacements.push(hash_info)

    count += 1
  end
  [count, file_replacements]
end

.parse_code_duplications(data_hash) ⇒ Object



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/assets/junit_parser.rb', line 231

def self.parse_code_duplications(data_hash)
  xml = ''
  duplications = data_hash['pmd_cpd']['duplication']
  if duplications.kind_of?(Array)
    index = 1
    duplications.each do |error|
      parsed_files = parse_inspected_files(error['file'])
      failure = add_failure("lines:#{error['lines']} tokens:#{error['tokens']} #{xml_level(3)}files:#{parsed_files}", '', "\n#{add_code(error['codefragment'])}")
      xml += add_failed_testcase("duplication #{index}", failure)
      index += 1
    end
  else
    parsed_files = parse_inspected_files(duplications['file'])
    failure = add_failure("lines:#{duplications['lines']} tokens:#{duplications['tokens']} #{xml_level(3)}files:#{parsed_files}", '',
                          "\n #{add_code(duplications['codefragment'])}")
    xml += add_failed_testcase('single duplication', failure)
  end
  xml
end

.parse_hash(data_hash) ⇒ Object

Method return testsuites xml content after that call create_junit_xml to get full JUnit file



396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
# File 'lib/assets/junit_parser.rb', line 396

def self.parse_hash(data_hash)
  testcase_xml = ''
  testcases = data_hash[:testcase]
  testcases.each do |error|
    testcase_name = error[:name]
    testcase_err_num = error[:assertions]
    testcase_message = error[:message]
    case error[:status].downcase
    when 'success'
      testcase_xml += add_success_testcase(testcase_name, testcase_err_num, '')
    when 'fail'
      if testcase_message.nil?
        failure = add_failure('', '', '')
      else
        failure = add_failure(testcase_message[:additional_info], testcase_message[:type], testcase_message[:message])
      end
      testcase_xml += add_failed_testcase(testcase_name, failure)
    when 'skip'
      testcase_xml += add_skipped_testcase(testcase_name, testcase_err_num, '')
    end
  end
  properties = ''
  unless data_hash[:properties].nil?
    keys = data_hash[:properties].keys
    values = data_hash[:properties].values
    properties = add_properties(keys, values)
  end
  testsuite = add_testsuite(data_hash[:test_group_name], properties + testcase_xml)
  testsuite
end

.parse_inspected_files(file_list) ⇒ Object



251
252
253
254
255
256
257
258
259
# File 'lib/assets/junit_parser.rb', line 251

def self.parse_inspected_files(file_list)
  index = 1
  file_list_info = []
  file_list.each do |file|
    file_list_info.push("File #{index}: #{file['path']}::#{file['line']}")
    index += 1
  end
  file_list_info
end

.parse_json(file) ⇒ Object

Rubocop-json Parser ================


174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/assets/junit_parser.rb', line 174

def self.parse_json(file)
  data_read = File.read(file)
  data_hash = Crack::JSON.parse(data_read)

  keys = data_hash['metadata'].keys.zip(data_hash['summary'].keys).flatten.compact
  values = data_hash['metadata'].values.zip(data_hash['summary'].values).flatten.compact
  properties = add_properties(keys, values)

  testcase = parse_main_json(data_hash)

  properties + testcase
end

.parse_location(location) ⇒ Object



211
212
213
# File 'lib/assets/junit_parser.rb', line 211

def self.parse_location(location)
  "#{location['line']}:#{location['column']}:#{location['length']}"
end

.parse_main_json(data_hash) ⇒ Object

create main xml content



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/assets/junit_parser.rb', line 188

def self.parse_main_json(data_hash)
  xml = ''
  data_hash['files'].each do |inspected_file|
    error_text = ''
    errors = inspected_file['offenses']
    if errors.empty?
      xml += add_success_testcase((inspected_file['path']).to_s, '')
    else
      errors.each do |error|
        error_text += construct_failure_mes(
          ['Error isCorrected', 'Error ClassType', 'Error Line', 'Error Message'],
          [error['corrected'], "#{error['cop_name']} (#{error['severity']})",
           parse_location(error['location']), error['message'].tr("\n", '')]
        )
      end
      # TODO: corrected:6 failded:0 (if needed this info)
      failures = add_failure('lineformat=line:column:length', '', error_text)
      xml += add_failed_testcase((inspected_file['path']).to_s, failures)
    end
  end
  xml
end

.parse_str(str) ⇒ Object



349
350
351
352
353
354
355
356
357
358
# File 'lib/assets/junit_parser.rb', line 349

def self.parse_str(str)
  # TODO: check if no any replacements...will it be crashes
  byte_offset = str.match(/offset='[0-9]+'/).to_s.tr('\'', '').split('=')[1]
  length_of_changes = str.match(/length='[0-9]+'/).to_s.tr('\'', '').split('=')[1]
  replaced = str.match(%r{>(.)*</replacement>}).to_s
  replaced[0] = ''
  replaced = replaced.sub('</replacement>', '')

  { offset: byte_offset, length: length_of_changes, replacements: replaced }
end

.parse_xcode_log(file, project, is_warn) ⇒ Object

Xcode-log Parser ================


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
# File 'lib/assets/junit_parser.rb', line 117

def self.parse_xcode_log(file, project, is_warn)
  if is_warn
    error_text = ''
    temp_testcase = ''
    File.open(file).each do |line|
      next unless line =~ /warning:|error:|BCEROR/
      failure_type = get_failure_type(line)
      warning_params = line.split(':')
      if warning_params.count == 5
        error_text = construct_failure_mes(
          ['Error ClassType', 'Error Message'],
          [failure_type, warning_params[4].tr("\n", '')]
        )
        testcase_name = project + ':' + warning_params[0].tr('<', '').tr('>', '') +
                        ":#{warning_params[1]}:#{warning_params[2]}"
      else
        error_text = construct_failure_mes(
          ['Error ClassType', 'Error Message'],
          [failure_type, line.tr("\n", '').gsub('warning:', '')]
        )
        testcase_name = project
        testcase_name += ':project configuration' if line =~ /BCEROR/
        file_info = check_for_file_info(warning_params)
        testcase_name += ":#{file_info[0]}" unless file_info[0].nil?
        testcase_name += ":#{file_info[1]}" unless file_info[1].nil?
      end
      failures = add_failure('', '', error_text)
      temp_testcase += add_failed_testcase(testcase_name, failures)
    end
    temp_testcase
  else
    add_success_testcase(project, '')
  end
end

.parse_xml(file) ⇒ Object

CPD-xml Parser ==================


219
220
221
222
223
224
225
226
227
228
229
# File 'lib/assets/junit_parser.rb', line 219

def self.parse_xml(file)
  data_read = File.read(file)
  data_hash = Crack::XML.parse(data_read)

  if data_hash.empty? or data_hash['pmd_cpd'].nil?
    puts 'empty data_hash'
    add_success_testcase('casino duplications', '')
  else
    parse_code_duplications(data_hash)
  end
end

.read_lines_in_file(file, read_start, read_to, is_fixed) ⇒ Object



328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/assets/junit_parser.rb', line 328

def self.read_lines_in_file(file, read_start, read_to, is_fixed)
  lines = ''
  read_from = (read_start - 5) < 0 ? 0 : (read_start - 5)
  read_to += 5
  index = read_from
  space_count = read_to.to_s.count "0-9"
  File.readlines(file).values_at(read_from..read_to).each do |spec_line|
    unless spec_line.nil?
      spec_line = spec_line.chomp
      replace_in(spec_line)
      if index == read_start and !is_fixed
        lines += format("\n&#62;&#62;&#32;%-#{space_count}s&#32;%s", (index + 1), add_code(spec_line))
      else
        lines += format("\n&#32;&#32;&#32;%-#{space_count}s&#32;%s", (index + 1), add_code(spec_line))
      end
    end
    index += 1
  end
  lines
end

.replace_in(text) ⇒ Object



382
383
384
385
386
387
388
# File 'lib/assets/junit_parser.rb', line 382

def self.replace_in(text)
  text.gsub!("&lt;",'<')
  text.gsub!("&gt;",'>')
  text.gsub!("&quot;",'"')
  text.gsub!("&amp;",'&')
  text.gsub!("&apos;",'\'')
end

.xml_level(level) ⇒ Object



97
98
99
100
101
102
103
104
105
# File 'lib/assets/junit_parser.rb', line 97

def self.xml_level(level)
  levelstr = "\n"
  i = 1
  while i < level
    levelstr += "\s\s"
    i += 1
  end
  levelstr
end