From 0b0906327a482533cbba1f28e6a0bb232c917e7a Mon Sep 17 00:00:00 2001 From: Cristiano Cinotti Date: Thu, 3 Sep 2026 15:58:52 +0200 Subject: [PATCH] Back to PhpUnit Return back to PhpUnit, managed with Phive. --- .github/workflows/coverage_report.yml | 15 ++ .github/workflows/test.yml | 43 +--- .phive/phars.xml | 1 + composer.json | 16 +- tests/Datasets/Inclusion.php | 40 ---- tests/Datasets/Xml.php | 103 --------- tests/Datasets/XmlNoTypes.php | 83 ------- tests/Datasets/XmlWithAttributes.php | 80 ------- tests/Functional/ConversionTest.php | 26 ++- tests/Pest.php | 17 -- tests/Unit/ConverterTest.php | 281 +++++++++++++----------- tests/Unit/FileConverterTest.php | 231 ++++++++------------ tests/VfsTestCase.php | 68 ++++++ tests/VfsTrait.php | 28 --- tests/XmlToArrayDataProvider.php | 298 ++++++++++++++++++++++++++ 15 files changed, 653 insertions(+), 677 deletions(-) delete mode 100644 tests/Datasets/Inclusion.php delete mode 100644 tests/Datasets/Xml.php delete mode 100644 tests/Datasets/XmlNoTypes.php delete mode 100644 tests/Datasets/XmlWithAttributes.php delete mode 100644 tests/Pest.php create mode 100644 tests/VfsTestCase.php delete mode 100644 tests/VfsTrait.php create mode 100644 tests/XmlToArrayDataProvider.php diff --git a/.github/workflows/coverage_report.yml b/.github/workflows/coverage_report.yml index 3111954..02323d9 100644 --- a/.github/workflows/coverage_report.yml +++ b/.github/workflows/coverage_report.yml @@ -4,8 +4,23 @@ on: push: branches: [master] jobs: + install_tools: + name: Install tools + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v7 + - name: Install tools + uses: ngmy/phive-install-action@master + - name: Upload tools to artifact store + uses: actions/upload-artifact@v7 + with: + name: tools + path: tools + coverage: name: coverage + needs: install_tools runs-on: ubuntu-latest steps: - name: Checkout diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ee674d7..77ab1cd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,15 +16,18 @@ jobs: name: tools path: tools test: - name: test + name: Test suite needs: install_tools strategy: fail-fast: false matrix: - operating-system: ["ubuntu-latest", "macOs-latest"] + operating-system: ["ubuntu-latest", "macOs-latest", "windows-latest"] php-versions: ["8.5"] runs-on: ${{ matrix.operating-system }} steps: + - name: Set autocrlf on windows + if: matrix.operating-system == 'windows-latest' + run: git config --global core.autocrlf false - name: Checkout uses: actions/checkout@v7 - name: Setup PHP, with composer and extensions @@ -42,45 +45,9 @@ jobs: with: name: tools path: tools - - name: Set tools as an executable - run: find tools -type f -print0 | xargs -0 chmod +x - name: Check coding standard run: composer cs:check - name: Static analysis tool run: composer analytics - name: Test suite run: composer test - test-windows: - name: test-windows - needs: install_tools - strategy: - fail-fast: false - matrix: - php-versions: ["8.5"] - runs-on: windows-latest - steps: - - name: Set autocrlf - run: git config --global core.autocrlf false - - name: Checkout - uses: actions/checkout@v7 - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-versions }} - extensions: libxml, simplexml, dom - coverage: none - - name: Install composer dependencies - uses: ramsey/composer-install@v4 - with: - composer-options: "--prefer-dist --optimize-autoloader" - - name: Download tools from artifact store - uses: actions/download-artifact@v7 - with: - name: tools - path: tools - - name: Check coding standard - run: php tools/php-cs-fixer fix -v --diff --dry-run - - name: Static analysis tool - run: php tools/phpstan analyze - - name: Test suite - run: composer test diff --git a/.phive/phars.xml b/.phive/phars.xml index a2d4939..a87ac73 100644 --- a/.phive/phars.xml +++ b/.phive/phars.xml @@ -2,4 +2,5 @@ + diff --git a/composer.json b/composer.json index f17eeff..5d50b0c 100644 --- a/composer.json +++ b/composer.json @@ -27,36 +27,28 @@ } }, "require-dev": { - "pestphp/pest": "^5", "mikey179/vfsstream": "^1.6" }, "scripts": { - "analytics": "tools/phpstan", + "analytics": "php tools/phpstan", "check": [ "@test", "@analytics", "@cs:fix" ], - "coverage": "@test --coverage", "coverage:html": "@test --coverage-html coverage/", "coverage:clover": "@test --coverage-clover clover.xml", - "cs:check": "tools/php-cs-fixer fix -v --diff --dry-run", - "cs:fix": "tools/php-cs-fixer fix -v --diff", - "test": "pest" + "cs:check": "php tools/php-cs-fixer fix -v --diff --dry-run", + "cs:fix": "php tools/php-cs-fixer fix -v --diff", + "test": "php tools/phpunit" }, "scripts-descriptions": { "analytics": "Run static analysis tool", "check": "Perform all tests and analysis, required before submitting a pull request", "cs:check": "Run code style analysis, without fixing errors", "cs:fix": "Run code style analysis and fix errors", - "coverage": "Show coverage report to the console", "coverage:html": "Create a code coverage report in html format, into the `coverage/` directory", "coverage:clover": "Create a code coverage report in xml format, into the `clover.xml` file", "test": "Run the test suite" - }, - "config": { - "allow-plugins": { - "pestphp/pest-plugin": true - } } } diff --git a/tests/Datasets/Inclusion.php b/tests/Datasets/Inclusion.php deleted file mode 100644 index a74243b..0000000 --- a/tests/Datasets/Inclusion.php +++ /dev/null @@ -1,40 +0,0 @@ - - - - ", - " - - - ", - [ - 'name' => 'named', - 'defaultIdMethod' => 'native', - 'table' => [ - 'name' => 'book', - 'phpName' => 'Book', - ], - ], - ], -]); diff --git a/tests/Datasets/Xml.php b/tests/Datasets/Xml.php deleted file mode 100644 index 70de153..0000000 --- a/tests/Datasets/Xml.php +++ /dev/null @@ -1,103 +0,0 @@ - - - - Star Wars - True - 32.5 - - - The Lord Of The Rings - false - - -" - , - ['movie' => [0 => ['title' => 'Star Wars', 'starred' => true, 'percentage' => 32.5], 1 => ['title' => 'The Lord Of The Rings', 'starred' => false]]], - ], - [ - " - - - - stream - /var/log/default.log - 300 - - - stream - /var/log/bookstore.log - - -", [ - 'log' => [ - 'logger' => [ - [ - 'name' => 'defaultLogger', - 'type' => 'stream', - 'path' => '/var/log/default.log', - 'level' => 300, - ], - [ - 'name' => 'bookstore', - 'type' => 'stream', - 'path' => '/var/log/bookstore.log', - ], - ], - ]], - ], - [ - " - -
-
-
-", [ - 'database' => [ - 'name' => 'TestDb', - 'table' => [ - 0 => ['name' => 'table1'], - 1 => ['name' => 'table2'], - ], - ], - ], - ], - [ - 'foo', - ['node' => 'foo'], - ], - [ - '', - ['node' => ['foo' => 'bar']], - ], - [ - '0', - ['node' => 0], - ], - [ - '', - ['node' => null], - ], - [ - 'Hello World!]]>', - ['node' => 'Hello World!'], - ], -]); diff --git a/tests/Datasets/XmlNoTypes.php b/tests/Datasets/XmlNoTypes.php deleted file mode 100644 index c3973de..0000000 --- a/tests/Datasets/XmlNoTypes.php +++ /dev/null @@ -1,83 +0,0 @@ - - - - Star Wars - True - 32.5 - - - The Lord Of The Rings - false - - -" - , - ['movie' => [0 => ['title' => 'Star Wars', 'starred' => 'True', 'percentage' => '32.5'], 1 => ['title' => 'The Lord Of The Rings', 'starred' => 'false']]], - ], - [ - " - - - - stream - /var/log/default.log - 300 - - - stream - /var/log/bookstore.log - - -", [ - 'log' => [ - 'logger' => [ - [ - 'name' => 'defaultLogger', - 'type' => 'stream', - 'path' => '/var/log/default.log', - 'level' => '300', - ], - [ - 'name' => 'bookstore', - 'type' => 'stream', - 'path' => '/var/log/bookstore.log', - ], - ], - ]], - ], - [ - " - -
-
-
-
", [ - 'database' => [ - 'name' => 'TestDb', - 'table' => [ - 0 => ['name' => 'table1'], - 1 => ['name' => 'table2'], - ], - ], - ], - ], -]); diff --git a/tests/Datasets/XmlWithAttributes.php b/tests/Datasets/XmlWithAttributes.php deleted file mode 100644 index 98c0337..0000000 --- a/tests/Datasets/XmlWithAttributes.php +++ /dev/null @@ -1,80 +0,0 @@ - - - - - stream - /var/log/default.log - 300 - - - stream - /var/log/bookstore.log - - -", [ - 'log' => [ - 'logger' => [ - [ - '@attributes' => [ - 'name' => 'defaultLogger', - ], - 'type' => 'stream', - 'path' => '/var/log/default.log', - 'level' => 300, - ], - [ - '@attributes' => [ - 'name' => 'bookstore', - ], - 'type' => 'stream', - 'path' => '/var/log/bookstore.log', - ], - ], - ]], - ], - [ - " - -
-
-
-
", [ - 'database' => [ - '@attributes' => [ - 'name' => 'TestDb', - ], - 'table' => [ - 0 => [ - '@attributes' => [ - 'name' => 'table1', - ], - ], - 1 => [ - '@attributes' => [ - 'name' => 'table2', - ], - ], - ], - ], - ], - ], -]); diff --git a/tests/Functional/ConversionTest.php b/tests/Functional/ConversionTest.php index 0b3f88d..dca5e88 100644 --- a/tests/Functional/ConversionTest.php +++ b/tests/Functional/ConversionTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); /* - * Copyright (c) Cristiano Cinotti 2024 - 2025. + * Copyright (c) Cristiano Cinotti 2024 - 2026. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,14 +15,24 @@ * limitations under the License. */ +namespace Susina\XmlToArray\Tests\Functional; + +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\TestCase; use Susina\XmlToArray\Converter; +use Susina\XmlToArray\Tests\XmlToArrayDataProvider; -it('converts real life XML files', function (string $file) { - $phpFile = __DIR__ . "/../Fixtures/$file.php"; - $xmlFile = __DIR__ . "/../Fixtures/$file.xml"; +class ConversionTest extends TestCase +{ + #[DataProviderExternal(XmlToArrayDataProvider::class, 'realCaseProvider')] + public function testRealLifeXmlConversion(string $file): void + { + $phpFile = __DIR__ . "/../Fixtures/$file.php"; + $xmlFile = __DIR__ . "/../Fixtures/$file.xml"; - $expected = include($phpFile); - $actual = Converter::create()->convert(file_get_contents($xmlFile)); + $expected = include($phpFile); + $actual = Converter::create()->convert(file_get_contents($xmlFile)); - expect($actual)->toBe($expected); -})->with(['joomla', 'propel']); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/Pest.php b/tests/Pest.php deleted file mode 100644 index c9730f4..0000000 --- a/tests/Pest.php +++ /dev/null @@ -1,17 +0,0 @@ -in('Unit'); diff --git a/tests/Unit/ConverterTest.php b/tests/Unit/ConverterTest.php index 57252b0..5bbb29a 100644 --- a/tests/Unit/ConverterTest.php +++ b/tests/Unit/ConverterTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); /* - * Copyright (c) Cristiano Cinotti 2024 - 2025. + * Copyright (c) Cristiano Cinotti 2024 - 2026. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,42 +15,80 @@ * limitations under the License. */ +namespace Susina\XmlToArray\Tests\Unit; + use org\bovigo\vfs\vfsStream; +use PHPUnit\Framework\Attributes\DataProviderExternal; use Susina\XmlToArray\Exception\ConverterException; use Susina\XmlToArray\Converter; +use Susina\XmlToArray\Tests\VfsTestCase; +use Susina\XmlToArray\Tests\XmlToArrayDataProvider; + +class ConverterTest extends VfsTestCase +{ + private Converter $converter; + public function setUp(): void + { + $this->converter = new Converter(); + } + + public function testStaticConstructor(): void + { + $this->assertInstanceOf(Converter::class, Converter::create()); + } + + #[DataProviderExternal(XmlToArrayDataProvider::class, 'xmlProvider')] + public function testConvertXmlToArray(string $xml, array $expected): void + { + $actual = $this->converter->convert($xml); + $this->assertSame($expected, $actual); + } + + public function testConvertXmlWithInclusions(): void + { + $xmlLoad = " + + getIncludedFile()->url()}\" xpointer=\"xpointer( /database/* )\" + /> +"; + $expected = [ + 'name' => 'named', + 'defaultIdMethod' => 'native', + 'table' => [ + 'name' => 'book', + 'phpName' => 'Book', + ], + ]; + $actual = $this->converter->convert($xmlLoad); -beforeEach(function () { - $this->converter = new Converter(); -}); - -it('instantiate the correct class, via static constructor', function () { - expect(Converter::create())->toBeInstanceOf(Converter::class); -}); - -it('converts xml to array', function (string $xml, array $expected) { - $actual = $this->converter->convert($xml); - expect($actual)->toBe($expected); -})->with('Xml'); - -it('converts xml with inclusion', function (string $xmlLoad, string $xmlInclude, array $expected) { - vfsStream::newFile('testconvert_include.xml')->at($this->getRoot())->setContent($xmlInclude); - $actual = $this->converter->convert($xmlLoad); - expect($actual)->toBe($expected); -})->with('Inclusion'); + $this->assertSame($expected, $actual); + } -it('converts an invalid xml', function () { - $invalidXml = <<< INVALID_XML + public function testInvalidXmlThrowsException(): void + { + $this->expectException(ConverterException::class); + $this->expectExceptionMessageIsOrContains( + "An error occurred while parsing XML string: + - Fatal 4: Start tag expected, '<' not found +", + ); + $invalidXml = <<< INVALID_XML No xml only plain text --------- INVALID_XML; - $this->converter->convert($invalidXml); -})->throws(ConverterException::class, "An error occurred while parsing XML string: - - Fatal 4: Start tag expected, '<' not found -"); -it('finds error in xml content', function () { - $xmlWithError = <<< XML + $this->converter->convert($invalidXml); + } + + public function testXmlContentErrorThrowsException(): void + { + $this->expectException(ConverterException::class); + $this->expectExceptionMessageIsOrContains("An error occurred while parsing XML string: + - Fatal 76: Opening and ending tag mismatch: titles line 4 and title +"); + $xmlWithError = <<< XML @@ -61,13 +99,21 @@ XML; - $this->converter->convert($xmlWithError); -})->throws(ConverterException::class, "An error occurred while parsing XML string: + + $this->converter->convert($xmlWithError); + } + + public function testMultipleXmlErrorsThrowsException(): void + { + $this->expectException(ConverterException::class); + $this->expectExceptionMessageIsOrContains( + "Some errors occurred while parsing XML string: - Fatal 76: Opening and ending tag mismatch: titles line 4 and title -"); + - Fatal 76: Opening and ending tag mismatch: movies line 2 and moviess +", + ); -it('finds multiple errors in xml', function () { - $xmlWithErrors = <<< XML + $xmlWithErrors = <<< XML @@ -78,103 +124,88 @@ XML; - $this->converter->convert($xmlWithErrors); -})->throws(ConverterException::class, "Some errors occurred while parsing XML string: - - Fatal 76: Opening and ending tag mismatch: titles line 4 and title - - Fatal 76: Opening and ending tag mismatch: movies line 2 and moviess -"); -it('converts an XML string without merging @attributes key', function (string $xml, array $expected) { - $actual = Converter::create(['mergeAttributes' => false])->convert($xml); - expect($actual)->toBe($expected); -})->with('XmlWithAttributes'); - -it('converts an XML string without preserving data types', function (string $xml, array $expected) { - $actual = Converter::create(['typesAsString' => true])->convert($xml); - expect($actual)->toBe($expected); -})->with('XmlNoTypes'); - -it('converts an XML string preserving the first tag', function () { - $expected = [ - 'breakfast_menu' => [ - 'food' => [ - 'name' => 'Waffles', + $this->converter->convert($xmlWithErrors); + } + + #[DataProviderExternal(XmlToArrayDataProvider::class, 'xmlWithAttributesProvider')] + public function testConvertXmlWithoutMergingAttributes(string $xml, array $expected): void + { + $actual = Converter::create(['mergeAttributes' => false])->convert($xml); + $this->assertSame($expected, $actual); + } + + #[DataProviderExternal(XmlToArrayDataProvider::class, 'xmlNoTypesProvider')] + public function testConvertXmlWithoutPreservingDataTypes(string $xml, array $expected): void + { + $actual = Converter::create(['typesAsString' => true])->convert($xml); + $this->assertSame($expected, $actual); + } + + public function testConvertiXmlPreservingTheFirstTag(): void + { + $expected = [ + 'breakfast_menu' => [ + 'food' => [ + 'name' => 'Waffles', + ], ], - ], - ]; + ]; - $xml = " + $xml = " Waffles -"; - - $actual = Converter::create(['preserveFirstTag' => true])->convert($xml); - expect($actual)->toBe($expected); -}); - -it('converts an xml string and save to a file', function (string $xml, array $expected, string $content) { - $file = vfsStream::newFile('saved_file.php')->at($this->getRoot()); - - $this->converter->convertAndSave($xml, $file->url()); - - $actual = include($file->url()); - - expect($actual)->toBe($expected) - ->and($content)->toBe($file->getContent()); -})->with([ - [" - - - Star Wars - True - 32.5 - - - The Lord Of The Rings - false - - -", - [ - 'movie' => [ - 0 => ['title' => 'Star Wars', 'starred' => true, 'percentage' => 32.5], - 1 => ['title' => 'The Lord Of The Rings', 'starred' => false], - ], - ], - " - array ( - 0 => - array ( - 'title' => 'Star Wars', - 'starred' => true, - 'percentage' => 32.5, - ), - 1 => - array ( - 'title' => 'The Lord Of The Rings', - 'starred' => false, - ), - ), -); -", - ], -]); - -it('try to save in a not existent directory', function () { - $xml = "The Lord Of The Ringsfalse"; - $this->converter->convertAndSave($xml, $this->getRoot()->url() . '/my_dir/my_array.php'); -})->throws(\RuntimeException::class, "The directory `vfs://root/my_dir` does not exist: you should create it before writing a file."); - -it('try to save in a not writeable directory', function () { - $dir = vfsStream::newDirectory('xml_dir', 000)->at($this->getRoot()); - $xml = "The Lord Of The Ringsfalse"; - $this->converter->convertAndSave($xml, $dir->url() . '/my_array.php'); -})->throws(\RuntimeException::class, "It's impossible to write into `vfs://root/xml_dir` directory: do you have the correct permissions?"); +" + ; + $actual = Converter::create(['preserveFirstTag' => true])->convert($xml); + + $this->assertSame($expected, $actual); + } + + #[DataProviderExternal(XmlToArrayDataProvider::class, 'convertAndSaveProvider')] + public function testConvertXmlAndSavesIntoExistentFile(string $xml, array $expectedArray, string $expectedContent): void + { + $file = $this->createFile('saved_file.php'); + + $this->converter->convertAndSave($xml, $file->url()); + $actual = include($file->url()); + + $this->assertSame($expectedArray, $actual); + $this->assertSame($expectedContent, $file->getContent()); + $this->assertSame($expectedContent, file_get_contents($file->url())); + } + + #[DataProviderExternal(XmlToArrayDataProvider::class, 'convertAndSaveProvider')] + public function testConvertAndSaveCreatesOutputFileIfNotExistent(string $xml, array $expectedArray, string $expectedContent): void + { + $this->converter->convertAndSave($xml, $this->root->url() . '/my_saved_file.php'); + + $this->assertFileExists('vfs://root/my_saved_file.php'); + + $actual = include($this->root->url() . '/my_saved_file.php'); + + $this->assertSame($expectedArray, $actual); + $this->assertSame($expectedContent, file_get_contents($this->root->url() . '/my_saved_file.php')); + } + + public function testSaveInNotExistentDirectoryThrowsException(): void + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessageIs("The directory `vfs://root/my_dir` does not exist: you should create it before writing a file."); + + $xml = "The Lord Of The Ringsfalse"; + $this->converter->convertAndSave($xml, $this->root->url() . '/my_dir/my_array.php'); + } + + public function testSaveInNotWriteableDirectoryThrowsException(): void + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessageIs("It's impossible to write into `vfs://root/xml_dir` directory: do you have the correct permissions?"); + + $dir = vfsStream::newDirectory('xml_dir', 000)->at($this->root); + $xml = "The Lord Of The Ringsfalse"; + $this->converter->convertAndSave($xml, $dir->url() . '/my_array.php'); + } +} diff --git a/tests/Unit/FileConverterTest.php b/tests/Unit/FileConverterTest.php index 1f80e4d..dc7a40a 100644 --- a/tests/Unit/FileConverterTest.php +++ b/tests/Unit/FileConverterTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); /* - * Copyright (c) Cristiano Cinotti 2024 - 2025. + * Copyright (c) Cristiano Cinotti 2024 - 2026. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,147 +15,92 @@ * limitations under the License. */ +namespace Susina\XmlToArray\Tests\Unit; + use org\bovigo\vfs\vfsStream; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use Susina\XmlToArray\Tests\VfsTestCase; use Susina\XmlToArray\FileConverter; - -it('converts an XML file to an array', function (string $xml, array $expected) { - $file = vfsStream::newFile("test_file.xml")->at($this->getRoot())->setContent($xml); - $actual = FileConverter::create()->convert($file->url()); - - expect($expected)->toBe($actual); -})->with('Xml'); - -it('try to convert a not existent file', function () { - $converter = new FileConverter(); - $converter->convert('vfs://root/notexistent.xml'); -})->throws(\RuntimeException::class, 'The file `vfs://root/notexistent.xml` does not exist.'); - -it('try to convert a not readable file', function () { - $file = vfsStream::newFile('notreadable.xml', 200)->at($this->getRoot())->setContent(""); - FileConverter::create()->convert($file->url()); -})->throws(\RuntimeException::class, 'The file `vfs://root/notreadable.xml` is not readable: do you have the correct permissions?'); - -it('converts an xml file into an array and save to a file', function (string $xml, array $expected, string $content) { - $xmlFile = vfsStream::newFile('xml_file.xml')->at($this->getRoot())->setContent($xml); - $saveFile = vfsStream::newFile('saved_file.php')->at($this->getRoot()); - - FileConverter::create()->convertAndSave($xmlFile->url(), $saveFile->url()); - - $actual = include($saveFile->url()); - - expect($actual)->toBe($expected) - ->and($content)->toBe($saveFile->getContent()); -})->with([ - [" - - - Star Wars - True - 32.5 - - - The Lord Of The Rings - false - - -", - [ - 'movie' => [ - 0 => ['title' => 'Star Wars', 'starred' => true, 'percentage' => 32.5], - 1 => ['title' => 'The Lord Of The Rings', 'starred' => false], - ], - ], - " - array ( - 0 => - array ( - 'title' => 'Star Wars', - 'starred' => true, - 'percentage' => 32.5, - ), - 1 => - array ( - 'title' => 'The Lord Of The Rings', - 'starred' => false, - ), - ), -); -", - ], -]); - -it('converts an xml string and save to a file, creating it', function (string $xml, array $expected, string $content) { - $xmlFile = vfsStream::newFile('xml_file.xml')->at($this->getRoot())->setContent($xml); - FileConverter::create()->convertAndSave($xmlFile->url(), $this->getRoot()->url() . '/save_file.php'); - expect('vfs://root/save_file.php')->toBeFile(); - - $actual = include('vfs://root/save_file.php'); - - expect($actual)->toBe($expected) - ->and($content)->toBe(file_get_contents('vfs://root/save_file.php')); -})->with([ - [" - - - Star Wars - True - 32.5 - - - The Lord Of The Rings - false - - -", - [ - 'movie' => [ - 0 => ['title' => 'Star Wars', 'starred' => true, 'percentage' => 32.5], - 1 => ['title' => 'The Lord Of The Rings', 'starred' => false], - ], - ], - " - array ( - 0 => - array ( - 'title' => 'Star Wars', - 'starred' => true, - 'percentage' => 32.5, - ), - 1 => - array ( - 'title' => 'The Lord Of The Rings', - 'starred' => false, - ), - ), -); -", - ], -]); - -it('try to save in a not existent directory', function () { - $xmlFile = vfsStream::newFile('xml_file.xml') - ->at($this->getRoot()) - ->setContent("The Lord Of The Ringsfalse"); - $converter = new FileConverter(); - $converter->convertAndSave($xmlFile->url(), $this->getRoot()->url() . '/my_dir/my_array.php'); -})->throws(\RuntimeException::class, "The directory `vfs://root/my_dir` does not exist: you should create it before writing a file."); - -it('try to save in a not writeable directory', function () { - $dir = vfsStream::newDirectory('xml_dir', 000)->at($this->getRoot()); - $xmlFile = vfsStream::newFile('xml_file.xml') - ->at($this->getRoot()) - ->setContent("The Lord Of The Ringsfalse"); - FileConverter::create()->convertAndSave($xmlFile->url(), $dir->url() . '/my_array.php'); -})->throws(\RuntimeException::class, "It's impossible to write into `vfs://root/xml_dir` directory: do you have the correct permissions?"); +use Susina\XmlToArray\Tests\XmlToArrayDataProvider; + +class FileConverterTest extends VfsTestCase +{ + #[DataProviderExternal(XmlToArrayDataProvider::class, 'xmlProvider')] + public function testConvertXmlFileToArray(string $xml, array $expected): void + { + $file = $this->createFile('test_file.xml', $xml); + $actual = FileConverter::create()->convert($file->url()); + + $this->assertSame($expected, $actual); + } + + public function testConvertNotExistentXmlFileThrowsException(): void + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessageIs('The file `vfs://root/notexistent.xml` does not exist.'); + FileConverter::create()->convert('vfs://root/notexistent.xml'); + } + + public function testConvertNotReadableXmlFileThrowsException(): void + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessageIs('The file `vfs://root/notreadable.xml` is not readable: do you have the correct permissions?'); + + $file = $this->createFile('notreadable.xml', ''); + $file->chmod(000); + + FileConverter::create()->convert($file->url()); + } + + #[DataProviderExternal(XmlToArrayDataProvider::class, 'convertAndSaveProvider')] + public function testConvertXmlFileAndSaveIntoAnotherFile(string $xml, array $expectedArray, string $expectedContent): void + { + $xmlFile = $this->createFile('xml_file.xml', $xml); + $saveFile = $this->createFile('saved_file.php'); + + $converter = new FileConverter(); + $converter->convertAndSave($xmlFile->url(), $saveFile->url()); + $actual = include($saveFile->url()); + + $this->assertSame($expectedArray, $actual); + $this->assertSame($expectedContent, $saveFile->getContent()); + $this->assertSame($expectedContent, file_get_contents($saveFile->url())); + } + + #[DataProviderExternal(XmlToArrayDataProvider::class, 'convertAndSaveProvider')] + public function testConvertAndSaveCreatesOutputFileIfNotExistent(string $xml, array $expectedArray, string $expectedContent): void + { + $xmlFile = $this->createFile('xml_file.xml', $xml); + + $converter = new FileConverter(); + $converter->convertAndSave($xmlFile->url(), $this->root->url() . '/my_saved_file.php'); + + $this->assertFileExists('vfs://root/my_saved_file.php'); + + $actual = include($this->root->url() . '/my_saved_file.php'); + + $this->assertSame($expectedArray, $actual); + $this->assertSame($expectedContent, file_get_contents($this->root->url() . '/my_saved_file.php')); + } + + public function testSaveInNotExistentDirectoryThrowsException(): void + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessageIs("The directory `vfs://root/my_dir` does not exist: you should create it before writing a file."); + + $xmlFile = $this->createFile('xml_file.xml', "The Lord Of The Ringsfalse"); + $converter = new FileConverter(); + $converter->convertAndSave($xmlFile->url(), $this->root->url() . '/my_dir/my_array.php'); + } + + public function testSaveInNotWriteableDirectoryThrowsException(): void + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessageIs("It's impossible to write into `vfs://root/xml_dir` directory: do you have the correct permissions?"); + + $dir = vfsStream::newDirectory('xml_dir', 000)->at($this->root); + $xmlFile = $this->createFile('xml_file.xml', "The Lord Of The Ringsfalse"); + $converter = new FileConverter(); + $converter->convertAndSave($xmlFile->url(), $dir->url() . '/my_array.php'); + } +} diff --git a/tests/VfsTestCase.php b/tests/VfsTestCase.php new file mode 100644 index 0000000..9891dd7 --- /dev/null +++ b/tests/VfsTestCase.php @@ -0,0 +1,68 @@ + $this->root ??= vfsStream::setup(); + } + + /** + * Create a vfsStreamFile based on $path parameter. + * It creates the directory structure, too. + * + * @param string $path + * @param string $content + * @return vfsStreamFile + */ + public function createFile(string $path, string $content = ''): vfsStreamFile + { + $dirs = explode('/', $path); + $fileName = array_pop($dirs); + $currentDir = $this->root; + + foreach ($dirs as $dir) { + if (!$currentDir->hasChild($dir)) { + $currentDir->addChild(vfsStream::newDirectory($dir)); + } + $currentDir = $currentDir->getChild($dir); + } + + $file = vfsStream::newFile($fileName)->withContent($content); + $currentDir->addChild($file); + + return $file; + } + + public function getIncludedFile(): vfsStreamFile + { + return vfsStream::newFile('testconvert_include.xml') + ->at($this->root) + ->setContent(" + + +") + ; + } +} diff --git a/tests/VfsTrait.php b/tests/VfsTrait.php deleted file mode 100644 index 5921eeb..0000000 --- a/tests/VfsTrait.php +++ /dev/null @@ -1,28 +0,0 @@ -root === null) { - $this->root = vfsStream::setup(); - } - - return $this->root; - } -} diff --git a/tests/XmlToArrayDataProvider.php b/tests/XmlToArrayDataProvider.php new file mode 100644 index 0000000..ff2e901 --- /dev/null +++ b/tests/XmlToArrayDataProvider.php @@ -0,0 +1,298 @@ + + + + Star Wars + True + 32.5 + + + The Lord Of The Rings + false + + + " + , + ['movie' => [0 => ['title' => 'Star Wars', 'starred' => true, 'percentage' => 32.5], 1 => ['title' => 'The Lord Of The Rings', 'starred' => false]]], + ]; + yield [ + " + + + + stream + /var/log/default.log + 300 + + + stream + /var/log/bookstore.log + + + ", [ + 'log' => [ + 'logger' => [ + [ + 'name' => 'defaultLogger', + 'type' => 'stream', + 'path' => '/var/log/default.log', + 'level' => 300, + ], + [ + 'name' => 'bookstore', + 'type' => 'stream', + 'path' => '/var/log/bookstore.log', + ], + ], + ]], + ]; + yield [ + " + +
+
+
+ ", [ + 'database' => [ + 'name' => 'TestDb', + 'table' => [ + 0 => ['name' => 'table1'], + 1 => ['name' => 'table2'], + ], + ], + ], + ]; + yield [ + 'foo', + ['node' => 'foo'], + ]; + yield [ + '', + ['node' => ['foo' => 'bar']], + ]; + yield [ + '0', + ['node' => 0], + ]; + yield [ + '', + ['node' => null], + ]; + yield [ + 'Hello World!]]>', + ['node' => 'Hello World!'], + ]; + } + + public static function xmlNoTypesProvider(): Generator + { + yield [ + " + + + Star Wars + True + 32.5 + + + The Lord Of The Rings + false + + + " + , + ['movie' => [0 => ['title' => 'Star Wars', 'starred' => 'True', 'percentage' => '32.5'], 1 => ['title' => 'The Lord Of The Rings', 'starred' => 'false']]], + ]; + yield [ + " + + + + stream + /var/log/default.log + 300 + + + stream + /var/log/bookstore.log + + + ", [ + 'log' => [ + 'logger' => [ + [ + 'name' => 'defaultLogger', + 'type' => 'stream', + 'path' => '/var/log/default.log', + 'level' => '300', + ], + [ + 'name' => 'bookstore', + 'type' => 'stream', + 'path' => '/var/log/bookstore.log', + ], + ], + ]], + ]; + yield [ + " + +
+
+
+
", [ + 'database' => [ + 'name' => 'TestDb', + 'table' => [ + 0 => ['name' => 'table1'], + 1 => ['name' => 'table2'], + ], + ], + ], + ]; + } + + public static function xmlWithAttributesProvider(): Generator + { + yield [ + " + + + + stream + /var/log/default.log + 300 + + + stream + /var/log/bookstore.log + + + ", [ + 'log' => [ + 'logger' => [ + [ + '@attributes' => [ + 'name' => 'defaultLogger', + ], + 'type' => 'stream', + 'path' => '/var/log/default.log', + 'level' => 300, + ], + [ + '@attributes' => [ + 'name' => 'bookstore', + ], + 'type' => 'stream', + 'path' => '/var/log/bookstore.log', + ], + ], + ]], + ]; + yield [ + " + +
+
+
+
", [ + 'database' => [ + '@attributes' => [ + 'name' => 'TestDb', + ], + 'table' => [ + 0 => [ + '@attributes' => [ + 'name' => 'table1', + ], + ], + 1 => [ + '@attributes' => [ + 'name' => 'table2', + ], + ], + ], + ], + ], + ]; + } + + public static function convertAndSaveProvider(): Generator + { + yield [ + " + + + Star Wars + True + 32.5 + + + The Lord Of The Rings + false + + +" + , + [ + 'movie' => [ + 0 => ['title' => 'Star Wars', 'starred' => true, 'percentage' => 32.5], + 1 => ['title' => 'The Lord Of The Rings', 'starred' => false], + ], + ], + " + array ( + 0 => + array ( + 'title' => 'Star Wars', + 'starred' => true, + 'percentage' => 32.5, + ), + 1 => + array ( + 'title' => 'The Lord Of The Rings', + 'starred' => false, + ), + ), +); +", + ]; + } + + public static function realCaseProvider(): Generator + { + yield ['propel']; + yield ['joomla']; + } +}