1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.lang3.text;
18
19 import org.junit.Test;
20 import org.junit.Before;
21 import static org.junit.Assert.*;
22 import static org.apache.commons.lang3.JavaVersion.JAVA_1_4;
23
24 import java.text.ChoiceFormat;
25 import java.text.DateFormat;
26 import java.text.FieldPosition;
27 import java.text.Format;
28 import java.text.MessageFormat;
29 import java.text.NumberFormat;
30 import java.text.ParsePosition;
31 import java.util.Arrays;
32 import java.util.Calendar;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.HashSet;
36 import java.util.Locale;
37 import java.util.Map;
38
39 import org.apache.commons.lang3.SystemUtils;
40
41
42
43
44
45
46
47 public class ExtendedMessageFormatTest {
48
49 private final Map<String, FormatFactory> registry = new HashMap<String, FormatFactory>();
50
51 @Before
52 public void setUp() throws Exception {
53 registry.put("lower", new LowerCaseFormatFactory());
54 registry.put("upper", new UpperCaseFormatFactory());
55 }
56
57
58
59
60 @Test
61 public void testExtendedFormats() {
62 final String pattern = "Lower: {0,lower} Upper: {1,upper}";
63 final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
64 assertPatternsEqual("TOPATTERN", pattern, emf.toPattern());
65 assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "bar"}));
66 assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"Foo", "Bar"}));
67 assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "BAR"}));
68 assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "bar"}));
69 assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "BAR"}));
70 }
71
72
73
74
75 @Test
76 public void testEscapedQuote_LANG_477() {
77 final String pattern = "it''s a {0,lower} 'test'!";
78 final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
79 assertEquals("it's a dummy test!", emf.format(new Object[] {"DUMMY"}));
80 }
81
82
83
84
85 @Test
86 public void testExtendedAndBuiltInFormats() {
87 final Calendar cal = Calendar.getInstance();
88 cal.set(2007, Calendar.JANUARY, 23, 18, 33, 05);
89 final Object[] args = new Object[] {"John Doe", cal.getTime(), Double.valueOf("12345.67")};
90 final String builtinsPattern = "DOB: {1,date,short} Salary: {2,number,currency}";
91 final String extendedPattern = "Name: {0,upper} ";
92 final String pattern = extendedPattern + builtinsPattern;
93
94 final HashSet<Locale> testLocales = new HashSet<Locale>();
95 testLocales.addAll(Arrays.asList(DateFormat.getAvailableLocales()));
96 testLocales.retainAll(Arrays.asList(NumberFormat.getAvailableLocales()));
97 testLocales.add(null);
98
99 for (final Locale locale : testLocales) {
100 final MessageFormat builtins = createMessageFormat(builtinsPattern, locale);
101 final String expectedPattern = extendedPattern + builtins.toPattern();
102 DateFormat df = null;
103 NumberFormat nf = null;
104 ExtendedMessageFormat emf = null;
105 if (locale == null) {
106 df = DateFormat.getDateInstance(DateFormat.SHORT);
107 nf = NumberFormat.getCurrencyInstance();
108 emf = new ExtendedMessageFormat(pattern, registry);
109 } else {
110 df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
111 nf = NumberFormat.getCurrencyInstance(locale);
112 emf = new ExtendedMessageFormat(pattern, locale, registry);
113 }
114 final StringBuilder expected = new StringBuilder();
115 expected.append("Name: ");
116 expected.append(args[0].toString().toUpperCase());
117 expected.append(" DOB: ");
118 expected.append(df.format(args[1]));
119 expected.append(" Salary: ");
120 expected.append(nf.format(args[2]));
121 assertPatternsEqual("pattern comparison for locale " + locale, expectedPattern, emf.toPattern());
122 assertEquals(String.valueOf(locale), expected.toString(), emf.format(args));
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 @Test
185 public void testBuiltInChoiceFormat() {
186 final Object[] values = new Number[] {Integer.valueOf(1), Double.valueOf("2.2"), Double.valueOf("1234.5")};
187 String choicePattern = null;
188 final Locale[] availableLocales = ChoiceFormat.getAvailableLocales();
189
190 choicePattern = "{0,choice,1#One|2#Two|3#Many {0,number}}";
191 for (final Object value : values) {
192 checkBuiltInFormat(value + ": " + choicePattern, new Object[] {value}, availableLocales);
193 }
194
195 choicePattern = "{0,choice,1#''One''|2#\"Two\"|3#''{Many}'' {0,number}}";
196 for (final Object value : values) {
197 checkBuiltInFormat(value + ": " + choicePattern, new Object[] {value}, availableLocales);
198 }
199 }
200
201
202
203
204 @Test
205 public void testBuiltInDateTimeFormat() {
206 final Calendar cal = Calendar.getInstance();
207 cal.set(2007, Calendar.JANUARY, 23, 18, 33, 05);
208 final Object[] args = new Object[] {cal.getTime()};
209 final Locale[] availableLocales = DateFormat.getAvailableLocales();
210
211 checkBuiltInFormat("1: {0,date,short}", args, availableLocales);
212 checkBuiltInFormat("2: {0,date,medium}", args, availableLocales);
213 checkBuiltInFormat("3: {0,date,long}", args, availableLocales);
214 checkBuiltInFormat("4: {0,date,full}", args, availableLocales);
215 checkBuiltInFormat("5: {0,date,d MMM yy}", args, availableLocales);
216 checkBuiltInFormat("6: {0,time,short}", args, availableLocales);
217 checkBuiltInFormat("7: {0,time,medium}", args, availableLocales);
218 checkBuiltInFormat("8: {0,time,long}", args, availableLocales);
219 checkBuiltInFormat("9: {0,time,full}", args, availableLocales);
220 checkBuiltInFormat("10: {0,time,HH:mm}", args, availableLocales);
221 checkBuiltInFormat("11: {0,date}", args, availableLocales);
222 checkBuiltInFormat("12: {0,time}", args, availableLocales);
223 }
224
225 @Test
226 public void testOverriddenBuiltinFormat() {
227 final Calendar cal = Calendar.getInstance();
228 cal.set(2007, Calendar.JANUARY, 23);
229 final Object[] args = new Object[] {cal.getTime()};
230 final Locale[] availableLocales = DateFormat.getAvailableLocales();
231 final Map<String, ? extends FormatFactory> registry = Collections.singletonMap("date", new OverrideShortDateFormatFactory());
232
233
234 checkBuiltInFormat("1: {0,date}", registry, args, availableLocales);
235 checkBuiltInFormat("2: {0,date,medium}", registry, args, availableLocales);
236 checkBuiltInFormat("3: {0,date,long}", registry, args, availableLocales);
237 checkBuiltInFormat("4: {0,date,full}", registry, args, availableLocales);
238 checkBuiltInFormat("5: {0,date,d MMM yy}", registry, args, availableLocales);
239
240
241 for (int i = -1; i < availableLocales.length; i++) {
242 final Locale locale = i < 0 ? null : availableLocales[i];
243 final MessageFormat dateDefault = createMessageFormat("{0,date}", locale);
244 final String pattern = "{0,date,short}";
245 final ExtendedMessageFormat dateShort = new ExtendedMessageFormat(pattern, locale, registry);
246 assertEquals("overridden date,short format", dateDefault.format(args), dateShort.format(args));
247 assertEquals("overridden date,short pattern", pattern, dateShort.toPattern());
248 }
249 }
250
251
252
253
254 @Test
255 public void testBuiltInNumberFormat() {
256 final Object[] args = new Object[] {Double.valueOf("6543.21")};
257 final Locale[] availableLocales = NumberFormat.getAvailableLocales();
258 checkBuiltInFormat("1: {0,number}", args, availableLocales);
259 checkBuiltInFormat("2: {0,number,integer}", args, availableLocales);
260 checkBuiltInFormat("3: {0,number,currency}", args, availableLocales);
261 checkBuiltInFormat("4: {0,number,percent}", args, availableLocales);
262 checkBuiltInFormat("5: {0,number,00000.000}", args, availableLocales);
263 }
264
265
266
267
268 @Test
269 public void testEqualsHashcode() {
270 final Map<String, ? extends FormatFactory> registry = Collections.singletonMap("testfmt", new LowerCaseFormatFactory());
271 final Map<String, ? extends FormatFactory> otherRegitry = Collections.singletonMap("testfmt", new UpperCaseFormatFactory());
272
273 final String pattern = "Pattern: {0,testfmt}";
274 final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, Locale.US, registry);
275
276 ExtendedMessageFormat other = null;
277
278
279 assertTrue("same, equals()", emf.equals(emf));
280 assertTrue("same, hashcode()", emf.hashCode() == emf.hashCode());
281
282
283 other = new ExtendedMessageFormat(pattern, Locale.US, registry);
284 assertTrue("equal, equals()", emf.equals(other));
285 assertTrue("equal, hashcode()", emf.hashCode() == other.hashCode());
286
287
288 other = new OtherExtendedMessageFormat(pattern, Locale.US, registry);
289 assertFalse("class, equals()", emf.equals(other));
290 assertTrue("class, hashcode()", emf.hashCode() == other.hashCode());
291
292
293 other = new ExtendedMessageFormat("X" + pattern, Locale.US, registry);
294 assertFalse("pattern, equals()", emf.equals(other));
295 assertFalse("pattern, hashcode()", emf.hashCode() == other.hashCode());
296
297
298 other = new ExtendedMessageFormat(pattern, Locale.US, otherRegitry);
299 assertFalse("registry, equals()", emf.equals(other));
300 assertFalse("registry, hashcode()", emf.hashCode() == other.hashCode());
301
302
303 other = new ExtendedMessageFormat(pattern, Locale.FRANCE, registry);
304 assertFalse("locale, equals()", emf.equals(other));
305 assertTrue("locale, hashcode()", emf.hashCode() == other.hashCode());
306 }
307
308
309
310
311
312
313
314 private void checkBuiltInFormat(final String pattern, final Object[] args, final Locale[] locales) {
315 checkBuiltInFormat(pattern, null, args, locales);
316 }
317
318
319
320
321
322
323
324
325 private void checkBuiltInFormat(final String pattern, final Map<String, ?> registry, final Object[] args, final Locale[] locales) {
326 checkBuiltInFormat(pattern, registry, args, (Locale) null);
327 for (final Locale locale : locales) {
328 checkBuiltInFormat(pattern, registry, args, locale);
329 }
330 }
331
332
333
334
335
336
337
338
339
340 private void checkBuiltInFormat(final String pattern, final Map<String, ?> registry, final Object[] args, final Locale locale) {
341 final StringBuilder buffer = new StringBuilder();
342 buffer.append("Pattern=[");
343 buffer.append(pattern);
344 buffer.append("], locale=[");
345 buffer.append(locale);
346 buffer.append("]");
347 final MessageFormat mf = createMessageFormat(pattern, locale);
348
349 ExtendedMessageFormat emf = null;
350 if (locale == null) {
351 emf = new ExtendedMessageFormat(pattern);
352 } else {
353 emf = new ExtendedMessageFormat(pattern, locale);
354 }
355 assertEquals("format " + buffer.toString(), mf.format(args), emf.format(args));
356 assertPatternsEqual("toPattern " + buffer.toString(), mf.toPattern(), emf.toPattern());
357 }
358
359
360 private void assertPatternsEqual(final String message, final String expected, final String actual) {
361 if (SystemUtils.isJavaVersionAtLeast(JAVA_1_4)) {
362 assertEquals(message, expected, actual);
363 }
364 }
365
366
367
368
369
370
371
372 private MessageFormat createMessageFormat(final String pattern, final Locale locale) {
373 final MessageFormat result = new MessageFormat(pattern);
374 if (locale != null) {
375 result.setLocale(locale);
376 result.applyPattern(pattern);
377 }
378 return result;
379 }
380
381
382
383
384
385
386 private static class LowerCaseFormat extends Format {
387 @Override
388 public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
389 return toAppendTo.append(((String)obj).toLowerCase());
390 }
391 @Override
392 public Object parseObject(final String source, final ParsePosition pos) {throw new UnsupportedOperationException();}
393 }
394
395
396
397
398 private static class UpperCaseFormat extends Format {
399 @Override
400 public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
401 return toAppendTo.append(((String)obj).toUpperCase());
402 }
403 @Override
404 public Object parseObject(final String source, final ParsePosition pos) {throw new UnsupportedOperationException();}
405 }
406
407
408
409
410
411
412 private static class LowerCaseFormatFactory implements FormatFactory {
413 private static final Format LOWER_INSTANCE = new LowerCaseFormat();
414 @Override
415 public Format getFormat(final String name, final String arguments, final Locale locale) {
416 return LOWER_INSTANCE;
417 }
418 }
419
420
421
422 private static class UpperCaseFormatFactory implements FormatFactory {
423 private static final Format UPPER_INSTANCE = new UpperCaseFormat();
424 @Override
425 public Format getFormat(final String name, final String arguments, final Locale locale) {
426 return UPPER_INSTANCE;
427 }
428 }
429
430
431
432 private static class OverrideShortDateFormatFactory implements FormatFactory {
433 @Override
434 public Format getFormat(final String name, final String arguments, final Locale locale) {
435 return !"short".equals(arguments) ? null
436 : locale == null ? DateFormat
437 .getDateInstance(DateFormat.DEFAULT) : DateFormat
438 .getDateInstance(DateFormat.DEFAULT, locale);
439 }
440 }
441
442
443
444
445 private static class OtherExtendedMessageFormat extends ExtendedMessageFormat {
446 public OtherExtendedMessageFormat(final String pattern, final Locale locale,
447 final Map<String, ? extends FormatFactory> registry) {
448 super(pattern, locale, registry);
449 }
450
451 }
452
453 }