require "teaspoon/formatter/base" module Teaspoon module Formatter class Teamcity < Base def initialize(*args) log("enteredTheMatrix timestamp='#{Time.now.to_json.gsub('"', '')}'") super end protected def log_runner(result) log("testCount count='#{result.total}' timestamp='#{result.start}'") end def log_suite(result) log_end_suite log("testSuiteStarted name='#{result.label}'") end def log_passing_spec(result) log_teamcity_spec(type: "testStarted", desc: escape(result.description)) end def log_pending_spec(result) log_teamcity_spec(type: "testIgnored", desc: escape(result.description)) end def log_failing_spec(result) log_teamcity_spec(type: "testStarted", desc: escape(result.description)) do log("testFailed name='#{escape(result.description)}' message='#{escape(result.message)}'") end end def log_error(result) log("message text='#{escape(result.message)}' errorDetails='#{escape_trace(result.trace)}' status='ERROR'") end def log_result(result) log_end_suite @result = result end def log_coverage(message) log("testSuiteStarted name='Coverage summary'") log_line(message) log("testSuiteFinished name='Coverage summary'") end def log_threshold_failure(message) log("testSuiteStarted name='Coverage thresholds'") log_teamcity_spec(type: "testStarted", desc: "Coverage thresholds") do log("testFailed name='Coverage thresholds' message='were not met'") log_line(message) end log("testSuiteFinished name='Coverage thresholds'") end def log_complete(failure_count) log_line("\nFinished in #{@result.elapsed} seconds") stats = "#{pluralize('example', run_count)}, #{pluralize('failure', failure_count)}" stats << ", #{pendings.size} pending" if pendings.size > 0 log_line(stats) log_line if failure_count > 0 end private def log_end_suite log("testSuiteFinished name='#{escape(@last_suite.label)}'") if @last_suite end def log_teamcity_spec(opts, &_block) log("#{opts[:type]} name='#{opts[:desc]}' captureStandardOutput='true'") log_line(@stdout.gsub(/\n$/, "")) unless @stdout.blank? yield if block_given? log("testFinished name='#{opts[:desc]}'") end def log(str) log_line("##teamcity[#{str}]") end def escape(str) str = str.gsub(/[|'\[\]]/) { |c| "|#{c}" } str.gsub("\n", "|n").gsub("\r", "|r") end def escape_trace(trace) lines = trace.map { |t| ["#{t['file']}:#{t['line']}", t["function"]].compact.join(" ") } escape(lines.join("\n")) end end end end