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