Skip to content

Commit

Permalink
Exceptions for large numbers instead of TypeErrors
Browse files Browse the repository at this point in the history
Did not deal with newFromFloat yet.
For floats there is PHP_FLOAT_DIG, added in PHP 7.2
  • Loading branch information
JeroenDeDauw committed Jan 17, 2019
1 parent 6722dbc commit 5d45110
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Expand Up @@ -96,6 +96,10 @@ For a full CI run

## Release notes

### 1.1.1 (dev)

* Large numbers now cause an InvalidArgumentException rather than a TypeError

### 1.1.0 (2018-03-21)

* Bumped minimum PHP version from 7.0 to 7.1
Expand Down
12 changes: 12 additions & 0 deletions src/Euro.php
Expand Up @@ -54,6 +54,10 @@ public static function newFromString( string $euroAmount ): self {
throw new InvalidArgumentException( 'Not a number' );
}

if ( self::stringIsTooLong( $euroAmount ) ) {
throw new InvalidArgumentException( 'Number is too big' );
}

$parts = explode( '.', $euroAmount, 2 );

$euros = (int)$parts[0];
Expand All @@ -62,6 +66,10 @@ public static function newFromString( string $euroAmount ): self {
return new self( $euros * self::CENTS_PER_EURO + $cents );
}

private static function stringIsTooLong( string $euroString ): bool {
return strlen( $euroString ) + 2 > log10( PHP_INT_MAX );
}

private static function centsFromString( string $cents ): int {
if ( strlen( $cents ) > self::DECIMAL_COUNT ) {
return self::roundCentsToInt( $cents );
Expand Down Expand Up @@ -105,6 +113,10 @@ public static function newFromFloat( float $euroAmount ): self {
* @throws InvalidArgumentException
*/
public static function newFromInt( int $euroAmount ): self {
if ( $euroAmount > floor( PHP_INT_MAX / 101 ) ) {
throw new InvalidArgumentException( 'Number is too big' );
}

return new self( $euroAmount * self::CENTS_PER_EURO );
}

Expand Down
46 changes: 46 additions & 0 deletions tests/Unit/EuroTest.php
Expand Up @@ -4,6 +4,7 @@

namespace WMDE\Euro\Tests\Unit;

use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
use WMDE\Euro\Euro;

Expand Down Expand Up @@ -250,4 +251,49 @@ public function test9001centsDoesNotEqual9000cents() {
$this->assertFalse( Euro::newFromCents( 9001 )->equals( Euro::newFromCents( 9000 ) ) );
}

/**
* @dataProvider tooLongStringProvider
*/
public function testNewFromStringThrowsExceptionWhenStringIsTooLong( string $string ) {
$this->expectException( InvalidArgumentException::class );
$this->expectExceptionMessage( 'Number is too big' );

Euro::newFromString( $string );
}

public function tooLongStringProvider() {
yield [ '1111111111111111111111111111111' ];
yield [ (string)PHP_INT_MAX ];
yield [ substr( (string)PHP_INT_MAX, 0, -2 ) ];
}

public function testNewFromStringHandlesLongStrings() {
Euro::newFromString( substr( (string)PHP_INT_MAX, 0, -3 ) );
$this->assertTrue( true );
}

/**
* @dataProvider tooHighIntegerProvider
*/
public function testNewFromIntThrowsExceptionWhenIntegerIsTooHigh( int $int ) {
$this->expectException( InvalidArgumentException::class );
$this->expectExceptionMessage( 'Number is too big' );
Euro::newFromInt( $int );
}

public function tooHighIntegerProvider() {
yield [ PHP_INT_MAX ];
yield [ PHP_INT_MAX / 10 ];
yield [ PHP_INT_MAX / 100 ];
}

public function testNewFromIntHandlesBigIntegers() {
$number = (int)floor( PHP_INT_MAX / 101 );

$this->assertSame(
$number * 100,
Euro::newFromInt( $number )->getEuroCents()
);
}

}

0 comments on commit 5d45110

Please sign in to comment.