Files
oleibman 31174c1c90 Set All Locale Variables at Once in a Threadsafe Manner
Fix #954, which went stale 6 years ago and which I have now reopened. The `setLocale` method in `Calculation` and `Settings` does not affect the 3 localizable properties in `StringHelper` - `currencyCode`, `decimalSeparator`, and `thousandsSeparator`. One way to work around this problem is to set those properties separately; this is probably how most people handle it. Another way is to call Php's own `setlocale` function; this does not require any foreknowledge of what the values need to be, but it comes with baggage (data is maintained at process level rather than thread level), so its use is discouraged.

This PR adds a new `setLocale` method to `StringHelper`. It sets the 3 properties and the `Calculation` language all at once. It depends on the `Intl` extension, which is a recommendation but not a formal requirement for PhpSpreadsheet; the method will return `false` if `Intl` is not available or it thinks the supplied locale is not valid.
2025-12-25 19:24:44 -08:00

173 lines
5.9 KiB
PHP

<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Engineering\ConvertUOM;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalculationException;
use PhpOffice\PhpSpreadsheetTests\Calculation\Functions\FormulaArguments;
use PHPUnit\Framework\Attributes\DataProvider;
class ConvertUoMTest extends AllSetupTeardown
{
const UOM_PRECISION = 1E-12;
public function testGetConversionGroups(): void
{
$result = ConvertUOM::getConversionCategories();
self::assertContains('Weight and Mass', $result);
}
public function testGetConversionGroupUnits(): void
{
$result = ConvertUOM::getConversionCategoryUnits();
self::assertArrayHasKey('Speed', $result);
self::assertContains('mph', $result['Speed']);
}
public function testGetConversionGroupUnitDetails(): void
{
$result = ConvertUOM::getConversionCategoryUnitDetails();
self::assertArrayHasKey('Information', $result);
self::assertContains(['unit' => 'byte', 'description' => 'Byte'], $result['Information']);
}
public function testGetConversionMultipliers(): void
{
$result = ConvertUOM::getConversionMultipliers();
self::assertArrayHasKey('k', $result);
self::assertSame(['multiplier' => 1000.0, 'name' => 'kilo'], $result['k']);
}
public function testGetBinaryConversionMultipliers(): void
{
$result = ConvertUOM::getBinaryConversionMultipliers();
self::assertArrayHasKey('ki', $result);
self::assertSame(['multiplier' => 1024, 'name' => 'kibi'], $result['ki']);
}
#[DataProvider('providerCONVERTUOM')]
public function testDirectCallToCONVERTUOM(float|int|string $expectedResult, float|int|string $value, string $from, string $to): void
{
$result = ConvertUOM::convert($value, $from, $to);
self::assertEqualsWithDelta($expectedResult, $result, self::UOM_PRECISION);
}
#[DataProvider('providerCONVERTUOM')]
public function testCONVERTUOMAsFormula(mixed $expectedResult, mixed ...$args): void
{
$arguments = new FormulaArguments(...$args);
$calculation = Calculation::getInstance();
$formula = "=CONVERT({$arguments})";
$result = $calculation->calculateFormula($formula);
self::assertEqualsWithDelta($expectedResult, $result, self::UOM_PRECISION);
}
#[DataProvider('providerCONVERTUOM')]
public function testCONVERTUOMInWorksheet(mixed $expectedResult, mixed ...$args): void
{
$arguments = new FormulaArguments(...$args);
$worksheet = $this->getSheet();
$argumentCells = $arguments->populateWorksheet($worksheet);
$formula = "=CONVERT({$argumentCells})";
$result = $worksheet->setCellValue('A1', $formula)
->getCell('A1')
->getCalculatedValue();
self::assertEqualsWithDelta($expectedResult, $result, self::UOM_PRECISION);
}
/** @return mixed[] */
public static function providerCONVERTUOM(): array
{
/** @var mixed[] */
$return = require 'tests/data/Calculation/Engineering/CONVERTUOM.php';
return $return;
}
#[DataProvider('providerUnhappyCONVERTUOM')]
public function testCONVERTUOMUnhappyPath(string $expectedException, mixed ...$args): void
{
$arguments = new FormulaArguments(...$args);
$worksheet = $this->getSheet();
$argumentCells = $arguments->populateWorksheet($worksheet);
$formula = "=CONVERT({$argumentCells})";
$this->expectException(CalculationException::class);
$this->expectExceptionMessage($expectedException);
$worksheet->setCellValue('A1', $formula)
->getCell('A1')
->getCalculatedValue();
}
public static function providerUnhappyCONVERTUOM(): array
{
return [
['Formula Error: Wrong number of arguments for CONVERT() function'],
['Formula Error: Wrong number of arguments for CONVERT() function', 12.34],
['Formula Error: Wrong number of arguments for CONVERT() function', 12.34, 'kg'],
];
}
/** @param float[][] $expectedResult */
#[DataProvider('providerConvertUoMArray')]
public function testConvertUoMArray(array $expectedResult, string $value, string $fromUoM, string $toUoM): void
{
$calculation = Calculation::getInstance();
$formula = "=CONVERT({$value}, {$fromUoM}, {$toUoM})";
$result = $calculation->calculateFormula($formula);
self::assertEqualsWithDelta($expectedResult, $result, self::UOM_PRECISION);
}
/** @return mixed[] */
public static function providerConvertUoMArray(): array
{
return [
'Weight/Mass' => [
[
[71.42857142857142, 0.15747304441777],
[453.5923699999991, 1.0],
],
'1000',
'{"lbm", "g"}',
'{"stone"; "kg"}',
],
'Distance' => [
[
[2025371.8285214372, 1093.6132983377101],
[1851.9999999999984, 1.0],
],
'1000',
'{"Nmi", "m"}',
'{"yd"; "km"}',
],
'Volume' => [
[
[2.976190476190475, 0.00628981077043211],
[473.1764729999994, 1.0],
],
'1000',
'{"pt", "ml"}',
'{"barrel"; "l"}',
],
'Area' => [
[
[999.9960000040016, 0.247104393046628],
[404.6856422400005, 0.1],
],
'1000',
'{"uk_acre", "m2"}',
'{"us_acre"; "ha"}',
],
];
}
}