NumberTest.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  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. $result = $this->Number->currency($value, 'INR', ['locale' => 'en_IN']);
  178. $expected = '₹ 10,01,00,100.00';
  179. $this->assertEquals($expected, $result);
  180. $options = ['locale' => 'en_IN', 'pattern' => "Rs'.' #,##,###"];
  181. $result = $this->Number->currency($value, 'INR', $options);
  182. $expected = 'Rs. 10,01,00,100';
  183. $this->assertEquals($expected, $result);
  184. $result = $this->Number->currency($value, 'GBP');
  185. $expected = '£100,100,100.00';
  186. $this->assertEquals($expected, $result);
  187. $result = $this->Number->currency($value, 'GBP', ['locale' => 'da_DK']);
  188. $expected = '100.100.100,00 £';
  189. $this->assertEquals($expected, $result);
  190. $options = ['locale' => 'fr_FR', 'pattern' => 'EUR #,###.00'];
  191. $result = $this->Number->currency($value, 'EUR', $options);
  192. // The following tests use regexp because whitespace used
  193. // is inconsistent between *nix & windows.
  194. $expected = '/^EUR\W+100\W+100\W+100,00$/';
  195. $this->assertRegExp($expected, $result);
  196. $options = ['locale' => 'fr_FR', 'pattern' => '#,###.00 ¤¤'];
  197. $result = $this->Number->currency($value, 'EUR', $options);
  198. $expected = '/^100\W+100\W+100,00\W+EUR$/';
  199. $this->assertRegExp($expected, $result);
  200. $options = ['locale' => 'fr_FR', 'pattern' => '#,###.00;(¤#,###.00)'];
  201. $result = $this->Number->currency(-1235.03, 'EUR', $options);
  202. $expected = '/^\(€1\W+235,03\)$/';
  203. $this->assertRegExp($expected, $result);
  204. $result = $this->Number->currency(0.5, 'USD', ['locale' => 'en_US', 'fractionSymbol' => 'c']);
  205. $expected = '50c';
  206. $this->assertEquals($expected, $result);
  207. $options = ['fractionSymbol' => ' cents'];
  208. $result = $this->Number->currency(0.2, 'USD', $options);
  209. $expected = '20 cents';
  210. $this->assertEquals($expected, $result);
  211. $options = ['fractionSymbol' => 'cents ', 'fractionPosition' => 'before'];
  212. $result = $this->Number->currency(0.2, null, $options);
  213. $expected = 'cents 20';
  214. $this->assertEquals($expected, $result);
  215. $result = $this->Number->currency(0.2, 'EUR');
  216. $expected = '€0.20';
  217. $this->assertEquals($expected, $result);
  218. $options = ['fractionSymbol' => false, 'fractionPosition' => 'before'];
  219. $result = $this->Number->currency(0.5, null, $options);
  220. $expected = '$0.50';
  221. $this->assertEquals($expected, $result);
  222. $result = $this->Number->currency(0, 'GBP');
  223. $expected = '£0.00';
  224. $this->assertEquals($expected, $result);
  225. $result = $this->Number->currency(0, 'GBP', ['pattern' => '¤#,###.00;¤-#,###.00']);
  226. $expected = '£.00';
  227. $this->assertEquals($expected, $result);
  228. $result = $this->Number->currency(0, 'GBP', ['pattern' => '¤#,##0.00;¤-#,##0.00']);
  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('0.00000', 'GBP');
  235. $expected = '£0.00';
  236. $this->assertEquals($expected, $result);
  237. $result = $this->Number->currency('22.389', 'CAD');
  238. $expected = 'CA$22.39';
  239. $this->assertEquals($expected, $result);
  240. }
  241. /**
  242. * Test currency format with places and fraction exponents.
  243. * Places should only matter for non fraction values and vice versa.
  244. *
  245. * @return void
  246. */
  247. public function testCurrencyWithFractionAndPlaces()
  248. {
  249. $result = $this->Number->currency('1.23', 'EUR', ['locale' => 'de_DE', 'places' => 3]);
  250. $expected = '1,230 €';
  251. $this->assertEquals($expected, $result);
  252. $result = $this->Number->currency('0.23', 'GBP', ['places' => 3, 'fractionSymbol' => 'p']);
  253. $expected = '23p';
  254. $this->assertEquals($expected, $result);
  255. $result = $this->Number->currency('0.001', 'GBP', ['places' => 3, 'fractionSymbol' => 'p']);
  256. $expected = '0p';
  257. $this->assertEquals($expected, $result);
  258. $result = $this->Number->currency('1.23', 'EUR', ['locale' => 'de_DE', 'precision' => 1]);
  259. $expected = '1,2 €';
  260. $this->assertEquals($expected, $result);
  261. }
  262. /**
  263. * Test default currency
  264. *
  265. * @group deprecated
  266. * @return void
  267. */
  268. public function testDefaultCurrency()
  269. {
  270. $this->deprecated(function () {
  271. $this->assertEquals('USD', $this->Number->defaultCurrency());
  272. $this->Number->defaultCurrency(false);
  273. I18n::setLocale('es_ES');
  274. $this->assertEquals('EUR', $this->Number->defaultCurrency());
  275. $this->Number->defaultCurrency('JPY');
  276. $this->assertEquals('JPY', $this->Number->defaultCurrency());
  277. });
  278. }
  279. /**
  280. * Test get default currency
  281. *
  282. * @return void
  283. */
  284. public function testGetDefaultCurrency()
  285. {
  286. $this->assertEquals('USD', $this->Number->getDefaultCurrency());
  287. }
  288. /**
  289. * Test set default currency
  290. *
  291. * @return void
  292. */
  293. public function testSetDefaultCurrency()
  294. {
  295. $this->Number->setDefaultCurrency();
  296. I18n::setLocale('es_ES');
  297. $this->assertEquals('EUR', $this->Number->getDefaultCurrency());
  298. $this->Number->setDefaultCurrency('JPY');
  299. $this->assertEquals('JPY', $this->Number->getDefaultCurrency());
  300. }
  301. /**
  302. * Test get default currency format
  303. *
  304. * @return void
  305. */
  306. public function testGetDefaultCurrencyFormat()
  307. {
  308. $this->assertEquals('currency', $this->Number->getDefaultCurrencyFormat());
  309. }
  310. /**
  311. * Test set default currency format
  312. *
  313. * @return void
  314. */
  315. public function testSetDefaultCurrencyFormat()
  316. {
  317. $this->Number->setDefaultCurrencyFormat(Number::FORMAT_CURRENCY_ACCOUNTING);
  318. $this->assertEquals('currency_accounting', $this->Number->getDefaultCurrencyFormat());
  319. $this->assertEquals('($123.45)', $this->Number->currency(-123.45));
  320. }
  321. /**
  322. * testCurrencyCentsNegative method
  323. *
  324. * @return void
  325. */
  326. public function testCurrencyCentsNegative()
  327. {
  328. $value = '-0.99';
  329. $result = $this->Number->currency($value, 'EUR', ['locale' => 'de_DE']);
  330. $expected = '-0,99 €';
  331. $this->assertEquals($expected, $result);
  332. $result = $this->Number->currency($value, 'USD', ['fractionSymbol' => 'c']);
  333. $expected = '-99c';
  334. $this->assertEquals($expected, $result);
  335. }
  336. /**
  337. * testCurrencyZero method
  338. *
  339. * @return void
  340. */
  341. public function testCurrencyZero()
  342. {
  343. $value = '0';
  344. $result = $this->Number->currency($value, 'USD');
  345. $expected = '$0.00';
  346. $this->assertEquals($expected, $result);
  347. $result = $this->Number->currency($value, 'EUR', ['locale' => 'fr_FR']);
  348. $expected = '0,00 €';
  349. $this->assertEquals($expected, $result);
  350. }
  351. /**
  352. * testCurrencyOptions method
  353. *
  354. * @return void
  355. */
  356. public function testCurrencyOptions()
  357. {
  358. $value = '1234567.89';
  359. $result = $this->Number->currency($value, null, ['before' => 'Total: ']);
  360. $expected = 'Total: $1,234,567.89';
  361. $this->assertEquals($expected, $result);
  362. $result = $this->Number->currency($value, null, ['after' => ' in Total']);
  363. $expected = '$1,234,567.89 in Total';
  364. $this->assertEquals($expected, $result);
  365. }
  366. /**
  367. * Tests that it is possible to use the international currency code instead of the whole
  368. * when using the currency method
  369. *
  370. * @return void
  371. */
  372. public function testCurrencyIntlCode()
  373. {
  374. $value = '123';
  375. $result = $this->Number->currency($value, 'USD', ['useIntlCode' => true]);
  376. $expected = 'USD 123.00';
  377. $this->assertEquals($expected, $result);
  378. $result = $this->Number->currency($value, 'EUR', ['useIntlCode' => true]);
  379. $expected = 'EUR 123.00';
  380. $this->assertEquals($expected, $result);
  381. $result = $this->Number->currency($value, 'EUR', ['useIntlCode' => true, 'locale' => 'da_DK']);
  382. $expected = '123,00 EUR';
  383. $this->assertEquals($expected, $result);
  384. }
  385. /**
  386. * test precision() with locales
  387. *
  388. * @return void
  389. */
  390. public function testPrecisionLocalized()
  391. {
  392. I18n::setLocale('fr_FR');
  393. $result = $this->Number->precision(1.234);
  394. $this->assertEquals('1,234', $result);
  395. }
  396. /**
  397. * testToPercentage method
  398. *
  399. * @return void
  400. */
  401. public function testToPercentage()
  402. {
  403. $result = $this->Number->toPercentage(45, 0);
  404. $expected = '45%';
  405. $this->assertEquals($expected, $result);
  406. $result = $this->Number->toPercentage(45, 2);
  407. $expected = '45.00%';
  408. $this->assertEquals($expected, $result);
  409. $result = $this->Number->toPercentage(0, 0);
  410. $expected = '0%';
  411. $this->assertEquals($expected, $result);
  412. $result = $this->Number->toPercentage(0, 4);
  413. $expected = '0.0000%';
  414. $this->assertEquals($expected, $result);
  415. $result = $this->Number->toPercentage(45, 0, ['multiply' => false]);
  416. $expected = '45%';
  417. $this->assertEquals($expected, $result);
  418. $result = $this->Number->toPercentage(45, 2, ['multiply' => false]);
  419. $expected = '45.00%';
  420. $this->assertEquals($expected, $result);
  421. $result = $this->Number->toPercentage(0, 0, ['multiply' => false]);
  422. $expected = '0%';
  423. $this->assertEquals($expected, $result);
  424. $result = $this->Number->toPercentage(0, 4, ['multiply' => false]);
  425. $expected = '0.0000%';
  426. $this->assertEquals($expected, $result);
  427. $result = $this->Number->toPercentage(0.456, 0, ['multiply' => true]);
  428. $expected = '46%';
  429. $this->assertEquals($expected, $result);
  430. $result = $this->Number->toPercentage(0.456, 2, ['multiply' => true]);
  431. $expected = '45.60%';
  432. $this->assertEquals($expected, $result);
  433. $result = $this->Number->toPercentage(0.456, 2, ['locale' => 'de-DE', 'multiply' => true]);
  434. $expected = '45,60 %';
  435. $this->assertEquals($expected, $result);
  436. $result = $this->Number->toPercentage(13, 0, ['locale' => 'fi_FI']);
  437. $expected = '13 %';
  438. $this->assertEquals($expected, $result);
  439. $result = $this->Number->toPercentage(0.13, 0, ['locale' => 'fi_FI', 'multiply' => true]);
  440. $expected = '13 %';
  441. $this->assertEquals($expected, $result);
  442. }
  443. /**
  444. * testToReadableSize method
  445. *
  446. * @return void
  447. */
  448. public function testToReadableSize()
  449. {
  450. $result = $this->Number->toReadableSize(0);
  451. $expected = '0 Bytes';
  452. $this->assertEquals($expected, $result);
  453. $result = $this->Number->toReadableSize(1);
  454. $expected = '1 Byte';
  455. $this->assertEquals($expected, $result);
  456. $result = $this->Number->toReadableSize(45);
  457. $expected = '45 Bytes';
  458. $this->assertEquals($expected, $result);
  459. $result = $this->Number->toReadableSize(1023);
  460. $expected = '1,023 Bytes';
  461. $this->assertEquals($expected, $result);
  462. $result = $this->Number->toReadableSize(1024);
  463. $expected = '1 KB';
  464. $this->assertEquals($expected, $result);
  465. $result = $this->Number->toReadableSize(1024 + 123);
  466. $expected = '1.12 KB';
  467. $this->assertEquals($expected, $result);
  468. $result = $this->Number->toReadableSize(1024 * 512);
  469. $expected = '512 KB';
  470. $this->assertEquals($expected, $result);
  471. $result = $this->Number->toReadableSize(1024 * 1024 - 1);
  472. $expected = '1 MB';
  473. $this->assertEquals($expected, $result);
  474. $result = $this->Number->toReadableSize(512.05 * 1024 * 1024);
  475. $expected = '512.05 MB';
  476. $this->assertEquals($expected, $result);
  477. $result = $this->Number->toReadableSize(1024 * 1024 * 1024 - 1);
  478. $expected = '1 GB';
  479. $this->assertEquals($expected, $result);
  480. $result = $this->Number->toReadableSize(1024 * 1024 * 1024 * 512);
  481. $expected = '512 GB';
  482. $this->assertEquals($expected, $result);
  483. $result = $this->Number->toReadableSize(1024 * 1024 * 1024 * 1024 - 1);
  484. $expected = '1 TB';
  485. $this->assertEquals($expected, $result);
  486. $result = $this->Number->toReadableSize(1024 * 1024 * 1024 * 1024 * 512);
  487. $expected = '512 TB';
  488. $this->assertEquals($expected, $result);
  489. $result = $this->Number->toReadableSize(1024 * 1024 * 1024 * 1024 * 1024 - 1);
  490. $expected = '1,024 TB';
  491. $this->assertEquals($expected, $result);
  492. $result = $this->Number->toReadableSize(1024 * 1024 * 1024 * 1024 * 1024 * 1024);
  493. $expected = '1,048,576 TB';
  494. $this->assertEquals($expected, $result);
  495. }
  496. /**
  497. * test toReadableSize() with locales
  498. *
  499. * @return void
  500. */
  501. public function testReadableSizeLocalized()
  502. {
  503. I18n::setLocale('fr_FR');
  504. $result = $this->Number->toReadableSize(1321205);
  505. $this->assertEquals('1,26 MB', $result);
  506. $result = $this->Number->toReadableSize(512.05 * 1024 * 1024 * 1024);
  507. $this->assertEquals('512,05 GB', $result);
  508. }
  509. /**
  510. * test config()
  511. *
  512. * @return void
  513. */
  514. public function testConfig()
  515. {
  516. $result = $this->Number->currency(15000, 'INR', ['locale' => 'en_IN']);
  517. $this->assertEquals('₹ 15,000.00', $result);
  518. Number::config('en_IN', \NumberFormatter::CURRENCY, [
  519. 'pattern' => '¤ #,##,##0',
  520. ]);
  521. $result = $this->Number->currency(15000, 'INR', ['locale' => 'en_IN']);
  522. $this->assertEquals('₹ 15,000', $result);
  523. }
  524. /**
  525. * test ordinal() with locales
  526. *
  527. * @return void
  528. */
  529. public function testOrdinal()
  530. {
  531. I18n::setLocale('en_US');
  532. $result = $this->Number->ordinal(1);
  533. $this->assertEquals('1st', $result);
  534. $result = $this->Number->ordinal(2);
  535. $this->assertEquals('2nd', $result);
  536. $result = $this->Number->ordinal(2, [
  537. 'locale' => 'fr_FR',
  538. ]);
  539. $this->assertEquals('2e', $result);
  540. $result = $this->Number->ordinal(3);
  541. $this->assertEquals('3rd', $result);
  542. $result = $this->Number->ordinal(4);
  543. $this->assertEquals('4th', $result);
  544. I18n::setLocale('fr_FR');
  545. $result = $this->Number->ordinal(1);
  546. $this->assertEquals('1er', $result);
  547. $result = $this->Number->ordinal(2);
  548. $this->assertEquals('2e', $result);
  549. }
  550. }