fix: make bpn response failures diagnosable

This commit is contained in:
2026-09-19 11:51:15 +02:00
parent ec83ad598f
commit fbb3ebb8c1
5 changed files with 240 additions and 29 deletions
@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace App\Tests\BusProNet\XmlParser;
use App\BusProNet\ApiClient;
use App\BusProNet\Exception\ResponseParserException;
use App\BusProNet\XmlParser\ApiResponseParser;
use PHPUnit\Framework\TestCase;
/**
* A broken response used to collapse into either "Empty response received from server" —
* which is wrong for a malformed body — or an opaque "Unable to parse XML response".
* Each shape must now name itself, otherwise a production parse failure is not
* diagnosable after the fact.
*/
class ApiResponseParserFailureTest extends TestCase
{
public function testEmptyResponse(): void
{
$this->expectException(ResponseParserException::class);
$this->expectExceptionMessage('empty response (0 bytes)');
(new ApiResponseParser())->parseXmlString(ApiClient::TYPE_NOTIFICATION, '');
}
public function testTruncatedResponseNamesTheLibxmlReason(): void
{
$xml = '<?xml version="1.0" encoding="utf-8"?><ergebnis><satz typ="HINWEIS"></satz><hinweis';
try {
(new ApiResponseParser())->parseXmlString(ApiClient::TYPE_NOTIFICATION, $xml);
$this->fail('Expected a ResponseParserException');
} catch (ResponseParserException $e) {
self::assertStringContainsString('('.strlen($xml).' bytes)', $e->getMessage());
self::assertStringContainsString('line 1', $e->getMessage());
}
}
public function testWellFormedResponseOfAnUnknownType(): void
{
$xml = '<?xml version="1.0" encoding="utf-8"?><ergebnis><satz typ="IRGENDWAS"></satz></ergebnis>';
$this->expectException(ResponseParserException::class);
$this->expectExceptionMessage('Unrecognised BusProNet response type "IRGENDWAS"');
(new ApiResponseParser())->parseXmlString(ApiClient::TYPE_NOTIFICATION, $xml);
}
public function testUnknownCustomerDataSubtype(): void
{
$xml = '<?xml version="1.0" encoding="utf-8"?><ergebnis><satz typ="KUNDENKONTO"></satz><art>Irgendwas</art></ergebnis>';
$this->expectException(ResponseParserException::class);
$this->expectExceptionMessage('Unrecognised customer data subtype "Irgendwas"');
(new ApiResponseParser())->parseXmlString(ApiClient::TYPE_CUSTOMER_DATA, $xml);
}
public function testDiagnosingDoesNotLeakLibxmlErrorState(): void
{
$previous = libxml_use_internal_errors(false);
try {
try {
(new ApiResponseParser())->parseXmlString(ApiClient::TYPE_NOTIFICATION, '<ergebnis');
} catch (ResponseParserException) {
}
self::assertFalse(libxml_use_internal_errors(false));
self::assertSame([], libxml_get_errors());
} finally {
libxml_use_internal_errors($previous);
}
}
}