NumberTest.php 19 KB

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