Problems Using Builtin PHP Functions Directly As Excel Functions (#1799)
* Problems Using Builtin PHP Functions Directly As Excel Functions This fixes issue #1789. As originally reported, stricter typing was causing PHP8 to throw an exception when a non-numeric value was passed to the Round function. Previous releases of PHP did not see this problem, however, on further analysis, they were also incorrect in returning 0 as the result in the erroneous situation, when they should have been returning a VALUE error. Yet more analysis showed that other functions would also have problems, and, in addition, might not handle invalid input (e.g. a negative length passed to REPT) or output (e.g. NAN in the case of ACOS(2)) correctly. The following MathTrig functions are affected: ABS, ACOS, ACOSH, ASIN, ASINH, ATAN, ATANH, COS, COSH, DEGREES (rad2deg), EXP, LN (log), LOG10, RADIANS (deg2rad), REPT (str_repeat), SIN, SINH, SQRT, TAN, TANH. One TextData function (REPT) is also affected. This change lets PhpSpreadsheet validate the input for each of these functions before passing control to the builtin, and handle the output afterwards. There were no explicit tests for any of these functions, a fact made easy to ignore by the fact that PhpSpreadsheet delegated the heavy lifting to PHP itself for these cases. A full suite of tests is now added for each of the affected functions. * Scrutinizer Recommendations Only in 3 modules which are part of this PR. * Improved Handling of Tan(PI/2) Return DIV0 error for TAN when COS is very small. * Additional Trig Tests Results which should be infinity, i.e. DIV/0 error.
This commit is contained in:
parent
ec51b75fee
commit
4134ff246a
|
|
@ -228,7 +228,7 @@ class Calculation
|
|||
private static $phpSpreadsheetFunctions = [
|
||||
'ABS' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'abs',
|
||||
'functionCall' => [MathTrig::class, 'builtinABS'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'ACCRINT' => [
|
||||
|
|
@ -243,12 +243,12 @@ class Calculation
|
|||
],
|
||||
'ACOS' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'acos',
|
||||
'functionCall' => [MathTrig::class, 'builtinACOS'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'ACOSH' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'acosh',
|
||||
'functionCall' => [MathTrig::class, 'builtinACOSH'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'ACOT' => [
|
||||
|
|
@ -303,17 +303,17 @@ class Calculation
|
|||
],
|
||||
'ASIN' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'asin',
|
||||
'functionCall' => [MathTrig::class, 'builtinASIN'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'ASINH' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'asinh',
|
||||
'functionCall' => [MathTrig::class, 'builtinASINH'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'ATAN' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'atan',
|
||||
'functionCall' => [MathTrig::class, 'builtinATAN'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'ATAN2' => [
|
||||
|
|
@ -323,7 +323,7 @@ class Calculation
|
|||
],
|
||||
'ATANH' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'atanh',
|
||||
'functionCall' => [MathTrig::class, 'builtinATANH'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'AVEDEV' => [
|
||||
|
|
@ -604,12 +604,12 @@ class Calculation
|
|||
],
|
||||
'COS' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'cos',
|
||||
'functionCall' => [MathTrig::class, 'builtinCOS'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'COSH' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'cosh',
|
||||
'functionCall' => [MathTrig::class, 'builtinCOSH'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'COT' => [
|
||||
|
|
@ -834,7 +834,7 @@ class Calculation
|
|||
],
|
||||
'DEGREES' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'rad2deg',
|
||||
'functionCall' => [MathTrig::class, 'builtinDEGREES'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'DELTA' => [
|
||||
|
|
@ -974,7 +974,7 @@ class Calculation
|
|||
],
|
||||
'EXP' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'exp',
|
||||
'functionCall' => [MathTrig::class, 'builtinEXP'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'EXPONDIST' => [
|
||||
|
|
@ -1565,7 +1565,7 @@ class Calculation
|
|||
],
|
||||
'LN' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'log',
|
||||
'functionCall' => [MathTrig::class, 'builtinLN'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'LOG' => [
|
||||
|
|
@ -1575,7 +1575,7 @@ class Calculation
|
|||
],
|
||||
'LOG10' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'log10',
|
||||
'functionCall' => [MathTrig::class, 'builtinLOG10'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'LOGEST' => [
|
||||
|
|
@ -2037,7 +2037,7 @@ class Calculation
|
|||
],
|
||||
'RADIANS' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'deg2rad',
|
||||
'functionCall' => [MathTrig::class, 'builtinRADIANS'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'RAND' => [
|
||||
|
|
@ -2092,7 +2092,7 @@ class Calculation
|
|||
],
|
||||
'REPT' => [
|
||||
'category' => Category::CATEGORY_TEXT_AND_DATA,
|
||||
'functionCall' => 'str_repeat',
|
||||
'functionCall' => [TextData::class, 'builtinREPT'],
|
||||
'argumentCount' => '2',
|
||||
],
|
||||
'RIGHT' => [
|
||||
|
|
@ -2112,7 +2112,7 @@ class Calculation
|
|||
],
|
||||
'ROUND' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'round',
|
||||
'functionCall' => [MathTrig::class, 'builtinROUND'],
|
||||
'argumentCount' => '2',
|
||||
],
|
||||
'ROUNDDOWN' => [
|
||||
|
|
@ -2203,12 +2203,12 @@ class Calculation
|
|||
],
|
||||
'SIN' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'sin',
|
||||
'functionCall' => [MathTrig::class, 'builtinSIN'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'SINH' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'sinh',
|
||||
'functionCall' => [MathTrig::class, 'builtinSINH'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'SKEW' => [
|
||||
|
|
@ -2248,7 +2248,7 @@ class Calculation
|
|||
],
|
||||
'SQRT' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'sqrt',
|
||||
'functionCall' => [MathTrig::class, 'builtinSQRT'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'SQRTPI' => [
|
||||
|
|
@ -2364,12 +2364,12 @@ class Calculation
|
|||
],
|
||||
'TAN' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'tan',
|
||||
'functionCall' => [MathTrig::class, 'builtinTAN'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'TANH' => [
|
||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||
'functionCall' => 'tanh',
|
||||
'functionCall' => [MathTrig::class, 'builtinTANH'],
|
||||
'argumentCount' => '1',
|
||||
],
|
||||
'TBILLEQ' => [
|
||||
|
|
|
|||
|
|
@ -39,6 +39,13 @@ class MathTrig
|
|||
return ($num - ($num % $n)) / $n;
|
||||
}
|
||||
|
||||
private static function strSplit(string $roman): array
|
||||
{
|
||||
$rslt = str_split($roman);
|
||||
|
||||
return is_array($rslt) ? $rslt : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* ARABIC.
|
||||
*
|
||||
|
|
@ -66,7 +73,7 @@ class MathTrig
|
|||
}
|
||||
|
||||
try {
|
||||
$arabic = self::calculateArabic(str_split($roman));
|
||||
$arabic = self::calculateArabic(self::strSplit($roman));
|
||||
} catch (Exception $e) {
|
||||
return Functions::VALUE(); // Invalid character detected
|
||||
}
|
||||
|
|
@ -1666,7 +1673,7 @@ class MathTrig
|
|||
|
||||
$result = cos($angle);
|
||||
|
||||
return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
|
||||
return self::verySmallDivisor($result) ? Functions::DIV0() : (1 / $result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1710,7 +1717,7 @@ class MathTrig
|
|||
|
||||
$result = sin($angle);
|
||||
|
||||
return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
|
||||
return self::verySmallDivisor($result) ? Functions::DIV0() : (1 / $result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1752,9 +1759,9 @@ class MathTrig
|
|||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
$result = tan($angle);
|
||||
$result = sin($angle);
|
||||
|
||||
return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
|
||||
return self::verySmallDivisor($result) ? Functions::DIV0() : (cos($angle) / $result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1799,6 +1806,18 @@ class MathTrig
|
|||
return (M_PI / 2) - atan($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return NAN or value depending on argument.
|
||||
*
|
||||
* @param float $result Number
|
||||
*
|
||||
* @return float|string
|
||||
*/
|
||||
public static function numberOrNan($result)
|
||||
{
|
||||
return is_nan($result) ? Functions::NAN() : $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* ACOTH.
|
||||
*
|
||||
|
|
@ -1818,6 +1837,412 @@ class MathTrig
|
|||
|
||||
$result = log(($number + 1) / ($number - 1)) / 2;
|
||||
|
||||
return is_nan($result) ? Functions::NAN() : $result;
|
||||
return self::numberOrNan($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* ROUND.
|
||||
*
|
||||
* Returns the result of builtin function round after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
* @param mixed $precision Should be int
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinROUND($number, $precision)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number) || !is_numeric($precision)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return round($number, $precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* ABS.
|
||||
*
|
||||
* Returns the result of builtin function abs after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|int|string Rounded number
|
||||
*/
|
||||
public static function builtinABS($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return abs($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* ACOS.
|
||||
*
|
||||
* Returns the result of builtin function acos after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinACOS($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return self::numberOrNan(acos($number));
|
||||
}
|
||||
|
||||
/**
|
||||
* ACOSH.
|
||||
*
|
||||
* Returns the result of builtin function acosh after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinACOSH($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return self::numberOrNan(acosh($number));
|
||||
}
|
||||
|
||||
/**
|
||||
* ASIN.
|
||||
*
|
||||
* Returns the result of builtin function asin after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinASIN($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return self::numberOrNan(asin($number));
|
||||
}
|
||||
|
||||
/**
|
||||
* ASINH.
|
||||
*
|
||||
* Returns the result of builtin function asinh after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinASINH($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return asinh($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* ASIN.
|
||||
*
|
||||
* Returns the result of builtin function atan after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinATAN($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return self::numberOrNan(atan($number));
|
||||
}
|
||||
|
||||
/**
|
||||
* ATANH.
|
||||
*
|
||||
* Returns the result of builtin function atanh after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinATANH($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return atanh($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* COS.
|
||||
*
|
||||
* Returns the result of builtin function cos after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinCOS($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return cos($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* COSH.
|
||||
*
|
||||
* Returns the result of builtin function cos after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinCOSH($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return cosh($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* DEGREES.
|
||||
*
|
||||
* Returns the result of builtin function rad2deg after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinDEGREES($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return rad2deg($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* EXP.
|
||||
*
|
||||
* Returns the result of builtin function exp after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinEXP($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return exp($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* LN.
|
||||
*
|
||||
* Returns the result of builtin function log after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinLN($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return log($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* LOG10.
|
||||
*
|
||||
* Returns the result of builtin function log after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinLOG10($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return log10($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* RADIANS.
|
||||
*
|
||||
* Returns the result of builtin function deg2rad after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinRADIANS($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return deg2rad($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* SIN.
|
||||
*
|
||||
* Returns the result of builtin function sin after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinSIN($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return sin($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* SINH.
|
||||
*
|
||||
* Returns the result of builtin function sinh after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinSINH($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return sinh($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* SQRT.
|
||||
*
|
||||
* Returns the result of builtin function sqrt after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinSQRT($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return self::numberOrNan(sqrt($number));
|
||||
}
|
||||
|
||||
/**
|
||||
* TAN.
|
||||
*
|
||||
* Returns the result of builtin function tan after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinTAN($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return self::verySmallDivisor(cos($number)) ? Functions::DIV0() : tan($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* TANH.
|
||||
*
|
||||
* Returns the result of builtin function sinh after validating args.
|
||||
*
|
||||
* @param mixed $number Should be numeric
|
||||
*
|
||||
* @return float|string Rounded number
|
||||
*/
|
||||
public static function builtinTANH($number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return tanh($number);
|
||||
}
|
||||
|
||||
private static function verySmallDivisor(float $number): bool
|
||||
{
|
||||
return abs($number) < 1.0E-12;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ class TextData
|
|||
if (!is_numeric($value) || !is_numeric($decimals)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
$decimals = floor($decimals);
|
||||
$decimals = (int) $decimals;
|
||||
|
||||
$mask = '$#,##0';
|
||||
if ($decimals > 0) {
|
||||
|
|
@ -673,4 +673,25 @@ class TextData
|
|||
|
||||
return implode($delimiter, $aArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* REPT.
|
||||
*
|
||||
* Returns the result of builtin function round after validating args.
|
||||
*
|
||||
* @param string $str Should be numeric
|
||||
* @param mixed $number Should be int
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function builtinREPT($str, $number)
|
||||
{
|
||||
$number = Functions::flattenSingleValue($number);
|
||||
|
||||
if (!is_numeric($number) || $number < 0) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
return str_repeat($str, $number);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class AbsTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerAbs
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testRound($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=ABS()';
|
||||
} else {
|
||||
$formula = "=ABS($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
|
||||
}
|
||||
|
||||
public function providerAbs()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/ABS.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class AcosTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerAcos
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testAcos($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=ACOS()';
|
||||
} else {
|
||||
$formula = "=ACOS($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerAcos()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/ACOS.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class AcoshTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerAcosh
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testAcosh($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=ACOSH()';
|
||||
} else {
|
||||
$formula = "=ACOSH($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerAcosh()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/ACOSH.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class AsinTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerAsin
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testAsin($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=ASIN()';
|
||||
} else {
|
||||
$formula = "=ASIN($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerAsin()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/ASIN.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class AsinhTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerAsinh
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testAsinh($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=ASINH()';
|
||||
} else {
|
||||
$formula = "=ASINH($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerAsinh()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/ASINH.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class AtanTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerAtan
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testAtan($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=ATAN()';
|
||||
} else {
|
||||
$formula = "=ATAN($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerAtan()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/ATAN.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class AtanhTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerAtanh
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testAtan($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=ATANH()';
|
||||
} else {
|
||||
$formula = "=ATANH($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerAtanh()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/ATANH.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CosTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerCos
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testCos($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=COS()';
|
||||
} else {
|
||||
$formula = "=COS($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerCos()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/COS.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CoshTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerCosh
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testCosh($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=COSH()';
|
||||
} else {
|
||||
$formula = "=COSH($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerCosh()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/COSH.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class DegreesTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerDEGREES
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testDEGREES($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=DEGREES()';
|
||||
} else {
|
||||
$formula = "=DEGREES($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerDegrees()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/DEGREES.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ExpTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerEXP
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testEXP($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=EXP()';
|
||||
} else {
|
||||
$formula = "=EXP($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerEXP()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/EXP.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class LnTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerLN
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testLN($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=LN()';
|
||||
} else {
|
||||
$formula = "=LN($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerLN()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/LN.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class Log10Test extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerLN
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testLN($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=LOG10()';
|
||||
} else {
|
||||
$formula = "=LOG10($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerLN()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/LOG10.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class RadiansTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerRADIANS
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testRADIANS($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=RADIANS()';
|
||||
} else {
|
||||
$formula = "=RADIANS($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerRADIANS()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/RADIANS.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class RoundTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerRound
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
* @param mixed $precision
|
||||
*/
|
||||
public function testRound($expectedResult, $val = null, $precision = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=ROUND()';
|
||||
} elseif ($precision === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = "=ROUND($val)";
|
||||
} else {
|
||||
$formula = "=ROUND($val, $precision)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
|
||||
}
|
||||
|
||||
public function providerRound()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/ROUND.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class SinTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerSin
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testSin($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=SIN()';
|
||||
} else {
|
||||
$formula = "=SIN($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerSin()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/SIN.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class SinhTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerCosh
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testSinh($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=SINH()';
|
||||
} else {
|
||||
$formula = "=SINH($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerCosh()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/SINH.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class SqrtTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerSQRT
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testSQRT($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=SQRT()';
|
||||
} else {
|
||||
$formula = "=SQRT($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerSqrt()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/SQRT.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class TanTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerTan
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testTan($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=TAN()';
|
||||
} else {
|
||||
$formula = "=TAN($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerTan()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/TAN.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class TanhTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerTanh
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function testTanh($expectedResult, $val = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=TANH()';
|
||||
} else {
|
||||
$formula = "=TANH($val)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-6);
|
||||
}
|
||||
|
||||
public function providerTanh()
|
||||
{
|
||||
return require 'tests/data/Calculation/MathTrig/TANH.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ReptTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerREPT
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $val
|
||||
* @param mixed $rpt
|
||||
*/
|
||||
public function testRound($expectedResult, $val = null, $rpt = null): void
|
||||
{
|
||||
if ($val === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = '=REPT()';
|
||||
} elseif ($rpt === null) {
|
||||
$this->expectException(CalcExp::class);
|
||||
$formula = "=REPT($val)";
|
||||
} else {
|
||||
$formula = "=REPT($val, $rpt)";
|
||||
}
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('A1')->setValue($formula);
|
||||
$result = $sheet->getCell('A1')->getCalculatedValue();
|
||||
self::assertEquals($expectedResult, $result);
|
||||
}
|
||||
|
||||
public function providerREPT()
|
||||
{
|
||||
return require 'tests/data/Calculation/TextData/REPT.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception - not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[35.51, '"35.51"'],
|
||||
[35.51, 35.51],
|
||||
[35.51, -35.51],
|
||||
[6, '"6"'],
|
||||
[7, '"-7"'],
|
||||
[0, 0],
|
||||
];
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception - not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[1.570796, 0],
|
||||
[3.141593, -1],
|
||||
[0, 1],
|
||||
['#NUM!', 2],
|
||||
];
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception - not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[1.316958, 2],
|
||||
[0, 1],
|
||||
['#NUM!', 0],
|
||||
['#NUM!', -1],
|
||||
];
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception - not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[1.570796, 1],
|
||||
[-1.570796, -1],
|
||||
[0, 0],
|
||||
['#NUM!', 2],
|
||||
];
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception - not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[0, 0],
|
||||
[0.881374, 1],
|
||||
[1.443635, 2],
|
||||
[-0.881374, -1],
|
||||
[14.508658, 1000000],
|
||||
// ['#NUM!', 2], Don't know if NAN is possible
|
||||
];
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception - not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[0, 0],
|
||||
[0.785398, 1],
|
||||
[1.107149, 2],
|
||||
[-0.785398, -1],
|
||||
[1.570795, 1000000],
|
||||
// ['#NUM!', 2], Believe NAN is not possible
|
||||
];
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception - not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[0, 0],
|
||||
[1.472219, 0.9],
|
||||
[-1.472219, -0.9],
|
||||
['#NUM!', 1],
|
||||
['#NUM!', -1],
|
||||
];
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[1, 0],
|
||||
[0, M_PI / 2],
|
||||
[0.540302, 1.0],
|
||||
[0.540302, -1.0],
|
||||
[-0.416147, 2.0],
|
||||
[-0.416147, -2.0],
|
||||
];
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[1, 0],
|
||||
[1.543081, 1],
|
||||
[1.543081, -1.0],
|
||||
[3.762196, 2.0],
|
||||
[11013.23292, 10],
|
||||
];
|
||||
|
|
@ -25,6 +25,14 @@ return [
|
|||
'#DIV/0!',
|
||||
0.0,
|
||||
],
|
||||
[
|
||||
'#DIV/0!',
|
||||
M_PI,
|
||||
],
|
||||
[
|
||||
'#DIV/0!',
|
||||
-M_PI,
|
||||
],
|
||||
[
|
||||
9.96664442325924,
|
||||
0.1,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,14 @@ return [
|
|||
'#DIV/0!',
|
||||
0.0,
|
||||
],
|
||||
[
|
||||
'#DIV/0!',
|
||||
M_PI,
|
||||
],
|
||||
[
|
||||
'#DIV/0!',
|
||||
-M_PI,
|
||||
],
|
||||
[
|
||||
10.01668613163480,
|
||||
0.1,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[45, M_PI / 4],
|
||||
];
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[2.718282, 1],
|
||||
];
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
['#NUM!', 0],
|
||||
['#NUM!', -1],
|
||||
[-2.302585, 0.1],
|
||||
[0, 1],
|
||||
[2.302585, 10],
|
||||
];
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
['#NUM!', 0],
|
||||
['#NUM!', -1],
|
||||
[-1, 0.1],
|
||||
[0, 1],
|
||||
[0.301030, 2],
|
||||
[1, 10],
|
||||
];
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[M_PI / 4, 45],
|
||||
];
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception - not enough args
|
||||
['#VALUE!', '"ABC"', 1],
|
||||
['#VALUE!', 35.51, '"test"'],
|
||||
['#VALUE!', 35.51], // exception - not enough args
|
||||
[35.5, '"35.51"', '"1"'],
|
||||
[35.5, 35.51, 1],
|
||||
[40, 35.51, -1],
|
||||
];
|
||||
|
|
@ -21,6 +21,14 @@ return [
|
|||
-1.0,
|
||||
-M_PI,
|
||||
],
|
||||
[
|
||||
'#DIV/0!',
|
||||
M_PI_2,
|
||||
],
|
||||
[
|
||||
'#DIV/0!',
|
||||
-M_PI_2,
|
||||
],
|
||||
[
|
||||
14.13683290296990,
|
||||
-1.5,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[0, 0],
|
||||
[1, M_PI / 2],
|
||||
[0.891207, 1.1],
|
||||
[-0.891207, -1.1],
|
||||
[0.909297, 2.0],
|
||||
];
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[0, 0],
|
||||
[1.175201, 1],
|
||||
[-1.175201, -1.0],
|
||||
[3.626860, 2.0],
|
||||
];
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[0, 0],
|
||||
[1.5, 2.25],
|
||||
[1.772454, M_PI],
|
||||
['#NUM!', -2.1],
|
||||
];
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[0, 0],
|
||||
[1.557408, 1],
|
||||
[-2.185040, 2],
|
||||
[1, M_PI / 4],
|
||||
['#DIV/0!', M_PI_2],
|
||||
['#DIV/0!', -M_PI_2],
|
||||
['#DIV/0!', 3 * M_PI_2],
|
||||
];
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception not enough args
|
||||
['#VALUE!', '"ABC"'],
|
||||
[0, 0],
|
||||
[0.761594, 1],
|
||||
[-0.761594, -1],
|
||||
[0.970452, 2.1],
|
||||
];
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
['#VALUE!'], // exception not enough args
|
||||
['#VALUE!', '"ABC"'], // exception not enough args
|
||||
['#VALUE!', '"ABC"', '"DEF"'],
|
||||
['ABCABCABC', '"ABC"', 3],
|
||||
['ABCABC', '"ABC"', 2.2],
|
||||
['', '"ABC"', 0],
|
||||
['#VALUE!', '"ABC"', -1],
|
||||
];
|
||||
Loading…
Reference in New Issue