import_export_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. package ut
  2. import (
  3. "fmt"
  4. "testing"
  5. "os"
  6. "github.com/go-playground/locales"
  7. "github.com/go-playground/locales/en"
  8. "github.com/go-playground/locales/nl"
  9. )
  10. // NOTES:
  11. // - Run "go test" to run tests
  12. // - Run "gocov test | gocov report" to report on test converage by file
  13. // - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
  14. //
  15. // or
  16. //
  17. // -- may be a good idea to change to output path to somewherelike /tmp
  18. // go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
  19. //
  20. func TestExportImportBasic(t *testing.T) {
  21. e := en.New()
  22. uni := New(e, e)
  23. en, found := uni.GetTranslator("en") // or fallback if fails to find 'en'
  24. if !found {
  25. t.Fatalf("Expected '%t' Got '%t'", true, found)
  26. }
  27. translations := []struct {
  28. key interface{}
  29. trans string
  30. expected error
  31. expectedError bool
  32. override bool
  33. }{
  34. {
  35. key: "test_trans",
  36. trans: "Welcome {0}",
  37. expected: nil,
  38. },
  39. {
  40. key: -1,
  41. trans: "Welcome {0}",
  42. expected: nil,
  43. },
  44. {
  45. key: "test_trans2",
  46. trans: "{0} to the {1}.",
  47. expected: nil,
  48. },
  49. {
  50. key: "test_trans3",
  51. trans: "Welcome {0} to the {1}",
  52. expected: nil,
  53. },
  54. {
  55. key: "test_trans4",
  56. trans: "{0}{1}",
  57. expected: nil,
  58. },
  59. {
  60. key: "test_trans",
  61. trans: "{0}{1}",
  62. expected: &ErrConflictingTranslation{locale: en.Locale(), key: "test_trans", text: "{0}{1}"},
  63. expectedError: true,
  64. },
  65. {
  66. key: -1,
  67. trans: "{0}{1}",
  68. expected: &ErrConflictingTranslation{locale: en.Locale(), key: -1, text: "{0}{1}"},
  69. expectedError: true,
  70. },
  71. {
  72. key: "test_trans",
  73. trans: "Welcome {0} to the {1}.",
  74. expected: nil,
  75. override: true,
  76. },
  77. }
  78. for _, tt := range translations {
  79. err := en.Add(tt.key, tt.trans, tt.override)
  80. if err != tt.expected {
  81. if !tt.expectedError {
  82. t.Errorf("Expected '%s' Got '%s'", tt.expected, err)
  83. } else {
  84. if err.Error() != tt.expected.Error() {
  85. t.Errorf("Expected '%s' Got '%s'", tt.expected.Error(), err.Error())
  86. }
  87. }
  88. }
  89. }
  90. filename := "testdata/basic-export-test.json"
  91. uni.Export(JSON, filename)
  92. uni = New(e, e)
  93. err := uni.Import(JSON, filename)
  94. if err != nil {
  95. t.Fatalf("Expected '%v' Got '%s'", nil, err)
  96. }
  97. en, found = uni.GetTranslator("en") // or fallback if fails to find 'en'
  98. if !found {
  99. t.Fatalf("Expected '%t' Got '%t'", true, found)
  100. }
  101. tests := []struct {
  102. key interface{}
  103. params []string
  104. expected string
  105. expectedError bool
  106. }{
  107. {
  108. key: "test_trans",
  109. params: []string{"Joeybloggs", "The Test"},
  110. expected: "Welcome Joeybloggs to the The Test.",
  111. },
  112. {
  113. key: "test_trans2",
  114. params: []string{"Joeybloggs", "The Test"},
  115. expected: "Joeybloggs to the The Test.",
  116. },
  117. {
  118. key: "test_trans3",
  119. params: []string{"Joeybloggs", "The Test"},
  120. expected: "Welcome Joeybloggs to the The Test",
  121. },
  122. {
  123. key: "test_trans4",
  124. params: []string{"Joeybloggs", "The Test"},
  125. expected: "JoeybloggsThe Test",
  126. },
  127. // bad translation
  128. {
  129. key: "non-existant-key",
  130. params: []string{"Joeybloggs", "The Test"},
  131. expected: "",
  132. expectedError: true,
  133. },
  134. }
  135. for _, tt := range tests {
  136. s, err := en.T(tt.key, tt.params...)
  137. if s != tt.expected {
  138. if !tt.expectedError || (tt.expectedError && err != ErrUnknowTranslation) {
  139. t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
  140. }
  141. }
  142. }
  143. }
  144. func TestExportImportCardinal(t *testing.T) {
  145. e := en.New()
  146. uni := New(e, e)
  147. en, found := uni.GetTranslator("en")
  148. if !found {
  149. t.Fatalf("Expected '%t' Got '%t'", true, found)
  150. }
  151. translations := []struct {
  152. key interface{}
  153. trans string
  154. rule locales.PluralRule
  155. expected error
  156. expectedError bool
  157. override bool
  158. }{
  159. // bad translation
  160. {
  161. key: "cardinal_test",
  162. trans: "You have a day left.",
  163. rule: locales.PluralRuleOne,
  164. expected: &ErrCardinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddCardinal'. locale: '%s' key: '%v' text: '%s'", paramZero, en.Locale(), "cardinal_test", "You have a day left.")},
  165. expectedError: true,
  166. },
  167. {
  168. key: "cardinal_test",
  169. trans: "You have {0} day",
  170. rule: locales.PluralRuleOne,
  171. expected: nil,
  172. },
  173. {
  174. key: "cardinal_test",
  175. trans: "You have {0} days left.",
  176. rule: locales.PluralRuleOther,
  177. expected: nil,
  178. },
  179. {
  180. key: "cardinal_test",
  181. trans: "You have {0} days left.",
  182. rule: locales.PluralRuleOther,
  183. expected: &ErrConflictingTranslation{locale: en.Locale(), key: "cardinal_test", rule: locales.PluralRuleOther, text: "You have {0} days left."},
  184. expectedError: true,
  185. },
  186. {
  187. key: "cardinal_test",
  188. trans: "You have {0} day left.",
  189. rule: locales.PluralRuleOne,
  190. expected: nil,
  191. override: true,
  192. },
  193. }
  194. for _, tt := range translations {
  195. err := en.AddCardinal(tt.key, tt.trans, tt.rule, tt.override)
  196. if err != tt.expected {
  197. if !tt.expectedError || err.Error() != tt.expected.Error() {
  198. t.Errorf("Expected '%s' Got '%s'", tt.expected, err)
  199. }
  200. }
  201. }
  202. filename := "testdata/cardinal-export-test.json"
  203. uni.Export(JSON, filename)
  204. uni = New(e, e)
  205. err := uni.Import(JSON, filename)
  206. if err != nil {
  207. t.Fatalf("Expected '%v' Got '%s'", nil, err)
  208. }
  209. en, found = uni.GetTranslator("en") // or fallback if fails to find 'en'
  210. if !found {
  211. t.Fatalf("Expected '%t' Got '%t'", true, found)
  212. }
  213. tests := []struct {
  214. key interface{}
  215. num float64
  216. digits uint64
  217. param string
  218. expected string
  219. expectedError bool
  220. }{
  221. {
  222. key: "cardinal_test",
  223. num: 1,
  224. digits: 0,
  225. param: string(en.FmtNumber(1, 0)),
  226. expected: "You have 1 day left.",
  227. },
  228. // bad translation key
  229. {
  230. key: "non-existant",
  231. num: 1,
  232. digits: 0,
  233. param: string(en.FmtNumber(1, 0)),
  234. expected: "",
  235. expectedError: true,
  236. },
  237. }
  238. for _, tt := range tests {
  239. s, err := en.C(tt.key, tt.num, tt.digits, tt.param)
  240. if err != nil {
  241. if !tt.expectedError && err != ErrUnknowTranslation {
  242. t.Errorf("Expected '<nil>' Got '%s'", err)
  243. }
  244. }
  245. if s != tt.expected {
  246. t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
  247. }
  248. }
  249. }
  250. func TestExportImportOrdinal(t *testing.T) {
  251. e := en.New()
  252. uni := New(e, e)
  253. en, found := uni.GetTranslator("en")
  254. if !found {
  255. t.Fatalf("Expected '%t' Got '%t'", true, found)
  256. }
  257. translations := []struct {
  258. key interface{}
  259. trans string
  260. rule locales.PluralRule
  261. expected error
  262. expectedError bool
  263. override bool
  264. }{
  265. // bad translation
  266. {
  267. key: "day",
  268. trans: "st",
  269. rule: locales.PluralRuleOne,
  270. expected: &ErrOrdinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddOrdinal'. locale: '%s' key: '%v' text: '%s'", paramZero, en.Locale(), "day", "st")},
  271. expectedError: true,
  272. },
  273. {
  274. key: "day",
  275. trans: "{0}sfefewt",
  276. rule: locales.PluralRuleOne,
  277. expected: nil,
  278. },
  279. {
  280. key: "day",
  281. trans: "{0}nd",
  282. rule: locales.PluralRuleTwo,
  283. expected: nil,
  284. },
  285. {
  286. key: "day",
  287. trans: "{0}rd",
  288. rule: locales.PluralRuleFew,
  289. expected: nil,
  290. },
  291. {
  292. key: "day",
  293. trans: "{0}th",
  294. rule: locales.PluralRuleOther,
  295. expected: nil,
  296. },
  297. // bad translation
  298. {
  299. key: "day",
  300. trans: "{0}th",
  301. rule: locales.PluralRuleOther,
  302. expected: &ErrConflictingTranslation{locale: en.Locale(), key: "day", rule: locales.PluralRuleOther, text: "{0}th"},
  303. expectedError: true,
  304. },
  305. {
  306. key: "day",
  307. trans: "{0}st",
  308. rule: locales.PluralRuleOne,
  309. expected: nil,
  310. override: true,
  311. },
  312. }
  313. for _, tt := range translations {
  314. err := en.AddOrdinal(tt.key, tt.trans, tt.rule, tt.override)
  315. if err != tt.expected {
  316. if !tt.expectedError || err.Error() != tt.expected.Error() {
  317. t.Errorf("Expected '<nil>' Got '%s'", err)
  318. }
  319. }
  320. }
  321. filename := "testdata/ordinal-export-test.json"
  322. uni.Export(JSON, filename)
  323. uni = New(e, e)
  324. err := uni.Import(JSON, filename)
  325. if err != nil {
  326. t.Fatalf("Expected '%v' Got '%s'", nil, err)
  327. }
  328. en, found = uni.GetTranslator("en") // or fallback if fails to find 'en'
  329. if !found {
  330. t.Fatalf("Expected '%t' Got '%t'", true, found)
  331. }
  332. tests := []struct {
  333. key interface{}
  334. num float64
  335. digits uint64
  336. param string
  337. expected string
  338. expectedError bool
  339. }{
  340. {
  341. key: "day",
  342. num: 1,
  343. digits: 0,
  344. param: string(en.FmtNumber(1, 0)),
  345. expected: "1st",
  346. },
  347. {
  348. key: "day",
  349. num: 2,
  350. digits: 0,
  351. param: string(en.FmtNumber(2, 0)),
  352. expected: "2nd",
  353. },
  354. {
  355. key: "day",
  356. num: 3,
  357. digits: 0,
  358. param: string(en.FmtNumber(3, 0)),
  359. expected: "3rd",
  360. },
  361. {
  362. key: "day",
  363. num: 4,
  364. digits: 0,
  365. param: string(en.FmtNumber(4, 0)),
  366. expected: "4th",
  367. },
  368. {
  369. key: "day",
  370. num: 10258.43,
  371. digits: 0,
  372. param: string(en.FmtNumber(10258.43, 0)),
  373. expected: "10,258th",
  374. },
  375. // bad translation
  376. {
  377. key: "d-day",
  378. num: 10258.43,
  379. digits: 0,
  380. param: string(en.FmtNumber(10258.43, 0)),
  381. expected: "",
  382. expectedError: true,
  383. },
  384. }
  385. for _, tt := range tests {
  386. s, err := en.O(tt.key, tt.num, tt.digits, tt.param)
  387. if err != nil {
  388. if !tt.expectedError && err != ErrUnknowTranslation {
  389. t.Errorf("Expected '<nil>' Got '%s'", err)
  390. }
  391. }
  392. if s != tt.expected {
  393. t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
  394. }
  395. }
  396. }
  397. func TestExportImportRange(t *testing.T) {
  398. n := nl.New()
  399. uni := New(n, n)
  400. // dutch
  401. nl, found := uni.GetTranslator("nl")
  402. if !found {
  403. t.Fatalf("Expected '%t' Got '%t'", true, found)
  404. }
  405. translations := []struct {
  406. key interface{}
  407. trans string
  408. rule locales.PluralRule
  409. expected error
  410. expectedError bool
  411. override bool
  412. }{
  413. // bad translation
  414. {
  415. key: "day",
  416. trans: "er -{1} dag vertrokken",
  417. rule: locales.PluralRuleOne,
  418. expected: &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, are you sure you're adding a Range Translation? locale: '%s' key: '%s' text: '%s'", paramZero, nl.Locale(), "day", "er -{1} dag vertrokken")},
  419. expectedError: true,
  420. },
  421. // bad translation
  422. {
  423. key: "day",
  424. trans: "er {0}- dag vertrokken",
  425. rule: locales.PluralRuleOne,
  426. expected: &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, a Range Translation requires two parameters. locale: '%s' key: '%s' text: '%s'", paramOne, nl.Locale(), "day", "er {0}- dag vertrokken")},
  427. expectedError: true,
  428. },
  429. {
  430. key: "day",
  431. trans: "er {0}-{1} dag",
  432. rule: locales.PluralRuleOne,
  433. expected: nil,
  434. },
  435. {
  436. key: "day",
  437. trans: "er zijn {0}-{1} dagen over",
  438. rule: locales.PluralRuleOther,
  439. expected: nil,
  440. },
  441. // bad translation
  442. {
  443. key: "day",
  444. trans: "er zijn {0}-{1} dagen over",
  445. rule: locales.PluralRuleOther,
  446. expected: &ErrConflictingTranslation{locale: nl.Locale(), key: "day", rule: locales.PluralRuleOther, text: "er zijn {0}-{1} dagen over"},
  447. expectedError: true,
  448. },
  449. {
  450. key: "day",
  451. trans: "er {0}-{1} dag vertrokken",
  452. rule: locales.PluralRuleOne,
  453. expected: nil,
  454. override: true,
  455. },
  456. }
  457. for _, tt := range translations {
  458. err := nl.AddRange(tt.key, tt.trans, tt.rule, tt.override)
  459. if err != tt.expected {
  460. if !tt.expectedError || err.Error() != tt.expected.Error() {
  461. t.Errorf("Expected '%#v' Got '%s'", tt.expected, err)
  462. }
  463. }
  464. }
  465. filename := "testdata/range-export-test.json"
  466. uni.Export(JSON, filename)
  467. uni = New(n, n)
  468. err := uni.Import(JSON, filename)
  469. if err != nil {
  470. t.Fatalf("Expected '%v' Got '%s'", nil, err)
  471. }
  472. nl, found = uni.GetTranslator("nl") // or fallback if fails to find 'en'
  473. if !found {
  474. t.Fatalf("Expected '%t' Got '%t'", true, found)
  475. }
  476. tests := []struct {
  477. key interface{}
  478. num1 float64
  479. digits1 uint64
  480. num2 float64
  481. digits2 uint64
  482. param1 string
  483. param2 string
  484. expected string
  485. expectedError bool
  486. }{
  487. {
  488. key: "day",
  489. num1: 1,
  490. digits1: 0,
  491. num2: 2,
  492. digits2: 0,
  493. param1: string(nl.FmtNumber(1, 0)),
  494. param2: string(nl.FmtNumber(2, 0)),
  495. expected: "er zijn 1-2 dagen over",
  496. },
  497. {
  498. key: "day",
  499. num1: 0,
  500. digits1: 0,
  501. num2: 1,
  502. digits2: 0,
  503. param1: string(nl.FmtNumber(0, 0)),
  504. param2: string(nl.FmtNumber(1, 0)),
  505. expected: "er 0-1 dag vertrokken",
  506. },
  507. {
  508. key: "day",
  509. num1: 0,
  510. digits1: 0,
  511. num2: 2,
  512. digits2: 0,
  513. param1: string(nl.FmtNumber(0, 0)),
  514. param2: string(nl.FmtNumber(2, 0)),
  515. expected: "er zijn 0-2 dagen over",
  516. },
  517. // bad translations from here
  518. {
  519. key: "d-day",
  520. num1: 0,
  521. digits1: 0,
  522. num2: 2,
  523. digits2: 0,
  524. param1: string(nl.FmtNumber(0, 0)),
  525. param2: string(nl.FmtNumber(2, 0)),
  526. expected: "",
  527. expectedError: true,
  528. },
  529. }
  530. for _, tt := range tests {
  531. s, err := nl.R(tt.key, tt.num1, tt.digits1, tt.num2, tt.digits2, tt.param1, tt.param2)
  532. if err != nil {
  533. if !tt.expectedError && err != ErrUnknowTranslation {
  534. t.Errorf("Expected '<nil>' Got '%s'", err)
  535. }
  536. }
  537. if s != tt.expected {
  538. t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
  539. }
  540. }
  541. }
  542. func TestImportRecursive(t *testing.T) {
  543. e := en.New()
  544. uni := New(e, e)
  545. dirname := "testdata/nested1"
  546. err := uni.Import(JSON, dirname)
  547. if err != nil {
  548. t.Fatalf("Expected '%v' Got '%s'", nil, err)
  549. }
  550. en, found := uni.GetTranslator("en") // or fallback if fails to find 'en'
  551. if !found {
  552. t.Fatalf("Expected '%t' Got '%t'", true, found)
  553. }
  554. tests := []struct {
  555. key interface{}
  556. params []string
  557. expected string
  558. expectedError bool
  559. }{
  560. {
  561. key: "test_trans",
  562. params: []string{"Joeybloggs", "The Test"},
  563. expected: "Welcome Joeybloggs to the The Test.",
  564. },
  565. {
  566. key: "test_trans2",
  567. params: []string{"Joeybloggs", "The Test"},
  568. expected: "Joeybloggs to the The Test.",
  569. },
  570. {
  571. key: "test_trans3",
  572. params: []string{"Joeybloggs", "The Test"},
  573. expected: "Welcome Joeybloggs to the The Test",
  574. },
  575. {
  576. key: "test_trans4",
  577. params: []string{"Joeybloggs", "The Test"},
  578. expected: "JoeybloggsThe Test",
  579. },
  580. // bad translation
  581. {
  582. key: "non-existant-key",
  583. params: []string{"Joeybloggs", "The Test"},
  584. expected: "",
  585. expectedError: true,
  586. },
  587. }
  588. for _, tt := range tests {
  589. s, err := en.T(tt.key, tt.params...)
  590. if s != tt.expected {
  591. if !tt.expectedError || (tt.expectedError && err != ErrUnknowTranslation) {
  592. t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
  593. }
  594. }
  595. }
  596. }
  597. func TestBadImport(t *testing.T) {
  598. // test non existant file
  599. e := en.New()
  600. uni := New(e, e)
  601. filename := "testdata/non-existant-file.json"
  602. expected := "stat testdata/non-existant-file.json: no such file or directory"
  603. err := uni.Import(JSON, filename)
  604. if err == nil || err.Error() != expected {
  605. t.Fatalf("Expected '%s' Got '%s'", expected, err)
  606. }
  607. // test bad parameter basic translation
  608. filename = "testdata/bad-translation1.json"
  609. expected = "error: bad parameter syntax, missing parameter '{0}' in translation. locale: 'en' key: 'test_trans3' text: 'Welcome {lettersnotpermitted} to the {1}'"
  610. err = uni.Import(JSON, filename)
  611. if err == nil || err.Error() != expected {
  612. t.Fatalf("Expected '%s' Got '%s'", expected, err)
  613. }
  614. // test missing bracket basic translation
  615. filename = "testdata/bad-translation2.json"
  616. expected = "error: missing bracket '{}', in translation. locale: 'en' key: 'test_trans3' text: 'Welcome {0 to the {1}'"
  617. err = uni.Import(JSON, filename)
  618. if err == nil || err.Error() != expected {
  619. t.Fatalf("Expected '%s' Got '%s'", expected, err)
  620. }
  621. // test missing locale basic translation
  622. filename = "testdata/bad-translation3.json"
  623. expected = "error: locale 'nl' not registered."
  624. err = uni.Import(JSON, filename)
  625. if err == nil || err.Error() != expected {
  626. t.Fatalf("Expected '%s' Got '%s'", expected, err)
  627. }
  628. // test bad plural definition
  629. filename = "testdata/bad-translation4.json"
  630. expected = "error: bad plural definition 'ut.translation{Locale:\"en\", Key:\"cardinal_test\", Translation:\"You have {0} day left.\", PluralType:\"NotAPluralType\", PluralRule:\"One\", OverrideExisting:false}'"
  631. err = uni.Import(JSON, filename)
  632. if err == nil || err.Error() != expected {
  633. t.Fatalf("Expected '%s' Got '%s'", expected, err)
  634. }
  635. // test bad plural rule for locale
  636. filename = "testdata/bad-translation5.json"
  637. expected = "error: cardinal plural rule 'Many' does not exist for locale 'en' key: 'cardinal_test' text: 'You have {0} day left.'"
  638. err = uni.Import(JSON, filename)
  639. if err == nil || err.Error() != expected {
  640. t.Fatalf("Expected '%s' Got '%s'", expected, err)
  641. }
  642. // test invalid JSON
  643. filename = "testdata/bad-translation6.json"
  644. expected = "invalid character ']' after object key:value pair"
  645. err = uni.Import(JSON, filename)
  646. if err == nil || err.Error() != expected {
  647. t.Fatalf("Expected '%s' Got '%s'", expected, err)
  648. }
  649. // test bad io.Reader
  650. f, err := os.Open(filename)
  651. if err != nil {
  652. t.Fatalf("Expected '%v' Got '%s'", nil, err)
  653. }
  654. f.Close()
  655. expected = "read testdata/bad-translation6.json: bad file descriptor"
  656. err = uni.ImportByReader(JSON, f)
  657. if err == nil || err.Error() != expected {
  658. t.Fatalf("Expected '%s' Got '%s'", expected, err)
  659. }
  660. }