Module: RSpecFlake

Defined in:
lib/rspec_flake/parse.rb,
lib/rspec_flake/merge.rb,
lib/rspec_flake/stats.rb,
lib/rspec_flake/convert.rb,
lib/rspec_flake/version.rb,
lib/rspec_flake/rspec_flake.rb

Overview

<testsuite errors=“0” failures=“0” skipped=“0” tests=“4” time=“0.001283” timestamp=“2015-01-15T10:25:40-05:00”>

<testsuite location="./spec/a_spec.rb:1" name="a" tests="2" errors="0" failures="0" skipped="0">
  <testcase name="a a 1" time="0.000177" location="./spec/a_spec.rb:6">

# sax parser # nokogiri.org/Nokogiri/XML/SAX.html

Defined Under Namespace

Classes: ReportParser, Runner

Constant Summary collapse

VERSION =
'0.0.2'
DATE =
'2015-01-16'

Class Method Summary collapse

Class Method Details

.cdata(content) ⇒ Object



30
31
32
# File 'lib/rspec_flake/convert.rb', line 30

def cdata content
  "\n<![CDATA[#{content}]]>\n"
end

.hash_to_xml(source_hash) ⇒ Object



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
# File 'lib/rspec_flake/convert.rb', line 3

def hash_to_xml source_hash
  # top level attribues from root node
  converted             = source_hash[:testsuites][:attrs] || {}
  converted[:testsuite] = []

  source_hash[:testsuites][:testsuite].each do |suite_location, suite_obj|
    suite_with_tests            = suite_obj[:attrs] || {}
    suite_with_tests[:testcase] = []
    suite_obj[:testcase].each do |testcase_location, testcase_obj|
      testcase = testcase_obj[:attrs]
      if testcase_obj[:failure]
        fail_content = testcase_obj[:failure][:content]
        fail_content = cdata fail_content
        # content key must be a string for xml simple
        testcase.merge!(failure: testcase_obj[:failure][:attrs].merge('content' => fail_content))
      end
      suite_with_tests[:testcase] << testcase
    end

    converted[:testsuite] << suite_with_tests
  end

  # ap converted, index: false, indent: 2

  xml_out converted
end

.merge_xml(opts = {}) ⇒ Object

merge input xml files into a hash

input - single path or array of paths to input xml files

Returns:

  • merged hash



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
# File 'lib/rspec_flake/merge.rb', line 8

def merge_xml opts={}
  input = opts[:input]
  raise 'input path(s) not provided' unless input
  input = [input] unless input.kind_of?(Array)

  merged = { testsuite: { testcase: {} } }

  # annotate each testcase node with two attributes
  #
  # failures - amount of times this test failed
  # runs     - amount of times this test was executed
  #
  # name/time - saved from the first run of the testcase
  # location - stored for each run

  input.each do |xml_path|
    parsed = parse_xml(xml_path)

    parsed[:testsuites][:testsuite].each do |suite_location, suite_obj|
      suite_obj[:testcase].each do |testcase_location, testcase_obj|
        attrs = testcase_obj[:attrs]
        test  = merged[:testsuite][:testcase][testcase_location] ||= { failures: 0, runs: 0, name: attrs['name'], location: attrs['location'], time: [] }

        if testcase_obj[:failure]
          test[:failures] += 1
          test[:failure]  ||= []
          test[:failure] << { 'content' => cdata(testcase_obj[:failure][:content]) }
        end
        test[:runs] += 1
        test[:time] << attrs['time']
      end
    end
  end

  # transform merge hash keyed on location into simple testcase array
  # for xml conversion
  converted = { testsuite: { testcase: [] } }

  merged[:testsuite][:testcase].each do |testcase_location, testcase_obj|
    converted[:testsuite][:testcase] << testcase_obj
  end

  xml_out converted
end

.parse_xml(xml_path) ⇒ Object



72
73
74
75
76
77
78
79
80
# File 'lib/rspec_flake/parse.rb', line 72

def parse_xml xml_path
  xml = read_as_utf8 xml_path

  parser = @parser ||= Nokogiri::XML::SAX::Parser.new(ReportParser.new)
  parser.document.reset
  parser.parse xml

  parser.document.result
end

.read_as_utf8(path) ⇒ Object



68
69
70
# File 'lib/rspec_flake/parse.rb', line 68

def read_as_utf8 path
  File.read(path).encode!('UTF-8', invalid: :replace, undef: :replace, replace: '')
end

.stats_from_merge_xml(xml_string) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/rspec_flake/stats.rb', line 3

def stats_from_merge_xml xml_string
  output = ''

  xml = Nokogiri::XML(xml_string)
  xml.xpath('//testcase').each do |testcase|
    # <testcase failures="0" runs="3" name="a a 1" location="./spec/a_spec.rb:6">
    failures = testcase[:failures]
    runs     = testcase[:runs]
    name     = testcase[:name]
    location = testcase[:location]

    times = []
    testcase.xpath('time').each do |time|
     times << time.content.to_f
    end

    average_time = (times.inject(:+).to_f / times.size).round 2

    output += "#{name} - runs: #{runs} - failures: #{failures} - avg time: #{average_time} - #{location}\n"
  end

  output
end

.xml_out(hash) ⇒ Object



34
35
36
37
38
39
40
# File 'lib/rspec_flake/convert.rb', line 34

def xml_out hash
  xml_header = %Q(<?xml version="1.0" encoding="UTF-8"?>\n)
  xml_body   = XmlSimple.xml_out(hash, RootName: 'testsuites')
  # xmlsimple will escape the cdata by default
  xml_body   = EscapeUtils.unescape_html xml_body
  xml_header + xml_body
end