diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6147152 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/vendor +/composer.lock +/.phpunit.* \ No newline at end of file diff --git a/composer.json b/composer.json index cbbc3dc..5c3308e 100644 --- a/composer.json +++ b/composer.json @@ -27,10 +27,16 @@ }, "minimum-stability": "dev", "prefer-stable": true, - "version": "1.0.0", + "version": "1.0.1", "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } + }, + "require-dev": { + "phpunit/phpunit": "^9" + }, + "scripts": { + "test": "vendor/bin/phpunit --testdox -c phpunit.xml" } } diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..4e0fe07 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,25 @@ + + + + + + + ./src/tests + + + + + + + + + + + \ No newline at end of file diff --git a/src/lib/Payment.php b/src/lib/Payment.php index 0f429e4..555fbc5 100644 --- a/src/lib/Payment.php +++ b/src/lib/Payment.php @@ -20,6 +20,7 @@ public function __construct($merchantId, $verifyKey, $secretKey, $environment) public function getPaymentUrl($orderid, $amount, $bill_name, $bill_email, $bill_mobile, $bill_desc = 'RMS PHP Library', $channel = null, $currency = null, $returnUrl = null, $callbackurl = null, $cancelurl = null) { + $amount = number_format($amount, 2, '.', ''); $data = [ 'orderid' => $orderid, 'amount' => $amount, diff --git a/src/support/helpers.php b/src/support/helpers.php new file mode 100644 index 0000000..b7162ca --- /dev/null +++ b/src/support/helpers.php @@ -0,0 +1,25 @@ +assertTrue( + class_exists(RmsPayment::class) + ); + } + + /** + * @depends testCanDiscoverThisPackage + */ + public function testCanInstantateBaseClass(): void + { + $rms = new RmsPayment(null, null, null, null); + + $this->assertNotNull($rms); + $this->assertEquals(get_class($rms), RmsPayment::class); + } +} \ No newline at end of file diff --git a/src/tests/PaymentTest.php b/src/tests/PaymentTest.php new file mode 100644 index 0000000..91a3333 --- /dev/null +++ b/src/tests/PaymentTest.php @@ -0,0 +1,148 @@ +assertEquals( + RmsPayment::class, + get_class($rms) + ); + + // TODO: add handling for invalid instantiations + // and then test the errors here + // $this->expectException(InvalidArgumentException::class); + + return $rms; + } + + /** + * @depends testCanHandleInstantiationErrors + */ + public function testCanCreatePaymentLink(RmsPayment $rms): string + { + $url = $rms->getPaymentUrl( + self::$orderid, + self::$amount, + self::$bill_name, + self::$bill_email, + self::$bill_mobile + ); + + writelog("Url - $url"); + // check payment type + $this->assertIsString($url); + + // check url must start with https:// + $this->assertStringStartsWith("https://", $url); + + // check domain must be pointing to correct endpoint + if (env("RMS_ENVIRONMENT") == "sandbox") { + $this->assertStringStartsWith("https://sandbox.merchant.razer.com", $url); + } else { + $this->assertStringStartsWith("https://pay.merchant.razer.com", $url); + } + + return $url; + } + + /** + * @depends testCanCreatePaymentLink + */ + public function testUrlContainsRequiredParameters(string $url): string + { + // check url must contain required parameters + $this->assertStringContainsString("orderid=".self::$orderid, $url); + $this->assertStringContainsString("amount=".self::$amount, $url); + $this->assertStringContainsString("bill_name=".urlencode(self::$bill_name), $url); + $this->assertStringContainsString("bill_email=".urlencode(self::$bill_email), $url); + $this->assertStringContainsString("bill_mobile=".urlencode(self::$bill_mobile), $url); + $this->assertStringContainsString("bill_desc=".urlencode("RMS PHP Library"), $url); + + return $url; + } + + /** + * @depends testUrlContainsRequiredParameters + */ + public function testVcodeIsProperlyCalculated(string $url): void + { + $amount = number_format(self::$amount*1, 2, '.', ''); + writelog("Amount: $amount"); + $calculatedVcode = md5($amount . env('RMS_MERCHANT_ID') . self::$orderid . env('RMS_VERIFY_KEY')); + writelog("Calculated Vcode - $calculatedVcode"); + // check url contains valid vcode + $this->assertStringContainsString("&vcode=$calculatedVcode", $url); + } + + /** + * @depends testCanHandleInstantiationErrors + */ + public function testCanVerifyValidSkey($rms) : void + { + $request = (object)[ + "tranID" => 1000, + "amount" => "1.10", + "orderid" => "TEST-ORDER", + "status" => "00", + "currency" => "MYR", + "paydate" => date("Ymd H:i:s"), + "domain" => env("RMS_MERCHANT_ID"), + "appcode" => "123456", + ]; + + $key = md5($request->tranID.$request->orderid.$request->status.$request->domain.$request->amount.$request->currency); + $request->skey = md5($request->paydate.$request->domain.$key.$request->appcode.env('RMS_SECRET_KEY')); + + $this->assertTrue( + $rms->verifySignature($request->paydate, $request->domain, $key, $request->appcode, $request->skey) + ); + } + + /** + * @depends testCanHandleInstantiationErrors + */ + public function testCanVerifyInvalidSkey($rms) : void + { + $request = (object)[ + "tranID" => 1000, + "amount" => "1.10", + "orderid" => "TEST-ORDER", + "status" => "00", + "currency" => "MYR", + "paydate" => date("Ymd H:i:s"), + "domain" => env("RMS_MERCHANT_ID"), + "appcode" => "123456", + ]; + + $key = md5($request->tranID.$request->orderid.$request->status.$request->domain.$request->amount.$request->currency); + $request->skey = "just-a-tampered-skey"; + + $this->assertNotTrue( + $rms->verifySignature($request->paydate, $request->domain, $key, $request->appcode, $request->skey) + ); + } +}