Instantly share code, notes, and snippets.

@veproza /setup.php
Last active Aug 25, 2018

Embed
What would you like to do?
TeamCity output including test duration for Nette Tester. Requires a custom Tester fork: https://github.com/veproza/tester (or just this commit: https://github.com/veproza/tester/commit/d3f4ad2c500d2b927eb372ec2be9b2f594bec9bc)
<?php
/**
* By jiripudil, https://github.com/jiripudil/intellij-nette-tester/blob/master/resources/setup.php
* @license https://github.com/jiripudil/intellij-nette-tester/blob/master/LICENSE.md
*/
use Tester\Runner\Runner;
final class TeamCityOutputHandler implements \Tester\Runner\StartAwareOutputHandler
{
/**
* @var resource
*/
private $file;
/**
* @var float[]
*/
private $startTimes;
public function __construct($output = 'php://output')
{
$this->file = \fopen($output, 'w');
}
public function begin(): void
{
// \fwrite($this->file, $this->message('testCount', array('count' => 0)));
}
function start(\Tester\Runner\Test $test): void
{
$flowId = \md5($test->getSignature());
$this->startTimes[$flowId] = microtime(TRUE);
$testName = $this->getTestName($test);
\fwrite($this->file, $this->message('testStarted', ['name' => $testName, 'flowId' => $flowId]));
}
function finish(\Tester\Runner\Test $test): void
{
$testName = $this->getTestName($test);
$message = $test->message;
$flowId = \md5($test->getSignature());
$durationMicros = microtime(TRUE) - $this->startTimes[$flowId];
$duration = round($durationMicros * 1000);
if ($test->getResult() === \Tester\Runner\Test::SKIPPED) {
\fwrite($this->file, $this->message('testIgnored', ['name' => $testName, 'flowId' => $flowId, 'message' => 'Test skipped', 'details' => $message]));
} elseif ($test->getResult() === \Tester\Runner\Test::FAILED) { // Runner::FAILED, Test::FAILED
$extraArguments = [];
if (\preg_match("/^diff \"(.*)\" \"(.*)\"$/m", $message, $matches)) { // Windows build
$expectedFile = \str_replace('""', '"', $matches[1]);
$actualFile = \str_replace('""', '"', $matches[2]);
$extraArguments = ['type' => 'comparisonFailure', 'expectedFile' => $expectedFile, 'actualFile' => $actualFile];
} elseif (\preg_match("/^diff '?(.*)'? '?(.*)'?$/m", $message, $matches)) {
$expectedFile = \trim($matches[1], "'");
$actualFile = \trim($matches[2], "'");
$extraArguments = ['type' => 'comparisonFailure', 'expectedFile' => $expectedFile, 'actualFile' => $actualFile];
} elseif (\preg_match("/Failed: (.*) should be( equal to)?\s+\.*\s*(.*) in/is", $message, $matches)) {
$expected = $matches[3];
$actual = $matches[1];
$extraArguments = ['type' => 'comparisonFailure', 'expected' => $expected, 'actual' => $actual];
}
$args = \array_merge([
'name' => $testName,
'flowId' => $flowId,
'message' => 'Test failed',
'details' => $message,
'duration' => $duration,
], $extraArguments);
\fwrite($this->file, $this->message('testFailed', $args));
}
\fwrite($this->file, $this->message('testFinished', ['name' => $testName, 'flowId' => $flowId, 'duration' => $duration]));
}
private function message($messageName, $args)
{
$argsPairs = [];
foreach ($args as $arg => $value) {
$argsPairs[] = \sprintf("%s='%s'", $arg, $this->escape($value));
}
return \sprintf(
"##teamcity[%s %s]\n\n",
$messageName,
\implode(' ', $argsPairs)
);
}
private function escape($value)
{
$replace = [
"|" => "||",
"'" => "|'",
"\n" => "|n",
"\r" => "|r",
"]" => "|]",
"[" => "|[",
];
return \strtr($value, $replace);
}
public function end(): void
{
}
function prepare(\Tester\Runner\Test $test): void
{
// noop
}
/**
* @param \Tester\Runner\Test $test
* @return null|string
*/
private function getTestName(\Tester\Runner\Test $test)
{
return $test->title
? $test->title
: str_replace(__DIR__ . DIRECTORY_SEPARATOR, '', $test->getFile());
}
}
/** @var Runner $runner */
// replace registered output handlers with TC
$runner->outputHandlers = [new TeamCityOutputHandler()];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment