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