18 Commits

Author SHA1 Message Date
59d4612a0a Documentation update for development part 2026-01-13 18:42:12 +09:00
aeb84dcb60 Switch to PHPunit 12 and adjust code accordingly 2026-01-13 18:26:16 +09:00
b0d8c55536 Add phive tools folder, Switch to tabs for indent and add phpcs.xml 2026-01-13 11:06:11 +09:00
4adbf4e30a Run CI only on pull requests 2025-03-10 19:53:43 +09:00
09df49009a Fix .gitignore 2025-02-28 12:57:54 +09:00
33a48f47de Update unit tests to allow skip if AWS API flood
on Github a lot of API tests will fail with "T001" flooding, so we just skip them
2025-01-21 11:11:56 +09:00
cf5ece0b5f github flow yml had tabs instead of spaces 2025-01-21 11:07:10 +09:00
db8df612b4 Remove phpunit from github actions 2025-01-21 11:05:58 +09:00
75f4d0b10a Add phpstan to compoer dev install 2025-01-21 11:02:55 +09:00
7fed1c2a85 Readme update 2025-01-21 10:55:11 +09:00
28a9e390cc Code clean up with declare strict and php stan level 9 checks
add "declare(strict_types=1);" to all pages

Add a json handler class to handle that json_decode always returns array<mixed> and throws error otherwise
On failure these will throw the normal JSON encoded error was FAILURE with code "J-" and the number is the json error
If 0 then the return was null or some other problem that did not return an array

amount is float and not string and checks are done that the returned value is a float

various updates for phpdoc array delcarations
- curl header is array<int, string>
- the log array is proper declared as array with string key and a list of mixed arrays
2025-01-21 10:48:41 +09:00
a565d2899b Comment typo fix 2024-08-21 11:22:33 +09:00
58b126ab83 Rename the github action job 2024-05-22 18:42:48 +09:00
e9a6332ad0 Add skip on error for funds test 2024-05-22 18:26:46 +09:00
a79fd519ed Gitbub action cache 2024-05-22 18:02:01 +09:00
04aa9fa019 Github actions add 2024-05-22 17:27:20 +09:00
d86ad8c051 Switch to PSR12 with spaces instead of tabs 2023-01-19 12:51:12 +09:00
6f5cd028b9 Minor fix for return type alignment
make sure string returned is set to string in config getter
2023-01-06 10:36:24 +09:00
25 changed files with 362 additions and 157 deletions

55
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,55 @@
name: CI
run-name: ${{ github.actor}} runs CI
on:
pull_request:
branches:
- main
- master
- staging
- development
jobs:
ci-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: php-actions/composer@v6
env:
COMPOSER_ROOT_VERSION: dev-master
- name: "Restore result cache"
uses: actions/cache/restore@v4
with:
path: ./tmp
key: "result-cache-v1-${{ matrix.php-version }}-${{ github.run_id }}"
restore-keys: |
result-cache-v1-${{ matrix.php-version }}-
- name: PHPStan Static Analysis
uses: php-actions/phpstan@v3
with:
path: src/
- name: "Save result cache"
uses: actions/cache/save@v4
if: always()
with:
path: ./tmp
key: "result-cache-v1-${{ matrix.php-version }}-${{ github.run_id }}"
# We need to use phpunit from the self install to get the class paths
# Skip auto tests here, there are too many problems with flooding of the AWS API from github
- name: PHPunit Tests Prepare
env:
AWS_GIFT_CARD_ENDPOINT: "${{ secrets.AWS_GIFT_CARD_ENDPOINT }}"
AWS_GIFT_CARD_KEY: "${{ secrets.AWS_GIFT_CARD_KEY }}"
AWS_GIFT_CARD_SECRET: "${{ secrets.AWS_GIFT_CARD_SECRET }}"
AWS_GIFT_CARD_PARTNER_ID: "${{ secrets.AWS_GIFT_CARD_PARTNER_ID }}"
AWS_GIFT_CARD_CURRENCY: "${{ secrets.AWS_GIFT_CARD_CURRENCY }}"
run: |
echo "AWS_GIFT_CARD_ENDPOINT=${AWS_GIFT_CARD_ENDPOINT}" > test/.env;
echo "AWS_GIFT_CARD_KEY=${AWS_GIFT_CARD_KEY}" >> test/.env;
echo "AWS_GIFT_CARD_SECRET=${AWS_GIFT_CARD_SECRET}" >> test/.env;
echo "AWS_GIFT_CARD_PARTNER_ID=${AWS_GIFT_CARD_PARTNER_ID}" >> test/.env;
echo "AWS_GIFT_CARD_CURRENCY=${AWS_GIFT_CARD_CURRENCY}" >> test/.env;
echo "AWS_DEBUG=1" >> test/.env;
- name: PHPunit Tests
run: |
vendor/bin/phpunit

4
.gitignore vendored
View File

@@ -1,3 +1,7 @@
vendor vendor
.phpunit.result.cache .phpunit.result.cache
composer.lock composer.lock
**/.env
**/.target
.phpunit.cache/
tools/

View File

@@ -26,6 +26,10 @@
// use Phan\Config; // use Phan\Config;
return [ return [
// turn color on (-C)
"color_issue_messages_if_supported" => true,
// set minimum version
"minimum_target_php_version" => "7.4",
// If true, missing properties will be created when // If true, missing properties will be created when
// they are first seen. If false, we'll report an // they are first seen. If false, we'll report an
// error message. // error message.
@@ -65,7 +69,7 @@ return [
'directory_list' => [ 'directory_list' => [
// Change this to include the folders you wish to analyze // Change this to include the folders you wish to analyze
// (and the folders of their dependencies) // (and the folders of their dependencies)
'.' 'src/'
// 'www', // 'www',
// To speed up analysis, we recommend going back later and // To speed up analysis, we recommend going back later and
// limiting this to only the vendor/ subdirectories your // limiting this to only the vendor/ subdirectories your

8
.phive/phars.xml Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
<phar name="phpcs" version="^4.0.1" installed="4.0.1" location="./tools/phpcs" copy="false"/>
<phar name="phpcbf" version="^4.0.1" installed="4.0.1" location="./tools/phpcbf" copy="false"/>
<phar name="phan" version="^5.5.2" installed="5.5.2" location="./tools/phan" copy="false"/>
<phar name="phpstan" version="^2.1.33" installed="2.1.33" location="./tools/phpstan" copy="false"/>
<phar name="phpunit" version="^12.5.4" installed="12.5.4" location="./tools/phpunit" copy="false"/>
</phive>

View File

@@ -127,6 +127,11 @@ fif code is C001 curl failed to init
if code is C002 a curl error has happened if code is C002 a curl error has happened
### J-number
if a JSON error was encountered during some encoding this error will be found.
The number is the json error code.
### empty error code ### empty error code
any other NON amazon error will have only 'message' set if run through decode any other NON amazon error will have only 'message' set if run through decode
@@ -147,3 +152,40 @@ New entries can be written with
On sucessful run the log data is accessable with `$aws->getLog()` On sucessful run the log data is accessable with `$aws->getLog()`
On exception the log data is in the error message json (see exceptions) On exception the log data is in the error message json (see exceptions)
## Development
Run `composer install` or `phive install` to setup the tools
phpcs config is stored in `phpcs.xml` and should be picked up by the standard tools
* we use tabs instead of spaces for indents, the rest is standard PSR1+PSR12
### Direct tests
These direct run tests exist:
* `tests/aws_read_env_tests.php`: Equal to running `tests/aws_gift_card_tests.php?info=true`, will output env test data
* `test/aws_gift_card_tests.php`: The following parameters exists
* info: set to print out info
* fund: set to run funds get tests
* gift: run all the gift card get/set/remove tests
* mocks: run the error checks
* debug: print out debug information
* debug_mock: print out all the debug logs too
### Phan
`vendor/bin/phan --analyze-twice` or `tools/phan --analyze-twice`
### PHPstan
`vendor/bin/phpstan` or `tools/phpstan`
> [!notice] Level 9 is set as we have various mixed values that cannot be easily changed into a direct value type
### PHPUnit
Unit tests have to be run from base folder with
`vendor/bin/phpunit` or `tools/phpunit`

View File

@@ -25,8 +25,10 @@
"exclude": ["/test/", "/test/*", "/phpstan.neon", "/psalm.xml", "/.phan/", "/.vscode/", "/phpunit.xml"] "exclude": ["/test/", "/test/*", "/phpstan.neon", "/psalm.xml", "/.phan/", "/.vscode/", "/phpunit.xml"]
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^9",
"gullevek/dotenv": "dev-master", "gullevek/dotenv": "dev-master",
"dg/bypass-finals": "dev-master" "dg/bypass-finals": "dev-master",
"phpstan/phpstan": "2.1.x-dev",
"phpstan/phpstan-deprecation-rules": "2.0.x-dev",
"phpunit/phpunit": "^12"
} }
} }

18
phpcs.xml Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<ruleset name="MyStandard">
<description>PSR12 override rules (strict, standard). Switch spaces indent to tab.</description>
<arg name="tab-width" value="4"/>
<rule ref="PSR1"/>
<rule ref="PSR12">
<!-- turn off white space check for tab -->
<exclude name="Generic.WhiteSpace.DisallowTabIndent"/>
</rule>
<!-- no space indent, must be tab, 4 is tab iwdth -->
<rule ref="Generic.WhiteSpace.DisallowSpaceIndent"/>
<rule ref="Generic.WhiteSpace.ScopeIndent">
<properties>
<property name="indent" value="4"/>
<property name="tabIndent" value="true"/>
</properties>
</rule>
</ruleset>

View File

@@ -1,10 +1,10 @@
# PHP Stan Config # PHP Stan Config
parameters: parameters:
tmpDir: /tmp/phpstan-codeblocks-amazon-incentives tmpDir: %currentWorkingDirectory%/tmp/phpstan-codeblocks-amazon-incentives
level: 8 level: 9
paths: paths:
- %currentWorkingDirectory% - %currentWorkingDirectory%/src
excludePaths: excludePaths:
# ignore composer # ignore composer
- vendor - vendor

View File

@@ -1,9 +1,12 @@
<phpunit <?xml version="1.0"?>
colors="true" <phpunit colors="true" cacheDirectory=".phpunit.cache" bootstrap="vendor/autoload.php" >
verbose="true"
>
<!-- Below removes final from classes for mock tests --> <!-- Below removes final from classes for mock tests -->
<extensions> <extensions>
<extension class="test\phpUnit\Hook\BypassFinalHook" file="test/phpUnit/Hook/BypassFinalHook.php" /> <bootstrap class="DG\BypassFinals\PHPUnitExtension"/>
</extensions> </extensions>
<testsuites>
<testsuite name="unit">
<directory>test/phpUnit/</directory>
</testsuite>
</testsuites>
</phpunit> </phpunit>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<psalm <psalm
errorLevel="3" errorLevel="8"
resolveFromConfigFile="true" resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config" xmlns="https://getpsalm.org/schema/config"

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\AWS; namespace gullevek\AmazonIncentives\AWS;
use gullevek\AmazonIncentives\Client\Client; use gullevek\AmazonIncentives\Client\Client;
@@ -9,6 +11,7 @@ use gullevek\AmazonIncentives\Debug\AmazonDebug;
use gullevek\AmazonIncentives\Response\CancelResponse; use gullevek\AmazonIncentives\Response\CancelResponse;
use gullevek\AmazonIncentives\Response\CreateBalanceResponse; use gullevek\AmazonIncentives\Response\CreateBalanceResponse;
use gullevek\AmazonIncentives\Response\CreateResponse; use gullevek\AmazonIncentives\Response\CreateResponse;
use gullevek\AmazonIncentives\Handle\Json;
class AWS class AWS
{ {
@@ -72,12 +75,12 @@ class AWS
$canonical_request = $this->getCanonicalRequest($service_operation, $payload); $canonical_request = $this->getCanonicalRequest($service_operation, $payload);
$date_time_string = $this->getTimestamp(); $date_time_string = $this->getTimestamp();
AmazonDebug::writeLog(['call' => __METHOD__]); AmazonDebug::writeLog(['call' => __METHOD__]);
$result = json_decode($this->makeRequest( $result = Json::jsonDecode($this->makeRequest(
$payload, $payload,
$canonical_request, $canonical_request,
$service_operation, $service_operation,
$date_time_string $date_time_string
), true); ));
return new CreateResponse($result); return new CreateResponse($result);
} }
@@ -97,12 +100,12 @@ class AWS
$canonical_request = $this->getCanonicalRequest($service_operation, $payload); $canonical_request = $this->getCanonicalRequest($service_operation, $payload);
$date_time_string = $this->getTimestamp(); $date_time_string = $this->getTimestamp();
AmazonDebug::writeLog(['call' => __METHOD__]); AmazonDebug::writeLog(['call' => __METHOD__]);
$result = json_decode($this->makeRequest( $result = Json::jsonDecode($this->makeRequest(
$payload, $payload,
$canonical_request, $canonical_request,
$service_operation, $service_operation,
$date_time_string $date_time_string
), true); ));
return new CancelResponse($result); return new CancelResponse($result);
} }
@@ -120,12 +123,12 @@ class AWS
$canonical_request = $this->getCanonicalRequest($service_operation, $payload); $canonical_request = $this->getCanonicalRequest($service_operation, $payload);
$date_time_string = $this->getTimestamp(); $date_time_string = $this->getTimestamp();
AmazonDebug::writeLog(['call' => __METHOD__]); AmazonDebug::writeLog(['call' => __METHOD__]);
$result = json_decode($this->makeRequest( $result = Json::jsonDecode($this->makeRequest(
$payload, $payload,
$canonical_request, $canonical_request,
$service_operation, $service_operation,
$date_time_string $date_time_string
), true); ));
return new CreateBalanceResponse($result); return new CreateBalanceResponse($result);
} }
@@ -212,7 +215,7 @@ class AWS
* @param string $date_time_string Ymd\THis\Z encoded timestamp, getTimestamp() * @param string $date_time_string Ymd\THis\Z encoded timestamp, getTimestamp()
* @param string $service_target Target service in the agcod string: * @param string $service_target Target service in the agcod string:
* Value like com.amazonaws.agcod.<sn>.<so> * Value like com.amazonaws.agcod.<sn>.<so>
* @return array<mixed> Header data as array for curl request * @return array<int,string> Header data as array for curl request
*/ */
public function buildHeaders( public function buildHeaders(
string $payload, string $payload,

View File

@@ -30,12 +30,12 @@ final class AmazonIncentives
* @param bool|null $debug Debug flag * @param bool|null $debug Debug flag
*/ */
public function __construct( public function __construct(
string $key = null, ?string $key = null,
string $secret = null, ?string $secret = null,
string $partner = null, ?string $partner = null,
string $endpoint = null, ?string $endpoint = null,
string $currency = null, ?string $currency = null,
bool $debug = null ?bool $debug = null
) { ) {
// load AWS settings // load AWS settings
// fail here if settings missing // fail here if settings missing
@@ -65,7 +65,7 @@ final class AmazonIncentives
* *
* @throws AmazonErrors * @throws AmazonErrors
*/ */
public function buyGiftCard(float $value, string $creation_request_id = null): Response\CreateResponse public function buyGiftCard(float $value, ?string $creation_request_id = null): Response\CreateResponse
{ {
return ($this->newAWS())->getCode($value, $creation_request_id); return ($this->newAWS())->getCode($value, $creation_request_id);
} }
@@ -109,12 +109,12 @@ final class AmazonIncentives
* @return AmazonIncentives self class * @return AmazonIncentives self class
*/ */
public static function make( public static function make(
string $key = null, ?string $key = null,
string $secret = null, ?string $secret = null,
string $partner = null, ?string $partner = null,
string $endpoint = null, ?string $endpoint = null,
string $currency = null, ?string $currency = null,
bool $debug = null ?bool $debug = null
): AmazonIncentives { ): AmazonIncentives {
return new static($key, $secret, $partner, $endpoint, $currency, $debug); return new static($key, $secret, $partner, $endpoint, $currency, $debug);
} }

View File

@@ -1,9 +1,12 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Client; namespace gullevek\AmazonIncentives\Client;
use gullevek\AmazonIncentives\Exceptions\AmazonErrors; use gullevek\AmazonIncentives\Exceptions\AmazonErrors;
use gullevek\AmazonIncentives\Debug\AmazonDebug; use gullevek\AmazonIncentives\Debug\AmazonDebug;
use gullevek\AmazonIncentives\Handle\Json;
class Client implements ClientInterface class Client implements ClientInterface
{ {
@@ -16,7 +19,7 @@ class Client implements ClientInterface
* *
* @param string $url The URL being requested, * @param string $url The URL being requested,
* including domain and protocol * including domain and protocol
* @param array<mixed> $headers Headers to be used in the request * @param array<int,string> $headers Headers to be used in the request
* @param array<mixed>|string $params Can be nested for arrays and hashes * @param array<mixed>|string $params Can be nested for arrays and hashes
* @return string Result as json string * @return string Result as json string
*/ */
@@ -50,7 +53,12 @@ class Client implements ClientInterface
$err = curl_errno($handle); $err = curl_errno($handle);
AmazonDebug::writeLog(['CURL_REQUEST_RESULT' => $result]); AmazonDebug::writeLog(['CURL_REQUEST_RESULT' => $result]);
// extract all the error codes from Amazon // extract all the error codes from Amazon
$result_ar = json_decode((string)$result, true); // note we do not care about result errors here, if json decode fails, just set to empty
try {
$result_ar = Json::jsonDecode((string)$result);
} catch (AmazonErrors $e) {
$result_ar = [];
}
// if message is 'Rate exceeded', set different error // if message is 'Rate exceeded', set different error
if (($result_ar['message'] ?? '') == 'Rate exceeded') { if (($result_ar['message'] ?? '') == 'Rate exceeded') {
$error_status = 'RESEND'; $error_status = 'RESEND';

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Client; namespace gullevek\AmazonIncentives\Client;
interface ClientInterface interface ClientInterface

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Config; namespace gullevek\AmazonIncentives\Config;
class Config implements ConfigInterface class Config implements ConfigInterface
@@ -85,7 +87,8 @@ class Config implements ConfigInterface
case 'AWS_GIFT_CARD_PARTNER_ID': case 'AWS_GIFT_CARD_PARTNER_ID':
case 'AWS_GIFT_CARD_ENDPOINT': case 'AWS_GIFT_CARD_ENDPOINT':
case 'AWS_GIFT_CARD_CURRENCY': case 'AWS_GIFT_CARD_CURRENCY':
$return = $_ENV[$key] ?? ''; $return = !empty($_ENV[$key]) && is_string($_ENV[$key]) ?
$_ENV[$key] : '';
break; break;
default: default:
break; break;

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Config; namespace gullevek\AmazonIncentives\Config;
interface ConfigInterface interface ConfigInterface

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
// simple write all into an array that we can poll in the return group // simple write all into an array that we can poll in the return group
// to activate AmazonDebug::setDebug(true) must be called once // to activate AmazonDebug::setDebug(true) must be called once
@@ -7,7 +9,7 @@ namespace gullevek\AmazonIncentives\Debug;
class AmazonDebug class AmazonDebug
{ {
/** @var array<mixed> Log data array log id -> array of log entries */ /** @var array<string,array<array<mixed>>> Log data array log id -> array of log entries */
private static $log = []; private static $log = [];
/** @var bool debug flag */ /** @var bool debug flag */
private static $debug = false; private static $debug = false;

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Exceptions; namespace gullevek\AmazonIncentives\Exceptions;
use RuntimeException; use RuntimeException;
@@ -32,7 +34,7 @@ final class AmazonErrors extends RuntimeException
'code' => $error_code, 'code' => $error_code,
'type' => $error_type, 'type' => $error_type,
'message' => $message, 'message' => $message,
// atach log data if exists // attach log data if exists
'log_id' => AmazonDebug::getId(), 'log_id' => AmazonDebug::getId(),
'log' => AmazonDebug::getLog(), 'log' => AmazonDebug::getLog(),
])) ?: 'AmazonErrors: json encode problem: ' . $message, ])) ?: 'AmazonErrors: json encode problem: ' . $message,
@@ -52,7 +54,7 @@ final class AmazonErrors extends RuntimeException
{ {
$message_ar = json_decode($message, true); $message_ar = json_decode($message, true);
// if we have an error, build empty block and only fill message // if we have an error, build empty block and only fill message
if (json_last_error()) { if (json_last_error() || $message_ar === null || !is_array($message_ar)) {
$message_ar = [ $message_ar = [
'status' => '', 'status' => '',
'code' => '', 'code' => '',

42
src/Handle/Json.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
/**
* Handle json conversions
*/
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Handle;
use gullevek\AmazonIncentives\Exceptions\AmazonErrors;
class Json
{
/**
* decode json string
*
* @param string $json
* @return array<mixed>
* @throws AmazonErrors
*/
public static function jsonDecode(string $json): array
{
$result = json_decode($json, true);
if (
($json_last_error = json_last_error()) ||
$result === null ||
!is_array($result)
) {
throw AmazonErrors::getError(
'FAILURE',
'J-' . $json_last_error,
'jsonDecoreError',
'Failed to decode json data',
0
);
}
return $result;
}
}
// __END__

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Response; namespace gullevek\AmazonIncentives\Response;
use gullevek\AmazonIncentives\Debug\AmazonDebug; use gullevek\AmazonIncentives\Debug\AmazonDebug;

View File

@@ -1,13 +1,15 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Response; namespace gullevek\AmazonIncentives\Response;
use gullevek\AmazonIncentives\Debug\AmazonDebug; use gullevek\AmazonIncentives\Debug\AmazonDebug;
class CreateBalanceResponse class CreateBalanceResponse
{ {
/** @var string Amazon Gift Card Balance Amount */ /** @var float Amazon Gift Card Balance Amount */
protected $amount = ''; protected $amount = 0;
/** @var string Amazon Gift Card Balance Currency */ /** @var string Amazon Gift Card Balance Currency */
protected $currency = ''; protected $currency = '';
/** @var string Amazon Gift Card Balance Status */ /** @var string Amazon Gift Card Balance Status */
@@ -41,9 +43,9 @@ class CreateBalanceResponse
/** /**
* Return the current available funds amount * Return the current available funds amount
* *
* @return string Funds amount in set currency * @return float Funds amount in set currency
*/ */
public function getAmount(): string public function getAmount(): float
{ {
return $this->amount; return $this->amount;
} }
@@ -98,10 +100,18 @@ class CreateBalanceResponse
*/ */
public function parseJsonResponse(array $json_response): self public function parseJsonResponse(array $json_response): self
{ {
if (array_key_exists('amount', $json_response['availableFunds'])) { if (
$this->amount = $json_response['availableFunds']['amount']; is_array($json_response['availableFunds']) &&
array_key_exists('amount', $json_response['availableFunds']) &&
is_numeric($json_response['availableFunds']['amount'])
) {
$this->amount = (float)$json_response['availableFunds']['amount'];
} }
if (array_key_exists('currencyCode', $json_response['availableFunds'])) { if (
is_array($json_response['availableFunds']) &&
array_key_exists('currencyCode', $json_response['availableFunds']) &&
is_string($json_response['availableFunds']['currencyCode'])
) {
$this->currency = $json_response['availableFunds']['currencyCode']; $this->currency = $json_response['availableFunds']['currencyCode'];
} }
// SUCCESS, FAILURE, RESEND // SUCCESS, FAILURE, RESEND

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Response; namespace gullevek\AmazonIncentives\Response;
use gullevek\AmazonIncentives\Debug\AmazonDebug; use gullevek\AmazonIncentives\Debug\AmazonDebug;

View File

@@ -6,14 +6,18 @@ namespace test\phpUnit;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestDox;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use gullevek\AmazonIncentives; use gullevek\AmazonIncentives;
use gullevek\dotEnv\DotEnv; use gullevek\dotEnv\DotEnv;
/** /**
* Test class for ACL\Login * Test class for ACL\Login
* @coversDefaultClass \gullevek\AmazonIncentives
* @testdox \gullevek\AmazonIncentives full flow test
*/ */
#[CoversClass(\gullevek\AmazonIncentives\AmazonIncentives::class)]
#[TestDox("\gullevek\AmazonIncentives full flow tests")]
final class AmazonIncentivesTest extends TestCase final class AmazonIncentivesTest extends TestCase
{ {
/** @var int wait tme in seconds between AWS side mock calls */ /** @var int wait tme in seconds between AWS side mock calls */
@@ -22,10 +26,10 @@ final class AmazonIncentivesTest extends TestCase
/** /**
* Client curl exception testing * Client curl exception testing
* *
* @testdox AWS Incentives curl exception handling
*
* @return void * @return void
*/ */
#[Test]
#[TestDox("AWS Incentives curl exception handling")]
public function testAwsIncentivesCurlException(): void public function testAwsIncentivesCurlException(): void
{ {
// this is the exceptio we want // this is the exceptio we want
@@ -41,7 +45,7 @@ final class AmazonIncentivesTest extends TestCase
* *
* @return array * @return array
*/ */
public function amazonIncentivesProviderErrors(): array public static function amazonIncentivesProviderErrors(): array
{ {
// parameter data only for this // parameter data only for this
// 0: url // 0: url
@@ -76,12 +80,12 @@ final class AmazonIncentivesTest extends TestCase
/** /**
* Test errors thrown in Client class * Test errors thrown in Client class
* *
* @dataProvider amazonIncentivesProviderErrors
* @testdox AWS Incentives error handling [$_dataName]
*
* @param string $url * @param string $url
* @return void * @return void
*/ */
#[Test]
#[TestDox('AWS Incentives curl error handling [$_dataName]')]
#[DataProvider('amazonIncentivesProviderErrors')]
public function testAwsIncentivesCurlErrors( public function testAwsIncentivesCurlErrors(
string $url, string $url,
string $expected_status, string $expected_status,
@@ -109,7 +113,7 @@ final class AmazonIncentivesTest extends TestCase
try { try {
// set expected throw error // set expected throw error
$result = $client->request($url, [], ''); $result = $client->request($url, [], '');
print "R: " . $result . "\n"; $this->assertTrue(true, 'Successful client request');
} catch (AmazonIncentives\Exceptions\AmazonErrors $e) { } catch (AmazonIncentives\Exceptions\AmazonErrors $e) {
$curl_error = AmazonIncentives\Exceptions\AmazonErrors::decodeExceptionMessage($e->getMessage()); $curl_error = AmazonIncentives\Exceptions\AmazonErrors::decodeExceptionMessage($e->getMessage());
// print "E-B: " . print_r($curl_error, true) . "\n"; // print "E-B: " . print_r($curl_error, true) . "\n";
@@ -239,7 +243,7 @@ final class AmazonIncentivesTest extends TestCase
* *
* @return array * @return array
*/ */
public function awsIncentivesProvider(): array public static function awsIncentivesProvider(): array
{ {
// 0: .env file folder // 0: .env file folder
// 1: .env file name (if not set use .env) // 1: .env file name (if not set use .env)
@@ -271,12 +275,12 @@ final class AmazonIncentivesTest extends TestCase
* *
* @return array * @return array
*/ */
public function amazonIncentivesProviderGetFunds(): array public static function amazonIncentivesProviderGetFunds(): array
{ {
// remove final keyword // remove final keyword
// BypassFinals::enable(); // BypassFinals::enable();
// get connectors // get connectors
$connectors = $this->awsIncentivesProvider(); $connectors = self::awsIncentivesProvider();
// 0: connect array (env file, env folder, parameters array) // 0: connect array (env file, env folder, parameters array)
// 1: mock or normal call // 1: mock or normal call
// 2: if mock connect response must be defined here // 2: if mock connect response must be defined here
@@ -286,9 +290,6 @@ final class AmazonIncentivesTest extends TestCase
'connect' => $connectors['env_test'], 'connect' => $connectors['env_test'],
'mock' => false, 'mock' => false,
'mock_response' => null, 'mock_response' => null,
'expected' => [
//
]
], ],
'mock data test' => [ 'mock data test' => [
'connect' => $connectors['parameter_dummy'], 'connect' => $connectors['parameter_dummy'],
@@ -308,14 +309,14 @@ final class AmazonIncentivesTest extends TestCase
/** /**
* Undocumented function * Undocumented function
* *
* @dataProvider amazonIncentivesProviderGetFunds
* @testdox AWS Incentives get available funds [$_dataName]
*
* @param array $connect * @param array $connect
* @param bool $mock * @param bool $mock
* @param array|null $mock_response * @param array|null $mock_response
* @return void * @return void
*/ */
#[Test]
#[TestDox('AWS Incentives get available funds [$_dataName]')]
#[DataProvider('amazonIncentivesProviderGetFunds')]
public function testAwsIncentivesGetAvailableFunds( public function testAwsIncentivesGetAvailableFunds(
array $connect, array $connect,
bool $mock, bool $mock,
@@ -333,7 +334,13 @@ final class AmazonIncentivesTest extends TestCase
// - getAmount // - getAmount
// - getCurrency // - getCurrency
// - getTimestamp // - getTimestamp
try {
$funds = $agcod->getAvailableFunds(); $funds = $agcod->getAvailableFunds();
} catch (\Exception $e) {
$this->markTestSkipped(
$e->getMessage()
);
}
// if not mock do type check // if not mock do type check
// if mock do matching check from mcok // if mock do matching check from mcok
if ($mock === false) { if ($mock === false) {
@@ -345,7 +352,7 @@ final class AmazonIncentivesTest extends TestCase
// numeric number // numeric number
$this->assertIsNumeric( $this->assertIsNumeric(
$funds->getAmount(), $funds->getAmount(),
'Assert amoount is numerc' 'Assert amoount is numeric'
); );
// USD, JPY, etc // USD, JPY, etc
$this->assertIsString( $this->assertIsString(
@@ -387,10 +394,10 @@ final class AmazonIncentivesTest extends TestCase
* *
* @return array * @return array
*/ */
public function amazonIncentivesProviderBuy(): array public static function amazonIncentivesProviderBuy(): array
{ {
// get connectors // get connectors
$connectors = $this->awsIncentivesProvider(); $connectors = self::awsIncentivesProvider();
// 0: connect array (env file, env folder, parameters array) // 0: connect array (env file, env folder, parameters array)
// 1: mock or normal call // 1: mock or normal call
// 2: if mock connect response must be defined here // 2: if mock connect response must be defined here
@@ -430,15 +437,15 @@ final class AmazonIncentivesTest extends TestCase
/** /**
* Undocumented function * Undocumented function
* *
* @dataProvider amazonIncentivesProviderBuy
* @testdox AWS Incentives buy gift card [$_dataName]
*
* @param array $connect * @param array $connect
* @param bool $mock * @param bool $mock
* @param array|null $mock_response * @param array|null $mock_response
* @param float $amount * @param float $amount
* @return void * @return void
*/ */
#[Test]
#[TestDox('AWS Incentives buy gift card [$_dataName]')]
#[DataProvider('amazonIncentivesProviderBuy')]
public function testAwsIncentivesBuyGiftCard( public function testAwsIncentivesBuyGiftCard(
array $connect, array $connect,
bool $mock, bool $mock,
@@ -559,10 +566,7 @@ final class AmazonIncentivesTest extends TestCase
/** /**
* Buy a gift card and use same creation request id to get another gift card * Buy a gift card and use same creation request id to get another gift card
* has to return same data ggain * has to return same data again
*
* @dataProvider amazonIncentivesProviderBuy
* @testdox AWS Incentives buy gift card and again with same creation request id [$_dataName]
* *
* @param array $connect * @param array $connect
* @param bool $mock * @param bool $mock
@@ -570,6 +574,9 @@ final class AmazonIncentivesTest extends TestCase
* @param float $amount * @param float $amount
* @return void * @return void
*/ */
#[Test]
#[TestDox('AWS Incentives buy gift card and again with same creation request id [$_dataName]')]
#[DataProvider('amazonIncentivesProviderBuy')]
public function testAwsIncentivesSameBuyGiftCard( public function testAwsIncentivesSameBuyGiftCard(
array $connect, array $connect,
bool $mock, bool $mock,
@@ -635,10 +642,10 @@ final class AmazonIncentivesTest extends TestCase
* *
* @return array * @return array
*/ */
public function amazonIncentivesProviderCancel(): array public static function amazonIncentivesProviderCancel(): array
{ {
// get connectors // get connectors
$connectors = $this->awsIncentivesProvider(); $connectors = self::awsIncentivesProvider();
// 0: connect array (env file, env folder, parameters array) // 0: connect array (env file, env folder, parameters array)
// 1: mock or normal call // 1: mock or normal call
// 2: if mock connect response must be defined here // 2: if mock connect response must be defined here
@@ -664,14 +671,14 @@ final class AmazonIncentivesTest extends TestCase
/** /**
* Cancel a bought gift card * Cancel a bought gift card
* *
* @dataProvider amazonIncentivesProviderCancel
* @testdox AWS Incentives cancel gift card [$_dataName]
*
* @param array $connect * @param array $connect
* @param bool $mock * @param bool $mock
* @param array|null $mock_response * @param array|null $mock_response
* @return void * @return void
*/ */
#[Test]
#[TestDox('AWS Incentives cancel gift card [$_dataName]')]
#[DataProvider('amazonIncentivesProviderCancel')]
public function testAwsIncentivesCancelGiftCard( public function testAwsIncentivesCancelGiftCard(
array $connect, array $connect,
bool $mock, bool $mock,
@@ -736,10 +743,10 @@ final class AmazonIncentivesTest extends TestCase
* *
* @return array * @return array
*/ */
public function amazonIncentivesProviderRefunded(): array public static function amazonIncentivesProviderRefunded(): array
{ {
// get connectors // get connectors
$connectors = $this->awsIncentivesProvider(); $connectors = self::awsIncentivesProvider();
// 0: connect array (env file, env folder, parameters array) // 0: connect array (env file, env folder, parameters array)
// 1: mock or normal call // 1: mock or normal call
// 2: if mock connect response must be defined here // 2: if mock connect response must be defined here
@@ -775,14 +782,14 @@ final class AmazonIncentivesTest extends TestCase
/** /**
* Undocumented function * Undocumented function
* *
* @dataProvider amazonIncentivesProviderRefunded
* @testdox AWS Incentives request cancled gift card [$_dataName]
*
* @param array $connect * @param array $connect
* @param bool $mock * @param bool $mock
* @param array|null $mock_response * @param array|null $mock_response
* @return void * @return void
*/ */
#[Test]
#[TestDox('AWS Incentives request canceled gift card [$_dataName]')]
#[DataProvider('amazonIncentivesProviderRefunded')]
public function testAwsIncentivesRequestRefundedGiftCard( public function testAwsIncentivesRequestRefundedGiftCard(
array $connect, array $connect,
bool $mock, bool $mock,
@@ -826,83 +833,83 @@ final class AmazonIncentivesTest extends TestCase
* *
* @return array * @return array
*/ */
public function awsIncentivesMockProvider(): array public static function awsIncentivesMockProvider(): array
{ {
return [ return [
'successMock' => [ 'successMock' => [
'creation_request_id' => 'F0000', 'creation_request_id' => 'F0000',
'return_code' => '', 'expected_code' => '',
'status' => 'SUCCESS' 'expected_status' => 'SUCCESS'
], ],
'SimpleAmountIsNull' => [ 'SimpleAmountIsNull' => [
'creation_request_id' => 'F1000', 'creation_request_id' => 'F1000',
'return_code' => 'F100', 'expected_code' => 'F100',
'status' => 'FAILURE' 'expected_status' => 'FAILURE'
], ],
'InvalidAmountInput' => [ 'InvalidAmountInput' => [
'creation_request_id' => 'F2003', 'creation_request_id' => 'F2003',
'return_code' => 'F200', 'expected_code' => 'F200',
'status' => 'FAILURE' 'expected_status' => 'FAILURE'
], ],
'InvalidAmountValue' => [ 'InvalidAmountValue' => [
'creation_request_id' => 'F2004', 'creation_request_id' => 'F2004',
'return_code' => 'F200', 'expected_code' => 'F200',
'status' => 'FAILURE' 'expected_status' => 'FAILURE'
], ],
'InvalidCurrencyCodeInput' => [ 'InvalidCurrencyCodeInput' => [
'creation_request_id' => 'F2005', 'creation_request_id' => 'F2005',
'return_code' => 'F200', 'expected_code' => 'F200',
'status' => 'FAILURE' 'expected_status' => 'FAILURE'
], ],
'CardActivatedWithDifferentRequestId' => [ 'CardActivatedWithDifferentRequestId' => [
'creation_request_id' => 'F2010', 'creation_request_id' => 'F2010',
'return_code' => 'F200', 'expected_code' => 'F200',
'status' => 'FAILURE' 'expected_status' => 'FAILURE'
], ],
'MaxAmountExceeded' => [ 'MaxAmountExceeded' => [
'creation_request_id' => 'F2015', 'creation_request_id' => 'F2015',
'return_code' => 'F200', 'expected_code' => 'F200',
'status' => 'FAILURE' 'expected_status' => 'FAILURE'
], ],
'CurrencyCodeMismatch' => [ 'CurrencyCodeMismatch' => [
'creation_request_id' => 'F2016', 'creation_request_id' => 'F2016',
'return_code' => 'F200', 'expected_code' => 'F200',
'status' => 'FAILURE' 'expected_status' => 'FAILURE'
], ],
'FractionalAmountNotAllowed' => [ 'FractionalAmountNotAllowed' => [
'creation_request_id' => 'F2017', 'creation_request_id' => 'F2017',
'return_code' => 'F200', 'expected_code' => 'F200',
'status' => 'FAILURE' 'expected_status' => 'FAILURE'
], ],
'CancelRequestArrivedAfterTimeLimit' => [ 'CancelRequestArrivedAfterTimeLimit' => [
'creation_request_id' => 'F2047', 'creation_request_id' => 'F2047',
'return_code' => 'F200', 'expected_code' => 'F200',
'status' => 'FAILURE' 'expected_status' => 'FAILURE'
], ],
'InsufficientFunds' => [ 'InsufficientFunds' => [
'creation_request_id' => 'F3003', 'creation_request_id' => 'F3003',
'return_code' => 'F300', 'expected_code' => 'F300',
'status' => 'FAILURE' 'expected_status' => 'FAILURE'
], ],
'AccountHasProblems' => [ 'AccountHasProblems' => [
'creation_request_id' => 'F3005', 'creation_request_id' => 'F3005',
'return_code' => 'F300', 'expected_code' => 'F300',
'status' => 'FAILURE' 'expected_status' => 'FAILURE'
], ],
'CustomerSurpassedDailyVelocityLimit' => [ 'CustomerSurpassedDailyVelocityLimit' => [
'creation_request_id' => 'F3010', 'creation_request_id' => 'F3010',
'return_code' => 'F300', 'expected_code' => 'F300',
'status' => 'FAILURE' 'expected_status' => 'FAILURE'
], ],
'SystemTemporarilyUnavailable' => [ 'SystemTemporarilyUnavailable' => [
'creation_request_id' => 'F4000', 'creation_request_id' => 'F4000',
'return_code' => 'F400', 'expected_code' => 'F400',
'status' => 'RESEND' 'expected_status' => 'RESEND'
], ],
'UnknownError' => [ 'UnknownError' => [
'creation_request_id' => 'F5000', 'creation_request_id' => 'F5000',
'return_code' => 'F500', 'expected_code' => 'F500',
'status' => 'FAILURE' 'expected_status' => 'FAILURE'
], ],
]; ];
} }
@@ -912,11 +919,11 @@ final class AmazonIncentivesTest extends TestCase
* This only works with a valid server connection. * This only works with a valid server connection.
* Runs through AWS Incentives mock values and checks the return code and status * Runs through AWS Incentives mock values and checks the return code and status
* *
* @dataProvider awsIncentivesMockProvider
* @testdox AWS Incentives Mock $creation_request_id will be $expected_status with $expected_code [$_dataName]
*
* @return void * @return void
*/ */
#[Test]
#[Testdox('AWS Incentives Mock $creation_request_id will be $expected_status with $expected_code [$_dataName]')]
#[DataProvider('awsIncentivesMockProvider')]
public function testAwsIncentivesWithMocks( public function testAwsIncentivesWithMocks(
string $creation_request_id, string $creation_request_id,
string $expected_code, string $expected_code,
@@ -948,6 +955,11 @@ final class AmazonIncentivesTest extends TestCase
); );
} catch (\Exception $e) { } catch (\Exception $e) {
$error = AmazonIncentives\Exceptions\AmazonErrors::decodeExceptionMessage($e->getMessage()); $error = AmazonIncentives\Exceptions\AmazonErrors::decodeExceptionMessage($e->getMessage());
if ($error['code'] == "T001") {
$this->markTestSkipped(
"Skipped because of flooding"
);
}
$this->assertEquals( $this->assertEquals(
[ [
'code' => $expected_code, 'code' => $expected_code,
@@ -969,14 +981,14 @@ final class AmazonIncentivesTest extends TestCase
* *
* @return array * @return array
*/ */
public function checkMeProvider(): array public static function checkMeProvider(): array
{ {
// 0: .env file folder // 0: .env file folder
// 1: .env file name (if not set use .env) // 1: .env file name (if not set use .env)
// 2: parameters that override _ENV variables // 2: parameters that override _ENV variables
return [ return [
'default all empty' => [ 'default all empty' => [
'use_env' => null, 'env_folder' => null,
'env_file' => null, 'env_file' => null,
'parameters' => null, 'parameters' => null,
], ],
@@ -991,7 +1003,6 @@ final class AmazonIncentivesTest extends TestCase
'currency' => 'currency', 'currency' => 'currency',
'debug' => true, 'debug' => true,
], ],
'expected' => [],
], ],
'load from env' => [ 'load from env' => [
'env_folder' => __DIR__ . DIRECTORY_SEPARATOR . '..', 'env_folder' => __DIR__ . DIRECTORY_SEPARATOR . '..',
@@ -1020,15 +1031,14 @@ final class AmazonIncentivesTest extends TestCase
* - parseing for endoint as url * - parseing for endoint as url
* - override check for _ENV vs parameter * - override check for _ENV vs parameter
* *
* @cover ::checkMe
* @dataProvider checkMeProvider
* @testdox AmazonIncentives tests [$_dataName]
*
* @param string|null $env_folder * @param string|null $env_folder
* @param string|null $env_file * @param string|null $env_file
* @param array|null $parameters * @param array|null $parameters
* @return void * @return void
*/ */
#[Test]
#[TestDox('AmazonIncentives tests [$_dataName]')]
#[DataProvider('checkMeProvider')]
public function testCheckMe(?string $env_folder, ?string $env_file, ?array $parameters): void public function testCheckMe(?string $env_folder, ?string $env_file, ?array $parameters): void
{ {
// reset _ENV before each run to avoid nothing to load errors // reset _ENV before each run to avoid nothing to load errors

View File

@@ -1,21 +0,0 @@
<?php
// strip the final name from a to be mocked class
declare(strict_types=1);
namespace test\phpUnit\Hook;
use DG\BypassFinals;
use PHPUnit\Runner\BeforeFirstTestHook;
// only works if it is the FIRST load and not before EACH test
final class BypassFinalHook implements BeforeFirstTestHook
{
public function executeBeforeFirstTest(): void
{
BypassFinals::enable();
}
}
// __END__

2
tmp/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*
!.gitignore