class TeamCityLogger
@no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@internal This class is not covered by the backward compatibility promise for PHPUnit
Hierarchy
- class \PHPUnit\Logging\TeamCity\TeamCityLogger
Expanded class hierarchy of TeamCityLogger
2 files declare their use of TeamCityLogger
- Application.php in vendor/
phpunit/ phpunit/ src/ TextUI/ Application.php - Facade.php in vendor/
phpunit/ phpunit/ src/ TextUI/ Output/ Facade.php
File
-
vendor/
phpunit/ phpunit/ src/ Logging/ TeamCity/ TeamCityLogger.php, line 47
Namespace
PHPUnit\Logging\TeamCityView source
final class TeamCityLogger {
private readonly Printer $printer;
private bool $isSummaryTestCountPrinted = false;
private ?HRTime $time = null;
private ?int $flowId;
/**
* @throws EventFacadeIsSealedException
* @throws UnknownSubscriberTypeException
*/
public function __construct(Printer $printer, Facade $facade) {
$this->printer = $printer;
$this->registerSubscribers($facade);
$this->setFlowId();
}
public function testSuiteStarted(TestSuiteStarted $event) : void {
$testSuite = $event->testSuite();
if (!$this->isSummaryTestCountPrinted) {
$this->isSummaryTestCountPrinted = true;
$this->writeMessage('testCount', [
'count' => $testSuite->count(),
]);
}
$parameters = [
'name' => $testSuite->name(),
];
if ($testSuite->isForTestClass()) {
assert($testSuite instanceof TestSuiteForTestClass);
$parameters['locationHint'] = sprintf('php_qn://%s::\\%s', $testSuite->file(), $testSuite->name());
}
elseif ($testSuite->isForTestMethodWithDataProvider()) {
assert($testSuite instanceof TestSuiteForTestMethodWithDataProvider);
$parameters['locationHint'] = sprintf('php_qn://%s::\\%s', $testSuite->file(), $testSuite->name());
$parameters['name'] = $testSuite->methodName();
}
$this->writeMessage('testSuiteStarted', $parameters);
}
public function testSuiteFinished(TestSuiteFinished $event) : void {
$testSuite = $event->testSuite();
$parameters = [
'name' => $testSuite->name(),
];
if ($testSuite->isForTestMethodWithDataProvider()) {
assert($testSuite instanceof TestSuiteForTestMethodWithDataProvider);
$parameters['name'] = $testSuite->methodName();
}
$this->writeMessage('testSuiteFinished', $parameters);
}
public function testPrepared(Prepared $event) : void {
$test = $event->test();
$parameters = [
'name' => $test->name(),
];
if ($test->isTestMethod()) {
assert($test instanceof TestMethod);
$parameters['locationHint'] = sprintf('php_qn://%s::\\%s::%s', $test->file(), $test->className(), $test->name());
}
$this->writeMessage('testStarted', $parameters);
$this->time = $event->telemetryInfo()
->time();
}
/**
* @throws InvalidArgumentException
*/
public function testMarkedIncomplete(MarkedIncomplete $event) : void {
if ($this->time === null) {
$this->time = $event->telemetryInfo()
->time();
}
$this->writeMessage('testIgnored', [
'name' => $event->test()
->name(),
'message' => $event->throwable()
->message(),
'details' => $this->details($event->throwable()),
'duration' => $this->duration($event),
]);
}
/**
* @throws InvalidArgumentException
*/
public function testSkipped(Skipped $event) : void {
if ($this->time === null) {
$this->time = $event->telemetryInfo()
->time();
}
$parameters = [
'name' => $event->test()
->name(),
'message' => $event->message(),
];
$parameters['duration'] = $this->duration($event);
$this->writeMessage('testIgnored', $parameters);
}
/**
* @throws InvalidArgumentException
*/
public function testErrored(Errored $event) : void {
if ($this->time === null) {
$this->time = $event->telemetryInfo()
->time();
}
$this->writeMessage('testFailed', [
'name' => $event->test()
->name(),
'message' => $this->message($event->throwable()),
'details' => $this->details($event->throwable()),
'duration' => $this->duration($event),
]);
}
/**
* @throws InvalidArgumentException
*/
public function testFailed(Failed $event) : void {
if ($this->time === null) {
$this->time = $event->telemetryInfo()
->time();
}
$parameters = [
'name' => $event->test()
->name(),
'message' => $this->message($event->throwable()),
'details' => $this->details($event->throwable()),
'duration' => $this->duration($event),
];
if ($event->hasComparisonFailure()) {
$parameters['type'] = 'comparisonFailure';
$parameters['actual'] = $event->comparisonFailure()
->actual();
$parameters['expected'] = $event->comparisonFailure()
->expected();
}
$this->writeMessage('testFailed', $parameters);
}
/**
* @throws InvalidArgumentException
*/
public function testConsideredRisky(ConsideredRisky $event) : void {
if ($this->time === null) {
$this->time = $event->telemetryInfo()
->time();
}
$this->writeMessage('testFailed', [
'name' => $event->test()
->name(),
'message' => $event->message(),
'details' => '',
'duration' => $this->duration($event),
]);
}
/**
* @throws InvalidArgumentException
*/
public function testFinished(Finished $event) : void {
$this->writeMessage('testFinished', [
'name' => $event->test()
->name(),
'duration' => $this->duration($event),
]);
$this->time = null;
}
public function flush() : void {
$this->printer
->flush();
}
/**
* @throws EventFacadeIsSealedException
* @throws UnknownSubscriberTypeException
*/
private function registerSubscribers(Facade $facade) : void {
$facade->registerSubscribers(new TestSuiteStartedSubscriber($this), new TestSuiteFinishedSubscriber($this), new TestPreparedSubscriber($this), new TestFinishedSubscriber($this), new TestErroredSubscriber($this), new TestFailedSubscriber($this), new TestMarkedIncompleteSubscriber($this), new TestSkippedSubscriber($this), new TestConsideredRiskySubscriber($this), new TestRunnerExecutionFinishedSubscriber($this));
}
private function setFlowId() : void {
if (stripos(ini_get('disable_functions'), 'getmypid') === false) {
$this->flowId = getmypid();
}
}
private function writeMessage(string $eventName, array $parameters = []) : void {
$this->printer
->print(sprintf('##teamcity[%s', $eventName));
if ($this->flowId !== null) {
$parameters['flowId'] = $this->flowId;
}
foreach ($parameters as $key => $value) {
$this->printer
->print(sprintf(" %s='%s'", $key, $this->escape((string) $value)));
}
$this->printer
->print("]\n");
}
/**
* @throws InvalidArgumentException
*/
private function duration(Event $event) : int {
if ($this->time === null) {
return 0;
}
return (int) round($event->telemetryInfo()
->time()
->duration($this->time)
->asFloat() * 1000);
}
private function escape(string $string) : string {
return str_replace([
'|',
"'",
"\n",
"\r",
']',
'[',
], [
'||',
"|'",
'|n',
'|r',
'|]',
'|[',
], $string);
}
private function message(Throwable $throwable) : string {
if (is_a($throwable->className(), FrameworkException::class, true)) {
return $throwable->message();
}
$buffer = $throwable->className();
if (!empty($throwable->message())) {
$buffer .= ': ' . $throwable->message();
}
return $buffer;
}
private function details(Throwable $throwable) : string {
$buffer = $throwable->stackTrace();
while ($throwable->hasPrevious()) {
$throwable = $throwable->previous();
$buffer .= sprintf("\nCaused by\n%s\n%s", $throwable->description(), $throwable->stackTrace());
}
return $buffer;
}
}