From 268ee0cbfa4fba5ddc46a7b23101a044501ad6bc Mon Sep 17 00:00:00 2001 From: Niklas Ekman Date: Fri, 23 Feb 2018 19:48:58 +0700 Subject: [PATCH 1/5] Add new testcase. --- tests/LuhnAlgorithmTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/LuhnAlgorithmTest.php b/tests/LuhnAlgorithmTest.php index b32dd50..0144561 100644 --- a/tests/LuhnAlgorithmTest.php +++ b/tests/LuhnAlgorithmTest.php @@ -52,6 +52,7 @@ public function provideIsValid_success() { ["410321-9202", true], ["410321 - 9202", true], [4103219202, true], + [31997233700020, true], ]; } @@ -79,6 +80,7 @@ public function provideCalcCheckDigit_success() { return [ [12345, 5], [410321920, 2], + [3199723370002, 0], ]; } } From 33d3d0aa7c411eb5adab26559ba787c83276c799 Mon Sep 17 00:00:00 2001 From: Niklas Ekman Date: Mon, 26 Feb 2018 18:40:39 +0100 Subject: [PATCH 2/5] New implementation. --- .gitignore | 1 + README.md | 19 ++----- src/Contract/LuhnAlgorithmInterface.php | 12 ++-- src/LuhnAlgorithm.php | 76 +++++++++++++------------ src/LuhnAlgorithmFactory.php | 1 - tests/LuhnAlgorithmTest.php | 14 ++--- 6 files changed, 60 insertions(+), 63 deletions(-) diff --git a/.gitignore b/.gitignore index f2a1ce6..7044502 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ index.php nbproject/ +.idea/ # Created by http://www.gitignore.io diff --git a/README.md b/README.md index 974d75a..e4badb9 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,13 @@ [![Build Status](https://travis-ci.org/Ekman/Luhn-Algorithm.svg?branch=master)](https://travis-ci.org/Ekman/Luhn-Algorithm) This is an implementation of the Luhn Algorithm in PHP. The Luhn Algorithm is -used to validate things like credit cards and national identifcation numbers. -More information on the algorithm can be found at [Wikipedia](http://en.wikipedia.org/wiki/Luhn_algorithm) +used to validate things like credit cards and national identification numbers. +More information on the algorithm can be found at [Wikipedia](http://en.wikipedia.org/wiki/Luhn_algorithm). ## Installation -Can be installed using composer: +Install with [Composer](https://getcomposer.org/): + ```bash composer require nekman/luhn-algorithm ``` @@ -26,15 +27,7 @@ if ($luhn->isValid(123456789)) { // Number is valid. } -$checkSum = $luhn->calcCheckSum(123456789); +$checkSum = $luhn->calcChecksum(123456789); $checkDigit = $luhn->calcCheckDigit(123456789); -``` - -## Changelog - -* 4.0.0 - Rewrite of the implementation. -* 3.0.0 - Completely restructured the interface of the library. -* 2.0.1 - Fixed typos in interface. -* 2.0.0 - Added namespace. -* 1.0.0 - Initial release. +``` \ No newline at end of file diff --git a/src/Contract/LuhnAlgorithmInterface.php b/src/Contract/LuhnAlgorithmInterface.php index 83388d4..bf20512 100644 --- a/src/Contract/LuhnAlgorithmInterface.php +++ b/src/Contract/LuhnAlgorithmInterface.php @@ -34,33 +34,33 @@ interface LuhnAlgorithmInterface { /** * Determine if a number is valid according to the Luhn Algorithm. * - * @param string $input The number to validate. + * @param string $number The number to validate. * * @return bool true if number is valid, false otherwise. * * @throws \InvalidArgumentException If the input is invalid. */ - public function isValid(string $input): bool; + public function isValid(string $number): bool; /** * Calculate the check digit for an input. * - * @param int $input The input to calculate the check digit for. + * @param int $numberWithoutCheckDigit The number, without check digit, to calculate the check digit for. * * @return int The check digit. * * @throws \InvalidArgumentException If the input is invalid. */ - public function calcCheckDigit(int $input): int; + public function calcCheckDigit(int $numberWithoutCheckDigit): int; /** * Calulates the checksum for number. * - * @param int $input The number to calculate the checksum for. + * @param int $numberWithoutCheckDigit The number, without check digit, to calculate the checksum for. * * @return int The checksum. * * @throws \InvalidArgumentException If the input is invalid. */ - public function calcChecksum(int $input): int; + public function calcChecksum(int $numberWithoutCheckDigit): int; } diff --git a/src/LuhnAlgorithm.php b/src/LuhnAlgorithm.php index 10e7766..f8dcd4a 100644 --- a/src/LuhnAlgorithm.php +++ b/src/LuhnAlgorithm.php @@ -28,66 +28,70 @@ use Nekman\LuhnAlgorithm\Contract\LuhnAlgorithmInterface; /** - * Handles the Luhn Algorithm. - * - * @link http://en.wikipedia.org/wiki/Luhn_algorithm + * {@inheritdoc} */ class LuhnAlgorithm implements LuhnAlgorithmInterface { /** * {@inheritDoc} */ - public function isValid(string $input): bool { + public function isValid(string $number): bool { // Remove everything except digits from the input. - $number = (int) preg_replace("/[^\d]/", "", $input); - - $checksum = $this->calcChecksum($number); + $number = preg_replace("/[^\d]/", "", $number); + $nDigits = strlen($number); + $checkDigit = $number[$nDigits - 1]; + + // Remove the last digit of number. + $number = (int) $number; + $numberWithoutCheckDigit = (int) ($number / 10); + + $checksum = $this->calcChecksum($numberWithoutCheckDigit); + $sum = $checksum + $checkDigit; // If the checksum is divisible by 10 it is valid - return ($checksum % 10) === 0; + return ($sum % 10) === 0; } /** * {@inheritDoc} */ - public function calcCheckDigit(int $input): int { - $checkSum = (string) $this->calcChecksum($input . 0); + public function calcCheckDigit(int $numberWithoutCheckDigit): int { + $checksum = (string) $this->calcChecksum($numberWithoutCheckDigit); + $nDigits = strlen($checksum); - // Get the last digit of the checksum - $checkDigit = (int) $checkSum[strlen($checkSum) - 1]; + // Get the last digit of the checksum. + $checkDigit = (int) $checksum[$nDigits - 1]; - // If the checkdigit is not 0, then subtract the value from 10 - return $checkDigit === 0 ? $checkDigit : 10 - $checkDigit; + // If the check digit is not 0, then subtract the value from 10. + return $checkDigit === 0 + ? $checkDigit + : 10 - $checkDigit; } /** * {@inheritDoc} */ - public function calcChecksum(int $input): int { - $input = (string) $input; - $length = strlen($input); - - $checkSum = 0; + public function calcChecksum(int $numberWithoutCheckDigit): int { + $numberWithoutCheckDigit = (string) $numberWithoutCheckDigit; + $nDigits = strlen($numberWithoutCheckDigit); + $checksum = 0; + $parity = $nDigits % 2; - // Start at the next last digit - for ($i = $length - 2; $i >= 0; $i -= 2) { - // Multiply number with 2 - $tmp = (int) ($input[$i]) * 2; + for ($i = 0; $i < $nDigits; $i++) { + $digit = (int) $numberWithoutCheckDigit[$i]; - // If a 2 digit number, split and add togheter - if ($tmp > 9) { - $tmp = ($tmp / 10) + ($tmp % 10); - } + // Every other digit, starting from the leftmost, + // shall be doubled. + if (($i % 2) !== $parity) { + $digit *= 2; - // Sum it upp - $checkSum += $tmp; - } + if ($digit > 9) { + $digit -= 9; + } + } - // Start at the next last digit - for ($i = $length - 1; $i >= 0; $i -= 2) { - // Sum it upp - $checkSum += (int) $input[$i]; - } + $checksum += $digit; + } - return $checkSum; + return $checksum; } } diff --git a/src/LuhnAlgorithmFactory.php b/src/LuhnAlgorithmFactory.php index 17eeb13..d08a4a1 100644 --- a/src/LuhnAlgorithmFactory.php +++ b/src/LuhnAlgorithmFactory.php @@ -26,7 +26,6 @@ namespace Nekman\LuhnAlgorithm; use Nekman\LuhnAlgorithm\Contract\LuhnAlgorithmInterface; -use Nekman\LuhnAlgorithm\LuhmAlgorithm; /** * Factory for creating implementations of the Luhn Algorithm. diff --git a/tests/LuhnAlgorithmTest.php b/tests/LuhnAlgorithmTest.php index 0144561..21b2b84 100644 --- a/tests/LuhnAlgorithmTest.php +++ b/tests/LuhnAlgorithmTest.php @@ -32,25 +32,25 @@ class LuhnAlgorithmTest extends TestCase { /** * @var LuhnAlgorithm */ - private $object; + private $luhn; public function setUp() { parent::setUp(); - $this->object = new LuhnAlgorithm(); + $this->luhn = new LuhnAlgorithm(); } /** * @dataProvider provideIsValid_success */ public function testIsValid_success($number, $expected) { - $this->assertEquals($expected, $this->object->isValid($number)); + $this->assertEquals($expected, $this->luhn->isValid($number)); } public function provideIsValid_success() { return [ ["410321-9202", true], - ["410321 - 9202", true], + [123455, true], [4103219202, true], [31997233700020, true], ]; @@ -60,12 +60,12 @@ public function provideIsValid_success() { * @dataProvider provideCalcChecksum_success */ public function testCalcChecksum_success($number, $expected) { - $this->assertEquals($expected, $this->object->calcChecksum($number)); + $this->assertEquals($expected, $this->luhn->calcChecksum($number)); } public function provideCalcChecksum_success() { return [ - [4103219202, 30], + [3199723370002, 50], ]; } @@ -73,7 +73,7 @@ public function provideCalcChecksum_success() { * @dataProvider provideCalcCheckDigit_success */ public function testCalcCheckDigit_success($number, $expected) { - $this->assertEquals($expected, $this->object->calcCheckDigit($number)); + $this->assertEquals($expected, $this->luhn->calcCheckDigit($number)); } public function provideCalcCheckDigit_success() { From 71dd3bd1db9e927da21b6f905a9e09d589c6b1ca Mon Sep 17 00:00:00 2001 From: Niklas Ekman Date: Mon, 26 Feb 2018 19:53:47 +0100 Subject: [PATCH 3/5] Add class for describing a number. --- .travis.yml | 1 - README.md | 15 +++- composer.json | 2 +- src/Contract/LuhnAlgorithmInterface.php | 32 ++++---- src/Contract/NumberInterface.php | 46 +++++++++++ src/LuhnAlgorithm.php | 35 ++++----- src/Number.php | 100 ++++++++++++++++++++++++ tests/LuhnAlgorithmTest.php | 16 ++-- tests/NumberTest.php | 48 ++++++++++++ 9 files changed, 243 insertions(+), 52 deletions(-) create mode 100644 src/Contract/NumberInterface.php create mode 100644 src/Number.php create mode 100644 tests/NumberTest.php diff --git a/.travis.yml b/.travis.yml index 678b85e..30db937 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: php php: - - '7.0' - '7.1' - '7.2' before_script: composer install diff --git a/README.md b/README.md index e4badb9..0edc3af 100644 --- a/README.md +++ b/README.md @@ -20,14 +20,21 @@ Use the class like this: ```php use Nekman\LuhnAlgorithm\LuhnAlgorithmFactory; +use Nekman\LuhnAlgorithm\Number; $luhn = LuhnAlgorithmFactory::create(); -if ($luhn->isValid(123456789)) { - // Number is valid. +// Validate a credit card number entered in a form. +$ccNumber = Number::fromString($creditCard); +if ($luhn->isValid($ccNumber)) { + // Credit card number is valid. } -$checkSum = $luhn->calcChecksum(123456789); +// These methods are used internally by the library. You're free +// to make use of them as well. +$number = new Number(12345); -$checkDigit = $luhn->calcCheckDigit(123456789); +$checksum = $luhn->calcChecksum($number); + +$checkDigit = $luhn->calcCheckDigit($number); ``` \ No newline at end of file diff --git a/composer.json b/composer.json index 239e734..30db7b6 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ } }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { "phpunit/phpunit": "^6.5" diff --git a/src/Contract/LuhnAlgorithmInterface.php b/src/Contract/LuhnAlgorithmInterface.php index bf20512..455604f 100644 --- a/src/Contract/LuhnAlgorithmInterface.php +++ b/src/Contract/LuhnAlgorithmInterface.php @@ -33,34 +33,30 @@ interface LuhnAlgorithmInterface { /** * Determine if a number is valid according to the Luhn Algorithm. - * - * @param string $number The number to validate. - * + * + * @param NumberInterface $number The number to validate. + * * @return bool true if number is valid, false otherwise. - * - * @throws \InvalidArgumentException If the input is invalid. */ - public function isValid(string $number): bool; + public function isValid(NumberInterface $number): bool; /** * Calculate the check digit for an input. - * - * @param int $numberWithoutCheckDigit The number, without check digit, to calculate the check digit for. - * + * + * @param NumberInterface $number The number, without check digit, to calculate the check digit for. + * * @return int The check digit. - * - * @throws \InvalidArgumentException If the input is invalid. + * */ - public function calcCheckDigit(int $numberWithoutCheckDigit): int; + public function calcCheckDigit(NumberInterface $number): int; /** * Calulates the checksum for number. - * - * @param int $numberWithoutCheckDigit The number, without check digit, to calculate the checksum for. - * + * + * @param NumberInterface $number The number, without check digit, to calculate the checksum for. + * * @return int The checksum. - * - * @throws \InvalidArgumentException If the input is invalid. + * */ - public function calcChecksum(int $numberWithoutCheckDigit): int; + public function calcChecksum(NumberInterface $number): int; } diff --git a/src/Contract/NumberInterface.php b/src/Contract/NumberInterface.php new file mode 100644 index 0000000..210b65f --- /dev/null +++ b/src/Contract/NumberInterface.php @@ -0,0 +1,46 @@ +getCheckDigit() === null) { + throw new \InvalidArgumentException("Check digit cannot be null."); + } - $checksum = $this->calcChecksum($numberWithoutCheckDigit); - $sum = $checksum + $checkDigit; + $checksum = $this->calcChecksum($number); + $sum = $checksum + $number->getCheckDigit(); - // If the checksum is divisible by 10 it is valid + // If the checksum is divisible by 10 it is valid. return ($sum % 10) === 0; } /** * {@inheritDoc} */ - public function calcCheckDigit(int $numberWithoutCheckDigit): int { - $checksum = (string) $this->calcChecksum($numberWithoutCheckDigit); - $nDigits = strlen($checksum); + public function calcCheckDigit(NumberInterface $number): int { + $checksum = $this->calcChecksum($number); // Get the last digit of the checksum. - $checkDigit = (int) $checksum[$nDigits - 1]; + $checkDigit = $checksum % 10; // If the check digit is not 0, then subtract the value from 10. return $checkDigit === 0 @@ -70,14 +65,14 @@ public function calcCheckDigit(int $numberWithoutCheckDigit): int { /** * {@inheritDoc} */ - public function calcChecksum(int $numberWithoutCheckDigit): int { - $numberWithoutCheckDigit = (string) $numberWithoutCheckDigit; - $nDigits = strlen($numberWithoutCheckDigit); + public function calcChecksum(NumberInterface $number): int { + $number = (string) $number->getNumber(); + $nDigits = strlen($number); $checksum = 0; $parity = $nDigits % 2; for ($i = 0; $i < $nDigits; $i++) { - $digit = (int) $numberWithoutCheckDigit[$i]; + $digit = (int) $number[$i]; // Every other digit, starting from the leftmost, // shall be doubled. diff --git a/src/Number.php b/src/Number.php new file mode 100644 index 0000000..9efeaa6 --- /dev/null +++ b/src/Number.php @@ -0,0 +1,100 @@ +number = $number; + $this->checkDigit = $checkDigit; + } + + /** + * Create a new number from an input that contains the check digit + * already. + * + * @param string $input The input that contains the check digit already. + * + * @return self + */ + public static function fromString(string $input): self + { + $input = (int) preg_replace("/[^\d]/", "", $input); + + // Get the last digit. + $checkDigit = $input % 10; + + // Remove the last digit. + $number = (int) ($input / 10); + + return new self($number, $checkDigit); + } + + /** + * {@inheritdoc} + */ + public function getNumber(): int + { + return $this->number; + } + + /** + * {@inheritdoc} + */ + public function getCheckDigit(): ?int + { + return $this->checkDigit; + } + + /** + * {@inheritdoc} + */ + public function __toString() + { + return (string) $this->number . (string) $this->checkDigit; + } +} \ No newline at end of file diff --git a/tests/LuhnAlgorithmTest.php b/tests/LuhnAlgorithmTest.php index 21b2b84..aa40999 100644 --- a/tests/LuhnAlgorithmTest.php +++ b/tests/LuhnAlgorithmTest.php @@ -25,6 +25,7 @@ namespace Nekman\LuhnAlgorithm\Test; +use Nekman\LuhnAlgorithm\Number; use PHPUnit\Framework\TestCase; use Nekman\LuhnAlgorithm\LuhnAlgorithm; @@ -49,10 +50,9 @@ public function testIsValid_success($number, $expected) { public function provideIsValid_success() { return [ - ["410321-9202", true], - [123455, true], - [4103219202, true], - [31997233700020, true], + [new Number(12345, 5), true], + [new Number(410321920, 2), true], + [new Number(3199723370002, 0), true], ]; } @@ -65,7 +65,7 @@ public function testCalcChecksum_success($number, $expected) { public function provideCalcChecksum_success() { return [ - [3199723370002, 50], + [new Number(3199723370002), 50], ]; } @@ -78,9 +78,9 @@ public function testCalcCheckDigit_success($number, $expected) { public function provideCalcCheckDigit_success() { return [ - [12345, 5], - [410321920, 2], - [3199723370002, 0], + [new Number(12345), 5], + [new Number(410321920), 2], + [new Number(3199723370002), 0], ]; } } diff --git a/tests/NumberTest.php b/tests/NumberTest.php new file mode 100644 index 0000000..cf2fe85 --- /dev/null +++ b/tests/NumberTest.php @@ -0,0 +1,48 @@ +assertEquals($expected, Number::fromString($number)); + } + + public function provideWithCheckDigit_success() + { + return [ + ["410321-9202", new Number(410321920, 2)], + [4103219202, new Number(410321920, 2)] + ]; + } +} From dd9c761ac3835a157f1498bca1db22965dad0747 Mon Sep 17 00:00:00 2001 From: Niklas Ekman Date: Mon, 26 Feb 2018 20:04:02 +0100 Subject: [PATCH 4/5] Code review changes. --- .gitignore | 1 + .php_cs.dist | 14 ++ composer.json | 3 +- src/Contract/LuhnAlgorithmInterface.php | 125 +++++++-------- src/Contract/NumberInterface.php | 92 +++++------ src/LuhnAlgorithm.php | 78 ++++----- src/LuhnAlgorithmFactory.php | 96 ++++++------ src/Number.php | 200 ++++++++++++------------ tests/LuhnAlgorithmFactoryTest.php | 74 ++++----- tests/LuhnAlgorithmTest.php | 104 ++++++------ tests/NumberTest.php | 96 ++++++------ 11 files changed, 458 insertions(+), 425 deletions(-) create mode 100644 .php_cs.dist diff --git a/.gitignore b/.gitignore index 7044502..e214b97 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ index.php nbproject/ .idea/ +.php_cs.cache # Created by http://www.gitignore.io diff --git a/.php_cs.dist b/.php_cs.dist new file mode 100644 index 0000000..a70eec1 --- /dev/null +++ b/.php_cs.dist @@ -0,0 +1,14 @@ +setRules([ + '@PSR2' => true, + 'ordered_imports' => true, + 'phpdoc_order' => true, + 'simplified_null_return' => false, + 'no_unused_imports' => true, + ])->setFinder( + PhpCsFixer\Finder::create() + ->in(__DIR__.'/src') + ->in(__DIR__.'/tests') + ); diff --git a/composer.json b/composer.json index 30db7b6..dc867e3 100644 --- a/composer.json +++ b/composer.json @@ -34,6 +34,7 @@ "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.5" + "phpunit/phpunit": "^6.5", + "friendsofphp/php-cs-fixer": "^2.10" } } diff --git a/src/Contract/LuhnAlgorithmInterface.php b/src/Contract/LuhnAlgorithmInterface.php index 455604f..e80cacd 100644 --- a/src/Contract/LuhnAlgorithmInterface.php +++ b/src/Contract/LuhnAlgorithmInterface.php @@ -1,62 +1,63 @@ -getCheckDigit() === null) { - throw new \InvalidArgumentException("Check digit cannot be null."); +class LuhnAlgorithm implements LuhnAlgorithmInterface +{ + /** + * {@inheritDoc} + */ + public function isValid(NumberInterface $number): bool + { + if ($number->getCheckDigit() === null) { + throw new \InvalidArgumentException("Check digit cannot be null."); } $checksum = $this->calcChecksum($number); - $sum = $checksum + $number->getCheckDigit(); + $sum = $checksum + $number->getCheckDigit(); - // If the checksum is divisible by 10 it is valid. - return ($sum % 10) === 0; - } + // If the checksum is divisible by 10 it is valid. + return ($sum % 10) === 0; + } - /** - * {@inheritDoc} - */ - public function calcCheckDigit(NumberInterface $number): int { - $checksum = $this->calcChecksum($number); - - // Get the last digit of the checksum. - $checkDigit = $checksum % 10; + /** + * {@inheritDoc} + */ + public function calcCheckDigit(NumberInterface $number): int + { + $checksum = $this->calcChecksum($number); + + // Get the last digit of the checksum. + $checkDigit = $checksum % 10; - // If the check digit is not 0, then subtract the value from 10. - return $checkDigit === 0 + // If the check digit is not 0, then subtract the value from 10. + return $checkDigit === 0 ? $checkDigit : 10 - $checkDigit; - } + } - /** - * {@inheritDoc} - */ - public function calcChecksum(NumberInterface $number): int { - $number = (string) $number->getNumber(); - $nDigits = strlen($number); - $checksum = 0; - $parity = $nDigits % 2; + /** + * {@inheritDoc} + */ + public function calcChecksum(NumberInterface $number): int + { + $number = (string) $number->getNumber(); + $nDigits = strlen($number); + $checksum = 0; + $parity = $nDigits % 2; - for ($i = 0; $i < $nDigits; $i++) { - $digit = (int) $number[$i]; + for ($i = 0; $i < $nDigits; $i++) { + $digit = (int) $number[$i]; - // Every other digit, starting from the leftmost, + // Every other digit, starting from the leftmost, // shall be doubled. - if (($i % 2) !== $parity) { - $digit *= 2; + if (($i % 2) !== $parity) { + $digit *= 2; if ($digit > 9) { $digit -= 9; @@ -87,6 +91,6 @@ public function calcChecksum(NumberInterface $number): int { $checksum += $digit; } - return $checksum; - } + return $checksum; + } } diff --git a/src/LuhnAlgorithmFactory.php b/src/LuhnAlgorithmFactory.php index d08a4a1..6a95952 100644 --- a/src/LuhnAlgorithmFactory.php +++ b/src/LuhnAlgorithmFactory.php @@ -1,47 +1,49 @@ -number = $number; - $this->checkDigit = $checkDigit; - } - - /** - * Create a new number from an input that contains the check digit - * already. - * - * @param string $input The input that contains the check digit already. - * - * @return self - */ - public static function fromString(string $input): self - { - $input = (int) preg_replace("/[^\d]/", "", $input); - - // Get the last digit. - $checkDigit = $input % 10; - - // Remove the last digit. - $number = (int) ($input / 10); - - return new self($number, $checkDigit); - } - - /** - * {@inheritdoc} - */ - public function getNumber(): int - { - return $this->number; - } - - /** - * {@inheritdoc} - */ - public function getCheckDigit(): ?int - { - return $this->checkDigit; - } - - /** - * {@inheritdoc} - */ - public function __toString() - { - return (string) $this->number . (string) $this->checkDigit; - } -} \ No newline at end of file +number = $number; + $this->checkDigit = $checkDigit; + } + + /** + * Create a new number from an input that contains the check digit + * already. + * + * @param string $input The input that contains the check digit already. + * + * @return self + */ + public static function fromString(string $input): self + { + $input = (int) preg_replace("/[^\d]/", "", $input); + + // Get the last digit. + $checkDigit = $input % 10; + + // Remove the last digit. + $number = (int) ($input / 10); + + return new self($number, $checkDigit); + } + + /** + * {@inheritdoc} + */ + public function getNumber(): int + { + return $this->number; + } + + /** + * {@inheritdoc} + */ + public function getCheckDigit(): ?int + { + return $this->checkDigit; + } + + /** + * {@inheritdoc} + */ + public function __toString() + { + return (string) $this->number . (string) $this->checkDigit; + } +} diff --git a/tests/LuhnAlgorithmFactoryTest.php b/tests/LuhnAlgorithmFactoryTest.php index 865607a..f887f3e 100644 --- a/tests/LuhnAlgorithmFactoryTest.php +++ b/tests/LuhnAlgorithmFactoryTest.php @@ -1,36 +1,38 @@ -assertInstanceOf(LuhnAlgorithm::class, LuhnAlgorithmFactory::create()); - } -} +assertInstanceOf(LuhnAlgorithm::class, LuhnAlgorithmFactory::create()); + } +} diff --git a/tests/LuhnAlgorithmTest.php b/tests/LuhnAlgorithmTest.php index aa40999..de6a036 100644 --- a/tests/LuhnAlgorithmTest.php +++ b/tests/LuhnAlgorithmTest.php @@ -25,62 +25,70 @@ namespace Nekman\LuhnAlgorithm\Test; +use Nekman\LuhnAlgorithm\LuhnAlgorithm; use Nekman\LuhnAlgorithm\Number; use PHPUnit\Framework\TestCase; -use Nekman\LuhnAlgorithm\LuhnAlgorithm; -class LuhnAlgorithmTest extends TestCase { - /** - * @var LuhnAlgorithm - */ - private $luhn; +class LuhnAlgorithmTest extends TestCase +{ + /** + * @var LuhnAlgorithm + */ + private $luhn; - public function setUp() { - parent::setUp(); - - $this->luhn = new LuhnAlgorithm(); - } + public function setUp() + { + parent::setUp(); + + $this->luhn = new LuhnAlgorithm(); + } - /** - * @dataProvider provideIsValid_success - */ - public function testIsValid_success($number, $expected) { - $this->assertEquals($expected, $this->luhn->isValid($number)); - } + /** + * @dataProvider provideIsValid_success + */ + public function testIsValid_success($number, $expected) + { + $this->assertEquals($expected, $this->luhn->isValid($number)); + } - public function provideIsValid_success() { - return [ - [new Number(12345, 5), true], - [new Number(410321920, 2), true], - [new Number(3199723370002, 0), true], - ]; - } + public function provideIsValid_success() + { + return [ + [new Number(12345, 5), true], + [new Number(410321920, 2), true], + [new Number(3199723370002, 0), true], + ]; + } - /** - * @dataProvider provideCalcChecksum_success - */ - public function testCalcChecksum_success($number, $expected) { - $this->assertEquals($expected, $this->luhn->calcChecksum($number)); - } + /** + * @dataProvider provideCalcChecksum_success + */ + public function testCalcChecksum_success($number, $expected) + { + $this->assertEquals($expected, $this->luhn->calcChecksum($number)); + } - public function provideCalcChecksum_success() { - return [ - [new Number(3199723370002), 50], - ]; - } + public function provideCalcChecksum_success() + { + return [ + [new Number(3199723370002), 50], + ]; + } - /** - * @dataProvider provideCalcCheckDigit_success - */ - public function testCalcCheckDigit_success($number, $expected) { - $this->assertEquals($expected, $this->luhn->calcCheckDigit($number)); - } + /** + * @dataProvider provideCalcCheckDigit_success + */ + public function testCalcCheckDigit_success($number, $expected) + { + $this->assertEquals($expected, $this->luhn->calcCheckDigit($number)); + } - public function provideCalcCheckDigit_success() { - return [ - [new Number(12345), 5], - [new Number(410321920), 2], - [new Number(3199723370002), 0], - ]; - } + public function provideCalcCheckDigit_success() + { + return [ + [new Number(12345), 5], + [new Number(410321920), 2], + [new Number(3199723370002), 0], + ]; + } } diff --git a/tests/NumberTest.php b/tests/NumberTest.php index cf2fe85..a4a5754 100644 --- a/tests/NumberTest.php +++ b/tests/NumberTest.php @@ -1,48 +1,48 @@ -assertEquals($expected, Number::fromString($number)); - } - - public function provideWithCheckDigit_success() - { - return [ - ["410321-9202", new Number(410321920, 2)], - [4103219202, new Number(410321920, 2)] - ]; - } -} +assertEquals($expected, Number::fromString($number)); + } + + public function provideWithCheckDigit_success() + { + return [ + ["410321-9202", new Number(410321920, 2)], + [4103219202, new Number(410321920, 2)] + ]; + } +} From efd2a93a520fc1921ce28f1009c99fadb093d914 Mon Sep 17 00:00:00 2001 From: Niklas Ekman Date: Mon, 26 Feb 2018 20:08:38 +0100 Subject: [PATCH 5/5] Add test for number toString() --- tests/NumberTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/NumberTest.php b/tests/NumberTest.php index a4a5754..443ab3f 100644 --- a/tests/NumberTest.php +++ b/tests/NumberTest.php @@ -45,4 +45,19 @@ public function provideWithCheckDigit_success() [4103219202, new Number(410321920, 2)] ]; } + + /** + * @dataProvider provideToString_success + */ + public function testToString_success($number, $expected) + { + $this->assertEquals($expected, (string) $number); + } + + public function provideToString_success() + { + return [ + [new Number(12345, 5), "123455"] + ]; + } }