View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.text;
18  
19  import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
20  import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertNotEquals;
23  
24  import java.text.DateFormat;
25  import java.text.FieldPosition;
26  import java.text.Format;
27  import java.text.MessageFormat;
28  import java.text.NumberFormat;
29  import java.text.ParsePosition;
30  import java.util.Arrays;
31  import java.util.Calendar;
32  import java.util.Collections;
33  import java.util.HashMap;
34  import java.util.HashSet;
35  import java.util.Locale;
36  import java.util.Map;
37  
38  import org.junit.jupiter.api.BeforeEach;
39  import org.junit.jupiter.api.Test;
40  
41  /**
42   * Test case for {@link ExtendedMessageFormat}.
43   */
44  public class ExtendedMessageFormatTest {
45  
46      /**
47       * {@link Format} implementation which converts to lower case.
48       */
49      private static final class LowerCaseFormat extends Format {
50          static final Format INSTANCE = new LowerCaseFormat();
51          static final FormatFactory FACTORY = (n, a, l) -> LowerCaseFormat.INSTANCE;
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  
59          @Override
60          public Object parseObject(final String source, final ParsePosition pos) {
61              throw new UnsupportedOperationException();
62          }
63      }
64  
65      /**
66       * Alternative ExtendedMessageFormat impl.
67       */
68      private static final class OtherExtendedMessageFormat extends ExtendedMessageFormat {
69          private static final long serialVersionUID = 1L;
70  
71          OtherExtendedMessageFormat(final String pattern, final Locale locale,
72                  final Map<String, ? extends FormatFactory> registry) {
73              super(pattern, locale, registry);
74          }
75      }
76  
77      /**
78       * {@link FormatFactory} implementation to override date format "short" to "default".
79       */
80      private static final class OverrideShortDateFormatFactory {
81          static final FormatFactory FACTORY = (n, a, l) -> !"short".equals(a) ? null
82                  : l == null ? DateFormat
83                          .getDateInstance(DateFormat.DEFAULT) : DateFormat
84                          .getDateInstance(DateFormat.DEFAULT, l);
85      }
86  
87      /**
88       * {@link Format} implementation which converts to upper case.
89       */
90      private static final class UpperCaseFormat extends Format {
91          static final Format INSTANCE = new UpperCaseFormat();
92          static final FormatFactory FACTORY = (n, a, l) -> UpperCaseFormat.INSTANCE;
93          private static final long serialVersionUID = 1L;
94  
95          @Override
96          public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
97              return toAppendTo.append(((String) obj).toUpperCase(Locale.ROOT));
98          }
99  
100         @Override
101         public Object parseObject(final String source, final ParsePosition pos) {
102             throw new UnsupportedOperationException();
103         }
104     }
105 
106     private final Map<String, FormatFactory> registry = new HashMap<>();
107 
108     /**
109      * Create an ExtendedMessageFormat for the specified pattern and locale and check the
110      * formatted output matches the expected result for the parameters.
111      * @param pattern string
112      * @param registryUnused map (currently unused)
113      * @param args Object[]
114      * @param locale Locale
115      */
116     private void checkBuiltInFormat(final String pattern, final Map<String, ?> registryUnused, final Object[] args,
117             final Locale locale) {
118         final StringBuilder buffer = new StringBuilder();
119         buffer.append("Pattern=[");
120         buffer.append(pattern);
121         buffer.append("], locale=[");
122         buffer.append(locale);
123         buffer.append("]");
124         final MessageFormat mf = createMessageFormat(pattern, locale);
125         // System.out.println(buffer + ", result=[" + mf.format(args) +"]");
126         ExtendedMessageFormat emf = null;
127         if (locale == null) {
128             emf = new ExtendedMessageFormat(pattern);
129         } else {
130             emf = new ExtendedMessageFormat(pattern, locale);
131         }
132         assertEquals(mf.format(args), emf.format(args), "format "    + buffer.toString());
133         assertEquals(mf.toPattern(), emf.toPattern(), "toPattern " + buffer.toString());
134     }
135 
136 //    /**
137 //     * Test extended formats with choice format.
138 //     *
139 //     * NOTE: FAILING - currently sub-formats not supported
140 //     */
141 //    public void testExtendedWithChoiceFormat() {
142 //        String pattern = "Choice: {0,choice,1.0#{1,lower}|2.0#{1,upper}}";
143 //        ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
144 //        assertPatterns(null, pattern, emf.toPattern());
145 //        try {
146 //            assertEquals("one", emf.format(new Object[] {Integer.valueOf(1), "ONE"}));
147 //            assertEquals("TWO", emf.format(new Object[] {Integer.valueOf(2), "two"}));
148 //        } catch (IllegalArgumentException e) {
149 //            // currently sub-formats not supported
150 //        }
151 //    }
152 
153 //    /**
154 //     * Test mixed extended and built-in formats with choice format.
155 //     *
156 //     * NOTE: FAILING - currently sub-formats not supported
157 //     */
158 //    public void testExtendedAndBuiltInWithChoiceFormat() {
159 //        String pattern = "Choice: {0,choice,1.0#{0} {1,lower} {2,number}|2.0#{0} {1,upper} {2,number,currency}}";
160 //        Object[] lowArgs  = new Object[] {Integer.valueOf(1), "Low",  Double.valueOf("1234.56")};
161 //        Object[] highArgs = new Object[] {Integer.valueOf(2), "High", Double.valueOf("9876.54")};
162 //        Locale[] availableLocales = ChoiceFormat.getAvailableLocales();
163 //        Locale[] testLocales = new Locale[availableLocales.length + 1];
164 //        testLocales[0] = null;
165 //        System.arraycopy(availableLocales, 0, testLocales, 1, availableLocales.length);
166 //        for (int i = 0; i < testLocales.length; i++) {
167 //            NumberFormat nf = null;
168 //            NumberFormat cf = null;
169 //            ExtendedMessageFormat emf = null;
170 //            if (testLocales[i] == null) {
171 //                nf = NumberFormat.getNumberInstance();
172 //                cf = NumberFormat.getCurrencyInstance();
173 //                emf = new ExtendedMessageFormat(pattern, registry);
174 //            } else {
175 //                nf = NumberFormat.getNumberInstance(testLocales[i]);
176 //                cf = NumberFormat.getCurrencyInstance(testLocales[i]);
177 //                emf = new ExtendedMessageFormat(pattern, testLocales[i], registry);
178 //            }
179 //            assertPatterns(null, pattern, emf.toPattern());
180 //            try {
181 //                String lowExpected = lowArgs[0] + " low "    + nf.format(lowArgs[2]);
182 //                String highExpected = highArgs[0] + " HIGH "  + cf.format(highArgs[2]);
183 //                assertEquals(lowExpected,  emf.format(lowArgs));
184 //                assertEquals(highExpected, emf.format(highArgs));
185 //            } catch (IllegalArgumentException e) {
186 //                // currently sub-formats not supported
187 //            }
188 //        }
189 //    }
190 
191     /**
192      * Test a built in format for the specified Locales, plus {@code null} Locale.
193      * @param pattern MessageFormat pattern
194      * @param fmtRegistry FormatFactory registry to use
195      * @param args MessageFormat arguments
196      * @param locales to test
197      */
198     private void checkBuiltInFormat(final String pattern, final Map<String, ?> fmtRegistry, final Object[] args,
199             final Locale[] locales) {
200         checkBuiltInFormat(pattern, fmtRegistry, args, (Locale) null);
201         for (final Locale locale : locales) {
202             checkBuiltInFormat(pattern, fmtRegistry, args, locale);
203         }
204     }
205 
206     /**
207      * Test a built in format for the specified Locales, plus {@code null} Locale.
208      * @param pattern MessageFormat pattern
209      * @param args MessageFormat arguments
210      * @param locales to test
211      */
212     private void checkBuiltInFormat(final String pattern, final Object[] args, final Locale[] locales) {
213         checkBuiltInFormat(pattern, null, args, locales);
214     }
215 
216     /**
217      * Replace MessageFormat(String, Locale) constructor (not available until JDK 1.4).
218      * @param pattern string
219      * @param locale Locale
220      * @return MessageFormat
221      */
222     private MessageFormat createMessageFormat(final String pattern, final Locale locale) {
223         final MessageFormat result = new MessageFormat(pattern);
224         if (locale != null) {
225             result.setLocale(locale);
226             result.applyPattern(pattern);
227         }
228         return result;
229     }
230 
231     @BeforeEach
232     public void setUp() {
233         registry.put("lower", LowerCaseFormat.FACTORY);
234         registry.put("upper", UpperCaseFormat.FACTORY);
235     }
236 
237     /**
238      * Test the built in choice format.
239      */
240     @Test
241     public void testBuiltInChoiceFormat() {
242         final Object[] values = new Number[] {1, Double.valueOf("2.2"), Double.valueOf("1234.5")};
243         String choicePattern;
244         final Locale[] availableLocales = NumberFormat.getAvailableLocales();
245 
246         choicePattern = "{0,choice,1#One|2#Two|3#Many {0,number}}";
247         for (final Object value : values) {
248             checkBuiltInFormat(value + ": " + choicePattern, new Object[] {value}, availableLocales);
249         }
250 
251         choicePattern = "{0,choice,1#''One''|2#\"Two\"|3#''{Many}'' {0,number}}";
252         for (final Object value : values) {
253             checkBuiltInFormat(value + ": " + choicePattern, new Object[] {value}, availableLocales);
254         }
255     }
256 
257     /**
258      * Test the built in date/time formats
259      */
260     @Test
261     public void testBuiltInDateTimeFormat() {
262         final Calendar cal = Calendar.getInstance();
263         cal.set(2007, Calendar.JANUARY, 23, 18, 33, 5);
264         final Object[] args = {cal.getTime()};
265         final Locale[] availableLocales = DateFormat.getAvailableLocales();
266 
267         checkBuiltInFormat("1: {0,date,short}",    args, availableLocales);
268         checkBuiltInFormat("2: {0,date,medium}",   args, availableLocales);
269         checkBuiltInFormat("3: {0,date,long}",     args, availableLocales);
270         checkBuiltInFormat("4: {0,date,full}",     args, availableLocales);
271         checkBuiltInFormat("5: {0,date,d MMM yy}", args, availableLocales);
272         checkBuiltInFormat("6: {0,time,short}",    args, availableLocales);
273         checkBuiltInFormat("7: {0,time,medium}",   args, availableLocales);
274         checkBuiltInFormat("8: {0,time,long}",     args, availableLocales);
275         checkBuiltInFormat("9: {0,time,full}",     args, availableLocales);
276         checkBuiltInFormat("10: {0,time,HH:mm}",   args, availableLocales);
277         checkBuiltInFormat("11: {0,date}",         args, availableLocales);
278         checkBuiltInFormat("12: {0,time}",         args, availableLocales);
279     }
280 
281     /**
282      * Test the built in number formats.
283      */
284     @Test
285     public void testBuiltInNumberFormat() {
286         final Object[] args = {Double.valueOf("6543.21")};
287         final Locale[] availableLocales = NumberFormat.getAvailableLocales();
288         checkBuiltInFormat("1: {0,number}",           args, availableLocales);
289         checkBuiltInFormat("2: {0,number,integer}",   args, availableLocales);
290         checkBuiltInFormat("3: {0,number,currency}",  args, availableLocales);
291         checkBuiltInFormat("4: {0,number,percent}",   args, availableLocales);
292         checkBuiltInFormat("5: {0,number,00000.000}", args, availableLocales);
293     }
294 
295     /**
296      * Test Bug TEXT-106 - Exception while using ExtendedMessageFormat and choice format element with quote just
297      * before brace end
298      */
299     @Test
300     public void testChoiceQuoteJustBeforeBraceEnd_TEXT_106() {
301         final String pattern2 = "Choice format element with quote just before brace end ''{0,choice,0#0|0<'1'}''";
302         final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern2, registry);
303         assertEquals("Choice format element with quote just before brace end '0'", emf.format(new Object[] {0}));
304         assertEquals("Choice format element with quote just before brace end '1'", emf.format(new Object[] {1}));
305     }
306 
307     @Test
308     public void testCreatesExtendedMessageFormatTakingString() {
309         final ExtendedMessageFormat extendedMessageFormat =
310                 new ExtendedMessageFormat("Unterminated format element at position ");
311         final Map<String, FormatFactory> map = new HashMap<>();
312         final ExtendedMessageFormat extendedMessageFormatTwo =
313                 new ExtendedMessageFormat("Unterminated format element at position ", map);
314 
315         assertEquals("Unterminated format element at position ", extendedMessageFormatTwo.toPattern());
316         assertNotEquals(extendedMessageFormat, extendedMessageFormatTwo);
317     }
318 
319     /**
320      * Test Bug LANG-917 - IndexOutOfBoundsException and/or infinite loop when using a choice pattern
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("Hi there, got 3, GREAT!", emf.format(new Object[] {"there", 3, "great"}));
327     }
328 
329     /**
330      * Test equals() and hashCode().
331      */
332     @Test
333     public void testEqualsHashcode() {
334         final Map<String, ? extends FormatFactory> fmtRegistry =
335                 Collections.singletonMap("testfmt", LowerCaseFormat.FACTORY);
336         final Map<String, ? extends FormatFactory> otherRegistry =
337                 Collections.singletonMap("testfmt", UpperCaseFormat.FACTORY);
338 
339         final String pattern = "Pattern: {0,testfmt}";
340         final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
341 
342         ExtendedMessageFormat other;
343 
344         // Same object
345         assertEquals(emf, emf, "same, equals()");
346         assertEquals(emf.hashCode(), emf.hashCode(), "same, hashCode()");
347 
348         assertNotEquals(null, emf, "null, equals");
349 
350         // Equal Object
351         other = new ExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
352         assertEquals(emf, other, "equal, equals()");
353         assertEquals(emf.hashCode(), other.hashCode(), "equal, hashCode()");
354 
355         // Different Class
356         other = new OtherExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
357         assertNotEquals(emf, other, "class, equals()");
358         assertEquals(emf.hashCode(), other.hashCode(), "class, hashCode()"); // same hash code
359 
360         // Different pattern
361         other = new ExtendedMessageFormat("X" + pattern, Locale.US, fmtRegistry);
362         assertNotEquals(emf, other, "pattern, equals()");
363         assertNotEquals(emf.hashCode(), other.hashCode(), "pattern, hashCode()");
364 
365         // Different registry
366         other = new ExtendedMessageFormat(pattern, Locale.US, otherRegistry);
367         assertNotEquals(emf, other, "registry, equals()");
368         assertNotEquals(emf.hashCode(), other.hashCode(), "registry, hashCode()");
369 
370         // Different Locale
371         other = new ExtendedMessageFormat(pattern, Locale.FRANCE, fmtRegistry);
372         assertNotEquals(emf, other, "locale, equals()");
373         assertEquals(emf.hashCode(), other.hashCode(), "locale, hashCode()"); // same hash code
374     }
375 
376     /**
377      * Test Bug LANG-948 - Exception while using ExtendedMessageFormat and escaping braces
378      */
379     @Test
380     public void testEscapedBraces_LANG_948() {
381         // message without placeholder because braces are escaped by quotes
382         final String pattern = "Message without placeholders '{}'";
383         final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
384         assertEquals("Message without placeholders {}", emf.format(new Object[] {"DUMMY"}));
385 
386         // message with placeholder because quotes are escaped by quotes
387         final String pattern2 = "Message with placeholder ''{0}''";
388         final ExtendedMessageFormat emf2 = new ExtendedMessageFormat(pattern2, registry);
389         assertEquals("Message with placeholder 'DUMMY'", emf2.format(new Object[] {"DUMMY"}));
390     }
391 
392     /**
393      * Test Bug LANG-477 - out of memory error with escaped quote
394      */
395     @Test
396     public void testEscapedQuote_LANG_477() {
397         final String pattern = "it''s a {0,lower} 'test'!";
398         final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
399         assertEquals("it's a dummy test!", emf.format(new Object[] {"DUMMY"}));
400     }
401 
402     /**
403      * Test extended and built in formats.
404      */
405     @Test
406     public void testExtendedAndBuiltInFormats() {
407         final Calendar cal = Calendar.getInstance();
408         cal.set(2007, Calendar.JANUARY, 23, 18, 33, 5);
409         final Object[] args = {"John Doe", cal.getTime(), Double.valueOf("12345.67")};
410         final String builtinsPattern = "DOB: {1,date,short} Salary: {2,number,currency}";
411         final String extendedPattern = "Name: {0,upper} ";
412         final String pattern = extendedPattern + builtinsPattern;
413 
414         final HashSet<Locale> testLocales = new HashSet<>(Arrays.asList(DateFormat.getAvailableLocales()));
415         testLocales.retainAll(Arrays.asList(NumberFormat.getAvailableLocales()));
416         testLocales.add(null);
417 
418         for (final Locale locale : testLocales) {
419             final MessageFormat builtins = createMessageFormat(builtinsPattern, locale);
420             final String expectedPattern = extendedPattern + builtins.toPattern();
421             DateFormat df = null;
422             NumberFormat nf = null;
423             ExtendedMessageFormat emf = null;
424             if (locale == null) {
425                 df = DateFormat.getDateInstance(DateFormat.SHORT);
426                 nf = NumberFormat.getCurrencyInstance();
427                 emf = new ExtendedMessageFormat(pattern, registry);
428             } else {
429                 df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
430                 nf = NumberFormat.getCurrencyInstance(locale);
431                 emf = new ExtendedMessageFormat(pattern, locale, registry);
432             }
433             final StringBuilder expected = new StringBuilder();
434             expected.append("Name: ");
435             expected.append(args[0].toString().toUpperCase(Locale.ROOT));
436             expected.append(" DOB: ");
437             expected.append(df.format(args[1]));
438             expected.append(" Salary: ");
439             expected.append(nf.format(args[2]));
440             assertEquals(expectedPattern, emf.toPattern(), "pattern comparison for locale " + locale);
441             assertEquals(expected.toString(), emf.format(args), String.valueOf(locale));
442         }
443     }
444 
445     /**
446      * Test extended formats.
447      */
448     @Test
449     public void testExtendedFormats() {
450         final String pattern = "Lower: {0,lower} Upper: {1,upper}";
451         final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
452         assertEquals(pattern, emf.toPattern(), "TOPATTERN");
453         assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "bar"}));
454         assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"Foo", "Bar"}));
455         assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "BAR"}));
456         assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "bar"}));
457         assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "BAR"}));
458     }
459 
460     @Test
461     public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionFive() {
462         assertThatIllegalArgumentException().isThrownBy(() -> new ExtendedMessageFormat("j/[_D9{0,\"&'+0o", new HashMap<>()));
463     }
464 
465     @Test
466     public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionFour() {
467         assertThatIllegalArgumentException().isThrownBy(() -> new ExtendedMessageFormat("RD,nXhM{}{", new HashMap<>()));
468     }
469 
470     @Test
471     public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionOne() {
472         assertThatIllegalArgumentException().isThrownBy(() -> new ExtendedMessageFormat("agdXdkR;T1{9 ^,LzXf?", new HashMap<>()));
473     }
474 
475     @Test
476     public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionThree() {
477         assertThatIllegalArgumentException().isThrownBy(() -> new ExtendedMessageFormat("9jLh_D9{ ", new HashMap<>()));
478     }
479 
480     @Test
481     public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionTwo() {
482         assertThatIllegalArgumentException().isThrownBy(() -> new ExtendedMessageFormat("a5XdkR;T1{9 ,LzXf?", new HashMap<>()));
483     }
484 
485     @Test
486     public void testOverriddenBuiltinFormat() {
487         final Calendar cal = Calendar.getInstance();
488         cal.set(2007, Calendar.JANUARY, 23);
489         final Object[] args = { cal.getTime() };
490         final Locale[] availableLocales = DateFormat.getAvailableLocales();
491         final Map<String, ? extends FormatFactory> dateRegistry = Collections.singletonMap("date", OverrideShortDateFormatFactory.FACTORY);
492 
493         // check the non-overridden builtins:
494         checkBuiltInFormat("1: {0,date}", dateRegistry, args, availableLocales);
495         checkBuiltInFormat("2: {0,date,medium}", dateRegistry, args, availableLocales);
496         checkBuiltInFormat("3: {0,date,long}", dateRegistry, args, availableLocales);
497         checkBuiltInFormat("4: {0,date,full}", dateRegistry, args, availableLocales);
498         checkBuiltInFormat("5: {0,date,d MMM yy}", dateRegistry, args, availableLocales);
499 
500         // check the overridden format:
501         for (int i = -1; i < availableLocales.length; i++) {
502             final Locale locale = i < 0 ? null : availableLocales[i];
503             final MessageFormat dateDefault = createMessageFormat("{0,date}", locale);
504             final String pattern = "{0,date,short}";
505             final ExtendedMessageFormat dateShort = new ExtendedMessageFormat(pattern, locale, dateRegistry);
506             assertEquals(dateDefault.format(args), dateShort.format(args), "overridden date,short format");
507             assertEquals(pattern, dateShort.toPattern(), "overridden date,short pattern");
508         }
509     }
510 
511     @Test
512     public void testSetFormatByArgumentIndexIsUnsupported() {
513         assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
514             final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
515             emf.setFormatByArgumentIndex(0, new LowerCaseFormat());
516         });
517     }
518     @Test
519     public void testSetFormatIsUnsupported() {
520         assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
521             final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
522             emf.setFormat(0, new LowerCaseFormat());
523         });
524     }
525     @Test
526     public void testSetFormatsByArgumentIndex() {
527         assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
528             final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
529             emf.setFormatsByArgumentIndex(new Format[] {new LowerCaseFormat(), new UpperCaseFormat()});
530         });
531     }
532 
533     @Test
534     public void testSetFormatsIsUnsupported() {
535         assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
536             final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
537             emf.setFormats(new Format[] {new LowerCaseFormat(), new UpperCaseFormat()});
538         });
539     }
540 
541 }