001/*
002 * ModeShape (http://www.modeshape.org)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *       http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.modeshape.common.i18n;
017
018import static org.hamcrest.core.Is.is;
019import static org.hamcrest.core.IsInstanceOf.instanceOf;
020import static org.hamcrest.core.IsNot.not;
021import static org.hamcrest.core.IsNull.notNullValue;
022import static org.hamcrest.core.IsNull.nullValue;
023import static org.junit.Assert.assertThat;
024import java.lang.reflect.Field;
025import java.lang.reflect.Modifier;
026import java.util.Iterator;
027import java.util.Locale;
028import java.util.Map;
029import java.util.Set;
030import java.util.Map.Entry;
031import org.junit.Before;
032import org.junit.BeforeClass;
033import org.junit.Test;
034import org.modeshape.common.CommonI18n;
035import org.modeshape.common.SystemFailureException;
036
037/**
038 * @author John Verhaeg
039 * @author Randall Hauch
040 */
041public final class I18nTest {
042
043    @BeforeClass
044    public static void beforeClass() {
045        Locale.setDefault(Locale.US);
046    }
047
048    @Before
049    public void beforeEach() throws Exception {
050        clearFields(TestI18n.class);
051        clearFields(TestI18nDuplicateProperty.class);
052        clearFields(TestI18nFinal.class);
053        clearFields(TestI18nFinalField.class);
054        clearFields(TestI18nInterface.class);
055        clearFields(TestI18nMissingLocalization.class);
056        clearFields(TestI18nMissingProperty.class);
057        clearFields(TestI18nNotPublicField.class);
058        clearFields(TestI18nNotStaticField.class);
059        clearFields(TestI18nPrivate.class);
060        clearFields(TestI18nUnusedProperty.class);
061        for (Entry<Locale, Map<Class<?>, Set<String>>> localeToMapEntry : I18n.LOCALE_TO_CLASS_TO_PROBLEMS_MAP.entrySet()) {
062            for (Iterator<Entry<Class<?>, Set<String>>> iter = localeToMapEntry.getValue().entrySet().iterator(); iter.hasNext();) {
063                if (iter.next().getKey() != CommonI18n.class) {
064                    iter.remove();
065                }
066            }
067        }
068    }
069
070    private void clearFields( Class<?> i18nClass ) throws Exception {
071        for (Field fld : i18nClass.getDeclaredFields()) {
072            if (fld.getType() == I18n.class && (fld.getModifiers() & Modifier.PUBLIC) == Modifier.PUBLIC
073                && (fld.getModifiers() & Modifier.STATIC) == Modifier.STATIC
074                && (fld.getModifiers() & Modifier.FINAL) != Modifier.FINAL) {
075                fld.set(null, null);
076            }
077        }
078    }
079
080    @Test( expected = IllegalArgumentException.class )
081    public void shouldFailToGetLocalizationProblemLocalesIfNoClassSupplied() {
082        I18n.getLocalizationProblemLocales(null);
083    }
084
085    @Test
086    public void shouldNeverReturnNullWhenGettingLocalizationProblemLocales() {
087        assertThat(I18n.getLocalizationProblemLocales(TestI18n.class), notNullValue());
088    }
089
090    @Test( expected = IllegalArgumentException.class )
091    public void shouldFailToGetLocalizationProblemsForDefaultLocaleIfNoClassSupplied() {
092        I18n.getLocalizationProblems(null);
093    }
094
095    @Test( expected = IllegalArgumentException.class )
096    public void shouldFailToGetLocalizationProblemsForSuppliedLocaleIfNoClassSupplied() {
097        I18n.getLocalizationProblems(null, Locale.US);
098    }
099
100    @Test
101    public void shouldNeverReturnNullWhenGettingLocalizationProblemsForDefaultLocale() {
102        assertThat(I18n.getLocalizationProblems(TestI18n.class), notNullValue());
103    }
104
105    @Test
106    public void shouldNeverReturnNullWhenGettingLocalizationProblemsForSuppliedLocale() {
107        assertThat(I18n.getLocalizationProblems(TestI18n.class, Locale.US), notNullValue());
108    }
109
110    @Test
111    public void shouldNotHaveLocalizationProblemsAfterInitializationButBeforeLocalization() {
112        I18n.initialize(TestI18nUnusedProperty.class);
113        assertThat(I18n.getLocalizationProblems(TestI18nUnusedProperty.class, null).isEmpty(), is(true));
114        assertThat(I18n.getLocalizationProblemLocales(TestI18nUnusedProperty.class).isEmpty(), is(true));
115    }
116
117    @Test
118    public void shouldGetLocalizationProblemsForDefaultLocaleIfNoLocaleSupplied() {
119        I18n.initialize(TestI18nUnusedProperty.class);
120        TestI18nUnusedProperty.testMessage.text("test");
121        assertThat(I18n.getLocalizationProblems(TestI18nUnusedProperty.class, null).isEmpty(), is(false));
122    }
123
124    @Test( expected = IllegalArgumentException.class )
125    public void shouldFailToInitializeIfNoClassSupplied() {
126        I18n.initialize(null);
127    }
128
129    @Test( expected = SystemFailureException.class )
130    public void shouldFailToInitializeFinalI18nField() {
131        try {
132            I18n.initialize(TestI18nFinalField.class);
133        } catch (SystemFailureException err) {
134            assertThat(err.getMessage(), is(CommonI18n.i18nFieldFinal.text("testMessage", TestI18nFinalField.class)));
135            System.err.println(err);
136            throw err;
137        }
138    }
139
140    @Test( expected = SystemFailureException.class )
141    public void shouldFailToInitializeNonPublicI18nField() {
142        try {
143            I18n.initialize(TestI18nNotPublicField.class);
144        } catch (SystemFailureException err) {
145            assertThat(err.getMessage(), is(CommonI18n.i18nFieldNotPublic.text("testMessage", TestI18nNotPublicField.class)));
146            System.err.println(err);
147            throw err;
148        }
149    }
150
151    @Test( expected = SystemFailureException.class )
152    public void shouldFailToInitializeNonStaticI18nField() {
153        try {
154            I18n.initialize(TestI18nNotStaticField.class);
155        } catch (SystemFailureException err) {
156            assertThat(err.getMessage(), is(CommonI18n.i18nFieldNotStatic.text("testMessage", TestI18nNotStaticField.class)));
157            System.err.println(err);
158            throw err;
159        }
160    }
161
162    @Test
163    public void shouldInitializeFinalClasses() {
164        I18n.initialize(TestI18nFinal.class);
165        assertThat(TestI18nFinal.testMessage, instanceOf(I18n.class));
166    }
167
168    @Test
169    public void shouldInitializePrivateClasses() {
170        I18n.initialize(TestI18nPrivate.class);
171        assertThat(TestI18nPrivate.testMessage, instanceOf(I18n.class));
172    }
173
174    @Test
175    public void shouldInitializeI18nFields() {
176        I18n.initialize(TestI18n.class);
177        assertThat(TestI18n.testMessage, instanceOf(I18n.class));
178    }
179
180    @Test
181    public void shouldNotInitializeNonI18nFields() {
182        I18n.initialize(TestI18n.class);
183        assertThat(TestI18n.nonI18n, nullValue());
184    }
185
186    @Test( expected = IllegalArgumentException.class )
187    public void shouldFailToInitializeInterfaces() {
188        try {
189            I18n.initialize(TestI18nInterface.class);
190        } catch (IllegalArgumentException err) {
191            assertThat(err.getMessage(), is(CommonI18n.i18nClassInterface.text(TestI18nInterface.class.getName())));
192            System.err.println(err);
193            throw err;
194        }
195    }
196
197    @Test
198    public void shouldProvideIdempotentInitialization() {
199        I18n.initialize(TestI18n.class);
200        assertThat(TestI18n.testMessage1.text("test"), is("test"));
201        I18n.initialize(TestI18n.class);
202        assertThat(TestI18n.testMessage1.text("test"), is("test"));
203    }
204
205    @Test
206    public void shouldNotBeLocalizedAfterInitialization() {
207        I18n.initialize(TestI18nDuplicateProperty.class);
208        assertThat(TestI18nDuplicateProperty.testMessage.localeToTextMap.get(Locale.getDefault()), nullValue());
209        assertThat(TestI18nDuplicateProperty.testMessage.localeToProblemMap.get(Locale.getDefault()), nullValue());
210    }
211
212    @Test
213    public void shouldHaveIdThatMatchesFieldName() {
214        I18n.initialize(TestI18n.class);
215        assertThat(TestI18n.testMessage.id(), is("testMessage"));
216    }
217
218    @Test
219    public void shouldNotBeLocalizedIfAskedForId() {
220        I18n.initialize(TestI18nDuplicateProperty.class);
221        TestI18nDuplicateProperty.testMessage.id();
222        assertThat(TestI18nDuplicateProperty.testMessage.localeToTextMap.get(Locale.getDefault()), nullValue());
223        assertThat(TestI18nDuplicateProperty.testMessage.localeToProblemMap.get(Locale.getDefault()), nullValue());
224    }
225
226    @Test
227    public void shouldBeLocalizedIfAskedIfHasProblem() {
228        I18n.initialize(TestI18nDuplicateProperty.class);
229        TestI18nDuplicateProperty.testMessage.hasProblem();
230        assertThat(TestI18nDuplicateProperty.testMessage.localeToTextMap.get(Locale.getDefault()), notNullValue());
231        assertThat(TestI18nDuplicateProperty.testMessage.localeToProblemMap.get(Locale.getDefault()), notNullValue());
232    }
233
234    @Test
235    public void shouldBeLocalizedIfAskedForProblem() {
236        I18n.initialize(TestI18nDuplicateProperty.class);
237        TestI18nDuplicateProperty.testMessage.problem();
238        assertThat(TestI18nDuplicateProperty.testMessage.localeToTextMap.get(Locale.getDefault()), notNullValue());
239        assertThat(TestI18nDuplicateProperty.testMessage.localeToProblemMap.get(Locale.getDefault()), notNullValue());
240    }
241
242    @Test
243    public void shouldBeLocalizedIfConvertedToString() {
244        I18n.initialize(TestI18nDuplicateProperty.class);
245        TestI18nDuplicateProperty.testMessage.toString();
246        assertThat(TestI18nDuplicateProperty.testMessage.localeToTextMap.get(Locale.getDefault()), notNullValue());
247        assertThat(TestI18nDuplicateProperty.testMessage.localeToProblemMap.get(Locale.getDefault()), notNullValue());
248    }
249
250    @Test
251    public void shouldContainAngleBracketedProblemInTextIfMissingLocalization() {
252        I18n.initialize(TestI18nMissingLocalization.class);
253        String text = TestI18nMissingLocalization.testMessage.text();
254        assertThat(text,
255                   is('<' + CommonI18n.i18nLocalizationProblems.text(TestI18nMissingLocalization.class, Locale.getDefault()) + '>'));
256        System.out.println("Text: " + text);
257    }
258
259    @Test
260    public void shouldHaveProblemIfMissingLocalization() {
261        I18n.initialize(TestI18nMissingLocalization.class);
262        assertThat(TestI18nMissingLocalization.testMessage.hasProblem(), is(true));
263        String problem = TestI18nMissingLocalization.testMessage.problem();
264        assertThat(problem, is(CommonI18n.i18nLocalizationProblems.text(TestI18nMissingLocalization.class, Locale.getDefault())));
265        System.out.println("Problem: " + problem);
266    }
267
268    @Test
269    public void shouldHaveLocalicationProblemIfMissingLocalization() {
270        I18n.initialize(TestI18nMissingLocalization.class);
271        TestI18nMissingLocalization.testMessage.text();
272        assertThat(I18n.getLocalizationProblems(TestI18nMissingLocalization.class).size(), is(1));
273        assertThat(I18n.getLocalizationProblems(TestI18nMissingLocalization.class).iterator().next(),
274                   is(CommonI18n.i18nLocalizationFileNotFound.text(TestI18nMissingLocalization.class.getName())));
275        assertThat(I18n.getLocalizationProblemLocales(TestI18nMissingLocalization.class).size(), is(1));
276        assertThat(I18n.getLocalizationProblemLocales(TestI18nMissingLocalization.class).iterator().next(),
277                   is(Locale.getDefault()));
278    }
279
280    @Test
281    public void shouldHaveTextIfPropertyDuplicate() {
282        I18n.initialize(TestI18nDuplicateProperty.class);
283        String text = TestI18nDuplicateProperty.testMessage.text("test");
284        assertThat(text.charAt(0), not('<'));
285        System.out.println("Text: " + text);
286    }
287
288    @Test
289    public void shouldHaveProblemIfPropertyDuplicate() {
290        I18n.initialize(TestI18nDuplicateProperty.class);
291        assertThat(TestI18nDuplicateProperty.testMessage.hasProblem(), is(true));
292        String problem = TestI18nDuplicateProperty.testMessage.problem();
293        assertThat(problem, notNullValue());
294        System.out.println("Problem: " + problem);
295    }
296
297    @Test
298    public void shouldNotHaveLocalicationProblemIfPropertyDuplicate() {
299        I18n.initialize(TestI18nDuplicateProperty.class);
300        TestI18nDuplicateProperty.testMessage.text("test");
301        assertThat(I18n.getLocalizationProblems(TestI18nDuplicateProperty.class).isEmpty(), is(true));
302        assertThat(I18n.getLocalizationProblemLocales(TestI18nDuplicateProperty.class).isEmpty(), is(true));
303    }
304
305    @Test
306    public void shouldContainAngleBracketedProblemInTextIfPropertyMissing() {
307        I18n.initialize(TestI18nMissingProperty.class);
308        String text = TestI18nMissingProperty.testMessage1.text("test");
309        assertThat(text.charAt(0), is('<'));
310        System.out.println("Text: " + text);
311    }
312
313    @Test
314    public void shouldHaveProblemIfPropertyMissing() {
315        I18n.initialize(TestI18nMissingProperty.class);
316        assertThat(TestI18nMissingProperty.testMessage1.hasProblem(), is(true));
317        String problem = TestI18nMissingProperty.testMessage1.problem();
318        assertThat(problem, notNullValue());
319        System.out.println("Problem: " + problem);
320    }
321
322    @Test
323    public void shouldNotHaveLocalicationProblemIfPropertyMissing() {
324        I18n.initialize(TestI18nMissingProperty.class);
325        TestI18nMissingProperty.testMessage1.text("test");
326        assertThat(I18n.getLocalizationProblems(TestI18nMissingProperty.class).isEmpty(), is(true));
327        assertThat(I18n.getLocalizationProblemLocales(TestI18nMissingProperty.class).isEmpty(), is(true));
328    }
329
330    @Test
331    public void shouldHaveLocalicationProblemIfPropertyUnused() {
332        I18n.initialize(TestI18nUnusedProperty.class);
333        TestI18nUnusedProperty.testMessage.text("test");
334        assertThat(I18n.getLocalizationProblems(TestI18nUnusedProperty.class).size(), is(1));
335        assertThat(I18n.getLocalizationProblemLocales(TestI18nUnusedProperty.class).size(), is(1));
336        assertThat(I18n.getLocalizationProblemLocales(TestI18nUnusedProperty.class).iterator().next(), is(Locale.getDefault()));
337    }
338
339    @Test
340    public void shouldHaveTextMatchingLocalizationFilePropertyValue() {
341        I18n.initialize(TestI18n.class);
342        assertThat(TestI18n.testMessage.text(), is("Test Message"));
343    }
344
345    @Test( expected = IllegalArgumentException.class )
346    public void shouldFailIfTooFewArgumentsSuppliedToText() {
347        I18n.initialize(TestI18n.class);
348        try {
349            TestI18n.testMessage1.text();
350        } catch (IllegalArgumentException err) {
351            System.err.println(err);
352            throw err;
353        }
354    }
355
356    @Test( expected = IllegalArgumentException.class )
357    public void shouldFailIfTooManyArgumentsSuppliedToText() {
358        I18n.initialize(TestI18n.class);
359        try {
360            TestI18n.testMessage1.text("Test", "Message");
361        } catch (IllegalArgumentException err) {
362            System.err.println(err);
363            throw err;
364        }
365    }
366
367    @Test
368    public void shouldContainArgumentsInRightOrderInText() {
369        I18n.initialize(TestI18n.class);
370        assertThat(TestI18n.testMessage2.text("Test", "Message"), is("Message Test"));
371    }
372
373    @Test
374    public void shouldAllowReuseOfArgumentsInText() {
375        I18n.initialize(TestI18n.class);
376        assertThat(TestI18n.testMessage3.text("Test", "Message"), is("Message Test Message"));
377    }
378
379    @Test
380    public void shouldContainLocaleSpecificText() {
381        I18n.initialize(TestI18n.class);
382        assertThat(TestI18n.testMessage.text(Locale.FRENCH), is("Message de Test"));
383    }
384
385    @Test
386    public void shouldContainTextForDefaultLocaleIfMissingLocalizationForSuppliedLocale() {
387        I18n.initialize(TestI18n.class);
388        assertThat(TestI18n.testMessage.text(Locale.CHINESE), is("Test Message"));
389    }
390
391    public static class TestI18n {
392
393        public static I18n testMessage;
394        public static I18n testMessage1;
395        public static I18n testMessage2;
396        public static I18n testMessage3;
397        public static Object nonI18n;
398    }
399
400    private static class TestI18nDuplicateProperty {
401
402        public static I18n testMessage;
403    }
404
405    public static final class TestI18nFinal {
406
407        public static I18n testMessage;
408    }
409
410    public static class TestI18nFinalField {
411
412        public static final I18n testMessage = null;
413    }
414
415    public static interface TestI18nInterface {
416
417        I18n testMessage = null;
418    }
419
420    private static class TestI18nMissingProperty {
421
422        @SuppressWarnings( "unused" )
423        public static I18n testMessage;
424        public static I18n testMessage1;
425    }
426
427    public static class TestI18nNotPublicField {
428
429        static I18n testMessage;
430    }
431
432    public static class TestI18nNotStaticField {
433
434        public I18n testMessage;
435    }
436
437    private static class TestI18nPrivate {
438
439        public static I18n testMessage;
440    }
441
442    private static class TestI18nUnusedProperty {
443
444        public static I18n testMessage;
445    }
446
447    private static class TestI18nMissingLocalization {
448
449        public static I18n testMessage;
450    }
451}