JEMBOT MAWOT Bypass Shell
<?php
/**
* This file is part of the PrestaShop\Decimal package
*
* @author PrestaShop SA <contact@prestashop.com>
* @license https://opensource.org/licenses/MIT MIT License
*/
namespace PrestaShop\Decimal\Test;
use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
use PrestaShop\Decimal\DecimalNumber;
use PrestaShop\Decimal\Operation\Rounding;
class DecimalNumberTest extends TestCase
{
/**
* Given a valid number in a string
* When constructing a DecimalNumber with it
* Then it should interpret the sign, decimal and fractional parts correctly
*
* @param string $number
* @param string $expectedSign
* @param string $expectedInteger
* @param string $expectedFraction
* @param string $expectedStr
*
* @dataProvider provideValidNumbers
*/
public function testItInterpretsNumbers($number, $expectedSign, $expectedInteger, $expectedFraction, $expectedStr)
{
$decimalNumber = new DecimalNumber($number);
$this->assertSame($expectedSign, $decimalNumber->getSign(), 'The sign is not as expected');
$this->assertSame($expectedInteger, $decimalNumber->getIntegerPart(), 'The integer part is not as expected');
$this->assertSame(
$expectedFraction,
$decimalNumber->getFractionalPart(),
'The fraction part is not as expected'
);
$this->assertSame($expectedStr, (string) $decimalNumber, 'The string representation is not as expected');
}
/**
* Given a valid coefficient and exponent
* When constructing a DecimalNumber with them
* Then it should convert them to the expected string
*
* @param string $coefficient
* @param int $exponent
* @param string $expectedStr
*
* @dataProvider provideValidExponents
*/
public function testItInterpretsExponents($coefficient, $exponent, $expectedStr)
{
$decimalNumber = new DecimalNumber($coefficient, $exponent);
$this->assertSame($expectedStr, (string) $decimalNumber);
}
/**
* Given an invalid number
* When constructing a DecimalNumber with it
* Then an InvalidArgumentException should be thrown
*
* @param mixed $number
*
* @dataProvider provideInvalidNumbers
*/
public function testItThrowsExceptionWhenGivenInvalidNumber($number)
{
$this->expectException(InvalidArgumentException::class);
new DecimalNumber($number);
}
/**
* Given an invalid coefficient or exponent
* When constructing a DecimalNumber with them
* Then an InvalidArgumentException should be thrown
*
* @param mixed $coefficient
* @param mixed $exponent
*
* @dataProvider provideInvalidCoefficients
*/
public function testItThrowsExceptionWhenGivenInvalidCoefficientOrExponent($coefficient, $exponent)
{
$this->expectException(InvalidArgumentException::class);
new DecimalNumber($coefficient, $exponent);
}
/**
* Given a DecimalNumber constructed with a valid number
* When casting the number to string
* The resulting string should not include leading nor trailing zeroes
*
* @param string $number
* @param string $expected
*
* @dataProvider provideNumbersWithNonSignificantCharacters
*/
public function testItDropsNonSignificantDigits($number, $expected)
{
$decimalNumber = new DecimalNumber($number);
$this->assertSame($expected, (string) $decimalNumber);
}
/**
* Given a DecimalNumber constructed with a valid number
* When rounding it to a specific precision, using a specific rounding mode
* The returned string should match the expectation
*
* @param string $number
* @param int $precision Number of decimal characters
* @param string $mode Rounding mode
* @param string $expected Expected result
*
* @dataProvider providePrecisionTestCases
*/
public function testPrecision($number, $precision, $mode, $expected)
{
$decimalNumber = new DecimalNumber($number);
$this->assertSame($expected, (string) $decimalNumber->toPrecision($precision, $mode));
}
/**
* Given a DecimalNumber constructed with a valid number
* When rounding it to a specific precision, using a specific rounding mode
* The returned string should match the expectation
*
* @param string $number
* @param int $precision Number of decimal characters
* @param string $mode Rounding mode
* @param string $expected Expected result
*
* @dataProvider provideRoundingTestCases
*/
public function testRounding($number, $precision, $mode, $expected)
{
$decimalNumber = new DecimalNumber($number);
$this->assertSame(
$expected,
(string) $decimalNumber->round($precision, $mode),
"Failed to assert that round $number to $precision decimals = $expected"
);
}
/**
* Given a DecimalNumber constructed with a valid number
* When rounding it to a greater precision than its current one
* The returned string should have been padded with the proper number of trailing zeroes
*
* @param string $number
* @param int $precision Target precision
* @param string $expected Expected result
*
* @dataProvider provideExtendedPrecisionTestCases
*/
public function testItExtendsPrecisionAsNeeded($number, $precision, $expected)
{
$decimalNumber = new DecimalNumber($number);
$this->assertSame(
$expected,
(string) $decimalNumber->toPrecision($precision),
"Failed to assert that fixing $number to $precision decimals = $expected"
);
}
/**
* Given two instances of DecimalNumber
* When comparing the first one with the second one
* Then the result should be true if the instances are equal, and false otherwise
*
* @param DecimalNumber $number1
* @param DecimalNumber $number2
* @param string $expected
*
* @dataProvider provideEqualityTestCases
*/
public function testItIsAbleToTellIfEqual($number1, $number2, $expected)
{
$this->assertSame(
$expected,
$number1->equals($number2),
sprintf('Failed to assert equality between "%s" and "%s"', $number1, $number2)
);
}
/**
* Given two numbers
* When asked if one number is greater than the other
* Then result should be true if the A > B, and false otherwise
*
* @param string $number1
* @param string $number2
* @param int $expected
*
* @dataProvider provideComparisonTestCases
*/
public function testIsAbleToTellIfGreaterThan($number1, $number2, $expected)
{
$shouldBeGreater = (1 === $expected);
$number1 = new DecimalNumber($number1);
$number2 = new DecimalNumber($number2);
$this->assertSame($number1->isGreaterThan($number2), $shouldBeGreater);
}
/**
* Given two numbers
* When asked if one number is lower than the other
* Then result should be true if the A < B, and false otherwise
*
* @param string $number1
* @param string $number2
* @param int $expected
*
* @dataProvider provideComparisonTestCases
*/
public function testIsAbleToTellIfLowerThan($number1, $number2, $expected)
{
$shouldBeLower = (-1 === $expected);
$number1 = new DecimalNumber($number1);
$number2 = new DecimalNumber($number2);
$this->assertSame($number1->isLowerThan($number2), $shouldBeLower);
}
/**
* Given a positive number
* When it's transformed to negative
* Then we should get the negative equivalent of the base number
*
* @param string $number
* @param string $expected
*
* @dataProvider provideToNegativeTransformationCases
*/
public function testItTransformsPositiveToNegative($number, $expected)
{
$number = (new DecimalNumber($number))
->toNegative();
$this->assertSame((string) $number, $expected);
}
/**
* Given a negative number
* When it's transformed to positive
* Then we should get the positive equivalent of the base number
*
* @param string $number
* @param string $expected
*
* @dataProvider provideToPositiveTransformationCases
*/
public function testItTransformsNegativeToPositive($number, $expected)
{
$number = (new DecimalNumber($number))
->toPositive();
$this->assertSame((string) $number, $expected);
}
public function provideValidNumbers()
{
return [
[
'number' => '0.0',
'expectedSign' => '',
'expectedInteger' => '0',
'expectedFraction' => '0',
'expectedStr' => '0',
],
['00000.0', '', '0', '0', '0'],
['0.00000', '', '0', '0', '0'],
['00000.00000', '', '0', '0', '0'],
['0.1', '', '0', '1', '0.1'],
['1.0', '', '1', '0', '1'],
['1.1', '', '1', '1', '1.1'],
['1.234', '', '1', '234', '1.234'],
['0.1245', '', '0', '1245', '0.1245'],
['1', '', '1', '0', '1'],
['01', '', '1', '0', '1'],
['01.0', '', '1', '0', '1'],
['01.01', '', '1', '01', '1.01'],
['10.2345', '', '10', '2345', '10.2345'],
'123917549171231.12451028401824' => ['123917549171231.12451028401824', '', '123917549171231', '12451028401824', '123917549171231.12451028401824'],
'+12351.49273592' => ['+12351.49273592', '', '12351', '49273592', '12351.49273592'],
'-12351.49273592' => ['-12351.49273592', '-', '12351', '49273592', '-12351.49273592'],
'-12351' => ['-12351', '-', '12351', '0', '-12351'],
'-0' => ['-0', '', '0', '0', '0'],
'-01' => ['-01', '-', '1', '0', '-1'],
'-01.0' => ['-01.0', '-', '1', '0', '-1'],
'-01.01' => ['-01.01', '-', '1', '01', '-1.01'],
'0.1e-1' => ['0.1e-1', '', '0', '01', '0.01'],
'0.1e-2' => ['0.1e-2', '', '0', '001', '0.001'],
'0.1e-3' => ['0.1e-3', '', '0', '0001', '0.0001'],
'0.1e-4' => ['0.1e-4', '', '0', '00001', '0.00001'],
'0.1e-5' => ['0.1e-5', '', '0', '000001', '0.000001'],
'0.01e-1' => ['0.01e-1', '', '0', '001', '0.001'],
'123.01e-1' => ['123.01e-1', '', '12', '301', '12.301'],
'12301e-4' => ['12301e-4', '', '1', '2301', '1.2301'],
'12301e-5' => ['12301e-5', '', '0', '12301', '0.12301'],
'12301e-6' => ['12301e-6', '', '0', '012301', '0.012301'],
'12301e-7' => ['12301e-7', '', '0', '0012301', '0.0012301'],
'12301e-10' => ['12301e-10', '', '0', '0000012301', '0.0000012301'],
'12301e+3' => ['12301e+3', '', '12301000', '0', '12301000'],
'0.1e+1' => ['0.1e+1', '', '1', '0', '1'],
'0.1e+2' => ['0.1e+2', '', '10', '0', '10'],
'0.1e+3' => ['0.1e+3', '', '100', '0', '100'],
'0.1e+4' => ['0.1e+4', '', '1000', '0', '1000'],
'0.1e+5' => ['0.1e+5', '', '10000', '0', '10000'],
'123.01e+1' => ['123.01e+1', '', '1230', '1', '1230.1'],
'123.01e+5' => ['123.01e+5', '', '12301000', '0', '12301000'],
'1.0E+15' => ['1.0E+15', '', '1000000000000000', '0', '1000000000000000'],
'-123.0456E+15' => ['-123.0456E+15', '-', '123045600000000000', '0', '-123045600000000000'],
'-123.04560E+15' => ['-123.04560E+15', '-', '123045600000000000', '0', '-123045600000000000'],
'.1e+2' => ['.1e+2', '', '10', '0', '10'],
'-.1e+2' => ['-.1e+2', '-', '10', '0', '-10'],
'+.1e+2' => ['+.1e+2', '', '10', '0', '10'],
'.01' => ['.01', '', '0', '01', '0.01'],
];
}
public function provideValidExponents()
{
return [
'exponent 0' => ['123456', 0, '123456'],
'exponent 1' => ['123456', 1, '12345.6'],
'exponent 2' => ['123456', 2, '1234.56'],
'exponent 3' => ['123456', 3, '123.456'],
'exponent 4' => ['123456', 4, '12.3456'],
'exponent 5' => ['123456', 5, '1.23456'],
'exponent 6' => ['123456', 6, '0.123456'],
'exponent 7' => ['123456', 7, '0.0123456'],
'exponent 8' => ['123456', 8, '0.00123456'],
'exponent 8 with leading' => ['0123456', 8, '0.00123456'],
'zero' => ['0', 8, '0'],
'leading zeroes' => ['00000', 8, '0'],
'plus leading zeroes' => ['+00000', 8, '0'],
'minus exponent 0' => ['-123456', 0, '-123456'],
'minus exponent 1' => ['-123456', 1, '-12345.6'],
'minus exponent 2' => ['-123456', 2, '-1234.56'],
'minus exponent 3' => ['-123456', 3, '-123.456'],
'minus exponent 4' => ['-123456', 4, '-12.3456'],
'minus exponent 5' => ['-123456', 5, '-1.23456'],
'minus exponent 6' => ['-123456', 6, '-0.123456'],
'minus exponent 7' => ['-123456', 7, '-0.0123456'],
'minus exponent 8' => ['-123456', 8, '-0.00123456'],
'minus exponent 8 with leading' => ['-0123456', 8, '-0.00123456'],
'minus zero' => ['-0', 8, '0'],
'minus leading zeroes' => ['-00000', 8, '0'],
// trailing zeroes should be dropped on the decimal part
'trailing zeroes 1' => ['10000000', 4, '1000'],
'trailing zeroes 2' => ['10002000', 4, '1000.2'],
];
}
public function provideInvalidNumbers()
{
return [
'bool false' => [false],
'bool true' => [true],
'empty string' => [''],
'NaN' => ['asd'],
'NaN with dot' => ['asd.foo'],
'NaN with comma' => ['asd,foo'],
'array' => [[]],
'null' => [null],
'1.' => ['1.'],
];
}
public function provideInvalidCoefficients()
{
return [
'bool false' => [false, 0],
'bool true' => [true, 0],
'empty string' => ['', 0],
'NaN' => ['asd', 0],
'NaN with dot' => ['asd.foo', 0],
'NaN with comma' => ['asd,foo', 0],
'array' => [[], 0],
'null' => [null, 0],
'negative coefficient' => ['123', -5],
];
}
public function provideNumbersWithNonSignificantCharacters()
{
return [
['01', '1'],
['010', '10'],
['000010', '10'],
['10.1', '10.1'],
['10.10', '10.1'],
['10.11230000', '10.1123'],
['0000010.11230000', '10.1123'],
['+0000010.11230000', '10.1123'],
['-01', '-1'],
['-010', '-10'],
['-000010', '-10'],
['-10.1', '-10.1'],
['-10.10', '-10.1'],
['-10.11230000', '-10.1123'],
['-0000010.11230000', '-10.1123'],
];
}
public function provideExtendedPrecisionTestCases()
{
return [
['1.23456789', 8, '1.23456789'],
['1.23456789', 9, '1.234567890'],
['1.23456789', 10, '1.2345678900'],
];
}
public function provideRoundingTestCases()
{
return [
'truncate 0' => ['1.23456789', 0, Rounding::ROUND_TRUNCATE, '1'],
'truncate 1' => ['1.23456789', 1, Rounding::ROUND_TRUNCATE, '1.2'],
'truncate 2' => ['1.23456789', 2, Rounding::ROUND_TRUNCATE, '1.23'],
'truncate 3' => ['1.23456789', 3, Rounding::ROUND_TRUNCATE, '1.234'],
'truncate 4' => ['1.23456789', 4, Rounding::ROUND_TRUNCATE, '1.2345'],
'truncate 5' => ['1.23456789', 5, Rounding::ROUND_TRUNCATE, '1.23456'],
'truncate 6' => ['1.23456789', 6, Rounding::ROUND_TRUNCATE, '1.234567'],
'truncate 7' => ['1.23456789', 7, Rounding::ROUND_TRUNCATE, '1.2345678'],
'truncate 8' => ['1.23456789', 8, Rounding::ROUND_TRUNCATE, '1.23456789'],
// does not add trailing zeroes
'truncate 9' => ['1.23456789', 9, Rounding::ROUND_TRUNCATE, '1.23456789'],
'truncate 10' => ['1.23456789', 10, Rounding::ROUND_TRUNCATE, '1.23456789'],
'truncate zeroes 1' => ['1.00000001', 3, Rounding::ROUND_TRUNCATE, '1'],
'truncate zeroes 2' => ['1.00000001', 9, Rounding::ROUND_TRUNCATE, '1.00000001'],
'ceil 0' => ['1.23456789', 0, Rounding::ROUND_CEIL, '2'],
'ceil 1' => ['1.23456789', 1, Rounding::ROUND_CEIL, '1.3'],
'ceil 2' => ['1.23456789', 2, Rounding::ROUND_CEIL, '1.24'],
'ceil 3' => ['1.23456789', 3, Rounding::ROUND_CEIL, '1.235'],
'ceil 4' => ['1.23456789', 4, Rounding::ROUND_CEIL, '1.2346'],
'ceil 5' => ['1.23456789', 5, Rounding::ROUND_CEIL, '1.23457'],
'ceil 6' => ['1.23456789', 6, Rounding::ROUND_CEIL, '1.234568'],
'ceil 7' => ['1.23456789', 7, Rounding::ROUND_CEIL, '1.2345679'],
'ceil 8' => ['1.23456789', 8, Rounding::ROUND_CEIL, '1.23456789'],
// does not add trailing zeroes
'ceil 9' => ['1.23456789', 9, Rounding::ROUND_CEIL, '1.23456789'],
'ceil 10' => ['1.23456789', 10, Rounding::ROUND_CEIL, '1.23456789'],
'round half up 0' => ['1.23456789', 0, Rounding::ROUND_HALF_UP, '1'],
'round half up 1' => ['1.23456789', 1, Rounding::ROUND_HALF_UP, '1.2'],
'round half up 2' => ['1.23456789', 2, Rounding::ROUND_HALF_UP, '1.23'],
'round half up 3' => ['1.23456789', 3, Rounding::ROUND_HALF_UP, '1.235'],
'round half up 4' => ['1.23456789', 4, Rounding::ROUND_HALF_UP, '1.2346'],
'round half up 5' => ['1.23456789', 5, Rounding::ROUND_HALF_UP, '1.23457'],
'round half up 6' => ['1.23456789', 6, Rounding::ROUND_HALF_UP, '1.234568'],
'round half up 7' => ['1.23456789', 7, Rounding::ROUND_HALF_UP, '1.2345679'],
'round half up 8' => ['1.23456789', 8, Rounding::ROUND_HALF_UP, '1.23456789'],
// does not add trailing zeroes
'round half up 9' => ['1.23456789', 9, Rounding::ROUND_HALF_UP, '1.23456789'],
'round half up 10' => ['1.23456789', 10, Rounding::ROUND_HALF_UP, '1.23456789'],
];
}
public function providePrecisionTestCases()
{
return [
'truncate 0' => ['1.23456789', 0, Rounding::ROUND_TRUNCATE, '1'],
'truncate 1' => ['1.23456789', 1, Rounding::ROUND_TRUNCATE, '1.2'],
'truncate 2' => ['1.23456789', 2, Rounding::ROUND_TRUNCATE, '1.23'],
'truncate 3' => ['1.23456789', 3, Rounding::ROUND_TRUNCATE, '1.234'],
'truncate 4' => ['1.23456789', 4, Rounding::ROUND_TRUNCATE, '1.2345'],
'truncate 5' => ['1.23456789', 5, Rounding::ROUND_TRUNCATE, '1.23456'],
'truncate 6' => ['1.23456789', 6, Rounding::ROUND_TRUNCATE, '1.234567'],
'truncate 7' => ['1.23456789', 7, Rounding::ROUND_TRUNCATE, '1.2345678'],
'truncate 8' => ['1.23456789', 8, Rounding::ROUND_TRUNCATE, '1.23456789'],
// adds trailing zeroes
'truncate 9' => ['1.23456789', 9, Rounding::ROUND_TRUNCATE, '1.234567890'],
'truncate 10' => ['1.23456789', 10, Rounding::ROUND_TRUNCATE, '1.2345678900'],
// keeps trailing zeroes
'truncate zeroes 1' => ['1.00000001', 3, Rounding::ROUND_TRUNCATE, '1.000'],
'truncate zeroes 2' => ['1.00000001', 8, Rounding::ROUND_TRUNCATE, '1.00000001'],
'ceil 0' => ['1.23456789', 0, Rounding::ROUND_CEIL, '2'],
'ceil 1' => ['1.23456789', 1, Rounding::ROUND_CEIL, '1.3'],
'ceil 2' => ['1.23456789', 2, Rounding::ROUND_CEIL, '1.24'],
'ceil 3' => ['1.23456789', 3, Rounding::ROUND_CEIL, '1.235'],
'ceil 4' => ['1.23456789', 4, Rounding::ROUND_CEIL, '1.2346'],
'ceil 5' => ['1.23456789', 5, Rounding::ROUND_CEIL, '1.23457'],
'ceil 6' => ['1.23456789', 6, Rounding::ROUND_CEIL, '1.234568'],
'ceil 7' => ['1.23456789', 7, Rounding::ROUND_CEIL, '1.2345679'],
'ceil 8' => ['1.23456789', 8, Rounding::ROUND_CEIL, '1.23456789'],
'ceil zeroes' => ['1.00000001', 7, Rounding::ROUND_CEIL, '1.0000001'],
// adds trailing zeroes
'ceil 9' => ['1.23456789', 9, Rounding::ROUND_CEIL, '1.234567890'],
'ceil 10' => ['1.23456789', 10, Rounding::ROUND_CEIL, '1.2345678900'],
'round half up 0' => ['1.23456789', 0, Rounding::ROUND_HALF_UP, '1'],
'round half up 1' => ['1.23456789', 1, Rounding::ROUND_HALF_UP, '1.2'],
'round half up 2' => ['1.23456789', 2, Rounding::ROUND_HALF_UP, '1.23'],
'round half up 3' => ['1.23456789', 3, Rounding::ROUND_HALF_UP, '1.235'],
'round half up 4' => ['1.23456789', 4, Rounding::ROUND_HALF_UP, '1.2346'],
'round half up 5' => ['1.23456789', 5, Rounding::ROUND_HALF_UP, '1.23457'],
'round half up 6' => ['1.23456789', 6, Rounding::ROUND_HALF_UP, '1.234568'],
'round half up 7' => ['1.23456789', 7, Rounding::ROUND_HALF_UP, '1.2345679'],
'round half up 8' => ['1.23456789', 8, Rounding::ROUND_HALF_UP, '1.23456789'],
// adds trailing zeroes
'round half up 9' => ['1.23456789', 9, Rounding::ROUND_HALF_UP, '1.234567890'],
'round half up 10' => ['1.23456789', 10, Rounding::ROUND_HALF_UP, '1.2345678900'],
];
}
public function provideEqualityTestCases()
{
return [
[
new DecimalNumber('0'),
new DecimalNumber('0', 5),
true,
],
[
new DecimalNumber('0.1234'),
new DecimalNumber('1234', 4),
true,
],
[
new DecimalNumber('1234.01'),
new DecimalNumber('123401', 2),
true,
],
[
new DecimalNumber('-0'),
new DecimalNumber('0'),
true,
],
[
new DecimalNumber('-1234.01'),
new DecimalNumber('-123401', 2),
true,
],
[
new DecimalNumber('-1234.01'),
new DecimalNumber('123401', 2),
false,
],
[
new DecimalNumber('1234.01'),
new DecimalNumber('-123401', 2),
false,
],
[
new DecimalNumber('1234.01'),
new DecimalNumber('-1234.01'),
false,
],
];
}
public function provideComparisonTestCases()
{
return [
// a is greater
'greater 1' => ['1', '0', 1],
'greater 2' => ['1.0', '0', 1],
'greater 3' => ['1.01', '1.0', 1],
'greater 4' => ['1.0000000000000000000000001', '1.0', 1],
'greater 5' => ['10', '001', 1],
'greater 6' => ['10', '-10', 1],
'greater 7' => ['10', '-100', 1],
'greater 8' => ['100', '10', 1],
'greater 9' => ['-1', '-2', 1],
'greater 10' => ['-1', '-0000002', 1],
'greater 11' => ['-1', '-1.0000000001', 1],
// a is equal
'equal 1' => ['1', '01', 0],
'equal 2' => ['0.1', '0000.1000000000000', 0],
// a is lower
'lower 1' => ['0', '1', -1],
'lower 2' => ['-1', '0', -1],
'lower 3' => ['-1', '0.0001', -1],
'lower 4' => ['-2', '-1', -1],
'lower 5' => ['-02', '-1', -1],
'lower 6' => ['-2', '-01', -1],
'lower 8' => ['10', '100', -1],
'lower 9' => ['-1.000001', '-1', -1],
'lower 10' => ['-1000.000001', '-10.0001', -1],
];
}
public function provideToNegativeTransformationCases()
{
return [
['1.2345', '-1.2345'],
['-1.2345', '-1.2345'],
['0', '0'],
['-0', '0'],
];
}
public function provideToPositiveTransformationCases()
{
return [
['-1.2345', '1.2345'],
['1.2345', '1.2345'],
['0', '0'],
['-0', '0'],
];
}
}
xxxxx1.0, XXX xxxx