'
. 'true'
. ''
. ''
. '';
$parsed = XmlParser::deleteRequest($body);
self::assertTrue($parsed['quiet']);
self::assertSame(['a.txt', 'dir/b c.txt'], $parsed['objects']);
}
public function testDeleteRequestDefaultsToVerbose(): void
{
$parsed = XmlParser::deleteRequest('');
self::assertFalse($parsed['quiet']);
self::assertSame(['x'], $parsed['objects']);
}
public function testDeleteRequestEmptyBodyThrowsMalformedXml(): void
{
$this->expectException(S3Exception::class);
$this->expectExceptionMessageMatches('/MalformedXML/');
XmlParser::deleteRequest(' ');
}
public function testDeleteRequestGarbageThrowsMalformedXml(): void
{
$this->expectException(S3Exception::class);
XmlParser::deleteRequest('');
}
public function testDeleteRequestWrongRootElementThrows(): void
{
$this->expectException(S3Exception::class);
$this->expectExceptionMessageMatches('/expected /');
XmlParser::deleteRequest('');
}
public function testDeleteRequestRejectsDtdEntityExpansion(): void
{
$body = ']>'
. '';
// DOCTYPE is rejected outright: no entity resolution can ever run,
// and no parser quirks are reachable.
$this->expectException(S3Exception::class);
$this->expectExceptionMessageMatches('/DOCTYPE/');
XmlParser::deleteRequest($body);
}
public function testReadBodyReadsACompleteStream(): void
{
$stream = fopen('php://temp', 'r+');
fwrite($stream, '');
rewind($stream);
try {
self::assertSame('', XmlParser::readBody($stream));
} finally {
fclose($stream);
}
}
public function testReadBodyRejectsBodiesOverTheCap(): void
{
$stream = fopen('php://temp', 'r+');
fwrite($stream, str_repeat('a', 8 * 1024 * 1024 + 1));
rewind($stream);
try {
$this->expectException(S3Exception::class);
$this->expectExceptionMessageMatches('/too large/');
XmlParser::readBody($stream);
} finally {
fclose($stream);
}
}
public function testCompleteRequestParsesPartsAndUnquotesEtags(): void
{
$body = ''
. '1"abc123"'
. '2def456'
. '';
self::assertSame(
[
['partNumber' => 1, 'etag' => 'abc123'],
['partNumber' => 2, 'etag' => 'def456'],
],
XmlParser::completeRequest($body),
);
}
public function testCompleteRequestRejectsOutOfRangePartNumber(): void
{
$this->expectException(S3Exception::class);
$this->expectExceptionMessageMatches('/PartNumber/');
XmlParser::completeRequest(
'10001x',
);
}
public function testCompleteRequestRejectsMissingEtag(): void
{
$this->expectException(S3Exception::class);
XmlParser::completeRequest(
'1',
);
}
}