summaryrefslogtreecommitdiff
path: root/spec/mspec/lib/mspec/runner/formatters/junit.rb
blob: 647deee7e1b5af7fbcc02de017c962e4fed2282c (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
require 'mspec/expectations/expectations'
require 'mspec/utils/ruby_name'
require 'mspec/runner/formatters/yaml'

class JUnitFormatter < YamlFormatter
  def initialize(out=nil)
    super
    @tests = []
  end

  def after(state = nil)
    super
    @tests << {:test => state, :exception => false} unless exception?
  end

  def exception(exception)
    super
    @tests << {:test => exception, :exception => true}
  end

  def finish
    switch

    time = @timer.elapsed
    tests = @tally.counter.examples
    errors = @tally.counter.errors
    failures = @tally.counter.failures

    printf <<-XML

<?xml version="1.0" encoding="UTF-8" ?>
    <testsuites
        testCount="#{tests}"
        errorCount="#{errors}"
        failureCount="#{failures}"
        timeCount="#{time}" time="#{time}">
      <testsuite
          tests="#{tests}"
          errors="#{errors}"
          failures="#{failures}"
          time="#{time}"
          name="Spec Output For #{::RUBY_NAME} (#{::RUBY_VERSION})">
    XML
    @tests.each do |h|
      description = encode_for_xml h[:test].description

      printf <<-XML, "Spec", description, 0.0
        <testcase classname="%s" name="%s" time="%f">
      XML
      if h[:exception]
        outcome = h[:test].failure? ? "failure" : "error"
        message = encode_for_xml h[:test].message
        backtrace = encode_for_xml h[:test].backtrace
        print <<-XML
          <#{outcome} message="error in #{description}" type="#{outcome}">
            #{message}
            #{backtrace}
          </#{outcome}>
        XML
      end
      print <<-XML
        </testcase>
      XML
    end

    print <<-XML
      </testsuite>
    </testsuites>
    XML
  end

  private
  LT = "&lt;"
  GT = "&gt;"
  QU = "&quot;"
  AP = "&apos;"
  AM = "&amp;"
  TARGET_ENCODING = "ISO-8859-1"

  def encode_for_xml(str)
    encode_as_latin1(str).gsub("<", LT).gsub(">", GT).
      gsub('"', QU).gsub("'", AP).gsub("&", AM).
      tr("\x00-\x08", "?")
  end

  def encode_as_latin1(str)
    str.encode(TARGET_ENCODING, :undef => :replace, :invalid => :replace)
  end
end