require "teaspoon/formatter/base"
require "cgi"

module Teaspoon
  module Formatter
    class Junit < Base
      protected

      def log_runner(result)
        log_line(%{<?xml version="1.0" encoding="UTF-8"?>})
        log_line(%{<testsuites name="Teaspoon">})
        start_time = Time.parse(result.start).iso8601
        log_line(%{<testsuite name="#{escape(@suite_name)}" tests="#{@total_count}" timestamp="#{start_time}">})
      end

      def log_suite(result)
        log_end_suite
        log_line(%{<testsuite name="#{escape(result.label)}">})
      end

      def log_passing_spec(result)
        log_junit_spec(suite: result.suite, label: result.label)
      end

      def log_pending_spec(result)
        log_junit_spec(suite: result.suite, label: result.label) do
          log_line(%{  <skipped/>})
        end
      end

      def log_failing_spec(result)
        log_junit_spec(suite: result.suite, label: result.label) do
          log_line(%{  <failure type="AssertionFailed">#{cdata(result.message)}</failure>})
        end
      end

      def log_result(_result)
        log_end_suite
      end

      def log_coverage(message)
        properties = "<properties>#{cdata(message)}</properties>"
        log_line(%{<testsuite name="Coverage summary" tests="0">\n#{properties}\n</testsuite>})
      end

      def log_threshold_failure(message)
        log_line(%{<testsuite name="Coverage thresholds" tests="1">})
        log_junit_spec(suite: "Coverage thresholds", label: "were not met") do
          log_line(%{  <failure type="AssertionFailed">#{cdata(message)}</failure>})
        end
        log_line(%{</testsuite>})
      end

      def log_complete(_failure_count)
        log_line(%{</testsuite>\n</testsuites>})
      end

      private

      def log_end_suite
        log_line(%{</testsuite>}) if @last_suite
      end

      def log_junit_spec(opts, &_block)
        log_line(%{<testcase classname="#{escape(opts[:suite])}" name="#{escape(opts[:label])}">})
        yield if block_given?
        log_line(%{<system-out>#{cdata(@stdout)}</system-out>}) unless @stdout.blank?
        log_line(%{</testcase>})
      end

      def escape(str)
        CGI::escapeHTML(str)
      end

      def cdata(str)
        "\n<![CDATA[\n#{str.gsub(/\n$/, '')}\n]]>\n"
      end
    end
  end
end