format_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. // Copyright 2017 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package number
  5. import (
  6. "fmt"
  7. "log"
  8. "testing"
  9. "golang.org/x/text/language"
  10. )
  11. func TestAppendDecimal(t *testing.T) {
  12. type pairs map[string]string // alternates with decimal input and result
  13. testCases := []struct {
  14. pattern string
  15. // We want to be able to test some forms of patterns that cannot be
  16. // represented as a string.
  17. pat *Pattern
  18. test pairs
  19. }{{
  20. pattern: "0",
  21. test: pairs{
  22. "0": "0",
  23. "1": "1",
  24. "-1": "-1",
  25. ".00": "0",
  26. "10.": "10",
  27. "12": "12",
  28. "1.2": "1",
  29. "NaN": "NaN",
  30. "-Inf": "-∞",
  31. },
  32. }, {
  33. pattern: "+0;+0",
  34. test: pairs{
  35. "0": "+0",
  36. "1": "+1",
  37. "-1": "-1",
  38. ".00": "+0",
  39. "10.": "+10",
  40. "12": "+12",
  41. "1.2": "+1",
  42. "NaN": "NaN",
  43. "-Inf": "-∞",
  44. "Inf": "+∞",
  45. },
  46. }, {
  47. pattern: "0 +;0 +",
  48. test: pairs{
  49. "0": "0 +",
  50. "1": "1 +",
  51. "-1": "1 -",
  52. ".00": "0 +",
  53. },
  54. }, {
  55. pattern: "0;0-",
  56. test: pairs{
  57. "-1": "1-",
  58. "NaN": "NaN",
  59. "-Inf": "∞-",
  60. "Inf": "∞",
  61. },
  62. }, {
  63. pattern: "0000",
  64. test: pairs{
  65. "0": "0000",
  66. "1": "0001",
  67. "12": "0012",
  68. "12345": "12345",
  69. },
  70. }, {
  71. pattern: ".0",
  72. test: pairs{
  73. "0": ".0",
  74. "1": "1.0",
  75. "1.2": "1.2",
  76. "1.2345": "1.2",
  77. },
  78. }, {
  79. pattern: "#.0",
  80. test: pairs{
  81. "0": ".0",
  82. },
  83. }, {
  84. pattern: "#.0#",
  85. test: pairs{
  86. "0": ".0",
  87. "1": "1.0",
  88. },
  89. }, {
  90. pattern: "0.0#",
  91. test: pairs{
  92. "0": "0.0",
  93. },
  94. }, {
  95. pattern: "#0.###",
  96. test: pairs{
  97. "0": "0",
  98. "1": "1",
  99. "1.2": "1.2",
  100. "1.2345": "1.234", // rounding should have been done earlier
  101. "1234.5": "1234.5",
  102. "1234.567": "1234.567",
  103. },
  104. }, {
  105. pattern: "#0.######",
  106. test: pairs{
  107. "0": "0",
  108. "1234.5678": "1234.5678",
  109. "0.123456789": "0.123457",
  110. "NaN": "NaN",
  111. "Inf": "∞",
  112. },
  113. // Test separators.
  114. }, {
  115. pattern: "#,#.00",
  116. test: pairs{
  117. "100": "1,0,0.00",
  118. },
  119. }, {
  120. pattern: "#,0.##",
  121. test: pairs{
  122. "10": "1,0",
  123. },
  124. }, {
  125. pattern: "#,0",
  126. test: pairs{
  127. "10": "1,0",
  128. },
  129. }, {
  130. pattern: "#,##,#.00",
  131. test: pairs{
  132. "1000": "1,00,0.00",
  133. },
  134. }, {
  135. pattern: "#,##0.###",
  136. test: pairs{
  137. "0": "0",
  138. "1234.5678": "1,234.568",
  139. "0.123456789": "0.123",
  140. },
  141. }, {
  142. pattern: "#,##,##0.###",
  143. test: pairs{
  144. "0": "0",
  145. "123456789012": "1,23,45,67,89,012",
  146. "0.123456789": "0.123",
  147. },
  148. }, {
  149. pattern: "0,00,000.###",
  150. test: pairs{
  151. "0": "0,00,000",
  152. "123456789012": "1,23,45,67,89,012",
  153. "12.3456789": "0,00,012.346",
  154. "0.123456789": "0,00,000.123",
  155. },
  156. // Support for ill-formed patterns.
  157. }, {
  158. pattern: "#",
  159. test: pairs{
  160. ".00": "", // This is the behavior of fmt.
  161. "0": "", // This is the behavior of fmt.
  162. "1": "1",
  163. "10.": "10",
  164. },
  165. }, {
  166. pattern: ".#",
  167. test: pairs{
  168. "0": "", // This is the behavior of fmt.
  169. "1": "1",
  170. "1.2": "1.2",
  171. "1.2345": "1.2",
  172. },
  173. }, {
  174. pattern: "#,#.##",
  175. test: pairs{
  176. "10": "1,0",
  177. },
  178. }, {
  179. pattern: "#,#",
  180. test: pairs{
  181. "10": "1,0",
  182. },
  183. // Special patterns
  184. }, {
  185. pattern: "#,max_int=2",
  186. pat: &Pattern{
  187. RoundingContext: RoundingContext{
  188. MaxIntegerDigits: 2,
  189. },
  190. },
  191. test: pairs{
  192. "2017": "17",
  193. },
  194. }, {
  195. pattern: "0,max_int=2",
  196. pat: &Pattern{
  197. RoundingContext: RoundingContext{
  198. MaxIntegerDigits: 2,
  199. MinIntegerDigits: 1,
  200. },
  201. },
  202. test: pairs{
  203. "2000": "0",
  204. "2001": "1",
  205. "2017": "17",
  206. },
  207. }, {
  208. pattern: "00,max_int=2",
  209. pat: &Pattern{
  210. RoundingContext: RoundingContext{
  211. MaxIntegerDigits: 2,
  212. MinIntegerDigits: 2,
  213. },
  214. },
  215. test: pairs{
  216. "2000": "00",
  217. "2001": "01",
  218. "2017": "17",
  219. },
  220. }, {
  221. pattern: "@@@@,max_int=2",
  222. pat: &Pattern{
  223. RoundingContext: RoundingContext{
  224. MaxIntegerDigits: 2,
  225. MinSignificantDigits: 4,
  226. },
  227. },
  228. test: pairs{
  229. "2017": "17.00",
  230. "2000": "0.000",
  231. "2001": "1.000",
  232. },
  233. // Significant digits
  234. }, {
  235. pattern: "@@##",
  236. test: pairs{
  237. "1": "1.0",
  238. "0.1": "0.10", // leading zero does not count as significant digit
  239. "123": "123",
  240. "1234": "1234",
  241. "12345": "12340",
  242. },
  243. }, {
  244. pattern: "@@@@",
  245. test: pairs{
  246. "1": "1.000",
  247. ".1": "0.1000",
  248. ".001": "0.001000",
  249. "123": "123.0",
  250. "1234": "1234",
  251. "12345": "12340", // rounding down
  252. "NaN": "NaN",
  253. "-Inf": "-∞",
  254. },
  255. // TODO: rounding
  256. // {"@@@@": "23456": "23460"}, // rounding up
  257. // TODO: padding
  258. // Scientific and Engineering notation
  259. }, {
  260. pattern: "#E0",
  261. test: pairs{
  262. "0": "0\u202f×\u202f10⁰",
  263. "1": "1\u202f×\u202f10⁰",
  264. "123.456": "1\u202f×\u202f10²",
  265. },
  266. }, {
  267. pattern: "#E+0",
  268. test: pairs{
  269. "0": "0\u202f×\u202f10⁺⁰",
  270. "1000": "1\u202f×\u202f10⁺³",
  271. "1E100": "1\u202f×\u202f10⁺¹⁰⁰",
  272. "1E-100": "1\u202f×\u202f10⁻¹⁰⁰",
  273. "NaN": "NaN",
  274. "-Inf": "-∞",
  275. },
  276. }, {
  277. pattern: "##0E00",
  278. test: pairs{
  279. "100": "100\u202f×\u202f10⁰⁰",
  280. "12345": "12\u202f×\u202f10⁰³",
  281. "123.456": "123\u202f×\u202f10⁰⁰",
  282. },
  283. }, {
  284. pattern: "##0.###E00",
  285. test: pairs{
  286. "100": "100\u202f×\u202f10⁰⁰",
  287. "12345": "12.345\u202f×\u202f10⁰³",
  288. "123456": "123.456\u202f×\u202f10⁰³",
  289. "123.456": "123.456\u202f×\u202f10⁰⁰",
  290. "123.4567": "123.457\u202f×\u202f10⁰⁰",
  291. },
  292. }, {
  293. pattern: "##0.000E00",
  294. test: pairs{
  295. "100": "100.000\u202f×\u202f10⁰⁰",
  296. "12345": "12.345\u202f×\u202f10⁰³",
  297. "123.456": "123.456\u202f×\u202f10⁰⁰",
  298. "12.3456": "12.346\u202f×\u202f10⁰⁰",
  299. },
  300. }, {
  301. pattern: "@@E0",
  302. test: pairs{
  303. "0": "0.0\u202f×\u202f10⁰",
  304. "99": "9.9\u202f×\u202f10¹",
  305. "0.99": "9.9\u202f×\u202f10⁻¹",
  306. },
  307. }, {
  308. pattern: "@###E00",
  309. test: pairs{
  310. "0": "0\u202f×\u202f10⁰⁰",
  311. "1": "1\u202f×\u202f10⁰⁰",
  312. "11": "1.1\u202f×\u202f10⁰¹",
  313. "111": "1.11\u202f×\u202f10⁰²",
  314. "1111": "1.111\u202f×\u202f10⁰³",
  315. "11111": "1.111\u202f×\u202f10⁰⁴",
  316. "0.1": "1\u202f×\u202f10⁻⁰¹",
  317. "0.11": "1.1\u202f×\u202f10⁻⁰¹",
  318. "0.001": "1\u202f×\u202f10⁻⁰³",
  319. },
  320. }, {
  321. pattern: "*x##0",
  322. test: pairs{
  323. "0": "xx0",
  324. "10": "x10",
  325. "100": "100",
  326. "1000": "1000",
  327. },
  328. }, {
  329. pattern: "##0*x",
  330. test: pairs{
  331. "0": "0xx",
  332. "10": "10x",
  333. "100": "100",
  334. "1000": "1000",
  335. },
  336. }, {
  337. pattern: "* ###0.000",
  338. test: pairs{
  339. "0": " 0.000",
  340. "123": " 123.000",
  341. "123.456": " 123.456",
  342. "1234.567": "1234.567",
  343. },
  344. }, {
  345. pattern: "**0.0#######E00",
  346. test: pairs{
  347. "0": "***0.0\u202f×\u202f10⁰⁰",
  348. "10": "***1.0\u202f×\u202f10⁰¹",
  349. "11": "***1.1\u202f×\u202f10⁰¹",
  350. "111": "**1.11\u202f×\u202f10⁰²",
  351. "1111": "*1.111\u202f×\u202f10⁰³",
  352. "11111": "1.1111\u202f×\u202f10⁰⁴",
  353. "11110": "*1.111\u202f×\u202f10⁰⁴",
  354. "11100": "**1.11\u202f×\u202f10⁰⁴",
  355. "11000": "***1.1\u202f×\u202f10⁰⁴",
  356. "10000": "***1.0\u202f×\u202f10⁰⁴",
  357. },
  358. }, {
  359. pattern: "*xpre0suf",
  360. test: pairs{
  361. "0": "pre0suf",
  362. "10": "pre10suf",
  363. },
  364. }, {
  365. pattern: "*∞ pre ###0 suf",
  366. test: pairs{
  367. "0": "∞∞∞ pre 0 suf",
  368. "10": "∞∞ pre 10 suf",
  369. "100": "∞ pre 100 suf",
  370. "1000": " pre 1000 suf",
  371. },
  372. }, {
  373. pattern: "pre *∞###0 suf",
  374. test: pairs{
  375. "0": "pre ∞∞∞0 suf",
  376. "10": "pre ∞∞10 suf",
  377. "100": "pre ∞100 suf",
  378. "1000": "pre 1000 suf",
  379. },
  380. }, {
  381. pattern: "pre ###0*∞ suf",
  382. test: pairs{
  383. "0": "pre 0∞∞∞ suf",
  384. "10": "pre 10∞∞ suf",
  385. "100": "pre 100∞ suf",
  386. "1000": "pre 1000 suf",
  387. },
  388. }, {
  389. pattern: "pre ###0 suf *∞",
  390. test: pairs{
  391. "0": "pre 0 suf ∞∞∞",
  392. "10": "pre 10 suf ∞∞",
  393. "100": "pre 100 suf ∞",
  394. "1000": "pre 1000 suf ",
  395. },
  396. }, {
  397. // Take width of positive pattern.
  398. pattern: "**###0;**-#####0x",
  399. test: pairs{
  400. "0": "***0",
  401. "-1": "*-1x",
  402. },
  403. }, {
  404. pattern: "0.00%",
  405. test: pairs{
  406. "0.1": "10.00%",
  407. },
  408. }, {
  409. pattern: "0.##%",
  410. test: pairs{
  411. "0.1": "10%",
  412. "0.11": "11%",
  413. "0.111": "11.1%",
  414. "0.1111": "11.11%",
  415. "0.11111": "11.11%",
  416. },
  417. }, {
  418. pattern: "‰ 0.0#",
  419. test: pairs{
  420. "0.1": "‰ 100.0",
  421. "0.11": "‰ 110.0",
  422. "0.111": "‰ 111.0",
  423. "0.1111": "‰ 111.1",
  424. "0.11111": "‰ 111.11",
  425. "0.111111": "‰ 111.11",
  426. },
  427. }}
  428. // TODO:
  429. // "#,##0.00¤",
  430. // "#,##0.00 ¤;(#,##0.00 ¤)",
  431. for _, tc := range testCases {
  432. pat := tc.pat
  433. if pat == nil {
  434. var err error
  435. if pat, err = ParsePattern(tc.pattern); err != nil {
  436. log.Fatal(err)
  437. }
  438. }
  439. var f Formatter
  440. f.InitPattern(language.English, pat)
  441. for num, want := range tc.test {
  442. buf := make([]byte, 100)
  443. t.Run(tc.pattern+"/"+num, func(t *testing.T) {
  444. var d Decimal
  445. d.Convert(f.RoundingContext, dec(num))
  446. buf = f.Format(buf[:0], &d)
  447. if got := string(buf); got != want {
  448. t.Errorf("\n got %[1]q (%[1]s)\nwant %[2]q (%[2]s)", got, want)
  449. }
  450. })
  451. }
  452. }
  453. }
  454. func TestLocales(t *testing.T) {
  455. testCases := []struct {
  456. tag language.Tag
  457. num string
  458. want string
  459. }{
  460. {language.Make("en"), "123456.78", "123,456.78"},
  461. {language.Make("de"), "123456.78", "123.456,78"},
  462. {language.Make("de-CH"), "123456.78", "123’456.78"},
  463. {language.Make("fr"), "123456.78", "123 456,78"},
  464. {language.Make("bn"), "123456.78", "১,২৩,৪৫৬.৭৮"},
  465. }
  466. for _, tc := range testCases {
  467. t.Run(fmt.Sprint(tc.tag, "/", tc.num), func(t *testing.T) {
  468. var f Formatter
  469. f.InitDecimal(tc.tag)
  470. var d Decimal
  471. d.Convert(f.RoundingContext, dec(tc.num))
  472. b := f.Format(nil, &d)
  473. if got := string(b); got != tc.want {
  474. t.Errorf("got %[1]q (%[1]s); want %[2]q (%[2]s)", got, tc.want)
  475. }
  476. })
  477. }
  478. }
  479. func TestFormatters(t *testing.T) {
  480. var f Formatter
  481. testCases := []struct {
  482. init func(t language.Tag)
  483. num string
  484. want string
  485. }{
  486. {f.InitDecimal, "123456.78", "123,456.78"},
  487. {f.InitScientific, "123456.78", "1.23\u202f×\u202f10⁵"},
  488. {f.InitEngineering, "123456.78", "123.46\u202f×\u202f10³"},
  489. {f.InitEngineering, "1234", "1.23\u202f×\u202f10³"},
  490. {f.InitPercent, "0.1234", "12.34%"},
  491. {f.InitPerMille, "0.1234", "123.40‰"},
  492. }
  493. for i, tc := range testCases {
  494. t.Run(fmt.Sprint(i, "/", tc.num), func(t *testing.T) {
  495. tc.init(language.English)
  496. f.SetScale(2)
  497. var d Decimal
  498. d.Convert(f.RoundingContext, dec(tc.num))
  499. b := f.Format(nil, &d)
  500. if got := string(b); got != tc.want {
  501. t.Errorf("got %[1]q (%[1]s); want %[2]q (%[2]s)", got, tc.want)
  502. }
  503. })
  504. }
  505. }