i18n.test 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. ;;;; i18n.test --- Exercise the i18n API. -*- coding: utf-8; mode: scheme; -*-
  2. ;;;;
  3. ;;;; Copyright (C) 2006, 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
  4. ;;;; Ludovic Courtès
  5. ;;;;
  6. ;;;; This library is free software; you can redistribute it and/or
  7. ;;;; modify it under the terms of the GNU Lesser General Public
  8. ;;;; License as published by the Free Software Foundation; either
  9. ;;;; version 3 of the License, or (at your option) any later version.
  10. ;;;;
  11. ;;;; This library is distributed in the hope that it will be useful,
  12. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. ;;;; Lesser General Public License for more details.
  15. ;;;;
  16. ;;;; You should have received a copy of the GNU Lesser General Public
  17. ;;;; License along with this library; if not, write to the Free Software
  18. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. (define-module (test-suite i18n)
  20. :use-module (ice-9 i18n)
  21. :use-module (srfi srfi-1)
  22. :use-module (test-suite lib))
  23. ;; Start from a pristine locale state.
  24. (setlocale LC_ALL "C")
  25. (define exception:locale-error
  26. (cons 'system-error "Failed to install locale"))
  27. (with-test-prefix "locale objects"
  28. (pass-if "make-locale (2 args)"
  29. (not (not (make-locale LC_ALL "C"))))
  30. (pass-if "make-locale (2 args, list)"
  31. (not (not (make-locale (list LC_COLLATE LC_MESSAGES) "C"))))
  32. (pass-if "make-locale (3 args)"
  33. (not (not (make-locale (list LC_COLLATE) "C"
  34. (make-locale (list LC_MESSAGES) "C")))))
  35. (pass-if-exception "make-locale with unknown locale" exception:locale-error
  36. (make-locale LC_ALL "does-not-exist"))
  37. (pass-if "locale?"
  38. (and (locale? (make-locale (list LC_ALL) "C"))
  39. (locale? (make-locale (list LC_MESSAGES LC_NUMERIC) "C"
  40. (make-locale (list LC_CTYPE) "C")))))
  41. (pass-if "%global-locale"
  42. (and (locale? %global-locale))
  43. (locale? (make-locale (list LC_MONETARY) "C"
  44. %global-locale))))
  45. (with-test-prefix "text collation (English)"
  46. (pass-if "string-locale<?"
  47. (and (string-locale<? "hello" "world")
  48. (string-locale<? "hello" "world"
  49. (make-locale (list LC_COLLATE) "C"))))
  50. (pass-if "char-locale<?"
  51. (and (char-locale<? #\a #\b)
  52. (char-locale<? #\a #\b (make-locale (list LC_COLLATE) "C"))))
  53. (pass-if "string-locale-ci=?"
  54. (and (string-locale-ci=? "Hello" "HELLO")
  55. (string-locale-ci=? "Hello" "HELLO"
  56. (make-locale (list LC_COLLATE) "C"))))
  57. (pass-if "string-locale-ci<?"
  58. (and (string-locale-ci<? "hello" "WORLD")
  59. (string-locale-ci<? "hello" "WORLD"
  60. (make-locale (list LC_COLLATE) "C")))))
  61. (define %french-locale-name
  62. "fr_FR.ISO-8859-1")
  63. (define %french-utf8-locale-name
  64. "fr_FR.UTF-8")
  65. (define %turkish-utf8-locale-name
  66. "tr_TR.UTF-8")
  67. (define %german-utf8-locale-name
  68. "de_DE.UTF-8")
  69. (define %greek-utf8-locale-name
  70. "el_GR.UTF-8")
  71. (define %french-locale
  72. (false-if-exception
  73. (make-locale (list LC_CTYPE LC_COLLATE LC_NUMERIC LC_TIME)
  74. %french-locale-name)))
  75. (define %french-utf8-locale
  76. (false-if-exception
  77. (make-locale (list LC_CTYPE LC_COLLATE LC_NUMERIC LC_TIME)
  78. %french-utf8-locale-name)))
  79. (define %german-utf8-locale
  80. (false-if-exception
  81. (make-locale LC_ALL
  82. %german-utf8-locale-name)))
  83. (define %greek-utf8-locale
  84. (false-if-exception
  85. (make-locale LC_ALL
  86. %greek-utf8-locale-name)))
  87. (define %turkish-utf8-locale
  88. (false-if-exception
  89. (make-locale LC_ALL
  90. %turkish-utf8-locale-name)))
  91. (define (under-locale-or-unresolved locale thunk)
  92. ;; On non-GNU systems, an exception may be raised only when the locale is
  93. ;; actually used rather than at `make-locale'-time. Thus, we must guard
  94. ;; against both.
  95. (if locale
  96. (if (string-contains %host-type "-gnu")
  97. (thunk)
  98. (catch 'system-error thunk
  99. (lambda (key . args)
  100. (throw 'unresolved))))
  101. (throw 'unresolved)))
  102. (define (under-french-locale-or-unresolved thunk)
  103. (under-locale-or-unresolved %french-locale thunk))
  104. (define (under-french-utf8-locale-or-unresolved thunk)
  105. (under-locale-or-unresolved %french-utf8-locale thunk))
  106. (define (under-turkish-utf8-locale-or-unresolved thunk)
  107. (under-locale-or-unresolved %turkish-utf8-locale thunk))
  108. (define (under-german-utf8-locale-or-unresolved thunk)
  109. (under-locale-or-unresolved %german-utf8-locale thunk))
  110. (define (under-greek-utf8-locale-or-unresolved thunk)
  111. (under-locale-or-unresolved %greek-utf8-locale thunk))
  112. (with-test-prefix "text collation (French)"
  113. (pass-if "string-locale<?"
  114. (under-french-locale-or-unresolved
  115. (lambda ()
  116. (string-locale<? "été" "hiver" %french-locale))))
  117. (pass-if "char-locale<?"
  118. (under-french-locale-or-unresolved
  119. (lambda ()
  120. (char-locale<? #\é #\h %french-locale))))
  121. (pass-if "string-locale-ci=?"
  122. (under-french-locale-or-unresolved
  123. (lambda ()
  124. (string-locale-ci=? "ÉTÉ" "été" %french-locale))))
  125. (pass-if "string-locale-ci=? (2 args, wide strings)"
  126. (under-french-utf8-locale-or-unresolved
  127. (lambda ()
  128. ;; Note: Character `œ' is not part of Latin-1, so these are wide
  129. ;; strings.
  130. (dynamic-wind
  131. (lambda ()
  132. (setlocale LC_ALL "fr_FR.UTF-8"))
  133. (lambda ()
  134. (string-locale-ci=? "œuf" "ŒUF"))
  135. (lambda ()
  136. (setlocale LC_ALL "C"))))))
  137. (pass-if "string-locale-ci=? (3 args, wide strings)"
  138. (under-french-utf8-locale-or-unresolved
  139. (lambda ()
  140. (string-locale-ci=? "œuf" "ŒUF" %french-utf8-locale))))
  141. (pass-if "string-locale-ci<>?"
  142. (under-french-locale-or-unresolved
  143. (lambda ()
  144. (and (string-locale-ci<? "été" "Hiver" %french-locale)
  145. (string-locale-ci>? "HiVeR" "été" %french-locale)))))
  146. (pass-if "string-locale-ci<>? (wide strings)"
  147. (under-french-utf8-locale-or-unresolved
  148. (lambda ()
  149. ;; One of the strings is UCS-4, the other is Latin-1.
  150. (and (string-locale-ci<? "Œdème" "œuf" %french-utf8-locale)
  151. (string-locale-ci>? "Œuf" "œdÈMe" %french-utf8-locale)))))
  152. (pass-if "string-locale-ci<>? (wide and narrow strings)"
  153. (under-french-utf8-locale-or-unresolved
  154. (lambda ()
  155. ;; One of the strings is UCS-4, the other is Latin-1.
  156. (and (string-locale-ci>? "Œdème" "odyssée" %french-utf8-locale)
  157. (string-locale-ci<? "Odyssée" "œdème" %french-utf8-locale)))))
  158. (pass-if "char-locale-ci<>?"
  159. (under-french-locale-or-unresolved
  160. (lambda ()
  161. (and (char-locale-ci<? #\é #\H %french-locale)
  162. (char-locale-ci>? #\h #\É %french-locale)))))
  163. (pass-if "char-locale-ci<>? (wide)"
  164. (under-french-utf8-locale-or-unresolved
  165. (lambda ()
  166. (and (char-locale-ci<? #\o #\œ %french-utf8-locale)
  167. (char-locale-ci>? #\Œ #\e %french-utf8-locale))))))
  168. (with-test-prefix "text collation (German)"
  169. (pass-if "string-locale-ci=?"
  170. (under-german-utf8-locale-or-unresolved
  171. (lambda ()
  172. (let ((de (make-locale LC_ALL %german-utf8-locale-name)))
  173. (string-locale-ci=? "Straße" "STRASSE"))))))
  174. (with-test-prefix "text collation (Greek)"
  175. (pass-if "string-locale-ci=?"
  176. (under-greek-utf8-locale-or-unresolved
  177. (lambda ()
  178. (let ((gr (make-locale LC_ALL %greek-utf8-locale-name)))
  179. (string-locale-ci=? "ΧΑΟΣ" "χαος" gr))))))
  180. (with-test-prefix "character mapping"
  181. (pass-if "char-locale-downcase"
  182. (and (eq? #\a (char-locale-downcase #\A))
  183. (eq? #\a (char-locale-downcase #\A (make-locale LC_ALL "C")))))
  184. (pass-if "char-locale-upcase"
  185. (and (eq? #\Z (char-locale-upcase #\z))
  186. (eq? #\Z (char-locale-upcase #\z (make-locale LC_ALL "C")))))
  187. (pass-if "char-locale-titlecase"
  188. (and (eq? #\T (char-locale-titlecase #\t))
  189. (eq? #\T (char-locale-titlecase #\t (make-locale LC_ALL "C")))))
  190. (pass-if "char-locale-titlecase Dž"
  191. (and (eq? #\762 (char-locale-titlecase #\763))
  192. (eq? #\762 (char-locale-titlecase #\763 (make-locale LC_ALL "C")))))
  193. (pass-if "char-locale-upcase Turkish"
  194. (under-turkish-utf8-locale-or-unresolved
  195. (lambda ()
  196. (eq? #\İ (char-locale-upcase #\i %turkish-utf8-locale)))))
  197. (pass-if "char-locale-downcase Turkish"
  198. (under-turkish-utf8-locale-or-unresolved
  199. (lambda ()
  200. (eq? #\i (char-locale-downcase #\İ %turkish-utf8-locale))))))
  201. (with-test-prefix "string mapping"
  202. (pass-if "string-locale-downcase"
  203. (and (string=? "a" (string-locale-downcase "A"))
  204. (string=? "a" (string-locale-downcase "A" (make-locale LC_ALL "C")))))
  205. (pass-if "string-locale-upcase"
  206. (and (string=? "Z" (string-locale-upcase "z"))
  207. (string=? "Z" (string-locale-upcase "z" (make-locale LC_ALL "C")))))
  208. (pass-if "string-locale-titlecase"
  209. (and (string=? "Hello, World" (string-locale-titlecase "hello, world"))
  210. (string=? "Hello, World" (string-locale-titlecase
  211. "hello, world" (make-locale LC_ALL "C")))))
  212. (pass-if "string-locale-upcase German"
  213. (under-german-utf8-locale-or-unresolved
  214. (lambda ()
  215. (let ((de (make-locale LC_ALL %german-utf8-locale-name)))
  216. (string=? "STRASSE"
  217. (string-locale-upcase "Straße" de))))))
  218. (pass-if "string-locale-upcase Greek"
  219. (under-greek-utf8-locale-or-unresolved
  220. (lambda ()
  221. (let ((el (make-locale LC_ALL %greek-utf8-locale-name)))
  222. (string=? "ΧΑΟΣ"
  223. (string-locale-upcase "χαος" el))))))
  224. (pass-if "string-locale-upcase Greek (two sigmas)"
  225. (under-greek-utf8-locale-or-unresolved
  226. (lambda ()
  227. (let ((el (make-locale LC_ALL %greek-utf8-locale-name)))
  228. (string=? "ΓΕΙΆ ΣΑΣ"
  229. (string-locale-upcase "Γειά σας" el))))))
  230. (pass-if "string-locale-downcase Greek"
  231. (under-greek-utf8-locale-or-unresolved
  232. (lambda ()
  233. (let ((el (make-locale LC_ALL %greek-utf8-locale-name)))
  234. (string=? "χαος"
  235. (string-locale-downcase "ΧΑΟΣ" el))))))
  236. (pass-if "string-locale-downcase Greek (two sigmas)"
  237. (under-greek-utf8-locale-or-unresolved
  238. (lambda ()
  239. (let ((el (make-locale LC_ALL %greek-utf8-locale-name)))
  240. (string=? "γειά σας"
  241. (string-locale-downcase "ΓΕΙΆ ΣΑΣ" el))))))
  242. (pass-if "string-locale-upcase Turkish"
  243. (under-turkish-utf8-locale-or-unresolved
  244. (lambda ()
  245. (string=? "İI" (string-locale-upcase "iı" %turkish-utf8-locale)))))
  246. (pass-if "string-locale-downcase Turkish"
  247. (under-turkish-utf8-locale-or-unresolved
  248. (lambda ()
  249. (string=? "iı" (string-locale-downcase "İI" %turkish-utf8-locale))))))
  250. (with-test-prefix "number parsing"
  251. (pass-if "locale-string->integer"
  252. (call-with-values (lambda () (locale-string->integer "123"))
  253. (lambda (result char-count)
  254. (and (equal? result 123)
  255. (equal? char-count 3)))))
  256. (pass-if "locale-string->inexact"
  257. (call-with-values
  258. (lambda ()
  259. (locale-string->inexact "123.456"
  260. (make-locale (list LC_NUMERIC) "C")))
  261. (lambda (result char-count)
  262. (and (equal? result 123.456)
  263. (equal? char-count 7)))))
  264. (pass-if "locale-string->inexact (French)"
  265. (under-french-locale-or-unresolved
  266. (lambda ()
  267. (call-with-values
  268. (lambda ()
  269. (locale-string->inexact "123,456" %french-locale))
  270. (lambda (result char-count)
  271. (and (equal? result 123.456)
  272. (equal? char-count 7))))))))
  273. ;;;
  274. ;;; `nl-langinfo'
  275. ;;;
  276. (setlocale LC_ALL "C")
  277. (define %c-locale (make-locale LC_ALL "C"))
  278. (define %english-days
  279. '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday"))
  280. (define (every? . args)
  281. (not (not (apply every args))))
  282. (with-test-prefix "nl-langinfo et al."
  283. (pass-if "locale-day (1 arg)"
  284. (every? equal?
  285. %english-days
  286. (map locale-day (map 1+ (iota 7)))))
  287. (pass-if "locale-day (2 args)"
  288. (every? equal?
  289. %english-days
  290. (map (lambda (day)
  291. (locale-day day %c-locale))
  292. (map 1+ (iota 7)))))
  293. (pass-if "locale-day (2 args, using `%global-locale')"
  294. (every? equal?
  295. %english-days
  296. (map (lambda (day)
  297. (locale-day day %global-locale))
  298. (map 1+ (iota 7)))))
  299. (pass-if "locale-day (French)"
  300. (under-french-locale-or-unresolved
  301. (lambda ()
  302. (let ((result (locale-day 3 %french-locale)))
  303. (and (string? result)
  304. (string-ci=? result "mardi"))))))
  305. (pass-if "locale-day (French, using `%global-locale')"
  306. ;; Make sure `%global-locale' captures the current locale settings as
  307. ;; installed using `setlocale'.
  308. (under-french-locale-or-unresolved
  309. (lambda ()
  310. (dynamic-wind
  311. (lambda ()
  312. (setlocale LC_TIME %french-locale-name))
  313. (lambda ()
  314. (let* ((fr (make-locale (list LC_MONETARY) "C" %global-locale))
  315. (result (locale-day 3 fr)))
  316. (setlocale LC_ALL "C")
  317. (and (string? result)
  318. (string-ci=? result "mardi"))))
  319. (lambda ()
  320. (setlocale LC_ALL "C"))))))
  321. (pass-if "default locale"
  322. ;; Make sure the default locale does not capture the current locale
  323. ;; settings as installed using `setlocale'. The default locale should be
  324. ;; "C".
  325. (under-french-locale-or-unresolved
  326. (lambda ()
  327. (dynamic-wind
  328. (lambda ()
  329. (setlocale LC_ALL %french-locale-name))
  330. (lambda ()
  331. (let* ((locale (make-locale (list LC_MONETARY) "C"))
  332. (result (locale-day 3 locale)))
  333. (setlocale LC_ALL "C")
  334. (and (string? result)
  335. (string-ci=? result "Tuesday"))))
  336. (lambda ()
  337. (setlocale LC_ALL "C")))))))
  338. ;;;
  339. ;;; Numbers.
  340. ;;;
  341. (with-test-prefix "number->locale-string"
  342. ;; We assume the global locale is "C" at this point.
  343. (with-test-prefix "C"
  344. (pass-if "no thousand separator"
  345. ;; Unlike in English, the "C" locale has no thousand separator.
  346. ;; If this doesn't hold, the following tests will fail.
  347. (string=? "" (locale-thousands-separator)))
  348. (pass-if "integer"
  349. (string=? "123456" (number->locale-string 123456)))
  350. (pass-if "fraction"
  351. (string=? "1234.567" (number->locale-string 1234.567)))
  352. (pass-if "fraction, 1 digit"
  353. (string=? "1234.5" (number->locale-string 1234.567 1))))
  354. (with-test-prefix "French"
  355. (pass-if "integer"
  356. (under-french-locale-or-unresolved
  357. (lambda ()
  358. (let ((fr (make-locale LC_ALL %french-locale-name)))
  359. (string=? "123 456" (number->locale-string 123456 #t fr))))))
  360. (pass-if "fraction"
  361. (under-french-locale-or-unresolved
  362. (lambda ()
  363. (let ((fr (make-locale LC_ALL %french-locale-name)))
  364. (string=? "1 234,567" (number->locale-string 1234.567 #t fr))))))
  365. (pass-if "fraction, 1 digit"
  366. (under-french-locale-or-unresolved
  367. (lambda ()
  368. (let ((fr (make-locale LC_ALL %french-locale-name)))
  369. (string=? "1 234,5"
  370. (number->locale-string 1234.567 1 fr))))))))