From 61ba7fd1c504eebbd6a439267bfcde9cd25721a0 Mon Sep 17 00:00:00 2001 From: Marcel Strahl Date: Sun, 1 Dec 2019 23:18:03 +0100 Subject: [PATCH 1/3] - remove unnecessary exceptions, - extension of the tests (feature tests were added for the price calculator) - static code analysis added. - code type security improved --- composer.json | 10 +- composer.lock | 862 +++++++++++++++++- phpstan.neon.dist | 6 + src/Exceptions/ConverterException.php | 24 - src/Factory/Converter.php | 6 +- src/Helpers/Converter/ConverterInterface.php | 10 +- .../Converter/Currencies/CentToEuro.php | 18 +- .../Converter/Currencies/EuroToCent.php | 20 +- src/PriceCalculator.php | 24 +- src/PriceCalculatorInterface.php | 32 + src/Service/DiscountCalculator.php | 2 +- tests/Factory/ConverterFactoryTest.php | 6 +- tests/Feature/AddPriceTest.php | 136 +++ tests/Feature/DivPriceTest.php | 152 +++ tests/Feature/MulPriceTest.php | 123 +++ tests/Feature/SubPriceTest.php | 154 ++++ .../Converter/Currencies/CentToEuroTest.php | 15 +- .../Converter/Currencies/EuroToCentTest.php | 16 +- tests/Helpers/View/PriceFormatterTest.php | 10 - 19 files changed, 1506 insertions(+), 120 deletions(-) create mode 100644 phpstan.neon.dist delete mode 100644 src/Exceptions/ConverterException.php create mode 100644 tests/Feature/AddPriceTest.php create mode 100644 tests/Feature/DivPriceTest.php create mode 100644 tests/Feature/MulPriceTest.php create mode 100644 tests/Feature/SubPriceTest.php diff --git a/composer.json b/composer.json index 2c347c8..47d6f4d 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,8 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", + "phpstan/phpstan": "^0.11.19", + "phpstan/phpstan-phpunit": "^0.11.2", "phpunit/phpunit": "8.0.6" }, "autoload": { @@ -35,6 +37,12 @@ "scripts": { "cs-check": "php-cs-fixer -v --dry-run --using-cache=no fix", "cs-fix": "php-cs-fixer --using-cache=no fix", - "test": "phpunit --configuration ~/PriceCalculator/phpunit.xml" + "test": "phpunit --configuration ~/PriceCalculator/phpunit.xml", + "analyze": "vendor/bin/phpstan analyse -c phpstan.neon.dist src tests", + "check": [ + "@cs-check", + "@analyze", + "@test" + ] } } diff --git a/composer.lock b/composer.lock index 0206603..3b3fc51 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "47f02acded1f76e62ef7d6e0991a2608", + "content-hash": "6ae199bec5d6a882fc92c4ce40ff34a9", "packages": [], "packages-dev": [ { @@ -379,6 +379,57 @@ "description": "A tool to automatically fix PHP code style", "time": "2019-02-17T17:44:13+00:00" }, + { + "name": "jean85/pretty-package-versions", + "version": "1.2", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/75c7effcf3f77501d0e0caa75111aff4daa0dd48", + "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48", + "shasum": "" + }, + "require": { + "ocramius/package-versions": "^1.2.0", + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A wrapper for ocramius/package-versions to get pretty versions strings", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "time": "2018-06-13T13:22:40+00:00" + }, { "name": "myclabs/deep-copy", "version": "1.9.1", @@ -427,6 +478,636 @@ ], "time": "2019-04-07T13:18:21+00:00" }, + { + "name": "nette/bootstrap", + "version": "v3.0.1", + "source": { + "type": "git", + "url": "https://github.com/nette/bootstrap.git", + "reference": "b45a1e33b6a44beb307756522396551e5a9ff249" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/bootstrap/zipball/b45a1e33b6a44beb307756522396551e5a9ff249", + "reference": "b45a1e33b6a44beb307756522396551e5a9ff249", + "shasum": "" + }, + "require": { + "nette/di": "^3.0", + "nette/utils": "^3.0", + "php": ">=7.1" + }, + "conflict": { + "tracy/tracy": "<2.6" + }, + "require-dev": { + "latte/latte": "^2.2", + "nette/application": "^3.0", + "nette/caching": "^3.0", + "nette/database": "^3.0", + "nette/forms": "^3.0", + "nette/http": "^3.0", + "nette/mail": "^3.0", + "nette/robot-loader": "^3.0", + "nette/safe-stream": "^2.2", + "nette/security": "^3.0", + "nette/tester": "^2.0", + "tracy/tracy": "^2.6" + }, + "suggest": { + "nette/robot-loader": "to use Configurator::createRobotLoader()", + "tracy/tracy": "to use Configurator::enableTracy()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🅱 Nette Bootstrap: the simple way to configure and bootstrap your Nette application.", + "homepage": "https://nette.org", + "keywords": [ + "bootstrapping", + "configurator", + "nette" + ], + "time": "2019-09-30T08:19:38+00:00" + }, + { + "name": "nette/di", + "version": "v3.0.1", + "source": { + "type": "git", + "url": "https://github.com/nette/di.git", + "reference": "4aff517a1c6bb5c36fa09733d4cea089f529de6d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/di/zipball/4aff517a1c6bb5c36fa09733d4cea089f529de6d", + "reference": "4aff517a1c6bb5c36fa09733d4cea089f529de6d", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "nette/neon": "^3.0", + "nette/php-generator": "^3.2.2", + "nette/robot-loader": "^3.2", + "nette/schema": "^1.0", + "nette/utils": "^3.0", + "php": ">=7.1" + }, + "conflict": { + "nette/bootstrap": "<3.0" + }, + "require-dev": { + "nette/tester": "^2.2", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ], + "files": [ + "src/compatibility.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "💎 Nette Dependency Injection Container: Flexible, compiled and full-featured DIC with perfectly usable autowiring and support for all new PHP 7.1 features.", + "homepage": "https://nette.org", + "keywords": [ + "compiled", + "di", + "dic", + "factory", + "ioc", + "nette", + "static" + ], + "time": "2019-08-07T12:11:33+00:00" + }, + { + "name": "nette/finder", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/nette/finder.git", + "reference": "14164e1ddd69e9c5f627ff82a10874b3f5bba5fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/finder/zipball/14164e1ddd69e9c5f627ff82a10874b3f5bba5fe", + "reference": "14164e1ddd69e9c5f627ff82a10874b3f5bba5fe", + "shasum": "" + }, + "require": { + "nette/utils": "^2.4 || ~3.0.0", + "php": ">=7.1" + }, + "conflict": { + "nette/nette": "<2.2" + }, + "require-dev": { + "nette/tester": "^2.0", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🔍 Nette Finder: find files and directories with an intuitive API.", + "homepage": "https://nette.org", + "keywords": [ + "filesystem", + "glob", + "iterator", + "nette" + ], + "time": "2019-07-11T18:02:17+00:00" + }, + { + "name": "nette/neon", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/nette/neon.git", + "reference": "cbff32059cbdd8720deccf9e9eace6ee516f02eb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/neon/zipball/cbff32059cbdd8720deccf9e9eace6ee516f02eb", + "reference": "cbff32059cbdd8720deccf9e9eace6ee516f02eb", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "ext-json": "*", + "php": ">=7.0" + }, + "require-dev": { + "nette/tester": "^2.0", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "? Nette NEON: encodes and decodes NEON file format.", + "homepage": "http://ne-on.org", + "keywords": [ + "export", + "import", + "neon", + "nette", + "yaml" + ], + "time": "2019-02-05T21:30:40+00:00" + }, + { + "name": "nette/php-generator", + "version": "v3.3.1", + "source": { + "type": "git", + "url": "https://github.com/nette/php-generator.git", + "reference": "4240fd7adf499138c07b814ef9b9a6df9f6d7187" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/php-generator/zipball/4240fd7adf499138c07b814ef9b9a6df9f6d7187", + "reference": "4240fd7adf499138c07b814ef9b9a6df9f6d7187", + "shasum": "" + }, + "require": { + "nette/utils": "^2.4.2 || ~3.0.0", + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "^2.0", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 7.3 features.", + "homepage": "https://nette.org", + "keywords": [ + "code", + "nette", + "php", + "scaffolding" + ], + "time": "2019-11-22T11:12:11+00:00" + }, + { + "name": "nette/robot-loader", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/nette/robot-loader.git", + "reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/robot-loader/zipball/0712a0e39ae7956d6a94c0ab6ad41aa842544b5c", + "reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "nette/finder": "^2.5", + "nette/utils": "^3.0", + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "^2.0", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "? Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.", + "homepage": "https://nette.org", + "keywords": [ + "autoload", + "class", + "interface", + "nette", + "trait" + ], + "time": "2019-03-08T21:57:24+00:00" + }, + { + "name": "nette/schema", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "337117df1dade22e2ba1fdc4a4b832c1e9b06b76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/337117df1dade22e2ba1fdc4a4b832c1e9b06b76", + "reference": "337117df1dade22e2ba1fdc4a4b832c1e9b06b76", + "shasum": "" + }, + "require": { + "nette/utils": "^3.0.1", + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "^2.2", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "time": "2019-10-31T20:52:19+00:00" + }, + { + "name": "nette/utils", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "c133e18c922dcf3ad07673077d92d92cef25a148" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/c133e18c922dcf3ad07673077d92d92cef25a148", + "reference": "c133e18c922dcf3ad07673077d92d92cef25a148", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "~2.0", + "tracy/tracy": "^2.3" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize() and toAscii()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", + "ext-xml": "to use Strings::length() etc. when mbstring is not available" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "time": "2019-10-21T20:40:16+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.3.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/9a9981c347c5c49d6dfe5cf826bb882b824080dc", + "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "0.0.5", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2019-11-08T13:50:10+00:00" + }, + { + "name": "ocramius/package-versions", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/Ocramius/PackageVersions.git", + "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/1d32342b8c1eb27353c8887c366147b4c2da673c", + "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0.0", + "php": "^7.3.0" + }, + "require-dev": { + "composer/composer": "^1.8.6", + "doctrine/coding-standard": "^6.0.0", + "ext-zip": "*", + "infection/infection": "^0.13.4", + "phpunit/phpunit": "^8.2.5", + "vimeo/psalm": "^3.4.9" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "time": "2019-07-17T15:49:50+00:00" + }, { "name": "paragonie/random_compat", "version": "v9.99.99", @@ -840,6 +1521,185 @@ ], "time": "2018-08-05T17:53:17+00:00" }, + { + "name": "phpstan/phpdoc-parser", + "version": "0.3.5", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "8c4ef2aefd9788238897b678a985e1d5c8df6db4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/8c4ef2aefd9788238897b678a985e1d5c8df6db4", + "reference": "8c4ef2aefd9788238897b678a985e1d5c8df6db4", + "shasum": "" + }, + "require": { + "php": "~7.1" + }, + "require-dev": { + "consistence/coding-standard": "^3.5", + "jakub-onderka/php-parallel-lint": "^0.9.2", + "phing/phing": "^2.16.0", + "phpstan/phpstan": "^0.10", + "phpunit/phpunit": "^6.3", + "slevomat/coding-standard": "^4.7.2", + "squizlabs/php_codesniffer": "^3.3.2", + "symfony/process": "^3.4 || ^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.3-dev" + } + }, + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "time": "2019-06-07T19:13:52+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "0.11.19", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "63cc502f6957b7f74efbac444b4cf219dcadffd7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/63cc502f6957b7f74efbac444b4cf219dcadffd7", + "reference": "63cc502f6957b7f74efbac444b4cf219dcadffd7", + "shasum": "" + }, + "require": { + "composer/xdebug-handler": "^1.3.0", + "jean85/pretty-package-versions": "^1.0.3", + "nette/bootstrap": "^2.4 || ^3.0", + "nette/di": "^2.4.7 || ^3.0", + "nette/neon": "^2.4.3 || ^3.0", + "nette/robot-loader": "^3.0.1", + "nette/schema": "^1.0", + "nette/utils": "^2.4.5 || ^3.0", + "nikic/php-parser": "^4.2.3", + "php": "~7.1", + "phpstan/phpdoc-parser": "^0.3.5", + "symfony/console": "~3.2 || ~4.0", + "symfony/finder": "~3.2 || ~4.0" + }, + "conflict": { + "symfony/console": "3.4.16 || 4.1.5" + }, + "require-dev": { + "brianium/paratest": "^2.0 || ^3.0", + "consistence/coding-standard": "^3.5", + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", + "ext-intl": "*", + "ext-mysqli": "*", + "ext-simplexml": "*", + "ext-soap": "*", + "ext-zip": "*", + "jakub-onderka/php-parallel-lint": "^1.0", + "localheinz/composer-normalize": "^1.1.0", + "phing/phing": "^2.16.0", + "phpstan/phpstan-deprecation-rules": "^0.11", + "phpstan/phpstan-php-parser": "^0.11", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-strict-rules": "^0.11", + "phpunit/phpunit": "^7.5.14 || ^8.0", + "slevomat/coding-standard": "^4.7.2", + "squizlabs/php_codesniffer": "^3.3.2" + }, + "bin": [ + "bin/phpstan" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.11-dev" + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "time": "2019-10-22T20:20:22+00:00" + }, + { + "name": "phpstan/phpstan-phpunit", + "version": "0.11.2", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-phpunit.git", + "reference": "fbf2ad56c3b13189d29655e226c9b1da47c2fad9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/fbf2ad56c3b13189d29655e226c9b1da47c2fad9", + "reference": "fbf2ad56c3b13189d29655e226c9b1da47c2fad9", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.0", + "php": "~7.1", + "phpstan/phpdoc-parser": "^0.3", + "phpstan/phpstan": "^0.11.4" + }, + "conflict": { + "phpunit/phpunit": "<7.0" + }, + "require-dev": { + "consistence/coding-standard": "^3.0.1", + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", + "jakub-onderka/php-parallel-lint": "^1.0", + "phing/phing": "^2.16.0", + "phpstan/phpstan-strict-rules": "^0.11", + "phpunit/phpunit": "^7.0", + "satooshi/php-coveralls": "^1.0", + "slevomat/coding-standard": "^4.5.2" + }, + "type": "phpstan-extension", + "extra": { + "branch-alias": { + "dev-master": "0.11-dev" + }, + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPUnit extensions and rules for PHPStan", + "time": "2019-05-17T17:50:16+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "7.0.3", diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..6cd8b55 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,6 @@ +parameters: + paths: + - src + - tests + level: max + inferPrivatePropertyTypeFromConstructor: true \ No newline at end of file diff --git a/src/Exceptions/ConverterException.php b/src/Exceptions/ConverterException.php deleted file mode 100644 index 0f39e50..0000000 --- a/src/Exceptions/ConverterException.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @package MarcelStrahl\PriceCalculator\Exceptions - */ -class ConverterException extends Exception -{ - /** - * @param float $amout - * @return ConverterException - */ - public static function fromZeroAmount(float $amout): self - { - return new self( - sprintf('Division by zero is not allowed. Please check your injection. Given amount: %f', $amout) - ); - } -} diff --git a/src/Factory/Converter.php b/src/Factory/Converter.php index 4d8d56f..6c11d37 100644 --- a/src/Factory/Converter.php +++ b/src/Factory/Converter.php @@ -3,14 +3,12 @@ namespace MarcelStrahl\PriceCalculator\Factory; use MarcelStrahl\PriceCalculator\Exceptions\PriceCalculatorFactoryException; -use MarcelStrahl\PriceCalculator\Helpers\Converter\CentToEuro; +use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\CentToEuro; use MarcelStrahl\PriceCalculator\Helpers\Converter\ConverterInterface; -use MarcelStrahl\PriceCalculator\Helpers\Converter\EuroToCent; +use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\EuroToCent; /** - * Class ConverterFactory * @author Marcel Strahl - * @package MarcelStrahl\PriceCalculator\Factory */ class Converter implements ConverterFactoryInterface { diff --git a/src/Helpers/Converter/ConverterInterface.php b/src/Helpers/Converter/ConverterInterface.php index 16f87f3..4fa66f5 100644 --- a/src/Helpers/Converter/ConverterInterface.php +++ b/src/Helpers/Converter/ConverterInterface.php @@ -2,26 +2,20 @@ namespace MarcelStrahl\PriceCalculator\Helpers\Converter; -use MarcelStrahl\PriceCalculator\Exceptions\ConverterException; - /** - * Interface ConverterInterface * @author Marcel Strahl - * @package MarcelStrahl\PriceCalculator\Helpers\Converter */ interface ConverterInterface { /** * @param float $amount * @return float - * @throws ConverterException */ public function convert(float $amount): float; /** * @param float $amount - * @return void - * @throws ConverterException + * @return bool */ - public function isZeroAmount(float $amount): void; + public function isEmpty(float $amount): bool; } diff --git a/src/Helpers/Converter/Currencies/CentToEuro.php b/src/Helpers/Converter/Currencies/CentToEuro.php index 4ceeaef..c2ce628 100644 --- a/src/Helpers/Converter/Currencies/CentToEuro.php +++ b/src/Helpers/Converter/Currencies/CentToEuro.php @@ -1,13 +1,11 @@ - * @package MarcelStrahl\PriceCalculator\Helpers\Converter */ class CentToEuro implements ConverterInterface { @@ -16,18 +14,18 @@ class CentToEuro implements ConverterInterface */ public function convert(float $amount): float { - $this->isZeroAmount($amount); + if ($this->isEmpty($amount)) { + return 0; + } - return (float) bcdiv($amount, 100, 2); + return (float) bcdiv((string)$amount, '100', 2); } /** * {@inheritdoc} */ - public function isZeroAmount(float $amount): void + public function isEmpty(float $amount): bool { - if (empty($amount)) { - throw ConverterException::fromZeroAmount($amount); - } + return empty($amount) || $amount < 0; } } diff --git a/src/Helpers/Converter/Currencies/EuroToCent.php b/src/Helpers/Converter/Currencies/EuroToCent.php index b87c9f0..ca9b9b3 100644 --- a/src/Helpers/Converter/Currencies/EuroToCent.php +++ b/src/Helpers/Converter/Currencies/EuroToCent.php @@ -1,13 +1,11 @@ - * @package MarcelStrahl\PriceCalculator\Helpers\Converter */ class EuroToCent implements ConverterInterface { @@ -16,18 +14,18 @@ class EuroToCent implements ConverterInterface */ public function convert(float $amount): float { - $this->isZeroAmount($amount); + if ($this->isEmpty($amount)) { + return 0; + } - return (float) bcmul($amount, 100); + return (float) bcmul((string)$amount, '100'); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function isZeroAmount(float $amount): void + public function isEmpty(float $amount): bool { - if (empty($amount)) { - throw ConverterException::fromZeroAmount($amount); - } + return empty($amount) || $amount < 0; } } diff --git a/src/PriceCalculator.php b/src/PriceCalculator.php index 2274e2a..72f9eca 100644 --- a/src/PriceCalculator.php +++ b/src/PriceCalculator.php @@ -1,7 +1,5 @@ * @package MarcelStrahl\PriceCalculator */ interface PriceCalculatorInterface { + /** + * @param Price $total + * @param Price $price + * @return Price + */ + public function addPrice(Price $total, Price $price): Price; + + /** + * Sub an price from total + * + * @param Price $total + * @param Price $price + * @return Price + */ + public function subPrice(Price $total, Price $price): Price; + + /** + * Mul an price with amount + * + * @param Price $amount + * @param Price $price + * @return Price + */ + public function mulPrice(Price $amount, Price $price): Price; + /** + * @param int $amount + * @param Price $price + * @return Price + */ + public function divPrice(int $amount, Price $price): Price; } diff --git a/src/Service/DiscountCalculator.php b/src/Service/DiscountCalculator.php index d9ab61d..41ed480 100644 --- a/src/Service/DiscountCalculator.php +++ b/src/Service/DiscountCalculator.php @@ -42,7 +42,7 @@ public function calculateDiscountPriceFromTotal(Price $total, Discount $discount $totalPrice = $total->getPrice() / 100; $calculated = new Price(); - $calculated->setPrice($totalPrice * $discount->getDiscount()); + $calculated->setPrice((int)$totalPrice * $discount->getDiscount()); return $calculated; } diff --git a/tests/Factory/ConverterFactoryTest.php b/tests/Factory/ConverterFactoryTest.php index 610ad8f..bd0652b 100644 --- a/tests/Factory/ConverterFactoryTest.php +++ b/tests/Factory/ConverterFactoryTest.php @@ -5,15 +5,13 @@ use MarcelStrahl\PriceCalculator\Exceptions\PriceCalculatorFactoryException; use MarcelStrahl\PriceCalculator\Factory\Converter; use MarcelStrahl\PriceCalculator\Factory\ConverterFactoryInterface; -use MarcelStrahl\PriceCalculator\Helpers\Converter\CentToEuro; +use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\CentToEuro; use MarcelStrahl\PriceCalculator\Helpers\Converter\ConverterInterface; -use MarcelStrahl\PriceCalculator\Helpers\Converter\EuroToCent; +use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\EuroToCent; use PHPUnit\Framework\TestCase; /** - * Class ConverterFactoryTest * @author Marcel Strahl - * @package MarcelStrahl\PriceCalculator\Tests\Factory */ class ConverterFactoryTest extends TestCase { diff --git a/tests/Feature/AddPriceTest.php b/tests/Feature/AddPriceTest.php new file mode 100644 index 0000000..f4a052e --- /dev/null +++ b/tests/Feature/AddPriceTest.php @@ -0,0 +1,136 @@ + + */ +class AddPriceTest extends TestCase +{ + /** + * @var PriceCalculatorInterface + */ + private $priceCalculator; + + /** + * @var Formatter + */ + private $formatter; + + public function setUp(): void + { + parent::setUp(); + + $this->priceCalculator = PriceCalculator::getPriceCalculator(); + $this->formatter = new PriceFormatter(2, ',', '.', '€'); + } + + /** + * @test + * @dataProvider dataProviderCanAddCentPrices + */ + public function canAddCentPrices(Price $total, Price $addPrice, int $expectedPrice, string $expectedFormattedPrice) + { + $priceCalculator = PriceCalculator::getPriceCalculator(); + + $this->assertInstanceOf(PriceCalculatorInterface::class, $priceCalculator); + + $calculatedPrice = $priceCalculator->addPrice($total, $addPrice); + + $this->assertEquals($expectedPrice, $calculatedPrice->getPrice()); + + $converter = new CentToEuro(); + + $convertedPrice = $converter->convert($calculatedPrice->getPrice()); + + $formattedPrice = $this->formatter->formatPrice($convertedPrice); + + $this->assertEquals($expectedFormattedPrice, $formattedPrice); + } + + public function dataProviderCanAddCentPrices(): array + { + $samePrice = new Price(); + $samePrice->setPrice(300); + + $firstDifferentPrice = new Price(); + $firstDifferentPrice->setPrice(149); + + $secondDifferentPrice = new Price(); + $secondDifferentPrice->setPrice(1034); + + return [ + 'same_first_and_second_price' => [ + $samePrice, + $samePrice, + 600, + '6,00 €', + ], + 'first_and_second_price_are_different' => [ + $firstDifferentPrice, + $secondDifferentPrice, + 1183, + '11,83 €', + ], + ]; + } + + /** + * @test + * @dataProvider dataProviderCanAddEuroPrice + */ + public function canAddEuroPrice( + float $total, + float $addPrice, + int $expectedCalculatedPrice, + string $expectedFormattedPrice + ): void { + $euroToCentConverter = new EuroToCent(); + $totalPriceInCent = $euroToCentConverter->convert($total); + $addPriceInCent = $euroToCentConverter->convert($addPrice); + + $totalPrice = new Price(); + $totalPrice->setPrice((int)$totalPriceInCent); + + $addPrice = new Price(); + $addPrice->setPrice((int)$addPriceInCent); + + $calculatedPrice = $this->priceCalculator->addPrice($totalPrice, $addPrice); + + $this->assertEquals($expectedCalculatedPrice, $calculatedPrice->getPrice()); + + $centToEuroConverter = new CentToEuro(); + $convertedPrice = $centToEuroConverter->convert($calculatedPrice->getPrice()); + + $formattedPrice = $this->formatter->formatPrice($convertedPrice); + + $this->assertEquals($expectedFormattedPrice, $formattedPrice); + } + + public function dataProviderCanAddEuroPrice(): array + { + return [ + 'same_price' => [ + 3.00, + 3.00, + 600, + '6,00 €', + ], + 'first_and_second_price_are_different' => [ + 1.49, + 10.34, + 1183, + '11,83 €', + ], + ]; + } +} \ No newline at end of file diff --git a/tests/Feature/DivPriceTest.php b/tests/Feature/DivPriceTest.php new file mode 100644 index 0000000..7d6e9a0 --- /dev/null +++ b/tests/Feature/DivPriceTest.php @@ -0,0 +1,152 @@ + + */ +class DivPriceTest extends TestCase +{ + /** + * @var PriceCalculatorInterface + */ + private $priceCalculator; + + /** + * @var Formatter + */ + private $formatter; + + public function setUp(): void + { + parent::setUp(); + $this->priceCalculator = PriceCalculator::getPriceCalculator(); + $this->formatter = new PriceFormatter(2, ',', '.', '€'); + } + + /** + * @test + * @dataProvider dataProviderCanDivCentPrice + */ + public function canDivCentPrice( + int $amount, + Price $total, + int $expectedPrice, + string $expectedFormattedPrice + ): void { + $calculatedPrice = $this->priceCalculator->divPrice($amount, $total); + + $this->assertEquals($expectedPrice, $calculatedPrice->getPrice()); + + $converter = new CentToEuro(); + $convertedPrice = $converter->convert($calculatedPrice->getPrice()); + + $formattedPrice = $this->formatter->formatPrice($convertedPrice); + + $this->assertEquals($expectedFormattedPrice, $formattedPrice); + } + + public function dataProviderCanDivCentPrice(): array + { + $easyDivCalculation = new Price(); + $easyDivCalculation->setPrice(9); + + $differentTotalPrice = new Price(); + $differentTotalPrice->setPrice(5); + + $totalPriceIsLowerThanZero = new Price(); + $totalPriceIsLowerThanZero->setPrice(0); + + return [ + 'easy_div_calculation' => [ + 9, + $easyDivCalculation, + 1, + '0,01 €', + ], + 'different_prices' => [ + 15, + $differentTotalPrice, + 0, + '0,00 €', + ], + 'result_is_lower_than_zero' => [ + 9, + $totalPriceIsLowerThanZero, + 0, + '0,00 €', + ], + ]; + } + + /** + * @test + * @dataProvider dataProviderCanDivEuroPrice + */ + public function canDivEuroPrice( + int $amount, + float $total, + int $expectedPrice, + string $expectedFormattedPrice): void + { + $euroToCent = new EuroToCent(); + + $totalInCent = $euroToCent->convert($total); + + $totalPrice = new Price(); + $totalPrice->setPrice((int)$totalInCent); + + $calculatedPrice = $this->priceCalculator->divPrice($amount, $totalPrice); + + $this->assertEquals($expectedPrice, $calculatedPrice->getPrice()); + + $centToEuro = new CentToEuro(); + $convertedPrice = $centToEuro->convert($calculatedPrice->getPrice()); + + $formattedPrice = $this->formatter->formatPrice($convertedPrice); + + $this->assertEquals($expectedFormattedPrice, $formattedPrice); + } + + public function dataProviderCanDivEuroPrice(): array + { + $easyDivCalculation = new Price(); + $easyDivCalculation->setPrice(9); + + $differentTotalPrice = new Price(); + $differentTotalPrice->setPrice(5); + + $totalPriceIsLowerThanZero = new Price(); + $totalPriceIsLowerThanZero->setPrice(0); + + return [ + 'easy_div_calculation' => [ + 9, + 0.09, + 1, + '0,01 €', + ], + 'different_prices' => [ + 15, + 0.05, + 0, + '0,00 €', + ], + 'result_is_lower_than_zero' => [ + 9, + 0.00, + 0, + '0,00 €', + ], + ]; + } +} diff --git a/tests/Feature/MulPriceTest.php b/tests/Feature/MulPriceTest.php new file mode 100644 index 0000000..bdc1cd1 --- /dev/null +++ b/tests/Feature/MulPriceTest.php @@ -0,0 +1,123 @@ + + */ +class MulPriceTest extends TestCase +{ + /** + * @var PriceCalculatorInterface + */ + private $priceCalculator; + + /** + * @var Formatter + */ + private $formatter; + + public function setUp(): void + { + parent::setUp(); + $this->priceCalculator = PriceCalculator::getPriceCalculator(); + $this->formatter = new PriceFormatter(2, ',', '.', '€'); + } + + /** + * @test + * @dataProvider dataProviderCanMulCentPrice + */ + public function canMulCentPrice( + Price $amount, + Price $total, + int $expectedPrice, + string $expectedFormattedPrice + ): void + { + $calculatedPrice = $this->priceCalculator->mulPrice($amount, $total); + + $this->assertEquals($expectedPrice, $calculatedPrice->getPrice()); + + $converter = new CentToEuro(); + $convertedPrice = $converter->convert($calculatedPrice->getPrice()); + + $formattedPrice = $this->formatter->formatPrice($convertedPrice); + + $this->assertEquals($expectedFormattedPrice, $formattedPrice); + } + + public function dataProviderCanMulCentPrice(): array + { + $easyMulCalculation = new Price(); + $easyMulCalculation->setPrice(9); + + $easyMulCalculationAmount = new Price(); + $easyMulCalculationAmount->setPrice(9); + + $differentTotalPrice = new Price(); + $differentTotalPrice->setPrice(5); + + $differentAmount = new Price(); + $differentAmount->setPrice(15); + + $totalPriceIsLowerThanZero = new Price(); + $totalPriceIsLowerThanZero->setPrice(0); + + $amountOfIsLowerThanZero = new Price(); + $amountOfIsLowerThanZero->setPrice(9); + + $highTotalPrice = new Price(); + $highTotalPrice->setPrice(5000); + + $highAmount = new Price(); + $highAmount->setPrice(50000); + + $highFloatPriceAmount = new Price(); + $highFloatPriceAmount->setPrice(500); + + $highFloatPriceTotal = new Price(); + $highFloatPriceTotal->setPrice(59596); + + return [ + 'easy_div_calculation' => [ + $easyMulCalculationAmount, + $easyMulCalculation, + 81, + '0,81 €', + ], + 'different_prices' => [ + $differentAmount, + $differentTotalPrice, + 75, + '0,75 €', + ], + 'result_is_lower_than_zero' => [ + $amountOfIsLowerThanZero, + $totalPriceIsLowerThanZero, + 0, + '0,00 €', + ], + 'use_high_numbers' => [ + $highAmount, + $highTotalPrice, + 250000000, + '2.500.000,00 €', + ], + 'use_high_float_price' => [ + $highFloatPriceAmount, + $highFloatPriceTotal, + 29798000, + '297.980,00 €', + ], + ]; + } +} diff --git a/tests/Feature/SubPriceTest.php b/tests/Feature/SubPriceTest.php new file mode 100644 index 0000000..a1b0257 --- /dev/null +++ b/tests/Feature/SubPriceTest.php @@ -0,0 +1,154 @@ + + */ +class SubPriceTest extends TestCase +{ + /** + * @var PriceCalculatorInterface + */ + private $priceCalculator; + + /** + * @var Formatter + */ + private $formatter; + + public function setUp(): void + { + parent::setUp(); + $this->priceCalculator = PriceCalculator::getPriceCalculator(); + $this->formatter = new PriceFormatter(2, ',', '.', '€'); + } + + /** + * @test + * @dataProvider dataProviderCanSubCentPrice + */ + public function canSubCentPrice( + Price $total, + Price $subPrice, + int $expectedPrice, + string $expectedFormattedPrice + ): void { + $calculatedPrice = $this->priceCalculator->subPrice($total, $subPrice); + + $this->assertEquals($expectedPrice, $calculatedPrice->getPrice()); + + $converter = new CentToEuro(); + $convertedPrice = $converter->convert($calculatedPrice->getPrice()); + + $formattedPrice = $this->formatter->formatPrice($convertedPrice); + + $this->assertEquals($expectedFormattedPrice, $formattedPrice); + } + + public function dataProviderCanSubCentPrice(): array + { + $samePrice = new Price(); + $samePrice->setPrice(12); + + $differentTotalPrice = new Price(); + $differentTotalPrice->setPrice(1500); + + $differentSubPrice = new Price(); + $differentSubPrice->setPrice(1000); + + $totalPriceIsLowerThanZero = new Price(); + $totalPriceIsLowerThanZero->setPrice(100); + + $secondPriceIsLowerThanZero = new Price(); + $secondPriceIsLowerThanZero->setPrice(200); + + + return [ + 'same_price' => [ + $samePrice, + $samePrice, + 0, + '0,00 €', + ], + 'different_prices' => [ + $differentTotalPrice, + $differentSubPrice, + 500, + '5,00 €', + ], + 'result_is_lower_than_zero' => [ + $totalPriceIsLowerThanZero, + $secondPriceIsLowerThanZero, + 0, + '0,00 €', + ], + ]; + } + + /** + * @test + * @dataProvider dataProviderCanSubEuroPrice + */ + public function canSubEuroPrice( + float $total, + float $subPrice, + int $expectedPrice, + string $expectedFormattedPrice + ): void { + $euroToCent = new EuroToCent(); + + $totalInCent = $euroToCent->convert($total); + $subPriceInCent = $euroToCent->convert($subPrice); + + $totalPrice = new Price(); + $totalPrice->setPrice((int)$totalInCent); + + $sub = new Price(); + $sub->setPrice((int)$subPriceInCent); + + $calculatedPrice = $this->priceCalculator->subPrice($totalPrice, $sub); + + $this->assertEquals($expectedPrice, $calculatedPrice->getPrice()); + + $centToEuro = new CentToEuro(); + $convertedPrice = $centToEuro->convert($calculatedPrice->getPrice()); + + $formattedPrice = $this->formatter->formatPrice($convertedPrice); + + $this->assertEquals($expectedFormattedPrice, $formattedPrice); + } + + public function dataProviderCanSubEuroPrice(): array + { + return [ + 'same_price' => [ + 15.51, + 15.51, + 0, + '0,00 €', + ], + 'different_prices' => [ + 20.85, + 19.99, + 86, + '0,86 €', + ], + 'result_is_lower_than_zero' => [ + 1.00, + 2.85, + 0, + '0,00 €', + ], + ]; + } +} diff --git a/tests/Helpers/Converter/Currencies/CentToEuroTest.php b/tests/Helpers/Converter/Currencies/CentToEuroTest.php index b5d58f2..aa77e45 100644 --- a/tests/Helpers/Converter/Currencies/CentToEuroTest.php +++ b/tests/Helpers/Converter/Currencies/CentToEuroTest.php @@ -2,15 +2,12 @@ namespace MarcelStrahl\PriceCalculator\Tests\Helpers\Converter\Currencies; -use MarcelStrahl\PriceCalculator\Exceptions\ConverterException; -use MarcelStrahl\PriceCalculator\Helpers\Converter\CentToEuro; +use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\CentToEuro; use MarcelStrahl\PriceCalculator\Helpers\Converter\ConverterInterface; use PHPUnit\Framework\TestCase; /** - * Class CentToEuroTest * @author Marcel Strahl - * @package MarcelStrahl\PriceCalculator\Tests\Helpers\Converter */ class CentToEuroTest extends TestCase { @@ -26,19 +23,11 @@ public function testImplements(): void /** * @dataProvider dataProviderConvert - * @param null|float $amount - * @param null|float $expected - * @return void - * @throws ConverterException */ public function testConvert(float $amount, float $expected): void { $converter = new CentToEuro(); - if ($amount === .00) { - $this->expectException(ConverterException::class); - } - $this->assertSame($expected, $converter->convert($amount)); } @@ -51,7 +40,7 @@ public function dataProviderConvert(): array [100.00, 1.00], [250.00, 2.50], [178, 1.78], - [.00, .00], + [.00, 0], ]; } } diff --git a/tests/Helpers/Converter/Currencies/EuroToCentTest.php b/tests/Helpers/Converter/Currencies/EuroToCentTest.php index 8a853f2..02f0ed0 100644 --- a/tests/Helpers/Converter/Currencies/EuroToCentTest.php +++ b/tests/Helpers/Converter/Currencies/EuroToCentTest.php @@ -2,15 +2,12 @@ namespace MarcelStrahl\PriceCalculator\Tests\Helpers\Converter\Currencies; -use MarcelStrahl\PriceCalculator\Exceptions\ConverterException; use MarcelStrahl\PriceCalculator\Helpers\Converter\ConverterInterface; -use MarcelStrahl\PriceCalculator\Helpers\Converter\EuroToCent; +use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\EuroToCent; use PHPUnit\Framework\TestCase; /** - * Class EuroToCentTest * @author Marcel Strahl - * @package MarcelStrahl\PriceCalculator\Tests\Helpers\Converter */ class EuroToCentTest extends TestCase { @@ -26,18 +23,11 @@ public function testImplements(): void /** * @dataProvider dataProviderConvert - * @param null|float $amount - * @param null|float $expected - * @return void - * @throws ConverterException */ - public function testConvert(?float $amount, ?float $expected): void + public function testConvert(float $amount, ?float $expected): void { $converter = new EuroToCent(); - if ($amount === .00) { - $this->expectException(ConverterException::class); - } $this->assertSame($expected, $converter->convert($amount)); } @@ -50,7 +40,7 @@ public function dataProviderConvert(): array [1.00, 100.00], [1.15, 115.00], [116.80, 11680.00], - [.00, .00], + [.00, 0], ]; } } diff --git a/tests/Helpers/View/PriceFormatterTest.php b/tests/Helpers/View/PriceFormatterTest.php index 6a36bb5..eec6abb 100644 --- a/tests/Helpers/View/PriceFormatterTest.php +++ b/tests/Helpers/View/PriceFormatterTest.php @@ -8,9 +8,7 @@ use TypeError; /** - * Class PriceFormatterTest * @author Marcel Strahl - * @package Tests\Helpers\View */ class PriceFormatterTest extends TestCase { @@ -134,12 +132,4 @@ public function dataProviderFormatPriceForView(): array ], ]; } - - public function testThrowExceptionByNonNumeric(): void - { - $this->expectException(TypeError::class); - - $priceFormatter = $this->getPriceFormatter(2, ',', '.', '€'); - $priceFormatter->formatPrice('Hello World'); - } } From b2eec210a0460e90225d57bfcd13fb423a59d6d2 Mon Sep 17 00:00:00 2001 From: Marcel Strahl Date: Tue, 3 Dec 2019 22:52:03 +0100 Subject: [PATCH 2/3] - fix code style - add DiscountCalculator Feature-Test --- src/Facade/VatCalculator.php | 4 +- src/Factory/Converter.php | 2 +- .../Converter/Currencies/CentToEuro.php | 2 +- .../Converter/Currencies/EuroToCent.php | 4 +- src/PriceCalculator.php | 8 +- src/Service/DiscountCalculator.php | 2 +- tests/Facade/VatCalculatorTest.php | 6 +- tests/Factory/ConverterFactoryTest.php | 2 +- tests/Feature/AddPriceTest.php | 6 +- tests/Feature/DiscountCalculationTest.php | 95 +++++++++++++++++++ tests/Feature/DivPriceTest.php | 5 +- tests/Feature/SubPriceTest.php | 5 +- .../Converter/Currencies/CentToEuroTest.php | 2 +- tests/Helpers/View/PriceFormatterTest.php | 1 - 14 files changed, 118 insertions(+), 26 deletions(-) create mode 100644 tests/Feature/DiscountCalculationTest.php diff --git a/src/Facade/VatCalculator.php b/src/Facade/VatCalculator.php index 52c1d06..d72c5c3 100644 --- a/src/Facade/VatCalculator.php +++ b/src/Facade/VatCalculator.php @@ -1,7 +1,5 @@ vat->setVat($vat); - return (new self())->createVatCalculator(); + return $instance->createVatCalculator(); } private function createVatCalculator() diff --git a/src/Factory/Converter.php b/src/Factory/Converter.php index 6c11d37..39751a1 100644 --- a/src/Factory/Converter.php +++ b/src/Factory/Converter.php @@ -3,8 +3,8 @@ namespace MarcelStrahl\PriceCalculator\Factory; use MarcelStrahl\PriceCalculator\Exceptions\PriceCalculatorFactoryException; -use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\CentToEuro; use MarcelStrahl\PriceCalculator\Helpers\Converter\ConverterInterface; +use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\CentToEuro; use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\EuroToCent; /** diff --git a/src/Helpers/Converter/Currencies/CentToEuro.php b/src/Helpers/Converter/Currencies/CentToEuro.php index c2ce628..43920eb 100644 --- a/src/Helpers/Converter/Currencies/CentToEuro.php +++ b/src/Helpers/Converter/Currencies/CentToEuro.php @@ -18,7 +18,7 @@ public function convert(float $amount): float return 0; } - return (float) bcdiv((string)$amount, '100', 2); + return (float) bcdiv((string) $amount, '100', 2); } /** diff --git a/src/Helpers/Converter/Currencies/EuroToCent.php b/src/Helpers/Converter/Currencies/EuroToCent.php index ca9b9b3..5528952 100644 --- a/src/Helpers/Converter/Currencies/EuroToCent.php +++ b/src/Helpers/Converter/Currencies/EuroToCent.php @@ -18,11 +18,11 @@ public function convert(float $amount): float return 0; } - return (float) bcmul((string)$amount, '100'); + return (float) bcmul((string) $amount, '100'); } /** - * {@inheritDoc} + * {@inheritdoc} */ public function isEmpty(float $amount): bool { diff --git a/src/PriceCalculator.php b/src/PriceCalculator.php index 72f9eca..b3d4778 100644 --- a/src/PriceCalculator.php +++ b/src/PriceCalculator.php @@ -11,7 +11,7 @@ class PriceCalculator implements PriceCalculatorInterface { /** - * {@inheritDoc} + * {@inheritdoc} */ public function addPrice(Price $total, Price $price): Price { @@ -21,7 +21,7 @@ public function addPrice(Price $total, Price $price): Price } /** - * {@inheritDoc} + * {@inheritdoc} */ public function subPrice(Price $total, Price $price): Price { @@ -35,7 +35,7 @@ public function subPrice(Price $total, Price $price): Price } /** - * {@inheritDoc} + * {@inheritdoc} */ public function mulPrice(Price $amount, Price $price): Price { @@ -45,7 +45,7 @@ public function mulPrice(Price $amount, Price $price): Price } /** - * {@inheritDoc} + * {@inheritdoc} */ public function divPrice(int $amount, Price $price): Price { diff --git a/src/Service/DiscountCalculator.php b/src/Service/DiscountCalculator.php index 41ed480..802429c 100644 --- a/src/Service/DiscountCalculator.php +++ b/src/Service/DiscountCalculator.php @@ -42,7 +42,7 @@ public function calculateDiscountPriceFromTotal(Price $total, Discount $discount $totalPrice = $total->getPrice() / 100; $calculated = new Price(); - $calculated->setPrice((int)$totalPrice * $discount->getDiscount()); + $calculated->setPrice((int) $totalPrice * $discount->getDiscount()); return $calculated; } diff --git a/tests/Facade/VatCalculatorTest.php b/tests/Facade/VatCalculatorTest.php index e3f4fdc..a599112 100644 --- a/tests/Facade/VatCalculatorTest.php +++ b/tests/Facade/VatCalculatorTest.php @@ -1,7 +1,5 @@ assertInstanceOf( VatCalculator::class, - VatCalculatorFacade::getVatCalculator(19) + $vatCalculator ); } } diff --git a/tests/Factory/ConverterFactoryTest.php b/tests/Factory/ConverterFactoryTest.php index bd0652b..d5a0f5c 100644 --- a/tests/Factory/ConverterFactoryTest.php +++ b/tests/Factory/ConverterFactoryTest.php @@ -5,8 +5,8 @@ use MarcelStrahl\PriceCalculator\Exceptions\PriceCalculatorFactoryException; use MarcelStrahl\PriceCalculator\Factory\Converter; use MarcelStrahl\PriceCalculator\Factory\ConverterFactoryInterface; -use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\CentToEuro; use MarcelStrahl\PriceCalculator\Helpers\Converter\ConverterInterface; +use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\CentToEuro; use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\EuroToCent; use PHPUnit\Framework\TestCase; diff --git a/tests/Feature/AddPriceTest.php b/tests/Feature/AddPriceTest.php index f4a052e..45ab70d 100644 --- a/tests/Feature/AddPriceTest.php +++ b/tests/Feature/AddPriceTest.php @@ -99,10 +99,10 @@ public function canAddEuroPrice( $addPriceInCent = $euroToCentConverter->convert($addPrice); $totalPrice = new Price(); - $totalPrice->setPrice((int)$totalPriceInCent); + $totalPrice->setPrice((int) $totalPriceInCent); $addPrice = new Price(); - $addPrice->setPrice((int)$addPriceInCent); + $addPrice->setPrice((int) $addPriceInCent); $calculatedPrice = $this->priceCalculator->addPrice($totalPrice, $addPrice); @@ -133,4 +133,4 @@ public function dataProviderCanAddEuroPrice(): array ], ]; } -} \ No newline at end of file +} diff --git a/tests/Feature/DiscountCalculationTest.php b/tests/Feature/DiscountCalculationTest.php new file mode 100644 index 0000000..90d656e --- /dev/null +++ b/tests/Feature/DiscountCalculationTest.php @@ -0,0 +1,95 @@ + + */ +class DiscountCalculationTest extends TestCase +{ + + /** + * @test + * @dataProvider dataProviderCanCalculateDiscountedTotal + */ + public function canCalculateDiscountedTotal(int $priceAmount, int $discountAmount, int $expectedPrice): void + { + $discountCalculator = new DiscountCalculator(); + + $price = new Price(); + $price->setPrice($priceAmount); + + $discount = new Discount($discountAmount); + + $total = $discountCalculator->calculateDiscountFromTotal($price, $discount); + + $this->assertEquals($expectedPrice, $total->getPrice()); + } + + /** + * @test + * @dataProvider dataProviderCanCalculateDiscountPrice + */ + public function canCalculateDiscountPrice(int $priceAmount, int $discountAmount, int $expectedPrice): void + { + $discountCalculator = new DiscountCalculator(); + + $price = new Price(); + $price->setPrice($priceAmount); + + $discount = new Discount($discountAmount); + + $discountPrice = $discountCalculator->calculateDiscountPriceFromTotal($price, $discount); + + $this->assertEquals($expectedPrice, $discountPrice->getPrice()); + } + + public function dataProviderCanCalculateDiscountPrice(): array + { + return [ + [ + 1500, + 15, + 225, + ], + [ + 2700, + 50, + 1350, + ], + [ + 50000, + 99, + 49500, + ], + ]; + } + + public function dataProviderCanCalculateDiscountedTotal(): array + { + return [ + [ + 1500, + 15, + 1275, + ], + [ + 2700, + 50, + 1350, + ], + [ + 50000, + 99, + 500, + ], + ]; + } +} diff --git a/tests/Feature/DivPriceTest.php b/tests/Feature/DivPriceTest.php index 7d6e9a0..4d51430 100644 --- a/tests/Feature/DivPriceTest.php +++ b/tests/Feature/DivPriceTest.php @@ -96,14 +96,15 @@ public function canDivEuroPrice( int $amount, float $total, int $expectedPrice, - string $expectedFormattedPrice): void + string $expectedFormattedPrice + ): void { $euroToCent = new EuroToCent(); $totalInCent = $euroToCent->convert($total); $totalPrice = new Price(); - $totalPrice->setPrice((int)$totalInCent); + $totalPrice->setPrice((int) $totalInCent); $calculatedPrice = $this->priceCalculator->divPrice($amount, $totalPrice); diff --git a/tests/Feature/SubPriceTest.php b/tests/Feature/SubPriceTest.php index a1b0257..3b35714 100644 --- a/tests/Feature/SubPriceTest.php +++ b/tests/Feature/SubPriceTest.php @@ -72,7 +72,6 @@ public function dataProviderCanSubCentPrice(): array $secondPriceIsLowerThanZero = new Price(); $secondPriceIsLowerThanZero->setPrice(200); - return [ 'same_price' => [ $samePrice, @@ -111,10 +110,10 @@ public function canSubEuroPrice( $subPriceInCent = $euroToCent->convert($subPrice); $totalPrice = new Price(); - $totalPrice->setPrice((int)$totalInCent); + $totalPrice->setPrice((int) $totalInCent); $sub = new Price(); - $sub->setPrice((int)$subPriceInCent); + $sub->setPrice((int) $subPriceInCent); $calculatedPrice = $this->priceCalculator->subPrice($totalPrice, $sub); diff --git a/tests/Helpers/Converter/Currencies/CentToEuroTest.php b/tests/Helpers/Converter/Currencies/CentToEuroTest.php index aa77e45..57d65fd 100644 --- a/tests/Helpers/Converter/Currencies/CentToEuroTest.php +++ b/tests/Helpers/Converter/Currencies/CentToEuroTest.php @@ -2,8 +2,8 @@ namespace MarcelStrahl\PriceCalculator\Tests\Helpers\Converter\Currencies; -use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\CentToEuro; use MarcelStrahl\PriceCalculator\Helpers\Converter\ConverterInterface; +use MarcelStrahl\PriceCalculator\Helpers\Converter\Currencies\CentToEuro; use PHPUnit\Framework\TestCase; /** diff --git a/tests/Helpers/View/PriceFormatterTest.php b/tests/Helpers/View/PriceFormatterTest.php index eec6abb..6f2f825 100644 --- a/tests/Helpers/View/PriceFormatterTest.php +++ b/tests/Helpers/View/PriceFormatterTest.php @@ -5,7 +5,6 @@ use MarcelStrahl\PriceCalculator\Helpers\View\Formatter; use MarcelStrahl\PriceCalculator\Helpers\View\PriceFormatter; use PHPUnit\Framework\TestCase; -use TypeError; /** * @author Marcel Strahl From e047ae21400ffe90f8329c568f31931cc43a56bf Mon Sep 17 00:00:00 2001 From: Marcel Strahl Date: Tue, 3 Dec 2019 22:59:04 +0100 Subject: [PATCH 3/3] - add php travis check for php 7.3 and 7.4 --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index bcb5d58..8b9ece5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,8 @@ matrix: include: - php: 7.1 - php: 7.2 + - php: 7.3 + - php: 7.4 allow_failures: - php: hhvm