NumberTest.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. <?php
  2. /**
  3. * NumberTest file
  4. *
  5. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  6. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  7. *
  8. * Licensed under The MIT License
  9. * For full copyright and license information, please see the LICENSE.txt
  10. * Redistributions of files must retain the above copyright notice
  11. *
  12. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  13. * @link https://cakephp.org CakePHP(tm) Project
  14. * @since 1.2.0
  15. * @license https://opensource.org/licenses/mit-license.php MIT License
  16. */
  17. namespace Cake\Test\TestCase\I18n;
  18. use Cake\I18n\I18n;
  19. use Cake\I18n\Number;
  20. use Cake\TestSuite\TestCase;
  21. /**
  22. * NumberTest class
  23. */
  24. class NumberTest extends TestCase
  25. {
  26. /**
  27. * Backup the locale property
  28. *
  29. * @var string
  30. */
  31. protected $locale;
  32. /**
  33. * setUp method
  34. *
  35. * @return void
  36. */
  37. public function setUp()
  38. {
  39. parent::setUp();
  40. $this->Number = new Number();
  41. $this->locale = I18n::getLocale();
  42. }
  43. /**
  44. * tearDown method
  45. *
  46. * @return void
  47. */
  48. public function tearDown()
  49. {
  50. parent::tearDown();
  51. unset($this->Number);
  52. I18n::setLocale($this->locale);
  53. Number::setDefaultCurrency();
  54. Number::setDefaultCurrencyFormat();
  55. }
  56. /**
  57. * testFormatAndCurrency method
  58. *
  59. * @return void
  60. */
  61. public function testFormat()
  62. {
  63. $value = '100100100';
  64. $result = $this->Number->format($value);
  65. $expected = '100,100,100';
  66. $this->assertEquals($expected, $result);
  67. $result = $this->Number->format($value, ['before' => '#']);
  68. $expected = '#100,100,100';
  69. $this->assertEquals($expected, $result);
  70. $result = $this->Number->format($value, ['places' => 3]);
  71. $expected = '100,100,100.000';
  72. $this->assertEquals($expected, $result);
  73. $result = $this->Number->format($value, ['locale' => 'es_VE']);
  74. $expected = '100.100.100';
  75. $this->assertEquals($expected, $result);
  76. $value = 0.00001;
  77. $result = $this->Number->format($value, ['places' => 1, 'before' => '$']);
  78. $expected = '$0.0';
  79. $this->assertEquals($expected, $result);
  80. $value = -0.00001;
  81. $result = $this->Number->format($value, ['places' => 1, 'before' => '$']);
  82. $expected = '$-0.0';
  83. $this->assertEquals($expected, $result);
  84. $value = 1.23;
  85. $options = ['locale' => 'fr_FR', 'after' => ' €'];
  86. $result = $this->Number->format($value, $options);
  87. $expected = '1,23 €';
  88. $this->assertEquals($expected, $result);
  89. }
  90. /**
  91. * testParseFloat method
  92. *
  93. * @return void
  94. */
  95. public function testParseFloat()
  96. {
  97. I18n::setLocale('de_DE');
  98. $value = '1.234.567,891';
  99. $result = $this->Number->parseFloat($value);
  100. $expected = 1234567.891;
  101. $this->assertEquals($expected, $result);
  102. I18n::setLocale('pt_BR');
  103. $value = '1.234,37';
  104. $result = $this->Number->parseFloat($value);
  105. $expected = 1234.37;
  106. $this->assertEquals($expected, $result);
  107. $value = '1,234.37';
  108. $result = $this->Number->parseFloat($value, ['locale' => 'en_US']);
  109. $expected = 1234.37;
  110. $this->assertEquals($expected, $result);
  111. }
  112. /**
  113. * testFormatDelta method
  114. *
  115. * @return void
  116. */
  117. public function testFormatDelta()
  118. {
  119. $value = '100100100';
  120. $result = $this->Number->formatDelta($value, ['places' => 0]);
  121. $expected = '+100,100,100';
  122. $this->assertEquals($expected, $result);
  123. $result = $this->Number->formatDelta($value, ['before' => '', 'after' => '']);
  124. $expected = '+100,100,100';
  125. $this->assertEquals($expected, $result);
  126. $result = $this->Number->formatDelta($value, ['before' => '[', 'after' => ']']);
  127. $expected = '[+100,100,100]';
  128. $this->assertEquals($expected, $result);
  129. $result = $this->Number->formatDelta(-$value, ['before' => '[', 'after' => ']']);
  130. $expected = '[-100,100,100]';
  131. $this->assertEquals($expected, $result);
  132. $result = $this->Number->formatDelta(-$value, ['before' => '[ ', 'after' => ' ]']);
  133. $expected = '[ -100,100,100 ]';
  134. $this->assertEquals($expected, $result);
  135. $value = 0;
  136. $result = $this->Number->formatDelta($value, ['places' => 1, 'before' => '[', 'after' => ']']);
  137. $expected = '[0.0]';
  138. $this->assertEquals($expected, $result);
  139. $value = 0.0001;
  140. $result = $this->Number->formatDelta($value, ['places' => 1, 'before' => '[', 'after' => ']']);
  141. $expected = '[0.0]';
  142. $this->assertEquals($expected, $result);
  143. $value = 9876.1234;
  144. $result = $this->Number->formatDelta($value, ['places' => 1, 'locale' => 'de_DE']);
  145. $expected = '+9.876,1';
  146. $this->assertEquals($expected, $result);
  147. }
  148. /**
  149. * Test currency method.
  150. *
  151. * @return void
  152. */
  153. public function testCurrency()
  154. {
  155. $value = '100100100';
  156. $result = $this->Number->currency($value);
  157. $expected = '$100,100,100.00';
  158. $this->assertEquals($expected, $result);
  159. $result = $this->Number->currency($value, 'USD');
  160. $expected = '$100,100,100.00';
  161. $this->assertEquals($expected, $result);
  162. $result = $this->Number->currency($value, 'EUR');
  163. $expected = '€100,100,100.00';
  164. $this->assertEquals($expected, $result);
  165. $result = $this->Number->currency($value, 'EUR', ['locale' => 'de_DE']);
  166. $expected = '100.100.100,00 €';
  167. $this->assertEquals($expected, $result);
  168. $result = $this->Number->currency($value, 'USD', ['locale' => 'de_DE']);
  169. $expected = '100.100.100,00 $';
  170. $this->assertEquals($expected, $result);
  171. $result = $this->Number->currency($value, 'USD', ['locale' => 'en_US']);
  172. $expected = '$100,100,100.00';
  173. $this->assertEquals($expected, $result);
  174. $result = $this->Number->currency($value, 'USD', ['locale' => 'en_CA']);
  175. $expected = 'US$100,100,100.00';
  176. $this->assertEquals($expected, $result);
  177. $options = ['locale' => 'en_IN', 'pattern' => "Rs'.' #,##,###"];
  178. $result = $this->Number->currency($value, 'INR', $options);
  179. $expected = 'Rs. 10,01,00,100';
  180. $this->assertEquals($expected, $result);
  181. $result = $this->Number->currency($value, 'GBP');
  182. $expected = '£100,100,100.00';
  183. $this->assertEquals($expected, $result);
  184. $result = $this->Number->currency($value, 'GBP', ['locale' => 'da_DK']);
  185. $expected = '100.100.100,00 £';
  186. $this->assertEquals($expected, $result);
  187. $options = ['locale' => 'fr_FR', 'pattern' => 'EUR #,###.00'];
  188. $result = $this->Number->currency($value, 'EUR', $options);
  189. // The following tests use regexp because whitespace used
  190. // is inconsistent between *nix & windows.
  191. $expected = '/^EUR\W+100\W+100\W+100,00$/';
  192. $this->assertRegExp($expected, $result);
  193. $options = ['locale' => 'fr_FR', 'pattern' => '#,###.00 ¤¤'];
  194. $result = $this->Number->currency($value, 'EUR', $options);
  195. $expected = '/^100\W+100\W+100,00\W+EUR$/';
  196. $this->assertRegExp($expected, $result);
  197. $options = ['locale' => 'fr_FR', 'pattern' => '#,###.00;(¤#,###.00)'];
  198. $result = $this->Number->currency(-1235.03, 'EUR', $options);
  199. $expected = '/^\(€1\W+235,03\)$/';
  200. $this->assertRegExp($expected, $result);
  201. $result = $this->Number->currency(0.5, 'USD', ['locale' => 'en_US', 'fractionSymbol' => 'c']);
  202. $expected = '50c';
  203. $this->assertEquals($expected, $result);
  204. $options = ['fractionSymbol' => ' cents'];
  205. $result = $this->Number->currency(0.2, 'USD', $options);
  206. $expected = '20 cents';
  207. $this->assertEquals($expected, $result);
  208. $options = ['fractionSymbol' => 'cents ', 'fractionPosition' => 'before'];
  209. $result = $this->Number->currency(0.2, null, $options);
  210. $expected = 'cents 20';
  211. $this->assertEquals($expected, $result);
  212. $result = $this->Number->currency(0.2, 'EUR');
  213. $expected = '€0.20';
  214. $this->assertEquals($expected, $result);
  215. $options = ['fractionSymbol' => false, 'fractionPosition' => 'before'];
  216. $result = $this->Number->currency(0.5, null, $options);
  217. $expected = '$0.50';
  218. $this->assertEquals($expected, $result);
  219. $result = $this->Number->currency(0, 'GBP');
  220. $expected = '£0.00';
  221. $this->assertEquals($expected, $result);
  222. $result = $this->Number->currency(0, 'GBP', ['pattern' => '¤#,###.00;¤-#,###.00']);
  223. $expected = '£.00';
  224. $this->assertEquals($expected, $result);
  225. $result = $this->Number->currency(0, 'GBP', ['pattern' => '¤#,##0.00;¤-#,##0.00']);
  226. $expected = '£0.00';
  227. $this->assertEquals($expected, $result);
  228. $result = $this->Number->currency(0.00000, 'GBP');
  229. $expected = '£0.00';
  230. $this->assertEquals($expected, $result);
  231. $result = $this->Number->currency('0.00000', 'GBP');
  232. $expected = '£0.00';
  233. $this->assertEquals($expected, $result);
  234. $result = $this->Number->currency('22.389', 'CAD');
  235. $expected = 'CA$22.39';
  236. $this->assertEquals($expected, $result);
  237. }
  238. /**
  239. * Test currency format with places and fraction exponents.
  240. * Places should only matter for non fraction values and vice versa.
  241. *
  242. * @return void
  243. */
  244. public function testCurrencyWithFractionAndPlaces()
  245. {
  246. $result = $this->Number->currency('1.23', 'EUR', ['locale' => 'de_DE', 'places' => 3]);
  247. $expected = '1,230 €';
  248. $this->assertEquals($expected, $result);
  249. $result = $this->Number->currency('0.23', 'GBP', ['places' => 3, 'fractionSymbol' => 'p']);
  250. $expected = '23p';
  251. $this->assertEquals($expected, $result);
  252. $result = $this->Number->currency('0.001', 'GBP', ['places' => 3, 'fractionSymbol' => 'p']);
  253. $expected = '0p';
  254. $this->assertEquals($expected, $result);
  255. $result = $this->Number->currency('1.23', 'EUR', ['locale' => 'de_DE', 'precision' => 1]);
  256. $expected = '1,2 €';
  257. $this->assertEquals($expected, $result);
  258. }
  259. /**
  260. * Test default currency
  261. *
  262. * @group deprecated
  263. * @return void
  264. */
  265. public function testDefaultCurrency()
  266. {
  267. $this->deprecated(function () {
  268. $this->assertEquals('USD', $this->Number->defaultCurrency());
  269. $this->Number->defaultCurrency(false);
  270. I18n::setLocale('es_ES');
  271. $this->assertEquals('EUR', $this->Number->defaultCurrency());
  272. $this->Number->defaultCurrency('JPY');
  273. $this->assertEquals('JPY', $this->Number->defaultCurrency());
  274. });
  275. }
  276. /**
  277. * Test get default currency
  278. *
  279. * @return void
  280. */
  281. public function testGetDefaultCurrency()
  282. {
  283. $this->assertEquals('USD', $this->Number->getDefaultCurrency());
  284. }
  285. /**
  286. * Test set default currency
  287. *
  288. * @return void
  289. */
  290. public function testSetDefaultCurrency()
  291. {
  292. $this->Number->setDefaultCurrency();
  293. I18n::setLocale('es_ES');
  294. $this->assertEquals('EUR', $this->Number->getDefaultCurrency());
  295. $this->Number->setDefaultCurrency('JPY');
  296. $this->assertEquals('JPY', $this->Number->getDefaultCurrency());
  297. }
  298. /**
  299. * Test get default currency format
  300. *
  301. * @return void
  302. */
  303. public function testGetDefaultCurrencyFormat()
  304. {
  305. $this->assertEquals('currency', $this->Number->getDefaultCurrencyFormat());
  306. }
  307. /**
  308. * Test set default currency format
  309. *
  310. * @return void
  311. */
  312. public function testSetDefaultCurrencyFormat()
  313. {
  314. $this->Number->setDefaultCurrencyFormat(Number::FORMAT_CURRENCY_ACCOUNTING);
  315. $this->assertEquals('currency_accounting', $this->Number->getDefaultCurrencyFormat());
  316. $this->assertEquals('($123.45)', $this->Number->currency(-123.45));
  317. }
  318. /**
  319. * testCurrencyCentsNegative method
  320. *
  321. * @return void
  322. */
  323. public function testCurrencyCentsNegative()
  324. {
  325. $value = '-0.99';
  326. $result = $this->Number->currency($value, 'EUR', ['locale' => 'de_DE']);
  327. $expected = '-0,99 €';
  328. $this->assertEquals($expected, $result);
  329. $result = $this->Number->currency($value, 'USD', ['fractionSymbol' => 'c']);
  330. $expected = '-99c';
  331. $this->assertEquals($expected, $result);
  332. }
  333. /**
  334. * testCurrencyZero method
  335. *
  336. * @return void
  337. */
  338. public function testCurrencyZero()
  339. {
  340. $value = '0';
  341. $result = $this->Number->currency($value, 'USD');
  342. $expected = '$0.00';
  343. $this->assertEquals($expected, $result);
  344. $result = $this->Number->currency($value, 'EUR', ['locale' => 'fr_FR']);
  345. $expected = '0,00 €';
  346. $this->assertEquals($expected, $result);
  347. }
  348. /**
  349. * testCurrencyOptions method
  350. *
  351. * @return void
  352. */
  353. public function testCurrencyOptions()
  354. {
  355. $value = '1234567.89';
  356. $result = $this->Number->currency($value, null, ['before' => 'Total: ']);
  357. $expected = 'Total: $1,234,567.89';
  358. $this->assertEquals($expected, $result);
  359. $result = $this->Number->currency($value, null, ['after' => ' in Total']);
  360. $expected = '$1,234,567.89 in Total';
  361. $this->assertEquals($expected, $result);
  362. }
  363. /**
  364. * Tests that it is possible to use the international currency code instead of the whole
  365. * when using the currency method
  366. *
  367. * @return void
  368. */
  369. public function testCurrencyIntlCode()
  370. {
  371. $value = '123';
  372. $result = $this->Number->currency($value, 'USD', ['useIntlCode' => true]);
  373. $expected = 'USD 123.00';
  374. $this->assertEquals($expected, $result);
  375. $result = $this->Number->currency($value, 'EUR', ['useIntlCode' => true]);
  376. $expected = 'EUR 123.00';
  377. $this->assertEquals($expected, $result);
  378. $result = $this->Number->currency($value, 'EUR', ['useIntlCode' => true, 'locale' => 'da_DK']);
  379. $expected = '123,00 EUR';
  380. $this->assertEquals($expected, $result);
  381. }
  382. /**
  383. * test precision() with locales
  384. *
  385. * @return void
  386. */
  387. public function testPrecisionLocalized()
  388. {
  389. I18n::setLocale('fr_FR');
  390. $result = $this->Number->precision(1.234);
  391. $this->assertEquals('1,234', $result);
  392. }
  393. /**
  394. * testToPercentage method
  395. *
  396. * @return void
  397. */
  398. public function testToPercentage()
  399. {
  400. $result = $this->Number->toPercentage(45, 0);
  401. $expected = '45%';
  402. $this->assertEquals($expected, $result);
  403. $result = $this->Number->toPercentage(45, 2);
  404. $expected = '45.00%';
  405. $this->assertEquals($expected, $result);
  406. $result = $this->Number->toPercentage(0, 0);
  407. $expected = '0%';
  408. $this->assertEquals($expected, $result);
  409. $result = $this->Number->toPercentage(0, 4);
  410. $expected = '0.0000%';
  411. $this->assertEquals($expected, $result);
  412. $result = $this->Number->toPercentage(45, 0, ['multiply' => false]);
  413. $expected = '45%';
  414. $this->assertEquals($expected, $result);
  415. $result = $this->Number->toPercentage(45, 2, ['multiply' => false]);
  416. $expected = '45.00%';
  417. $this->assertEquals($expected, $result);
  418. $result = $this->Number->toPercentage(0, 0, ['multiply' => false]);
  419. $expected = '0%';
  420. $this->assertEquals($expected, $result);
  421. $result = $this->Number->toPercentage(0, 4, ['multiply' => false]);
  422. $expected = '0.0000%';
  423. $this->assertEquals($expected, $result);
  424. $result = $this->Number->toPercentage(0.456, 0, ['multiply' => true]);
  425. $expected = '46%';
  426. $this->assertEquals($expected, $result);
  427. $result = $this->Number->toPercentage(0.456, 2, ['multiply' => true]);
  428. $expected = '45.60%';
  429. $this->assertEquals($expected, $result);
  430. $result = $this->Number->toPercentage(0.456, 2, ['locale' => 'de-DE', 'multiply' => true]);
  431. $expected = '45,60 %';
  432. $this->assertEquals($expected, $result);
  433. $result = $this->Number->toPercentage(13, 0, ['locale' => 'fi_FI']);
  434. $expected = '13 %';
  435. $this->assertEquals($expected, $result);
  436. $result = $this->Number->toPercentage(0.13, 0, ['locale' => 'fi_FI', 'multiply' => true]);
  437. $expected = '13 %';
  438. $this->assertEquals($expected, $result);
  439. }
  440. /**
  441. * testToReadableSize method
  442. *
  443. * @return void
  444. */
  445. public function testToReadableSize()
  446. {
  447. $result = $this->Number->toReadableSize(0);
  448. $expected = '0 Bytes';
  449. $this->assertEquals($expected, $result);
  450. $result = $this->Number->toReadableSize(1);
  451. $expected = '1 Byte';
  452. $this->assertEquals($expected, $result);
  453. $result = $this->Number->toReadableSize(45);
  454. $expected = '45 Bytes';
  455. $this->assertEquals($expected, $result);
  456. $result = $this->Number->toReadableSize(1023);
  457. $expected = '1,023 Bytes';
  458. $this->assertEquals($expected, $result);
  459. $result = $this->Number->toReadableSize(1024);
  460. $expected = '1 KB';
  461. $this->assertEquals($expected, $result);
  462. $result = $this->Number->toReadableSize(1024 + 123);
  463. $expected = '1.12 KB';
  464. $this->assertEquals($expected, $result);
  465. $result = $this->Number->toReadableSize(1024 * 512);
  466. $expected = '512 KB';
  467. $this->assertEquals($expected, $result);
  468. $result = $this->Number->toReadableSize(1024 * 1024 - 1);
  469. $expected = '1 MB';
  470. $this->assertEquals($expected, $result);
  471. $result = $this->Number->toReadableSize(512.05 * 1024 * 1024);
  472. $expected = '512.05 MB';
  473. $this->assertEquals($expected, $result);
  474. $result = $this->Number->toReadableSize(1024 * 1024 * 1024 - 1);
  475. $expected = '1 GB';
  476. $this->assertEquals($expected, $result);
  477. $result = $this->Number->toReadableSize(1024 * 1024 * 1024 * 512);
  478. $expected = '512 GB';
  479. $this->assertEquals($expected, $result);
  480. $result = $this->Number->toReadableSize(1024 * 1024 * 1024 * 1024 - 1);
  481. $expected = '1 TB';
  482. $this->assertEquals($expected, $result);
  483. $result = $this->Number->toReadableSize(1024 * 1024 * 1024 * 1024 * 512);
  484. $expected = '512 TB';
  485. $this->assertEquals($expected, $result);
  486. $result = $this->Number->toReadableSize(1024 * 1024 * 1024 * 1024 * 1024 - 1);
  487. $expected = '1,024 TB';
  488. $this->assertEquals($expected, $result);
  489. $result = $this->Number->toReadableSize(1024 * 1024 * 1024 * 1024 * 1024 * 1024);
  490. $expected = '1,048,576 TB';
  491. $this->assertEquals($expected, $result);
  492. }
  493. /**
  494. * test toReadableSize() with locales
  495. *
  496. * @return void
  497. */
  498. public function testReadableSizeLocalized()
  499. {
  500. I18n::setLocale('fr_FR');
  501. $result = $this->Number->toReadableSize(1321205);
  502. $this->assertEquals('1,26 MB', $result);
  503. $result = $this->Number->toReadableSize(512.05 * 1024 * 1024 * 1024);
  504. $this->assertEquals('512,05 GB', $result);
  505. }
  506. /**
  507. * test config()
  508. *
  509. * @return void
  510. */
  511. public function testConfig()
  512. {
  513. $result = $this->Number->currency(150000, 'USD', ['locale' => 'en_US']);
  514. $this->assertSame('$150,000.00', $result);
  515. Number::config('en_US', \NumberFormatter::CURRENCY, [
  516. 'pattern' => '¤ #,##,##0',
  517. ]);
  518. $result = $this->Number->currency(150000, 'USD', ['locale' => 'en_US']);
  519. $this->assertSame('$ 1,50,000', $result);
  520. }
  521. /**
  522. * test ordinal() with locales
  523. *
  524. * @return void
  525. */
  526. public function testOrdinal()
  527. {
  528. I18n::setLocale('en_US');
  529. $result = $this->Number->ordinal(1);
  530. $this->assertEquals('1st', $result);
  531. $result = $this->Number->ordinal(2);
  532. $this->assertEquals('2nd', $result);
  533. $result = $this->Number->ordinal(2, [
  534. 'locale' => 'fr_FR',
  535. ]);
  536. $this->assertEquals('2e', $result);
  537. $result = $this->Number->ordinal(3);
  538. $this->assertEquals('3rd', $result);
  539. $result = $this->Number->ordinal(4);
  540. $this->assertEquals('4th', $result);
  541. I18n::setLocale('fr_FR');
  542. $result = $this->Number->ordinal(1);
  543. $this->assertEquals('1er', $result);
  544. $result = $this->Number->ordinal(2);
  545. $this->assertEquals('2e', $result);
  546. }
  547. }