diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..303c5b1 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# see https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners +/.github/* @phpcfdi/core-mantainers diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..59d8b28 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,112 @@ +name: build +on: + pull_request: + branches: [ main ] + push: + branches: [ main ] + schedule: + - cron: '0 16 * * 0' # sunday 16:00 + +jobs: + + ci: # this job runs all the development tools and upload code coverage to scrutinizer + + name: PHP 8.0 (full) + runs-on: "ubuntu-latest" + + steps: + + - name: Checkout + uses: actions/checkout@v2 + + # see https://github.com/marketplace/actions/setup-php-action + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.0' + extensions: dom + coverage: xdebug + tools: composer:v2, phpcs, php-cs-fixer, phpstan, psalm, infection, cs2pr + env: + fail-fast: true + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install project dependencies + run: composer upgrade --no-interaction --no-progress --prefer-dist + + - name: Code style (phpcs) + run: phpcs -q --report=checkstyle | cs2pr + + - name: Code style (php-cs-fixer) + run: php-cs-fixer fix --dry-run --format=checkstyle | cs2pr + + - name: Tests (phpunit with code coverage) + run: vendor/bin/phpunit --testdox --verbose --coverage-clover=build/coverage-clover.xml --coverage-xml=build/coverage --log-junit=build/coverage/junit.xml + + - name: Code analysis (phpstan) + run: phpstan analyse --no-progress --verbose + + - name: Code analysis (psalm) + run: psalm --no-progress --output-format=github + + - name: Mutation testing analysis + run: infection --skip-initial-tests --coverage=build/coverage --no-progress --no-interaction --logger-github + + # see https://github.com/marketplace/actions/action-scrutinizer + - name: Upload code coverage to scrutinizer + uses: sudo-bot/action-scrutinizer@latest + with: + cli-args: "--format=php-clover build/coverage-clover.xml" + continue-on-error: true + + build: # this job runs tests on all php supported versions + + name: PHP ${{ matrix.php-versions }} (tests) + runs-on: "ubuntu-latest" + + strategy: + matrix: + php-versions: ['7.3', '7.4'] + + steps: + + - name: Checkout + uses: actions/checkout@v2 + + # see https://github.com/marketplace/actions/setup-php-action + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: dom + coverage: none + tools: composer:v2, cs2pr + env: + fail-fast: true + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install project dependencies + run: composer upgrade --no-interaction --no-progress --prefer-dist + + - name: Tests + run: vendor/bin/phpunit --testdox --verbose diff --git a/.phive/phars.xml b/.phive/phars.xml new file mode 100644 index 0000000..012e080 --- /dev/null +++ b/.phive/phars.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.php_cs.dist b/.php-cs-fixer.dist.php similarity index 68% rename from .php_cs.dist rename to .php-cs-fixer.dist.php index 08de141..969cb89 100644 --- a/.php_cs.dist +++ b/.php-cs-fixer.dist.php @@ -1,51 +1,52 @@ setRiskyAllowed(true) ->setCacheFile(__DIR__ . '/build/php_cs.cache') ->setRules([ - '@PSR2' => true, - '@PHP70Migration' => true, - '@PHP70Migration:risky' => true, - '@PHP71Migration' => true, + '@PSR12' => true, + '@PSR12:risky' => true, '@PHP71Migration:risky' => true, - // '@PHP73Migration' => true, + '@PHP73Migration' => true, + // PSR12 (remove when php-cs-fixer reaches ^3.1.1) + 'class_definition' => ['space_before_parenthesis' => true], // symfony 'class_attributes_separation' => true, 'whitespace_after_comma_in_array' => true, 'no_empty_statement' => true, 'no_extra_blank_lines' => true, 'function_typehint_space' => true, - 'no_alias_functions' => true, - 'trailing_comma_in_multiline_array' => true, - 'new_with_braces' => true, - 'no_blank_lines_after_class_opening' => true, 'no_blank_lines_after_phpdoc' => true, 'object_operator_without_whitespace' => true, 'binary_operator_spaces' => true, 'phpdoc_scalar' => true, - 'self_accessor' => true, 'no_trailing_comma_in_singleline_array' => true, 'single_quote' => true, 'no_singleline_whitespace_before_semicolons' => true, 'no_unused_imports' => true, - 'no_whitespace_in_blank_line' => true, 'yoda_style' => ['equal' => true, 'identical' => true, 'less_and_greater' => null], 'standardize_not_equals' => true, - // contrib 'concat_space' => ['spacing' => 'one'], - 'not_operator_with_successor_space' => true, - 'single_blank_line_before_namespace' => true, 'linebreak_after_opening_tag' => true, - 'blank_line_after_opening_tag' => true, - 'ordered_imports' => true, - 'array_syntax' => ['syntax' => 'short'], + // symfony:risky + 'no_alias_functions' => true, + 'self_accessor' => true, + // contrib + 'not_operator_with_successor_space' => true, ]) ->setFinder( PhpCsFixer\Finder::create() ->in(__DIR__) + ->append([__FILE__]) ->exclude(['vendor', 'build']) ) ; diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 3df7e54..bf297bf 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -1,23 +1,19 @@ filter: excluded_paths: - 'tests/' + dependency_paths: + - 'tools/' - 'vendor/' build: dependencies: override: - - composer self-update --2 --stable --no-interaction --no-progress - - composer remove squizlabs/php_codesniffer friendsofphp/php-cs-fixer phpstan/phpstan --dev --no-interaction --no-progress --no-update - - composer update --no-interaction --no-progress + - composer update --no-interaction --prefer-dist nodes: - analysis: - project_setup: - override: true + analysis: # see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/ + project_setup: {override: true} tests: override: - php-scrutinizer-run --enable-security-analysis - - phpcs-run --standard=phpcs.xml.dist src/ tests/ - - command: vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover - coverage: - file: coverage.clover - format: clover +tools: + external_code_coverage: true \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5b6e2eb..0000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: php - -# php compatibility -php: ["7.2", "7.3", "7.4", "8.0"] - -cache: - - directories: - - $HOME/.composer - -env: - global: - - PHP_CS_FIXER_IGNORE_ENV=yes - -before_script: - - phpenv config-rm xdebug.ini || true - - travis_retry composer self-update --2 --stable --no-interaction --no-progress - - travis_retry composer upgrade --prefer-dist --no-interaction --no-progress - -script: - - vendor/bin/php-cs-fixer fix --dry-run --verbose - - vendor/bin/phpcs --colors -sp src/ tests/ - - vendor/bin/phpunit --testdox --verbose - - vendor/bin/phpstan analyse --no-progress --level max src/ tests/ - -notifications: - email: - if: branch = master diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 0a673cd..0d98501 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,5 +1,4 @@ - -# Código de Conducta convenido para Contribuyentes +# Código de Conducta Convenido para Contribuyentes ## Nuestro compromiso @@ -37,7 +36,7 @@ Este código de conducta aplica tanto a espacios del proyecto como a espacios p ## Aplicación -Instancias de comportamiento abusivo, acosador o inaceptable de otro modo podrán ser reportadas a los administradores de la comunidad responsables del cumplimiento a través de [coc@phpcfdi.com](). Todas las quejas serán evaluadas e investigadas de una manera puntual y justa. +Instancias de comportamiento abusivo, acosador o inaceptable de otro modo podrán ser reportadas a los administradores de la comunidad responsables del cumplimiento a través de [coc@phpcfdi.com](mailto:coc@phpcfdi.com). Todas las quejas serán evaluadas e investigadas de una manera puntual y justa. Todos los administradores de la comunidad están obligados a respetar la privacidad y la seguridad de quienes reporten incidentes. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8ad42ea..bba4278 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,6 +64,7 @@ Considera las siguientes directrices: ```shell # Actualiza tus dependencias composer update +phive update # Verificación de estilo de código composer dev:check-style @@ -74,12 +75,22 @@ composer dev:fix-style # Ejecución de pruebas composer dev:test -# Ejecución todo en uno, corregir estilo, verificar estilo y correr pruebas +# Ejecución todo en uno: corregir estilo, verificar estilo y correr pruebas composer dev:build ``` +## Ejecutar GitHub Actions localmente + +Puedes usar [`act`](https://github.com/nektos/act) para ejecutar GitHub Actions localmente, tal como se +muestra en [`actions/setup-php-action`](https://github.com/marketplace/actions/setup-php-action#local-testing-setup) +puedes ejecutar el siguiente comando: + +```shell +act -P ubuntu-latest=shivammathur/node:latest +``` + [phpCfdi]: https://github.com/phpcfdi/ [project]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr [contributors]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/graphs/contributors -[coc]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/blob/master/CODE_OF_CONDUCT.md +[coc]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/blob/main/CODE_OF_CONDUCT.md [issues]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/issues diff --git a/README.md b/README.md index 4fa89f8..0220472 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ > Consulta el estado de un CFDI en el webservice del SAT usando HTTP (PSR-17 y PSR-18) -:us: The documentation of this project is in spanish as this is the natural language for intented audience. +:us: The documentation of this project is in spanish as this is the natural language for intended audience. :mexico: La documentación del proyecto está en español porque ese es el lenguaje principal de los usuarios. @@ -88,7 +88,7 @@ Puedes ver los siguientes recursos para integrar `phpcfdi/sat-estado-cfdi-http-p - [Integración genérica](docs/integracion-generica.md) Implementación de los PSR-17 y PSR-18 que decidas, ejemplo usando Sunrise. -## Compatilibilidad +## Compatibilidad Esta librería se mantendrá compatible con al menos la versión con [soporte activo de PHP](https://www.php.net/supported-versions.php) más reciente. @@ -106,22 +106,22 @@ y recuerda revisar el archivo de tareas pendientes [TODO][] y el archivo [CHANGE The `phpcfdi/sat-estado-cfdi-http-psr` library is copyright © [PhpCfdi](https://www.phpcfdi.com/) and licensed for use under the MIT License (MIT). Please see [LICENSE][] for more information. -[contributing]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/blob/master/CONTRIBUTING.md -[changelog]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/blob/master/docs/CHANGELOG.md -[todo]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/blob/master/docs/TODO.md +[contributing]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/blob/main/CONTRIBUTING.md +[changelog]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/blob/main/docs/CHANGELOG.md +[todo]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/blob/main/docs/TODO.md [source]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr [release]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/releases -[license]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/blob/master/LICENSE -[build]: https://travis-ci.com/phpcfdi/sat-estado-cfdi-http-psr?branch=master +[license]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/blob/main/LICENSE +[build]: https://github.com/phpcfdi/sat-estado-cfdi-http-psr/actions/workflows/build.yml?query=branch:main [quality]: https://scrutinizer-ci.com/g/phpcfdi/sat-estado-cfdi-http-psr/ -[coverage]: https://scrutinizer-ci.com/g/phpcfdi/sat-estado-cfdi-http-psr/code-structure/master/code-coverage +[coverage]: https://scrutinizer-ci.com/g/phpcfdi/sat-estado-cfdi-http-psr/code-structure/main/code-coverage [downloads]: https://packagist.org/packages/phpcfdi/sat-estado-cfdi-http-psr [badge-source]: https://img.shields.io/badge/source-phpcfdi/sat--estado--cfdi--http--psr-blue?style=flat-square [badge-release]: https://img.shields.io/github/release/phpcfdi/sat-estado-cfdi-http-psr?style=flat-square [badge-license]: https://img.shields.io/github/license/phpcfdi/sat-estado-cfdi-http-psr?style=flat-square -[badge-build]: https://img.shields.io/travis/com/phpcfdi/sat-estado-cfdi-http-psr/master?style=flat-square -[badge-quality]: https://img.shields.io/scrutinizer/g/phpcfdi/sat-estado-cfdi-http-psr/master?style=flat-square -[badge-coverage]: https://img.shields.io/scrutinizer/coverage/g/phpcfdi/sat-estado-cfdi-http-psr/master?style=flat-square +[badge-build]: https://img.shields.io/github/workflow/status/phpcfdi/sat-estado-cfdi-http-psr/build/main?style=flat-square +[badge-quality]: https://img.shields.io/scrutinizer/g/phpcfdi/sat-estado-cfdi-http-psr/main?style=flat-square +[badge-coverage]: https://img.shields.io/scrutinizer/coverage/g/phpcfdi/sat-estado-cfdi-http-psr/main?style=flat-square [badge-downloads]: https://img.shields.io/packagist/dt/phpcfdi/sat-estado-cfdi-http-psr?style=flat-square diff --git a/composer.json b/composer.json index 2f2d88a..9ba454e 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ } }, "require": { - "php": ">=7.2", + "php": ">=7.3", "ext-dom": "*", "phpcfdi/sat-estado-cfdi": "^1.0.0", "psr/http-client": "^1.0", @@ -35,10 +35,7 @@ "symfony/http-client": "^5.2", "sunrise/http-factory": "^1.0", "sunrise/http-message": "^1.0", - "phpunit/phpunit": "^8.0", - "squizlabs/php_codesniffer": "^3.0", - "friendsofphp/php-cs-fixer": "^2.4", - "phpstan/phpstan": "^0.12" + "phpunit/phpunit": "^9.5" }, "suggest": { "phpcfdi/cfdi-expresiones": "Genera expresiones de CFDI 3.3, CFDI 3.2 y RET 1.0" @@ -56,27 +53,29 @@ "scripts": { "dev:build": ["@dev:fix-style", "@dev:test"], "dev:check-style": [ - "@php vendor/bin/php-cs-fixer fix --dry-run --verbose", - "@php vendor/bin/phpcs --colors -sp src/ tests/" + "@php tools/php-cs-fixer fix --dry-run --verbose", + "@php tools/phpcs --colors -sp" ], "dev:fix-style": [ - "@php vendor/bin/php-cs-fixer fix --verbose", - "@php vendor/bin/phpcbf --colors -sp src/ tests/" + "@php tools/php-cs-fixer fix --verbose", + "@php tools/phpcbf --colors -sp" ], "dev:test": [ "@dev:check-style", "@php vendor/bin/phpunit --testdox --verbose --stop-on-failure", - "@php vendor/bin/phpstan analyse --no-progress --verbose --level max src/ tests/" + "@php tools/phpstan analyse --no-progress", + "@php tools/psalm --no-progress", + "@php tools/infection --no-progress --no-interaction --show-mutations" ], "dev:coverage": [ - "@php -dzend_extension=xdebug.so vendor/bin/phpunit --testdox --coverage-html build/coverage/html/" + "@php -dzend_extension=xdebug.so -dxdebug.mode=coverage vendor/bin/phpunit --verbose --coverage-html build/coverage/html/" ] }, "scripts-descriptions": { - "dev:build": "DEV: run dev:fix-style dev:tests and dev:docs, run before pull request", + "dev:build": "DEV: run dev:fix-style and dev:tests, run before pull request", "dev:check-style": "DEV: search for code style errors using php-cs-fixer and phpcs", "dev:fix-style": "DEV: fix code style errors using php-cs-fixer and phpcbf", - "dev:test": "DEV: run dev:check-style, phpunit and phpstan", + "dev:test": "DEV: run dev:check-style, phpunit, phpstan, psalm and infection", "dev:coverage": "DEV: run phpunit with xdebug and storage coverage in build/coverage/html/" } } diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8ed8d73..6004a10 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -11,6 +11,15 @@ versión aunque sí su incorporación en la rama principal de trabajo, generalme ## Listado de cambios +### Version 1.0.1 2021-09-03 + +- La versión menor de PHP es 7.3. +- Se actualiza PHPUnit a 9.5. +- Se migra de Travis-CI a GitHub Workflows. Gracias Travis-CI. +- Se instalan las herramientas de desarrollo usando `phive` en lugar de `composer`. +- Se agregan revisiones de `psalm` e `infection`. +- Se cambia la rama principal a `main`. + ### Version 1.0.0 2021-01-10 - A partir de esta versión se ha puesto la documentación del proyecto en español. diff --git a/docs/integracion-generica.md b/docs/integracion-generica.md index a515d7f..55758f3 100644 --- a/docs/integracion-generica.md +++ b/docs/integracion-generica.md @@ -34,7 +34,7 @@ $consumer = new HttpConsumerClient($factory); ## Extendiendo HttpConsumerFactory Otra forma de hacerlo es extendiendo la clase `HttpConsumerFactory`, un ejemplo de esto se puede ver -en +en ## Implementando HttpConsumerFactoryInterface diff --git a/infection.json.dist b/infection.json.dist new file mode 100644 index 0000000..b69deba --- /dev/null +++ b/infection.json.dist @@ -0,0 +1,18 @@ +{ + "timeout": 10, + "source": { + "directories": [ + "src" + ], + "excludes": [ + "ComplianceTester/ComplianceTester.php" + ] + }, + "logs": { + "text": "build\/infection.log" + }, + "mutators": { + "@default": true + }, + "initialTestsPhpOptions": "-dzend_extension=xdebug.so -dxdebug.mode=coverage" +} diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 24596ad..e7c3269 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -1,11 +1,17 @@ The EngineWorks (PSR-2 based) coding standard. + + src + tests + - + + + diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..e691e35 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,5 @@ +parameters: + level: max + paths: + - src/ + - tests/ diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 2081ce6..7557d0b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -2,17 +2,17 @@ + > - - ./tests/ + + tests - - + + ./src/ - - + + diff --git a/psalm.xml.dist b/psalm.xml.dist new file mode 100644 index 0000000..28c52a8 --- /dev/null +++ b/psalm.xml.dist @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/src/HttpConsumerClient.php b/src/HttpConsumerClient.php index e1f1860..03de0db 100644 --- a/src/HttpConsumerClient.php +++ b/src/HttpConsumerClient.php @@ -7,6 +7,7 @@ use PhpCfdi\SatEstadoCfdi\Contracts\ConsumerClientInterface; use PhpCfdi\SatEstadoCfdi\Contracts\ConsumerClientResponseInterface; use PhpCfdi\SatEstadoCfdi\HttpPsr\Internal\SoapXml; +use Psr\Http\Client\ClientExceptionInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; @@ -41,15 +42,14 @@ public function createHttpRequest(string $uri, string $expression): RequestInter // body $xml = $this->soapXml->createXmlRequest($expression); $body = $this->factory->streamFactory()->createStream($xml); - $request = $request->withBody($body); - return $request; + return $request->withBody($body); } public function createConsumerClientResponse(string $xmlResponse): ConsumerClientResponseInterface { // parse body - $dataExtracted = $this->soapXml->extractDataFromXmlResponse($xmlResponse); + $dataExtracted = $this->soapXml->extractDataFromXmlResponse($xmlResponse, 'ConsultaResult'); // create & populate container $container = $this->factory->newConsumerClientResponse(); @@ -60,6 +60,9 @@ public function createConsumerClientResponse(string $xmlResponse): ConsumerClien return $container; } + /** + * @throws ClientExceptionInterface + */ public function consume(string $uri, string $expression): ConsumerClientResponseInterface { // parameters --convert--> request --httpCall--> response --convert--> ConsumerClientResponse @@ -73,6 +76,7 @@ public function consume(string $uri, string $expression): ConsumerClientResponse * * @param RequestInterface $request * @return ResponseInterface + * @throws ClientExceptionInterface */ protected function sendRequest(RequestInterface $request): ResponseInterface { diff --git a/src/HttpConsumerFactoryInterface.php b/src/HttpConsumerFactoryInterface.php index 5facb3d..e68a26a 100644 --- a/src/HttpConsumerFactoryInterface.php +++ b/src/HttpConsumerFactoryInterface.php @@ -1,9 +1,6 @@ uri = $uri; } - public function uri(): string - { - return $this->uri; - } - /** * Extract the information from expected soap response * * @param string $xmlResponse + * @param string $elementName * @return array */ - public function extractDataFromXmlResponse(string $xmlResponse): array + public function extractDataFromXmlResponse(string $xmlResponse, string $elementName): array { - $extracted = []; $document = new DOMDocument(); $document->loadXML($xmlResponse); - /** @var DOMElement $consultaResult */ - foreach ($document->getElementsByTagNameNS($this->uri(), 'ConsultaResult') as $consultaResult) { - foreach ($consultaResult->childNodes as $children) { - if (! $children instanceof DOMElement) { - continue; - } - $extracted[$children->localName] = $children->textContent; + + $consultaResult = $this->obtainFirstElement($document, $elementName); + if (null === $consultaResult) { + return []; + } + + $extracted = []; + foreach ($consultaResult->childNodes as $children) { + if (! $children instanceof DOMElement) { + continue; } - break; // exit loop if for any reason got more than 1 element ConsultaResult + $extracted[$children->localName] = $children->textContent; } + return $extracted; } + private function obtainFirstElement(DOMDocument $document, string $elementName): ?DOMElement + { + foreach ($document->getElementsByTagNameNS($this->uri, $elementName) as $consultaResult) { + return $consultaResult; + } + return null; + } + public function createXmlRequest(string $expression): string { $soap = 'http://schemas.xmlsoap.org/soap/envelope/'; $document = new DOMDocument('1.0', 'UTF-8'); $document->appendChild($document->createElementNS($soap, 's:Envelope')) ->appendChild($document->createElementNS($soap, 's:Body')) - ->appendChild($document->createElementNS($this->uri(), 'c:Consulta')) - ->appendChild($document->createElementNS($this->uri(), 'c:expresionImpresa')) + ->appendChild($document->createElementNS($this->uri, 'c:Consulta')) + ->appendChild($document->createElementNS($this->uri, 'c:expresionImpresa')) ->appendChild($document->createTextNode($expression)); return $document->saveXML() ?: ''; } diff --git a/tests/Unit/HttpConsumerClientTest.php b/tests/Unit/HttpConsumerClientTest.php index 24f9547..041c9e6 100644 --- a/tests/Unit/HttpConsumerClientTest.php +++ b/tests/Unit/HttpConsumerClientTest.php @@ -6,8 +6,12 @@ use PhpCfdi\SatEstadoCfdi\Contracts\ConsumerClientInterface; use PhpCfdi\SatEstadoCfdi\HttpPsr\HttpConsumerClient; +use PhpCfdi\SatEstadoCfdi\HttpPsr\HttpConsumerFactoryInterface; use PhpCfdi\SatEstadoCfdi\Tests\HttpPsr\TestCase; use PHPUnit\Framework\MockObject\MockObject; +use Psr\Http\Client\ClientInterface as HttpClientInterface; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; use Sunrise\Http\Factory\ResponseFactory; class HttpConsumerClientTest extends TestCase @@ -75,4 +79,33 @@ public function testConsume(): void $container = $client->consume('http://example.com/', ''); $this->assertSame('S - Comprobante obtenido satisfactoriamente.', $container->get('CodigoEstatus')); } + + public function testMethodSendRequest(): void + { + $request = $this->createMock(RequestInterface::class); + $response = $this->createMock(ResponseInterface::class); + + /** @var HttpClientInterface&MockObject $httpClient */ + $httpClient = $this->createMock(HttpClientInterface::class); + $httpClient->expects($this->once()) + ->method('sendRequest') + ->with($request) + ->willReturn($response); + + /** @var HttpConsumerFactoryInterface&MockObject $factory */ + $factory = $this->createMock(HttpConsumerFactoryInterface::class); + $factory->expects($this->once()) + ->method('httpClient') + ->willReturn($httpClient); + + $httpConsumetClient = new class ($factory) extends HttpConsumerClient { + /** @noinspection PhpOverridingMethodVisibilityInspection */ + public function sendRequest(RequestInterface $request): ResponseInterface // phpcs:ignore + { + return parent::sendRequest($request); + } + }; + + $this->assertSame($response, $httpConsumetClient->sendRequest($request)); + } } diff --git a/tests/Unit/SoapXmlTest.php b/tests/Unit/SoapXmlTest.php new file mode 100644 index 0000000..9c16777 --- /dev/null +++ b/tests/Unit/SoapXmlTest.php @@ -0,0 +1,63 @@ + + + + + x-first + x-second + x-third + + + must be ignored + + + + + XML; + + $soapXml = new SoapXml('http://tempuri.org/'); + $extracted = $soapXml->extractDataFromXmlResponse($xml, 'Result'); + + $expected = [ + 'first' => 'x-first', + 'second' => 'x-second', + 'third' => 'x-third', + ]; + $this->assertSame($expected, $extracted); + } + + public function testCreateConsumerClientResponse(): void + { + $xmlns = 'http://tempuri.org/'; + $expression = 'Expresión con caracteres & y Ñ'; + + $expressionXml = htmlspecialchars($expression, ENT_XML1); + $expected = <<< XML + + + + $expressionXml + + + + XML; + + $soapXml = new SoapXml($xmlns); + $createdXml = $soapXml->createXmlRequest($expression); + + $this->assertXmlStringEqualsXmlString($expected, $createdXml); + } +} diff --git a/tools/infection b/tools/infection new file mode 120000 index 0000000..313fced --- /dev/null +++ b/tools/infection @@ -0,0 +1 @@ +/home/eclipxe/.phive/phars/infection-0.23.0.phar \ No newline at end of file diff --git a/tools/php-cs-fixer b/tools/php-cs-fixer new file mode 120000 index 0000000..44b0111 --- /dev/null +++ b/tools/php-cs-fixer @@ -0,0 +1 @@ +/home/eclipxe/.phive/phars/php-cs-fixer-3.1.0.phar \ No newline at end of file diff --git a/tools/phpcbf b/tools/phpcbf new file mode 120000 index 0000000..e439e7b --- /dev/null +++ b/tools/phpcbf @@ -0,0 +1 @@ +/home/eclipxe/.phive/phars/phpcbf-3.6.0.phar \ No newline at end of file diff --git a/tools/phpcs b/tools/phpcs new file mode 120000 index 0000000..b2cf86d --- /dev/null +++ b/tools/phpcs @@ -0,0 +1 @@ +/home/eclipxe/.phive/phars/phpcs-3.6.0.phar \ No newline at end of file diff --git a/tools/phpstan b/tools/phpstan new file mode 120000 index 0000000..0e2642d --- /dev/null +++ b/tools/phpstan @@ -0,0 +1 @@ +/home/eclipxe/.phive/phars/phpstan-0.12.98.phar \ No newline at end of file diff --git a/tools/psalm b/tools/psalm new file mode 120000 index 0000000..12be5d0 --- /dev/null +++ b/tools/psalm @@ -0,0 +1 @@ +/home/eclipxe/.phive/phars/psalm-4.9.3.phar \ No newline at end of file