diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml new file mode 100644 index 0000000..2e4aaa7 --- /dev/null +++ b/.github/workflows/phpunit.yml @@ -0,0 +1,65 @@ +name: "PHPUnit tests" + +on: + pull_request: + push: + branches: + - "master" + +jobs: + phpunit: + name: "PHPUnit tests" + + runs-on: "ubuntu-latest" + + strategy: + matrix: + dependencies: + - "highest" + php-version: + - "7.2" + - "7.3" + - "7.4" + - "8.0" + - "8.1" + - "8.2" + - "8.3" + - "8.4" + + include: + - php-version: '7.2' + dependencies: "lowest" + + steps: + - name: "Checkout" + uses: "actions/checkout@v4" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "pcov" + php-version: "${{ matrix.php-version }}" + ini-values: memory_limit=-1 + tools: composer:v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Fixes any pubkeys failure (add a `composer diagnose` step to debug if necessary) + - name: "Composer force self-update" + run: "composer self-update" + + - name: "Install lowest dependencies" + if: ${{ matrix.dependencies == 'lowest' }} + run: "composer update --prefer-lowest --no-interaction --no-progress" + + - name: "Install highest dependencies" + if: ${{ matrix.dependencies == 'highest' }} + run: "composer update --no-interaction --no-progress" + + - name: "Tests (PHPUnit 9)" + if: ${{ matrix.php-version <= '8.0' }} + run: "vendor/bin/phpunit --configuration phpunit9.xml.dist" + + - name: "Tests (PHPUnit 10+)" + if: ${{ matrix.php-version >= '8.1' }} + run: "vendor/bin/phpunit" diff --git a/.gitignore b/.gitignore index 8a282a5..472a3b6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ composer.lock composer.phar phpunit.xml +/.phpunit.result.cache +/build diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 091cc30..0000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: php - -dist: trusty -php: - - "7.4" - - "7.3" - - "7.2" - - "7.1" - - "7.0" - - "5.6" - -before_script: - - travis_retry composer self-update - - travis_retry composer install --no-interaction --prefer-source - -script: - - vendor/bin/phpcs --standard=PSR2 src - - vendor/bin/phpunit --verbose --coverage-clover coverage.clover - -after_success: - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover coverage.clover diff --git a/composer.json b/composer.json index 43675de..cfb24e5 100644 --- a/composer.json +++ b/composer.json @@ -35,29 +35,41 @@ "psr-4": { "Omnipay\\Redsys\\" : "tests/" } }, "require": { + "php": "^7.2|^8.0", "omnipay/common": "dev-address3-support" }, "require-dev": { "omnipay/tests": "dev-address3-support", - "squizlabs/php_codesniffer": "^3.5" + "squizlabs/php_codesniffer": "^3.5", + "http-interop/http-factory-guzzle": "^1.1" }, "suggest": { "ext-openssl": "Required for hashing functions to check message signatures" }, + "scripts": { + "test": "phpunit", + "check-style": "phpcs -p --standard=PSR2 src/", + "fix-style": "phpcbf -p --standard=PSR2 src/" + }, "extra": { "branch-alias": { - "dev-master": "3.2.x-dev" + "dev-master": "3.3.x-dev" } }, "repositories": [ { "type": "vcs", - "url": "https://github.com/CodeDruids/omnipay-common" + "url": "https://github.com/PatronBase/omnipay-common" }, { "type": "vcs", - "url": "https://github.com/CodeDruids/omnipay-tests" + "url": "https://github.com/PatronBase/omnipay-tests" } ], - "prefer-stable": true + "prefer-stable": true, + "config": { + "allow-plugins": { + "php-http/discovery": true + } + } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 50647d9..21263b8 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,25 +1,30 @@ - - - - - - - ./tests/ - - - - - ./src - - + stopOnFailure="false"> + + + + + + + + + + src/ + + + + + tests + + + + + diff --git a/phpunit9.xml.dist b/phpunit9.xml.dist new file mode 100644 index 0000000..5ab568e --- /dev/null +++ b/phpunit9.xml.dist @@ -0,0 +1,32 @@ + + + + + src/ + + + + + + + + + + tests + + + + + + diff --git a/src/Message/PurchaseRequest.php b/src/Message/PurchaseRequest.php index 2e7b6fd..21460e1 100644 --- a/src/Message/PurchaseRequest.php +++ b/src/Message/PurchaseRequest.php @@ -161,7 +161,7 @@ public function getConsumerLanguage() /** * Set the language presented to the consumer * - * @param null|string|int Either the ISO 639-1 code to be converted, or the gateway's own numeric language code + * @param null|string|int $value The ISO 639-1 code to be converted, or the gateway's own numeric language code */ public function setConsumerLanguage($value) { @@ -177,6 +177,41 @@ public function setConsumerLanguage($value) return $this->setParameter('consumerLanguage', $value); } + public function getDirectPayment() + { + return $this->getParameter('directPayment'); + } + + /** + * Set the "directness" of payment + * + * Can be true (merchant initiated), false/null (customer initiated) or "MOTO" (usually call centre initiated) + * Invalid values will be converted to null as that's the most secure option + * + * @param null|bool|string $value + */ + public function setDirectPayment($value) + { + if (is_bool($value)) { + // this is fine + } elseif (is_string($value)) { + if (strtoupper($value) == "TRUE") { + $value = true; + } elseif (strtoupper($value) == "FALSE") { + $value = false; + } elseif (strtoupper($value) == "MOTO") { + $value = "MOTO"; + } else { + // something invalid + $value = null; + } + } else { + // something invalid + $value = null; + } + return $this->setParameter('directPayment', $value); + } + public function getHmacKey() { return $this->getParameter('hmacKey'); @@ -278,11 +313,11 @@ public function setUse3DS($value) } /** - * Get the threeDSCompInd field - * Corresponds to the Ds_Merchant_Emv3Ds.threeDSCompInd field in Redsys documentation. + * Get the threeDSCompInd field, which indicates whether the 3DSMethod has been executed * - * @return null|string + * Corresponds to the Ds_Merchant_Emv3Ds.threeDSCompInd field in Redsys documentation. * + * @return null|string Y = Successfully completed, N = Completed with errors, U = 3DSMethod not executed */ public function getThreeDSCompInd() { @@ -303,11 +338,11 @@ public function setThreeDSCompInd($value) } /** - * Get the threeDSInfo field - * Corresponds to the Ds_Merchant_Emv3Ds.threeDSInfo field in Redsys documentation. + * Get the threeDSInfo field (the type of request) * - * @return null|string + * Corresponds to the Ds_Merchant_Emv3Ds.threeDSInfo field in Redsys documentation. * + * @return null|string Possible values: CardData, AuthenticationData, ChallengeResponse */ public function getThreeDSInfo() { @@ -1507,31 +1542,6 @@ public function setBrowserColorDepth($value) return $this->setParameter('browserColorDepth', $value); } - /** - * Get the browserIP field - * - * Corresponds to the Ds_Merchant_Emv3Ds.browserIP field - * - * @return null|string - */ - public function getBrowserIP() - { - return $this->getParameter('browserIP'); - } - - /** - * Set the browserIP field - * - * Corresponds to the Ds_Merchant_Emv3Ds.browserIP field - * - * @param null|string $value - * @return self - */ - public function setBrowserIP($value) - { - return $this->setParameter('browserIP', $value); - } - /** * Get the browserJavaEnabled field * @@ -1682,31 +1692,6 @@ public function setBrowserUserAgent($value) return $this->setParameter('browserUserAgent', $value); } - /** - * Get the notificationURL field - * - * Corresponds to the Ds_Merchant_Emv3Ds.notificationURL field - * - * @return null|string - */ - public function getNotificationURL() - { - return $this->getParameter('notificationURL'); - } - - /** - * Set the notificationURL field - * - * Corresponds to the Ds_Merchant_Emv3Ds.notificationURL field - * - * @param null|string $value - * @return self - */ - public function setNotificationURL($value) - { - return $this->setParameter('notificationURL', $value); - } - /** * Get the basic data fields that don't require any 3DS/SCA fields */ @@ -1727,7 +1712,7 @@ public function getBaseData() 'Ds_Merchant_ProductDescription' => $this->getDescription(), 'Ds_Merchant_Cardholder' => $this->getCardholder(), 'Ds_Merchant_UrlOK' => $this->getReturnUrl(), - 'Ds_Merchant_UrlKO' => $this->getReturnUrl(), + 'Ds_Merchant_UrlKO' => $this->getCancelUrl(), 'Ds_Merchant_MerchantName' => $this->getMerchantName(), 'Ds_Merchant_ConsumerLanguage' => $this->getConsumerLanguage(), 'Ds_Merchant_MerchantData' => $this->getMerchantData(), @@ -1797,6 +1782,11 @@ public function getMerchantRiskData() public function getData() { $data = $this->getBaseData(); + + if ($this->getDirectPayment() !== null) { + $data['Ds_Merchant_DirectPayment'] = $this->getDirectPayment(); + } + if ($this->getScaExemptionIndicator() !== null) { $data['Ds_Merchant_Excep_Sca'] = $this->getScaExemptionIndicator(); } @@ -1831,18 +1821,16 @@ public function getData() // required parameters for v2 'browserAcceptHeader' => $this->getBrowserAcceptHeader(), 'browserColorDepth' => $this->getBrowserColorDepth(), - 'browserIP' => $this->getBrowserIP(), + 'browserIP' => $this->getClientIp(), 'browserJavaEnabled' => $this->getBrowserJavaEnabled(), 'browserLanguage' => $this->getBrowserLanguage(), 'browserScreenHeight' => $this->getBrowserScreenHeight(), 'browserScreenWidth' => $this->getBrowserScreenWidth(), 'browserTZ' => $this->getBrowserTZ(), 'browserUserAgent' => $this->getBrowserUserAgent(), - 'notificationURL' => $this->getNotificationURL(), + 'notificationURL' => $this->getNotifyUrl(), 'protocolVersion' => $this->getProtocolVersion(), - // Indicates whether the 3DSMethod has been executed. Values ​​accepted: Y= Successfully completed, N = Completed with errors, U = 3DSMethod not executed 'threeDSCompInd' => $this->getThreeDSCompInd(), - // Type of request. Possible values: CardData, AuthenticationData, ChallengeResponse 'threeDSInfo' => $this->getThreeDSInfo(), 'threeDSServerTransID' => $this->getTransactionId(), // optional parameters for v2 diff --git a/tests/Message/PurchaseRequestTest.php b/tests/Message/PurchaseRequestTest.php index a67ae5a..3470634 100644 --- a/tests/Message/PurchaseRequestTest.php +++ b/tests/Message/PurchaseRequestTest.php @@ -26,35 +26,37 @@ class PurchaseRequestTest extends TestCase /** @var mixed[] */ protected $full3DSParams = []; - public function setUp() + public function setUp(): void { $this->fullBaseParams = $this->requiredRequestParams + [ + 'clientIp' => '192.0.0.0', 'transactionId' => '123abc', 'hmacKey' => 'Mk9m98IfEblmPfrpsawt7BmxObt98Jev', 'description' => 'My sales items', 'cardholder' => 'J Smith', + 'cancelUrl' => 'https://www.example.com/cancel', 'notifyUrl' => 'https://www.example.com/notify', 'returnUrl' => 'https://www.example.com/return', 'merchantName' => 'My Store', 'consumerLanguage' => 'en', 'merchantData' => 'Ref: 99zz', + 'directPayment' => false, ]; $this->full3DSParams = $this->fullBaseParams + [ 'use3DS' => true, 'protocolVersion' => '2.1.0', 'threeDSCompInd' => 'U', - 'threeDSInfo' => 'CardData', + 'threeDSInfo' => 'CardData', 'threeDSServerTransID' => '12345', 'browserAcceptHeader' => 'text/html,application', - 'browserColorDepth' => '24', - 'browserIP' => '192.0.0.0', - 'browserJavaEnabled' => true, - 'browserLanguage' => 'en-GB', - 'browserScreenHeight' => '1000', - 'browserScreenWidth' => '1200', - 'browserTZ' => '2', - 'browserUserAgent' => 'Mozilla/5.0', + 'browserColorDepth' => '24', + 'browserJavaEnabled' => true, + 'browserLanguage' => 'en-GB', + 'browserScreenHeight' => '1000', + 'browserScreenWidth' => '1200', + 'browserTZ' => '2', + 'browserUserAgent' => 'Mozilla/5.0', 'card' => new CreditCard([ 'email' => "test@example.net", 'shippingAddress1' => "Ship 1 Test", @@ -130,7 +132,7 @@ public function testGetBaseData() $this->assertSame('My sales items', $data['Ds_Merchant_ProductDescription']); $this->assertSame('J Smith', $data['Ds_Merchant_Cardholder']); $this->assertSame('https://www.example.com/return', $data['Ds_Merchant_UrlOK']); - $this->assertSame('https://www.example.com/return', $data['Ds_Merchant_UrlKO']); + $this->assertSame('https://www.example.com/cancel', $data['Ds_Merchant_UrlKO']); $this->assertSame('My Store', $data['Ds_Merchant_MerchantName']); $this->assertSame('002', $data['Ds_Merchant_ConsumerLanguage']); $this->assertSame('Ref: 99zz', $data['Ds_Merchant_MerchantData']); @@ -159,6 +161,31 @@ public function testSetConsumerLanguage() $this->assertSame('002', $this->request->getConsumerLanguage()); } + public function testSetDirectPayment() + { + // starts false in base test data + $this->assertFalse($this->request->getDirectPayment()); + // valid, but corrects case + $this->request->setDirectPayment("moto"); + $this->assertSame('MOTO', $this->request->getDirectPayment()); + // valid (effectively unsets) + $this->request->setDirectPayment(null); + $this->assertNull($this->request->getDirectPayment()); + // valid + $this->request->setDirectPayment(true); + $this->assertTrue($this->request->getDirectPayment()); + $this->request->setDirectPayment(false); + $this->assertFalse($this->request->getDirectPayment()); + // valid, but converts to bool + $this->request->setDirectPayment("true"); + $this->assertTrue($this->request->getDirectPayment()); + $this->request->setDirectPayment("false"); + $this->assertFalse($this->request->getDirectPayment()); + // invalid, forces back to null + $this->request->setDirectPayment(100); + $this->assertNull($this->request->getDirectPayment()); + } + public function testGet3DSAccountInfoData() { $data = $this->request->get3DSAccountInfoData(); diff --git a/tests/Message/PurchaseResponseTest.php b/tests/Message/PurchaseResponseTest.php index 2705d5a..0f9a5ca 100644 --- a/tests/Message/PurchaseResponseTest.php +++ b/tests/Message/PurchaseResponseTest.php @@ -30,7 +30,7 @@ class PurchaseResponseTest extends TestCase * 'Ds_Merchant_ConsumerLanguage' => '002', * 'Ds_Merchant_MerchantData' => 'Ref: 99zz', */ - public function setUp() + public function setUp(): void { $this->response = new PurchaseResponse($this->getMockRequest(), array( 'Ds_SignatureVersion' => 'HMAC_SHA256_V1', diff --git a/tests/Message/SecurityTest.php b/tests/Message/SecurityTest.php index 31b9abb..0012126 100644 --- a/tests/Message/SecurityTest.php +++ b/tests/Message/SecurityTest.php @@ -10,13 +10,13 @@ class SecurityTest extends TestCase protected $security; protected $mockSecurity; - public function setUp() + public function setUp(): void { $this->security = new Security; $this->mockSecurity = m::mock('\Omnipay\Redsys\Message\Security'); } - public function tearDown() + public function tearDown(): void { m::close(); } diff --git a/tests/Message/WebservicePurchaseRequestTest.php b/tests/Message/WebservicePurchaseRequestTest.php index 52fbfa0..3317aaa 100644 --- a/tests/Message/WebservicePurchaseRequestTest.php +++ b/tests/Message/WebservicePurchaseRequestTest.php @@ -10,7 +10,7 @@ class WebservicePurchaseRequestTest extends TestCase /** @var WebservicePurchaseRequest */ private $request; - public function setUp() + public function setUp(): void { $this->request = new WebservicePurchaseRequest($this->getHttpClient(), $this->getHttpRequest()); $this->request->initialize( @@ -24,7 +24,7 @@ public function setUp() 'card' => new CreditCard(array( 'number' => '4548812049400004', 'expiryMonth' => '12', - 'expiryYear' => '2020', + 'expiryYear' => '2030', 'cvv' => '285', )), @@ -50,7 +50,7 @@ public function testGetData() $this->assertSame('0123abc', $data['DATOSENTRADA']['DS_MERCHANT_ORDER']); $this->assertSame('4548812049400004', $data['DATOSENTRADA']['DS_MERCHANT_PAN']); - $this->assertSame('2012', $data['DATOSENTRADA']['DS_MERCHANT_EXPIRYDATE']); + $this->assertSame('3012', $data['DATOSENTRADA']['DS_MERCHANT_EXPIRYDATE']); $this->assertSame('285', $data['DATOSENTRADA']['DS_MERCHANT_CVV2']); // $this->assertSame('My sales items', $data['DATOSENTRADA']['DS_MERCHANT_PRODUCTDESCRIPTION']); @@ -61,7 +61,7 @@ public function testGetData() $this->assertSame('HMAC_SHA256_V1', $data['DS_SIGNATUREVERSION']); // signature will change if undocumented fields added - $this->assertSame('1RPtKuPpDldIa88VBPugTqm5BWJxoUWT0503BM/U5l4=', $data['DS_SIGNATURE']); + $this->assertSame('hgg101IGPL2CNEJzpx2xZzSGnw/0UDqVNPUh/d52ouM=', $data['DS_SIGNATURE']); } public function testGetHmacKey() diff --git a/tests/RedirectGatewayTest.php b/tests/RedirectGatewayTest.php index 15ece9f..c932669 100644 --- a/tests/RedirectGatewayTest.php +++ b/tests/RedirectGatewayTest.php @@ -9,7 +9,7 @@ class RedirectGatewayTest extends GatewayTestCase /** @var array */ protected $options; - public function setUp() + public function setUp(): void { parent::setUp(); diff --git a/tests/WebserviceGatewayTest.php b/tests/WebserviceGatewayTest.php index cafd389..0fc7c9c 100644 --- a/tests/WebserviceGatewayTest.php +++ b/tests/WebserviceGatewayTest.php @@ -10,7 +10,7 @@ class WebserviceGatewayTest extends GatewayTestCase /** @var array */ protected $options; - public function setUp() + public function setUp(): void { parent::setUp();