← joda-money  /  src/test/java/org/joda/money/format/TestMoneyFormatter.java

1
/*
2
 *  Copyright 2009-present, Stephen Colebourne
3
 *
4
 *  Licensed under the Apache License, Version 2.0 (the "License");
5
 *  you may not use this file except in compliance with the License.
6
 *  You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *  Unless required by applicable law or agreed to in writing, software
11
 *  distributed under the License is distributed on an "AS IS" BASIS,
12
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *  See the License for the specific language governing permissions and
14
 *  limitations under the License.
15
 */
16
package org.joda.money.format;
17
18
import static org.assertj.core.api.Assertions.assertThat;
19
import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
20
21
import java.io.ByteArrayInputStream;
22
import java.io.ByteArrayOutputStream;
23
import java.io.IOException;
24
import java.io.ObjectInputStream;
25
import java.io.ObjectOutputStream;
26
import java.math.BigDecimal;
27
import java.text.ParsePosition;
28
import java.util.Locale;
29
30
import org.joda.money.BigMoney;
31
import org.joda.money.BigMoneyProvider;
32
import org.joda.money.CurrencyUnit;
33
import org.joda.money.Money;
34
import org.junit.jupiter.api.AfterEach;
35
import org.junit.jupiter.api.BeforeEach;
36
import org.junit.jupiter.api.Test;
37
import org.junit.jupiter.params.ParameterizedTest;
38
import org.junit.jupiter.params.provider.MethodSource;
39
40
/**
41
 * Test MoneyFormatter.
42
 */
43
class TestMoneyFormatter {
44
45
    private static final Locale cCachedLocale = Locale.getDefault();
46
    private static final Locale TEST_GB_LOCALE = Locale.of("en", "GB", "TEST");
47
    private static final Locale TEST_FR_LOCALE = Locale.of("fr", "FR", "TEST");
48
    private static final Money MONEY_GBP_12_34 = Money.parse("GBP 12.34");
49
    private MoneyFormatter iPrintTest;
50
    private MoneyFormatter iCannotPrint;
51
    private MoneyFormatter iParseTest;
52
    private MoneyFormatter iCannotParse;
53
54
    @BeforeEach
55
    void beforeMethod() {
56
        Locale.setDefault(TEST_GB_LOCALE);
57
        iPrintTest = new MoneyFormatterBuilder()
58
            .appendCurrencyCode()
59
            .appendLiteral(" hello")
60
            .toFormatter();
61
        iCannotPrint = new MoneyFormatterBuilder()
62
            .append(null, context -> {})
63
            .toFormatter();
64
        iParseTest = new MoneyFormatterBuilder()
65
            .appendAmountLocalized()
66
            .appendLiteral(" ")
67
            .appendCurrencyCode()
68
            .toFormatter();
69
        iCannotParse = new MoneyFormatterBuilder()
70
            .append((context, appendable, money) -> {}, null)
71
            .toFormatter();
72
    }
73
74
    @AfterEach
75
    void afterMethod() {
76
        Locale.setDefault(cCachedLocale);
77
        iPrintTest = null;
78
    }
79
80
    //-----------------------------------------------------------------------
81
    // serialization
82
    //-----------------------------------------------------------------------
83
    @Test
84
    void test_serialization() throws Exception {
85
        var a = iPrintTest;
86
        var baos = new ByteArrayOutputStream();
87
        try (var oos = new ObjectOutputStream(baos)) {
88
            oos.writeObject(a);
89
            oos.close();
90
            var ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
91
            var input = (MoneyFormatter) ois.readObject();
92
            var value = MONEY_GBP_12_34;
93
            assertThat(input.print(value)).isEqualTo(a.print(value));
94
        }
95
    }
96
97
    //-----------------------------------------------------------------------
98
    // getLocale() withLocale(Locale)
99
    //-----------------------------------------------------------------------
100
    @Test
101
    void test_getLocale() {
102
        assertThat(iPrintTest.getLocale()).isEqualTo(TEST_GB_LOCALE);
103
    }
104
105
    @Test
106
    void test_withLocale() {
107
        var test = iPrintTest.withLocale(TEST_FR_LOCALE);
108
        assertThat(iPrintTest.getLocale()).isEqualTo(TEST_GB_LOCALE);
109
        assertThat(test.getLocale()).isEqualTo(TEST_FR_LOCALE);
110
    }
111
112
    @Test
113
    void test_withLocale_nullLocale() {
114
        assertThatExceptionOfType(NullPointerException.class)
115
            .isThrownBy(() -> iPrintTest.withLocale((Locale) null));
116
    }
117
118
    //-----------------------------------------------------------------------
119
    // print(BigMoneyProvider)
120
    //-----------------------------------------------------------------------
121
    @Test
122
    void test_print_BigMoneyProvider() {
123
        assertThat(iPrintTest.print(MONEY_GBP_12_34)).isEqualTo("GBP hello");
124
    }
125
126
    @Test
127
    void test_print_BigMoneyProvider_cannotPrint() {
128
        assertThatExceptionOfType(UnsupportedOperationException.class)
129
            .isThrownBy(() -> iCannotPrint.print(MONEY_GBP_12_34));
130
    }
131
132
    @Test
133
    void test_print_BigMoneyProvider_nullBigMoneyProvider() {
134
        assertThatExceptionOfType(NullPointerException.class)
135
            .isThrownBy(() -> iPrintTest.print((BigMoneyProvider) null));
136
    }
137
138
    //-----------------------------------------------------------------------
139
    // print(Appendable,BigMoneyProvider)
140
    //-----------------------------------------------------------------------
141
    @Test
142
    void test_print_AppendableBigMoneyProvider() {
143
        var buf = new StringBuilder();
144
        iPrintTest.print(buf, MONEY_GBP_12_34);
145
        assertThat(buf).hasToString("GBP hello");
146
    }
147
148
    @Test
149
    void test_print_AppendableBigMoneyProvider_IOException() {
150
        Appendable appendable = new IOAppendable();
151
        assertThatExceptionOfType(MoneyFormatException.class)
152
            .isThrownBy(() -> iPrintTest.print(appendable, MONEY_GBP_12_34))
153
            .withCauseInstanceOf(IOException.class);
154
    }
155
156
    @Test
157
    void test_print_AppendableBigMoneyProvider_cannotPrint() {
158
        assertThatExceptionOfType(UnsupportedOperationException.class)
159
            .isThrownBy(() -> iCannotPrint.print(new StringBuilder(), MONEY_GBP_12_34));
160
    }
161
162
    @Test
163
    void test_print_AppendableBigMoneyProvider_nullAppendable() {
164
        assertThatExceptionOfType(NullPointerException.class)
165
            .isThrownBy(() -> iPrintTest.print((Appendable) null, MONEY_GBP_12_34));
166
    }
167
168
    @Test
169
    void test_print_AppendableBigMoneyProvider_nullBigMoneyProvider() {
170
        assertThatExceptionOfType(NullPointerException.class)
171
            .isThrownBy(() -> iPrintTest.print(new StringBuilder(), (BigMoneyProvider) null));
172
    }
173
174
    //-----------------------------------------------------------------------
175
    // printIO(Appendable,BigMoneyProvider)
176
    //-----------------------------------------------------------------------
177
    @Test
178
    void test_printIO_AppendableBigMoneyProvider() throws IOException {
179
        var buf = new StringBuilder();
180
        iPrintTest.printIO(buf, MONEY_GBP_12_34);
181
        assertThat(buf).hasToString("GBP hello");
182
    }
183
184
    @Test
185
    void test_printIO_AppendableBigMoneyProvider_IOException() {
186
        Appendable appendable = new IOAppendable();
187
        assertThatExceptionOfType(IOException.class)
188
            .isThrownBy(() -> iPrintTest.printIO(appendable, MONEY_GBP_12_34));
189
    }
190
191
    @Test
192
    void test_printIO_AppendableBigMoneyProvider_cannotPrint() {
193
        assertThatExceptionOfType(UnsupportedOperationException.class)
194
            .isThrownBy(() -> iCannotPrint.printIO(new StringBuilder(), MONEY_GBP_12_34));
195
    }
196
197
    @Test
198
    void test_printIO_AppendableBigMoneyProvider_nullAppendable() {
199
        assertThatExceptionOfType(NullPointerException.class)
200
            .isThrownBy(() -> iPrintTest.printIO((Appendable) null, MONEY_GBP_12_34));
201
    }
202
203
    @Test
204
    void test_printIO_AppendableBigMoneyProvider_nullBigMoneyProvider() {
205
        assertThatExceptionOfType(NullPointerException.class)
206
            .isThrownBy(() -> iPrintTest.printIO(new StringBuilder(), (BigMoneyProvider) null));
207
    }
208
209
    //-----------------------------------------------------------------------
210
    // parseBigMoney(CharSequence)
211
    //-----------------------------------------------------------------------
212
    @Test
213
    void test_parseBigMoney_CharSequence() {
214
        CharSequence input = new StringBuilder("12.34 GBP");
215
        var test = iParseTest.parseBigMoney(input);
216
        assertThat(test).isEqualTo(MONEY_GBP_12_34.toBigMoney());
217
    }
218
219
    @Test
220
    void test_parseBigMoney_CharSequence_invalidCurrency() {
221
        assertThatExceptionOfType(MoneyFormatException.class)
222
            .isThrownBy(() -> iParseTest.parseBigMoney("12.34 GBX"));
223
    }
224
225
    @Test
226
    void test_parseBigMoney_CharSequence_notFullyParsed() {
227
        assertThatExceptionOfType(MoneyFormatException.class)
228
            .isThrownBy(() -> iParseTest.parseBigMoney("12.34 GBP X"));
229
    }
230
231
    @Test
232
    void test_parseBigMoney_CharSequence_incomplete() {
233
        assertThatExceptionOfType(MoneyFormatException.class)
234
            .isThrownBy(() -> iParseTest.parseBigMoney("12.34 GBP "));
235
    }
236
237
    @Test
238
    void test_parseBigMoney_CharSequence_incompleteLongText() {
239
        var str = "12.34 GBP ABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAB";
240
        assertThatExceptionOfType(MoneyFormatException.class)
241
            .isThrownBy(() -> iParseTest.parseBigMoney(str));
242
    }
243
244
    @Test
245
    void test_parseBigMoney_CharSequence_incompleteEmptyParser() {
246
        assertThatExceptionOfType(MoneyFormatException.class)
247
            .isThrownBy(() -> iCannotPrint.parseBigMoney("12.34 GBP"));
248
    }
249
250
    @Test
251
    void test_parseBigMoney_CharSequence_missingCurrency() {
252
        var f = new MoneyFormatterBuilder().appendAmount().toFormatter();
253
        assertThatExceptionOfType(MoneyFormatException.class)
254
            .isThrownBy(() -> f.parseBigMoney("12.34"));
255
    }
256
257
    @Test
258
    void test_parseBigMoney_CharSequence_cannotParse() {
259
        assertThatExceptionOfType(UnsupportedOperationException.class)
260
            .isThrownBy(() -> iCannotParse.parseBigMoney(new StringBuilder()));
261
    }
262
263
    @Test
264
    void test_parseBigMoney_CharSequence_nullCharSequence() {
265
        assertThatExceptionOfType(NullPointerException.class)
266
            .isThrownBy(() -> iParseTest.parseBigMoney((CharSequence) null));
267
    }
268
269
    //-----------------------------------------------------------------------
270
    // parseMoney(CharSequence)
271
    //-----------------------------------------------------------------------
272
    @Test
273
    void test_parseMoney_CharSequence() {
274
        CharSequence input = new StringBuilder("12.34 GBP");
275
        var test = iParseTest.parseMoney(input);
276
        assertThat(test).isEqualTo(MONEY_GBP_12_34);
277
    }
278
279
    @Test
280
    void test_parseMoney_CharSequence_invalidCurrency() {
281
        assertThatExceptionOfType(MoneyFormatException.class)
282
            .isThrownBy(() -> iParseTest.parseMoney("12.34 GBX"));
283
    }
284
285
    @Test
286
    void test_parseMoney_CharSequence_notFullyParsed() {
287
        assertThatExceptionOfType(MoneyFormatException.class)
288
            .isThrownBy(() -> iParseTest.parseMoney("12.34 GBP X"));
289
    }
290
291
    @Test
292
    void test_parseMoney_CharSequence_incomplete() {
293
        assertThatExceptionOfType(MoneyFormatException.class)
294
            .isThrownBy(() -> iCannotPrint.parseMoney("12.34 GBP"));
295
    }
296
297
    @Test
298
    void test_parseMoney_CharSequence_cannotParse() {
299
        assertThatExceptionOfType(UnsupportedOperationException.class)
300
            .isThrownBy(() -> iCannotParse.parseMoney(new StringBuilder()));
301
    }
302
303
    @Test
304
    void test_parseMoney_CharSequence_nullCharSequence() {
305
        assertThatExceptionOfType(NullPointerException.class)
306
            .isThrownBy(() -> iParseTest.parseMoney((CharSequence) null));
307
    }
308
309
    //-----------------------------------------------------------------------
310
    // parse(CharSequence,int)
311
    //-----------------------------------------------------------------------
312
    public static Object[][] data_parse() {
313
        return new Object[][] {
314
            new Object[] {"12.34 GBP", MONEY_GBP_12_34.getAmount(), MONEY_GBP_12_34.getCurrencyUnit(), 9, -1, false, true, true},
315
            new Object[] {"1,2.34 GBP", MONEY_GBP_12_34.getAmount(), MONEY_GBP_12_34.getCurrencyUnit(), 10, -1, false, true, true},
316
            new Object[] {"12,.34 GBP", MONEY_GBP_12_34.getAmount(), MONEY_GBP_12_34.getCurrencyUnit(), 10, -1, false, true, true},
317
            new Object[] {"12.,34 GBP", MONEY_GBP_12_34.getAmount(), MONEY_GBP_12_34.getCurrencyUnit(), 10, -1, false, true, true},
318
            new Object[] {"12.3,4 GBP", MONEY_GBP_12_34.getAmount(), MONEY_GBP_12_34.getCurrencyUnit(), 10, -1, false, true, true},
319
            new Object[] {".12 GBP", BigDecimal.valueOf(12, 2), MONEY_GBP_12_34.getCurrencyUnit(), 7, -1, false, true, true},
320
            new Object[] {"12. GBP", BigDecimal.valueOf(12), MONEY_GBP_12_34.getCurrencyUnit(), 7, -1, false, true, true},
321
            new Object[] {"12,34 GBP", BigDecimal.valueOf(1234), MONEY_GBP_12_34.getCurrencyUnit(), 9, -1, false, true, true},
322
323
            new Object[] {"-12.34 GBP", BigDecimal.valueOf(-1234, 2), CurrencyUnit.GBP, 10, -1, false, true, true},
324
            new Object[] {"+12.34 GBP", BigDecimal.valueOf(1234, 2), CurrencyUnit.GBP, 10, -1, false, true, true},
325
326
            new Object[] {"12.34 GB", BigDecimal.valueOf(1234, 2), null, 6, 6, true, false, false},
327
            new Object[] {",12.34 GBP", null, null, 0, 0, true, false, false},
328
            new Object[] {"12..34 GBP", BigDecimal.valueOf(12), null, 3, 3, true, false, false},
329
            new Object[] {"12,,34 GBP", BigDecimal.valueOf(12), null, 2, 2, true, false, false},
330
            new Object[] {"12.34 GBX", MONEY_GBP_12_34.getAmount(), null, 6, 6, true, false, false},
331
            new Object[] {"12.34 GBPX", MONEY_GBP_12_34.getAmount(), MONEY_GBP_12_34.getCurrencyUnit(), 9, -1, false, false, true},
332
        };
333
    }
334
335
    @ParameterizedTest
336
    @MethodSource("data_parse")
337
    void test_parse_CharSequenceInt(
338
            String str,
339
            BigDecimal amount,
340
            CurrencyUnit currency,
341
            int index,
342
            int errorIndex,
343
            boolean error,
344
            boolean fullyParsed,
345
            boolean complete) {
346
347
        CharSequence input = new StringBuilder(str);
348
        var test = iParseTest.parse(input, 0);
349
        assertThat(test.getAmount()).isEqualTo(amount);
350
        assertThat(test.getCurrency()).isEqualTo(currency);
351
        assertThat(test.getIndex()).isEqualTo(index);
352
        assertThat(test.getErrorIndex()).isEqualTo(errorIndex);
353
        assertThat(test.getText()).hasToString(str);
354
        assertThat(test.getTextLength()).isEqualTo(str.length());
355
        assertThat(test.isError()).isEqualTo(error);
356
        assertThat(test.isFullyParsed()).isEqualTo(fullyParsed);
357
        assertThat(test.isComplete()).isEqualTo(complete);
358
        var pp = new ParsePosition(index);
359
        pp.setErrorIndex(errorIndex);
360
        assertThat(test.toParsePosition()).isEqualTo(pp);
361
    }
362
363
    @Test
364
    void test_parse_CharSequenceInt_incomplete() {
365
        // this parser does nothing
366
        var test = iCannotPrint.parse("12.34 GBP", 0);
367
        assertThat(test.getAmount()).isNull();
368
        assertThat(test.getCurrency()).isNull();
369
        assertThat(test.getIndex()).isEqualTo(0);
370
        assertThat(test.getErrorIndex()).isEqualTo(-1);
371
        assertThat(test.getText()).hasToString("12.34 GBP");
372
        assertThat(test.getTextLength()).isEqualTo(9);
373
        assertThat(test.isError()).isFalse();
374
        assertThat(test.isFullyParsed()).isFalse();
375
        assertThat(test.isComplete()).isFalse();
376
    }
377
378
    @Test
379
    void test_parse_CharSequenceInt_continueAfterDoubleDecimal() {
380
        var f = new MoneyFormatterBuilder()
381
            .appendAmountLocalized().appendLiteral(".").appendCurrencyCode().toFormatter();
382
        var test = f.parse("12..GBP", 0);
383
        assertThat(test.getAmount()).isEqualTo(BigDecimal.valueOf(12));
384
        assertThat(test.getCurrency()).isEqualTo(CurrencyUnit.of("GBP"));
385
        assertThat(test.getIndex()).isEqualTo(7);
386
        assertThat(test.getErrorIndex()).isEqualTo(-1);
387
        assertThat(test.getText()).hasToString("12..GBP");
388
        assertThat(test.getTextLength()).isEqualTo(7);
389
        assertThat(test.isError()).isFalse();
390
        assertThat(test.isFullyParsed()).isTrue();
391
        assertThat(test.isComplete()).isTrue();
392
    }
393
394
    @Test
395
    void test_parse_CharSequenceInt_continueAfterSingleComma() {
396
        var f = new MoneyFormatterBuilder()
397
            .appendAmountLocalized().appendLiteral(",").appendCurrencyCode().toFormatter();
398
        var test = f.parse("12,GBP", 0);
399
        assertThat(test.getAmount()).isEqualTo(BigDecimal.valueOf(12));
400
        assertThat(test.getCurrency()).isEqualTo(CurrencyUnit.of("GBP"));
401
        assertThat(test.getIndex()).isEqualTo(6);
402
        assertThat(test.getErrorIndex()).isEqualTo(-1);
403
        assertThat(test.getText()).hasToString("12,GBP");
404
        assertThat(test.getTextLength()).isEqualTo(6);
405
        assertThat(test.isError()).isFalse();
406
        assertThat(test.isFullyParsed()).isTrue();
407
        assertThat(test.isComplete()).isTrue();
408
    }
409
410
    @Test
411
    void test_parse_CharSequenceInt_continueAfterDoubleComma() {
412
        var f = new MoneyFormatterBuilder()
413
            .appendAmountLocalized().appendLiteral(",,").appendCurrencyCode().toFormatter();
414
        var test = f.parse("12,,GBP", 0);
415
        assertThat(test.getAmount()).isEqualTo(BigDecimal.valueOf(12));
416
        assertThat(test.getCurrency()).isEqualTo(CurrencyUnit.of("GBP"));
417
        assertThat(test.getIndex()).isEqualTo(7);
418
        assertThat(test.getErrorIndex()).isEqualTo(-1);
419
        assertThat(test.getText()).hasToString("12,,GBP");
420
        assertThat(test.getTextLength()).isEqualTo(7);
421
        assertThat(test.isError()).isFalse();
422
        assertThat(test.isFullyParsed()).isTrue();
423
        assertThat(test.isComplete()).isTrue();
424
    }
425
426
    @Test
427
    void test_parse_CharSequenceInt_cannotParse() {
428
        assertThatExceptionOfType(UnsupportedOperationException.class)
429
            .isThrownBy(() -> iCannotParse.parse(new StringBuilder(), 0));
430
    }
431
432
    @Test
433
    void test_parse_CharSequenceInt_nullCharSequence() {
434
        assertThatExceptionOfType(NullPointerException.class)
435
            .isThrownBy(() -> iParseTest.parse((CharSequence) null, 0));
436
    }
437
438
    @Test
439
    void test_parse_CharSequenceInt_startIndexTooSmall() {
440
        assertThatExceptionOfType(IndexOutOfBoundsException.class)
441
            .isThrownBy(() -> iParseTest.parse("", -1));
442
    }
443
444
    @Test
445
    void test_parse_CharSequenceInt_startIndexTooBig() {
446
        assertThatExceptionOfType(IndexOutOfBoundsException.class)
447
            .isThrownBy(() -> iParseTest.parse("", 1));
448
    }
449
450
    //-----------------------------------------------------------------------
451
    @Test
452
    void test_printParse_zeroChar() {
453
        var style = MoneyAmountStyle.ASCII_DECIMAL_POINT_GROUP3_COMMA.withZeroCharacter('A');
454
        var f = new MoneyFormatterBuilder().appendCurrencyCode().appendLiteral(" ").appendAmount(style).toFormatter();
455
        assertThat(f.print(MONEY_GBP_12_34)).isEqualTo("GBP BC.DE");
456
        assertThat(f.parseMoney("GBP BC.DE")).isEqualTo(MONEY_GBP_12_34);
457
    }
458
459
    @Test
460
    void test_parseMoney_notFullyParsed() {
461
        assertThatExceptionOfType(MoneyFormatException.class)
462
            .isThrownBy(() -> iParseTest.parseMoney("GBP hello notfullyparsed"));
463
    }
464
465
    @Test
466
    void test_parseMoney_noAmount() {
467
        assertThatExceptionOfType(MoneyFormatException.class)
468
            .isThrownBy(() -> iParseTest.parseMoney("GBP hello"));
469
    }
470
471
    @Test
472
    void test_parseBigMoney_notFullyParsed() {
473
        assertThatExceptionOfType(MoneyFormatException.class)
474
            .isThrownBy(() -> iParseTest.parseBigMoney("GBP hello notfullyparsed"));
475
    }
476
477
    @Test
478
    void test_parseBigMoney_noAmount() {
479
        assertThatExceptionOfType(MoneyFormatException.class)
480
            .isThrownBy(() -> iParseTest.parseBigMoney("GBP hello"));
481
    }
482
483
    @Test
484
    void test_parse_notFullyParsed() {
485
        var context = iParseTest.parse("GBP hello notfullyparsed", 1);
486
        assertThatExceptionOfType(MoneyFormatException.class)
487
            .isThrownBy(() -> context.toBigMoney());
488
    }
489
490
    //-----------------------------------------------------------------------
491
    // toString()
492
    //-----------------------------------------------------------------------
493
    @Test
494
    void test_toString() {
495
        assertThat(iPrintTest.toString()).isEqualTo("${code}' hello'");
496
    }
497
498
    @Test
499
    void test_toString_differentPrinterParser() {
500
        MoneyPrinter printer = new MoneyPrinter() {
501
            @Override
502
            public void print(MoneyPrintContext context, Appendable appendable, BigMoney money) throws IOException {
503
            }
504
505
            @Override
506
            public String toString() {
507
                return "A";
508
            }
509
        };
510
        MoneyParser parser = new MoneyParser() {
511
            @Override
512
            public void parse(MoneyParseContext context) {
513
            }
514
515
            @Override
516
            public String toString() {
517
                return "B";
518
            }
519
        };
520
        var f = new MoneyFormatterBuilder().append(printer, parser).toFormatter();
521
        assertThat(f).hasToString("A:B");
522
    }
523
524
    //-----------------------------------------------------------------------
525
    private static final class IOAppendable implements Appendable {
526
        @Override
527
        public Appendable append(CharSequence csq, int start, int end) throws IOException {
528
            throw new IOException();
529
        }
530
531
        @Override
532
        public Appendable append(char c) throws IOException {
533
            throw new IOException();
534
        }
535
536
        @Override
537
        public Appendable append(CharSequence csq) throws IOException {
538
            throw new IOException();
539
        }
540
    }
541
542
}
543