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