1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
|
(ns puppetlabs.i18n.core-test
(:require
[clojure.java.io :as io]
[clojure.pprint :refer [pprint]]
[clojure.test :refer :all]
[puppetlabs.i18n.core
:refer [as-number
available-locales
bundle-for-namespace
info-map'
locale-negotiator
negotiate-locale
parse-http-accept-header
string-as-locale
system-locale
trs
trsn
tru
trun
user-locale
with-user-locale]]))
;; Set the JVM's default locale so we run in a known environment
(. java.util.Locale setDefault (string-as-locale "en-US"))
(def de (string-as-locale "de-DE"))
(def eo (string-as-locale "eo"))
(def en (string-as-locale "en-US"))
(def welcome_en "Welcome! This is localized")
(def welcome_de "Willkommen ! Draußen nur Kännchen")
(def welcome_eo "Welcome_pseudo_localized")
(def one_bottle "There is one bottle of beer on the wall.")
(def n_bottles "There are {0} bottles of beer on the wall.")
(def one_bottle_en "There is one bottle of beer on the wall.")
(def one_bottle_de "Es gibt eine Flasche Bier an der Wand.")
(def six_bottle_en "There are 6 bottles of beer on the wall.")
(def six_bottle_de "Es gibt 6 Flaschen Bier an der Wand.")
(deftest handling-of-user-locale
(testing "user-locale defaults to system-locale"
(is (= (system-locale) (user-locale))))
(testing "with-user-locale changes user-locale"
(with-user-locale de
(is (= de (user-locale)))))
(testing "user-locale is conveyed to future"
(with-user-locale de
(is (= de
@(future (user-locale))))))
(testing "with-user-locale fails when not passed a java.util.Locale"
(is (thrown? IllegalArgumentException (with-user-locale "de" nil)))))
(deftest test-tru
(testing "tru with no user locale"
(is (= welcome_en (tru welcome_en))))
(testing "tru in German"
(with-user-locale de
(is (= welcome_de (tru welcome_en)))))
(testing "tru in Esperanto"
;; We use Esperanto as our test locale
(with-user-locale eo
(is (= welcome_eo (tru welcome_en))))))
(deftest test-trun
(testing "trun with no user locale"
(is (= one_bottle_en (trun one_bottle n_bottles 1)))
(is (= six_bottle_en (trun one_bottle n_bottles 6))))
(testing "trun in German"
(with-user-locale de (is (= one_bottle_de (trun one_bottle n_bottles 1))))
(with-user-locale de (is (= six_bottle_de (trun one_bottle n_bottles 6))))))
(deftest test-trs
(testing "trs with no user locale"
(is (= welcome_en (trs welcome_en))))
(testing "trs with a user locale"
(with-user-locale de
(is (= welcome_en (trs welcome_en))))))
(deftest test-trsn
(testing "trsn with no user locale"
(is (= one_bottle_en (trsn one_bottle n_bottles 1)))
(is (= six_bottle_en (trsn one_bottle n_bottles 6))))
(testing "trsn with a user locale"
(with-user-locale de (is (= one_bottle_en (trsn one_bottle n_bottles 1))))
(with-user-locale de (is (= six_bottle_en (trsn one_bottle n_bottles 6))))))
(deftest test-empty-string-msgid-fallback-to-pot-no-header
(testing "trsn with no user locale"
(is (= "" (trsn "" "" 1)))
(is (= "" (trsn "" "" 6)))
(is (= "" (trsn "" "fred" 1)))
(is (= "fred" (trsn "" "fred" 6)))
; msgid/msgstr not in po/bundle render correctly
(is (= "fred" (trsn "fred" "" 1)))
(is (= "" (trsn "fred" "" 6))))
(testing "trsn with a user locale"
(with-user-locale de
(is (= "" (trsn "" "" 1)))
(is (= "" (trsn "" "" 6)))
(is (= "" (trsn "" "fred" 1)))
(is (= "fred" (trsn "" "fred" 6)))
; msgid/msgstr not in po/bundle render correctly
(is (= "fred" (trsn "fred" "" 1)))
(is (= "" (trsn "fred" "" 6)))))
(testing "trun can display an empty string"
(with-user-locale de
(is (= "" (trun "" "" 1)))
(is (= "" (trun "" "" 6)))
(is (= "" (trun "" "fred" 1)))
(is (= "fred" (trun "" "fred" 6)))
; msgid/msgstr not in po/bundle render correctly
(is (= "fred" (trun "fred" "" 1)))
(is (= "" (trun "fred" "" 6)))))
(testing "trs can display an empty string"
(with-user-locale de
(is (= "" (trs "")))
(is (= " " (trs " ")))))
(testing "tru can display an empty string"
(with-user-locale de
(is (= "" (tru "")))
(is (= " " (tru " "))))))
;;
;; Helper files in dev-resources; they have the same format as the
;; locales.clj file that the Makefile generates
;;
(defn one-locale-file
[]
[(io/resource "test-locales/de-ru-es.clj")])
(defn two-locale-files
[]
[(io/resource "test-locales/de-ru-es.clj")
(io/resource "test-locales/fr-it.clj")])
(defn conflicting-locale-files
[]
[(io/resource "test-locales/de-ru-es.clj")
(io/resource "test-locales/merge-eo.clj")
(io/resource "test-locales/conflicting-de.clj")])
(defn uberjar-locale-file
[]
[(io/resource "test-locales/uberjar-en-de.clj")])
(defn merge-locale-files
[]
[(io/resource "test-locales/de-ru-es.clj")
(io/resource "test-locales/merge-eo.clj")])
(defn multi-pacakge-locale-file
[]
[(io/resource "test-locales/multi-pacakge-es.clj")])
(defn overlapping-pacakge-locale-file
[]
[(io/resource "test-locales/overlapping-packages.clj")
(io/resource "test-locales/multi-pacakge-es.clj")])
(deftest test-infos
(with-redefs
[puppetlabs.i18n.core/info-files one-locale-file]
(testing "info-map"
(is (= ["example.i18n"] (keys (info-map'))))
(is (= "example.i18n.Messages" (:bundle (get (info-map') "example.i18n")))))
(testing "available-locales"
(is (= #{"de" "ru" "es"} (available-locales)))))
(with-redefs
[puppetlabs.i18n.core/info-files overlapping-pacakge-locale-file]
(testing "bundle-for-namespace ordering with overlapping packages and same length namespaces"
(are [bundle i18n-ns]
(= bundle (bundle-for-namespace (info-map') i18n-ns))
"overlapped_package.i18n.Messages" "example"
"multi_package.i18n.Messages" "example.i18n"
"multi_package.i18n.Messages" "alternate.i18n"
"overlapped_package.i18n.Messages" "alt3rnat3.i18n"
"overlapped_package.i18n.Messages" "example.i18n.another_package")))
(with-redefs
[puppetlabs.i18n.core/info-files two-locale-files]
(testing "info-map #2"
(is (= #{"example.i18n" "other.i18n"} (into #{} (keys (info-map')))))
(is (= "example.i18n.Messages" (:bundle (get (info-map') "example.i18n")))))
(testing "available-locales #2"
(is (= #{"it" "fr" "de" "ru" "es"} (available-locales))))
(testing "bundle-for-namespace"
(is (= "example.i18n.Messages" (bundle-for-namespace (info-map') "example.i18n")))
(is (= "example.i18n.Messages"
(bundle-for-namespace (info-map') "example.i18n.dog.cat")))
(is (nil? (bundle-for-namespace (info-map') "example")))
(is (= "other.i18n.Messages"
(bundle-for-namespace (info-map') "other.i18n.abbott.costello")))))
(with-redefs
[puppetlabs.i18n.core/info-files conflicting-locale-files]
(testing "conflicting locales"
(is (thrown-with-msg? Exception #"Invalid locales info: .* are both for package .* but set different bundles"
(info-map')))))
(with-redefs
[puppetlabs.i18n.core/info-files uberjar-locale-file]
(testing "info-map"
(is (= #{"puppetlabs.i18n" "puppetlabs.foo"} (set (keys (info-map')))))
(is (= "puppetlabs.foo.Messages" (:bundle (get (info-map') "puppetlabs.foo"))))
(is (= "puppetlabs.i18n.Messages" (:bundle (get (info-map') "puppetlabs.i18n")))))
(testing "available-locales"
(is (= #{"de" "en" "fr"} (available-locales)))))
(with-redefs
[puppetlabs.i18n.core/info-files merge-locale-files]
(testing "merged langauges"
(is (= #{"de" "ru" "es" "eo"} (available-locales)))
(is (= 1 (count (info-map'))))))
(with-redefs
[puppetlabs.i18n.core/info-files multi-pacakge-locale-file]
(testing "multi package locales"
(is (= "multi_package.i18n.Messages"
(bundle-for-namespace (info-map') "example.i18n.abbott.costello")))
(is (= "multi_package.i18n.Messages"
(bundle-for-namespace (info-map') "alternate.i18n.abbott.costello"))))))
(deftest test-as-number
(testing "convert number strings properly"
(is (= 0.1 (as-number "0.1")))
(is (= 1.0 (as-number "1.0")))
(is (= 0.5 (as-number 0.5))))
(testing "turns garbage into 0"
(is (= 0 (as-number "xyz")))
(is (= 0 (as-number true)))
(is (= 0 (as-number nil)))))
(deftest test-parse-http-accept-header
(let [p #(parse-http-accept-header %)]
(testing "parses q-values properly"
(is (= '(["de-DE" 1]) (p "de-DE")))
(is (= '(["de-DE" 0.5]) (p "de-DE;q=0.5")))
(is (= '() (p "de-DE;q=0.0")))
(is (= '() (p "de-DE;q=garbage"))))
(testing "sorts locales properly"
(is (= '(["de-DE" 1] ["de" 1]) (p "de-DE, de")))
(is (= '(["de-DE" 1.0] ["de" 1]) (p "de-DE;q=1, de")))
(is (= '(["de-DE" 1] ["de" 0.9] ) (p "de;q=0.9, de-DE")))
(is (= '(["de-DE" 0.8] ["de" 0.7]) (p "de;q=0.7, de-DE;q=0.8")))
(is (= '(["de-DE" 0.8] ["de" 0.7]) (p "de-DE;q=0.8 , de;q=0.7, ")))
(is (= '(["de" 1] ["en-gb" 0.8] ["en" 0.7])
(p "de, en-gb;q=0.8, en;q=0.7"))))))
(deftest test-negotiate-locale
(with-redefs
[puppetlabs.i18n.core/system-locale #(string-as-locale "oc")]
(let [check
(fn [exp wanted]
(is (= (string-as-locale exp)
(negotiate-locale wanted #{"de" "fr-FR" "en"}))))]
(testing "works"
(check "de" ["it" "de" "en"])
(check "en" ["it" "en" "de"])
(check "en" ["en_US" "en" "de"])
(check "oc" ["da" "no"]))
;; The next two tests are here to document current behavior, not
;; because that behavior is nevessarily a great idea
(testing "country variants for a locale we have are ignored"
(check "oc" ["de-CH" "it"]))
(testing "generic locale when we have country variant is ignored"
(check "fr-FR" ["fr" "fr-FR"])))))
(deftest test-locale-negotiator
(with-redefs
[puppetlabs.i18n.core/available-locales (fn [] #{"de" "fr-FR" "en"})
puppetlabs.i18n.core/system-locale #(string-as-locale "oc")]
(let [neg (locale-negotiator (fn [request] (user-locale)))
mk-request (fn [accept]
{:headers {"accept-language" accept}})
check (fn [exp accept]
(is (= (string-as-locale exp)
(neg (mk-request accept)))))]
(testing "works for valid headers"
(check "de" "de")
(check "de" "de_DE, de;q=0.9, en;q=0.8")
(check "oc" "it, fr"))
(testing "falls back to system-locale for empty/invalid headers"
(doseq [x ["" nil "en;q=garbage" ",,," ",;," "xyz" "de-US"]]
(check "oc" x))
(is (= (system-locale) (neg {:headers {}})))
(is (= (system-locale) (neg {}))))
(testing "conveys the locale"
(is (= (string-as-locale "de")
((locale-negotiator (fn [request] @(future (user-locale))))
(mk-request "de"))))))))
|