From 1b9f409f04d7ee96f71af75097aba637e9edb0a3 Mon Sep 17 00:00:00 2001 From: Toon Verwerft Date: Wed, 18 Sep 2024 17:07:47 +0200 Subject: [PATCH] Introduce breaking reader/writer PHP 8.4 changes and new stream functions --- docs/reader.md | 23 ++ docs/writer.md | 75 +++- src/Xml/Reader/Loader/xml_file_loader.php | 11 +- src/Xml/Reader/Loader/xml_stream_loader.php | 21 ++ src/Xml/Reader/Loader/xml_string_loader.php | 10 +- src/Xml/Reader/Reader.php | 10 + src/Xml/Writer/Applicative/Applicative.php | 10 + src/Xml/Writer/Applicative/flush.php | 20 + src/Xml/Writer/Configurator/open.php | 28 -- src/Xml/Writer/Opener/Opener.php | 2 +- src/Xml/Writer/Opener/memory_opener.php | 6 +- src/Xml/Writer/Opener/xml_file_opener.php | 9 +- src/Xml/Writer/Opener/xml_stream_opener.php | 21 ++ src/Xml/Writer/Writer.php | 23 +- src/bootstrap.php | 4 +- stubs/XMLReader.phpstub | 243 ++++++++++-- stubs/XMLWriter.phpstub | 353 +++++++++++++++++- tests/Xml/Reader/Loader/XmlFileLoaderTest.php | 21 +- .../Xml/Reader/Loader/XmlStreamLoaderTest.php | 63 ++++ .../Xml/Reader/Loader/XmlStringLoaderTest.php | 18 + tests/Xml/Reader/ReaderTest.php | 16 + tests/Xml/Writer/Configurator/OpenTest.php | 31 -- tests/Xml/Writer/Opener/MemoryOpenerTest.php | 4 +- .../Xml/Writer/Opener/XmlStreamOpenerTest.php | 44 +++ tests/Xml/Writer/Output/MemoryOutputTest.php | 4 +- tests/Xml/Writer/WriterTest.php | 17 +- 26 files changed, 944 insertions(+), 143 deletions(-) create mode 100644 src/Xml/Reader/Loader/xml_stream_loader.php create mode 100644 src/Xml/Writer/Applicative/Applicative.php create mode 100644 src/Xml/Writer/Applicative/flush.php delete mode 100644 src/Xml/Writer/Configurator/open.php create mode 100644 src/Xml/Writer/Opener/xml_stream_opener.php create mode 100644 tests/Xml/Reader/Loader/XmlStreamLoaderTest.php delete mode 100644 tests/Xml/Writer/Configurator/OpenTest.php create mode 100644 tests/Xml/Writer/Opener/XmlStreamOpenerTest.php diff --git a/docs/reader.md b/docs/reader.md index 32635e8f..c4b6dee2 100644 --- a/docs/reader.md +++ b/docs/reader.md @@ -175,16 +175,39 @@ $reader = Reader::configure($yourLoader, ...$configurators); ```php use VeeWee\Xml\Reader\Reader; +use VeeWee\Xml\Reader\Loader\xml_file_loader; $reader = Reader::fromXmlFile('some-file.xml', ...$configurators); + +// OR + +$reader = Reader::configure(xml_file_loader('some-file.xml', encoding: 'UTF-8', flags: LIBXML_NOBLANKS), ...$configurators); +``` + +#### xml_stream_loader + +```php +use VeeWee\Xml\Reader\Reader; +use function VeeWee\Xml\Reader\Loader\xml_stream_loader; + +$reader = Reader::fromXmlStream($stream, ...$configurators); + +// OR + +$reader = Reader::configure(xml_stream_loader($stream, encoding: 'UTF-8', flags: LIBXML_NOBLANKS), ...$configurators); ``` #### xml_string_loader ```php use VeeWee\Xml\Reader\Reader; +use function VeeWee\Xml\Reader\Loader\xml_string_loader; $reader = Reader::fromXmlString('', ...$configurators); + +// OR + +$reader = Reader::configure(xml_string_loader('', encoding: 'UTF-8', flags: LIBXML_NOBLANKS), ...$configurators); ``` #### Writing your own loader diff --git a/docs/writer.md b/docs/writer.md index 6713beb8..6fa9bc8c 100644 --- a/docs/writer.md +++ b/docs/writer.md @@ -43,6 +43,7 @@ The Writer consists out of following composable blocks: - [Builders](#builders): Lets you build XML by using a declarative API. - [Configurators](#configurators): Configure how the Writer behaves. - [Mappers](#mappers): Map the XMLWriter to something else. +- [Applicatives](#applicatives): Apply an action on the open writer. - [Openers](#openers): Specify where you want to write to. ## Builders @@ -446,20 +447,6 @@ class MyAttribute implements Builder Specify how you want to configure the XML writer. -#### open - -The opener configurator takes an [opener](#openers) to specify the target of the writer. - -```php -use VeeWee\Xml\Writer\Writer; -use function VeeWee\Xml\Writer\Configurator\open; -use function VeeWee\Xml\Writer\Opener\xml_file_opener; - -Writer::configure( - open(xml_file_opener('somefile.xml')) -); -``` - #### indentation By default, the writer does not indent. @@ -515,6 +502,47 @@ $doc = Writer::inMemory() ->map(memory_output()); ``` +## Applicatives + +Apply an action on the open writer. + + +#### flush + +Flushes the writer to the output. + +```php +use VeeWee\Xml\Writer\Writer; +use function VeeWee\Xml\Writer\Applicative\flush; + +$doc = Writer::forStream($stream) + ->write($yourXml) + ->apply(flush()); +``` + +#### Writing your own applicatives + +```php +namespace VeeWee\Xml\Writer\Applicative; + +interface Applicative +{ + /** + * @return mixed + */ + public function __invoke(\XMLWriter $writer): mixed; +} + +``` + +You can apply the applicative as followed: + +```php +namespace VeeWee\Xml\Writer\Writer; + +$writer = Writer::configure($opener)->apply($applicative); +``` + ## Openers #### memory_opener @@ -533,7 +561,7 @@ $doc = Writer::inMemory(...$configurators) #### xml_file_opener -Loads an XML document from a file. +Writes an XML document to a file. When the file or folder does not exists, the code will attempt to create it. If it is not possible to create a target to write to, a `RuntimException` will be thrown. @@ -543,6 +571,19 @@ use VeeWee\Xml\Writer\Writer; $doc = Writer::forFile('some-xml.xml', ...$configurators); ``` +#### xml_stream_opener + +Loads an XML document into an open resource stream. + +```php +use VeeWee\Xml\Writer\Writer; +use function VeeWee\Xml\Writer\Applicative\flush; + +$doc = Writer::forStream($stream, ...$configurators) + ->write($yourXml) + ->apply(flush()) +``` + #### Writing your own opener ```php @@ -552,7 +593,7 @@ use XMLWriter; interface Opener { - public function __invoke(XMLWriter $writer): bool; + public function __invoke(): XMLWriter; } ``` @@ -561,5 +602,5 @@ You can apply the loader as followed: ```php namespace VeeWee\Xml\Writer\Writer; -$writer = Writer::configure($loader, ...$configurators); +$writer = Writer::configure($opener, ...$configurators); ``` diff --git a/src/Xml/Reader/Loader/xml_file_loader.php b/src/Xml/Reader/Loader/xml_file_loader.php index 214ebd4a..408ba6ad 100644 --- a/src/Xml/Reader/Loader/xml_file_loader.php +++ b/src/Xml/Reader/Loader/xml_file_loader.php @@ -8,20 +8,17 @@ use Webmozart\Assert\Assert; use XMLReader; use function VeeWee\Xml\ErrorHandling\disallow_issues; -use function VeeWee\Xml\ErrorHandling\disallow_libxml_false_returns; /** * @return Closure(): XMLReader */ -function xml_file_loader(string $file): Closure +function xml_file_loader(string $file, ?string $encoding = null, int $flags = 0): Closure { return static fn (): XMLReader => disallow_issues( - static function () use ($file): XMLReader { + static function () use ($file, $encoding, $flags): XMLReader { Assert::fileExists($file); - return disallow_libxml_false_returns( - XMLReader::open($file), - 'Could not open the provided XML file!' - ); + + return XMLReader::fromUri($file, $encoding, $flags); } ); } diff --git a/src/Xml/Reader/Loader/xml_stream_loader.php b/src/Xml/Reader/Loader/xml_stream_loader.php new file mode 100644 index 00000000..b9bdfdad --- /dev/null +++ b/src/Xml/Reader/Loader/xml_stream_loader.php @@ -0,0 +1,21 @@ + disallow_issues( + static fn (): XMLReader => XMLReader::fromStream($stream, $encoding, $flags, $documentUri) + ); +} diff --git a/src/Xml/Reader/Loader/xml_string_loader.php b/src/Xml/Reader/Loader/xml_string_loader.php index 2b781282..0144e2a0 100644 --- a/src/Xml/Reader/Loader/xml_string_loader.php +++ b/src/Xml/Reader/Loader/xml_string_loader.php @@ -8,21 +8,17 @@ use Webmozart\Assert\Assert; use XMLReader; use function VeeWee\Xml\ErrorHandling\disallow_issues; -use function VeeWee\Xml\ErrorHandling\disallow_libxml_false_returns; /** * @return Closure(): XMLReader */ -function xml_string_loader(string $xml): Closure +function xml_string_loader(string $xml, ?string $encoding = null, int $flags = 0): Closure { return static fn (): XMLReader => disallow_issues( - static function () use ($xml): XMLReader { + static function () use ($xml, $encoding, $flags): XMLReader { Assert::notEmpty($xml, 'The provided XML can not be empty!'); - return disallow_libxml_false_returns( - XMLReader::XML($xml), - 'Could not read the provided XML!' - ); + return XMLReader::fromString($xml, $encoding, $flags); } ); } diff --git a/src/Xml/Reader/Reader.php b/src/Xml/Reader/Reader.php index 2bb39272..3759f2ed 100644 --- a/src/Xml/Reader/Reader.php +++ b/src/Xml/Reader/Reader.php @@ -14,6 +14,7 @@ use function VeeWee\Xml\ErrorHandling\stop_on_first_issue; use function VeeWee\Xml\Internal\configure; use function VeeWee\Xml\Reader\Loader\xml_file_loader; +use function VeeWee\Xml\Reader\Loader\xml_stream_loader; use function VeeWee\Xml\Reader\Loader\xml_string_loader; final class Reader @@ -57,6 +58,15 @@ public static function fromXmlString(string $xml, callable ... $configurators): return self::configure(xml_string_loader($xml), ...$configurators); } + /** + * @param resource $stream + * @param list $configurators + */ + public static function fromXmlStream(mixed $stream, callable ... $configurators): self + { + return self::configure(xml_stream_loader($stream), ...$configurators); + } + /** * @param callable(NodeSequence): bool $matcher * diff --git a/src/Xml/Writer/Applicative/Applicative.php b/src/Xml/Writer/Applicative/Applicative.php new file mode 100644 index 00000000..e3bbe861 --- /dev/null +++ b/src/Xml/Writer/Applicative/Applicative.php @@ -0,0 +1,10 @@ +flush($empty); + }; +} diff --git a/src/Xml/Writer/Configurator/open.php b/src/Xml/Writer/Configurator/open.php deleted file mode 100644 index dc9d0403..00000000 --- a/src/Xml/Writer/Configurator/open.php +++ /dev/null @@ -1,28 +0,0 @@ - disallow_issues( - static function () use ($writer, $opener): XMLWriter { - disallow_libxml_false_returns( - $opener($writer), - 'Could not open the writer stream.' - ); - - return $writer; - } - ); -} diff --git a/src/Xml/Writer/Opener/Opener.php b/src/Xml/Writer/Opener/Opener.php index ea90f5cf..85596200 100644 --- a/src/Xml/Writer/Opener/Opener.php +++ b/src/Xml/Writer/Opener/Opener.php @@ -8,5 +8,5 @@ interface Opener { - public function __invoke(XMLWriter $writer): bool; + public function __invoke(): XMLWriter; } diff --git a/src/Xml/Writer/Opener/memory_opener.php b/src/Xml/Writer/Opener/memory_opener.php index c964ec8b..0f96126a 100644 --- a/src/Xml/Writer/Opener/memory_opener.php +++ b/src/Xml/Writer/Opener/memory_opener.php @@ -8,11 +8,9 @@ use XMLWriter; /** - * @return Closure(XMLWriter): bool XMLWriter + * @return Closure(): XMLWriter */ function memory_opener(): Closure { - return static function (XMLWriter $writer): bool { - return $writer->openMemory(); - }; + return static fn () => XMLWriter::toMemory(); } diff --git a/src/Xml/Writer/Opener/xml_file_opener.php b/src/Xml/Writer/Opener/xml_file_opener.php index 066e264f..df53a044 100644 --- a/src/Xml/Writer/Opener/xml_file_opener.php +++ b/src/Xml/Writer/Opener/xml_file_opener.php @@ -8,20 +8,21 @@ use Psl\File\WriteMode; use XMLWriter; use function Psl\File\write; +use function VeeWee\Xml\ErrorHandling\disallow_issues; /** * @param non-empty-string $file * - * @return Closure(XMLWriter): bool XMLWriter + * @return Closure(): XMLWriter */ function xml_file_opener(string $file): Closure { - return static function (XMLWriter $writer) use ($file) : bool { + return static fn (): XMLWriter => disallow_issues(static function () use ($file) : XMLWriter { // Try to create the file first. // If the file exists, it will truncated. (Default behaviour of XMLWriter as well) // If it cannot be created, it will throw exceptions. write($file, '', WriteMode::Truncate); - return $writer->openUri($file); - }; + return XMLWriter::toUri($file); + }); } diff --git a/src/Xml/Writer/Opener/xml_stream_opener.php b/src/Xml/Writer/Opener/xml_stream_opener.php new file mode 100644 index 00000000..84a578dd --- /dev/null +++ b/src/Xml/Writer/Opener/xml_stream_opener.php @@ -0,0 +1,21 @@ + disallow_issues(static function () use ($stream) : XMLWriter { + return XMLWriter::toStream($stream); + }); +} diff --git a/src/Xml/Writer/Writer.php b/src/Xml/Writer/Writer.php index edd2e9dc..5f96cd67 100644 --- a/src/Xml/Writer/Writer.php +++ b/src/Xml/Writer/Writer.php @@ -10,9 +10,9 @@ use function VeeWee\Xml\ErrorHandling\disallow_issues; use function VeeWee\Xml\ErrorHandling\disallow_libxml_false_returns; use function VeeWee\Xml\Internal\configure; -use function VeeWee\Xml\Writer\Configurator\open; use function VeeWee\Xml\Writer\Opener\memory_opener; use function VeeWee\Xml\Writer\Opener\xml_file_opener; +use function VeeWee\Xml\Writer\Opener\xml_stream_opener; final class Writer { @@ -24,11 +24,12 @@ private function __construct(XMLWriter $writer) } /** + * @param callable(): XMLWriter $opener * @param list<(callable(XMLWriter): XMLWriter)> $configurators */ - public static function configure(callable ... $configurators): self + public static function configure(callable $opener, callable ... $configurators): self { - return self::fromUnsafeWriter(new XMLWriter(), ...$configurators); + return self::fromUnsafeWriter($opener(), ...$configurators); } /** @@ -46,7 +47,19 @@ public static function fromUnsafeWriter(XMLWriter $writer, callable ... $configu public static function forFile(string $file, callable ... $configurators): self { return self::configure( - open(xml_file_opener($file)), + xml_file_opener($file), + ...$configurators + ); + } + + /** + * @param resource $stream + * @param list<(callable(XMLWriter): XMLWriter)> $configurators + */ + public static function forStream(mixed $stream, callable ... $configurators): self + { + return self::configure( + xml_stream_opener($stream), ...$configurators ); } @@ -57,7 +70,7 @@ public static function forFile(string $file, callable ... $configurators): self public static function inMemory(callable ... $configurators): self { return self::configure( - open(memory_opener()), + memory_opener(), ...$configurators ); } diff --git a/src/bootstrap.php b/src/bootstrap.php index f44991d6..392fd8e9 100644 --- a/src/bootstrap.php +++ b/src/bootstrap.php @@ -125,6 +125,7 @@ 'Xml\Reader\Configurator\substitute_entities' => __DIR__.'/Xml/Reader/Configurator/substitute_entities.php', 'Xml\Reader\Configurator\xsd_schema' => __DIR__.'/Xml/Reader/Configurator/xsd_schema.php', 'Xml\Reader\Loader\xml_file_loader' => __DIR__.'/Xml/Reader/Loader/xml_file_loader.php', + 'Xml\Reader\Loader\xml_stream_loader' => __DIR__.'/Xml/Reader/Loader/xml_stream_loader.php', 'Xml\Reader\Loader\xml_string_loader' => __DIR__.'/Xml/Reader/Loader/xml_string_loader.php', 'Xml\Reader\Matcher\all' => __DIR__.'/Xml/Reader/Matcher/all.php', 'Xml\Reader\Matcher\any' => __DIR__.'/Xml/Reader/Matcher/any.php', @@ -142,6 +143,7 @@ 'Xml\Reader\Matcher\nested' => __DIR__.'/Xml/Reader/Matcher/nested.php', 'Xml\Reader\Matcher\not' => __DIR__.'/Xml/Reader/Matcher/not.php', 'Xml\Reader\Matcher\sequence' => __DIR__.'/Xml/Reader/Matcher/sequence.php', + 'Xml\Writer\Applicative\flush' => __DIR__.'/Xml/Writer/Applicative/flush.php', 'Xml\Writer\Builder\attribute' => __DIR__.'/Xml/Writer/Builder/attribute.php', 'Xml\Writer\Builder\attributes' => __DIR__.'/Xml/Writer/Builder/attributes.php', 'Xml\Writer\Builder\cdata' => __DIR__.'/Xml/Writer/Builder/cdata.php', @@ -159,10 +161,10 @@ 'Xml\Writer\Builder\raw' => __DIR__.'/Xml/Writer/Builder/raw.php', 'Xml\Writer\Builder\value' => __DIR__.'/Xml/Writer/Builder/value.php', 'Xml\Writer\Configurator\indentation' => __DIR__.'/Xml/Writer/Configurator/indentation.php', - 'Xml\Writer\Configurator\open' => __DIR__.'/Xml/Writer/Configurator/open.php', 'Xml\Writer\Mapper\memory_output' => __DIR__.'/Xml/Writer/Mapper/memory_output.php', 'Xml\Writer\Opener\memory_opener' => __DIR__.'/Xml/Writer/Opener/memory_opener.php', 'Xml\Writer\Opener\xml_file_opener' => __DIR__.'/Xml/Writer/Opener/xml_file_opener.php', + 'Xml\Writer\Opener\xml_stream_opener' => __DIR__.'/Xml/Writer/Opener/xml_stream_opener.php', 'Xml\Xsd\Schema\Manipulator\base_path' => __DIR__.'/Xml/Xsd/Schema/Manipulator/base_path.php', 'Xml\Xsd\Schema\Manipulator\overwrite_with_local_files' => __DIR__.'/Xml/Xsd/Schema/Manipulator/overwrite_with_local_files.php', 'Xml\Xslt\Configurator\all_functions' => __DIR__.'/Xml/Xslt/Configurator/all_functions.php', diff --git a/stubs/XMLReader.phpstub b/stubs/XMLReader.phpstub index 7e008bc8..2c742f11 100644 --- a/stubs/XMLReader.phpstub +++ b/stubs/XMLReader.phpstub @@ -1,26 +1,225 @@ expectException(RuntimeException::class); @@ -21,4 +20,24 @@ public function test_it_invalid_file_loader(): void xml_file_loader('invalid-file')(); } + + public function test_it_can_read_with_encoding(): void + { + [$file, $handle] = $this->fillFile('héllo'); + $reader = xml_file_loader($file, encoding: 'Windows-1252')(); + $reader->read(); + $actual = $reader->readOuterXml(); + + static::assertSame('héllo', $actual); + } + + public function test_it_can_read_with_libxml_flags(): void + { + [$file, $handle] = $this->fillFile(''); + $reader = xml_file_loader($file, flags: LIBXML_NOCDATA)(); + $reader->read(); + $actual = $reader->readOuterXml(); + + static::assertSame('hello', $actual); + } } diff --git a/tests/Xml/Reader/Loader/XmlStreamLoaderTest.php b/tests/Xml/Reader/Loader/XmlStreamLoaderTest.php new file mode 100644 index 00000000..2b9a76ae --- /dev/null +++ b/tests/Xml/Reader/Loader/XmlStreamLoaderTest.php @@ -0,0 +1,63 @@ +expectException(RuntimeException::class); + $this->expectExceptionMessage('supplied resource is not a valid stream resource'); + + [$_, $handle] = $this->fillFile('xxx'); + fclose($handle); + + xml_stream_loader($handle)(); + } + + public function test_it_can_read_with_encoding(): void + { + [$file, $handle] = $this->fillFile('héllo'); + rewind($handle); + + $reader = xml_stream_loader($handle, encoding: 'Windows-1252')(); + $reader->read(); + $actual = $reader->readOuterXml(); + + static::assertSame('héllo', $actual); + } + + public function test_it_can_read_with_libxml_flags(): void + { + [$file, $handle] = $this->fillFile(''); + rewind($handle); + + $reader = xml_stream_loader($handle, flags: LIBXML_NOCDATA)(); + $reader->read(); + $actual = $reader->readOuterXml(); + + static::assertSame('hello', $actual); + } + + public function test_it_can_set_a_base_uri(): void + { + [$file, $handle] = $this->fillFile('hello'); + rewind($handle); + + $reader = xml_stream_loader($handle, documentUri: $documentUri = 'http://xxxx')(); + $reader->read(); + $actual = $reader->readOuterXml(); + + static::assertSame($documentUri, $reader->baseURI); + static::assertSame('hello', $actual); + } +} diff --git a/tests/Xml/Reader/Loader/XmlStringLoaderTest.php b/tests/Xml/Reader/Loader/XmlStringLoaderTest.php index e1d62097..ebd58d58 100644 --- a/tests/Xml/Reader/Loader/XmlStringLoaderTest.php +++ b/tests/Xml/Reader/Loader/XmlStringLoaderTest.php @@ -17,4 +17,22 @@ public function test_it_can_handle_invalid_string_loader(): void xml_string_loader('')(); } + + public function test_it_can_read_with_encoding(): void + { + $reader = xml_string_loader('héllo', encoding: 'Windows-1252')(); + $reader->read(); + $actual = $reader->readOuterXml(); + + static::assertSame('héllo', $actual); + } + + public function test_it_can_read_with_libxml_flags(): void + { + $reader = xml_string_loader('', flags: LIBXML_NOCDATA)(); + $reader->read(); + $actual = $reader->readOuterXml(); + + static::assertSame('hello', $actual); + } } diff --git a/tests/Xml/Reader/ReaderTest.php b/tests/Xml/Reader/ReaderTest.php index ea4b7f06..334370ca 100644 --- a/tests/Xml/Reader/ReaderTest.php +++ b/tests/Xml/Reader/ReaderTest.php @@ -48,6 +48,22 @@ public function test_it_can_provide_xml_file(string $xml, callable $matcher, arr fclose($handle); } + /** + * @dataProvider provideXmlExpectations + */ + public function test_it_can_provide_xml_stream(string $xml, callable $matcher, array $expected): void + { + [$_, $handle] = $this->fillFile($xml); + rewind($handle); + + $reader = Reader::fromXmlStream($handle, identity()); + $iterator = $reader->provide($matcher); + + static::assertSame($expected, map($iterator, static fn (MatchingNode $match): string => $match->xml())); + + fclose($handle); + } + public function test_it_throws_exception_on_invalid_xml_during_iteration(): void { $xml = <<<'EOXML' diff --git a/tests/Xml/Writer/Configurator/OpenTest.php b/tests/Xml/Writer/Configurator/OpenTest.php deleted file mode 100644 index 4e9212e0..00000000 --- a/tests/Xml/Writer/Configurator/OpenTest.php +++ /dev/null @@ -1,31 +0,0 @@ - true)($xmlWriter); - - static::assertSame($result, $xmlWriter); - } - - - public function test_it_can_fail_opening(): void - { - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('Could not open the writer stream.'); - - $xmlWriter = new XMLWriter(); - open(static fn () => false)($xmlWriter); - } -} diff --git a/tests/Xml/Writer/Opener/MemoryOpenerTest.php b/tests/Xml/Writer/Opener/MemoryOpenerTest.php index be51337e..f887bfef 100644 --- a/tests/Xml/Writer/Opener/MemoryOpenerTest.php +++ b/tests/Xml/Writer/Opener/MemoryOpenerTest.php @@ -6,7 +6,6 @@ use PHPUnit\Framework\TestCase; use VeeWee\Xml\Writer\Writer; -use XMLWriter; use function VeeWee\Xml\Writer\Builder\raw; use function VeeWee\Xml\Writer\Mapper\memory_output; use function VeeWee\Xml\Writer\Opener\memory_opener; @@ -15,8 +14,7 @@ final class MemoryOpenerTest extends TestCase { public function test_it_can_open_in_memory(): void { - $writer = new XMLWriter(); - memory_opener()($writer); + $writer = memory_opener()(); $actual = Writer::fromUnsafeWriter($writer) ->write(raw('hello')) diff --git a/tests/Xml/Writer/Opener/XmlStreamOpenerTest.php b/tests/Xml/Writer/Opener/XmlStreamOpenerTest.php new file mode 100644 index 00000000..8b0eeebd --- /dev/null +++ b/tests/Xml/Writer/Opener/XmlStreamOpenerTest.php @@ -0,0 +1,44 @@ +fillFile(''); + + $writer = xml_stream_opener($handle)(); + Writer::fromUnsafeWriter($writer) + ->write(raw('hello')) + ->apply(flush()); + + rewind($handle); + + static::assertSame('hello', stream_get_contents($handle)); + static::assertSame('hello', file_get_contents($file)); + } + + public function test_it_can_not_open_closed_resource(): void + { + [$_, $handle] = $this->fillFile(''); + fclose($handle); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('supplied resource is not a valid stream resource'); + + xml_stream_opener($handle)(); + } +} diff --git a/tests/Xml/Writer/Output/MemoryOutputTest.php b/tests/Xml/Writer/Output/MemoryOutputTest.php index 32a4e37d..7a7e8a89 100644 --- a/tests/Xml/Writer/Output/MemoryOutputTest.php +++ b/tests/Xml/Writer/Output/MemoryOutputTest.php @@ -6,7 +6,6 @@ use PHPUnit\Framework\TestCase; use VeeWee\Xml\Writer\Writer; -use XMLWriter; use function VeeWee\Xml\Writer\Builder\raw; use function VeeWee\Xml\Writer\Mapper\memory_output; use function VeeWee\Xml\Writer\Opener\memory_opener; @@ -15,8 +14,7 @@ final class MemoryOutputTest extends TestCase { public function test_it_can_open_in_memory(): void { - $writer = new XMLWriter(); - memory_opener()($writer); + $writer = memory_opener()(); Writer::fromUnsafeWriter($writer) ->write(raw('hello')); diff --git a/tests/Xml/Writer/WriterTest.php b/tests/Xml/Writer/WriterTest.php index 1241813b..97cafdbe 100644 --- a/tests/Xml/Writer/WriterTest.php +++ b/tests/Xml/Writer/WriterTest.php @@ -5,15 +5,16 @@ namespace VeeWee\Tests\Xml\Writer; use PHPUnit\Framework\TestCase; +use VeeWee\Tests\Xml\Helper\FillFileTrait; use VeeWee\Tests\Xml\Helper\TmpFileTrait; use VeeWee\Tests\Xml\Writer\Helper\UseInMemoryWriterTrait; use VeeWee\Xml\Exception\RuntimeException; use VeeWee\Xml\Writer\Writer; use XMLWriter; use function Psl\Fun\identity; +use function VeeWee\Xml\Writer\Applicative\flush; use function VeeWee\Xml\Writer\Builder\element; use function VeeWee\Xml\Writer\Builder\raw; -use function VeeWee\Xml\Writer\Configurator\open; use function VeeWee\Xml\Writer\Mapper\memory_output; use function VeeWee\Xml\Writer\Opener\xml_file_opener; @@ -21,6 +22,7 @@ final class WriterTest extends TestCase { use UseInMemoryWriterTrait; use TmpFileTrait; + use FillFileTrait; public function test_it_can_open_a_file(): void @@ -40,10 +42,19 @@ public function test_it_can_open_in_memory(): void static::assertSame('hello', $actual); } + public function test_it_can_open_a_stream(): void + { + [$_, $handle] = $this->fillFile(''); + Writer::forStream($handle)->write(raw('hello'))->apply(flush()); + rewind($handle); + + static::assertSame('hello', stream_get_contents($handle)); + } + public function test_it_can_configure_a_writer(): void { $this->createTmpFile(static function (string $path): void { - $writer = Writer::configure(open(xml_file_opener($path)), identity()); + $writer = Writer::configure(xml_file_opener($path), identity()); $writer->write(element('root')); self::assertXmlStringEqualsXmlFile($path, ''); @@ -81,7 +92,7 @@ public function test_it_throws_error_on_not_initialized(): void { $this->expectExceptionMessage('Invalid or uninitialized XMLWriter object'); - $emptyWriter = Writer::configure(); + $emptyWriter = Writer::fromUnsafeWriter(new XMLWriter()); $emptyWriter->write(element('root')); }