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