View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.core5.http.impl.nio;
29  
30  import java.io.ByteArrayInputStream;
31  import java.io.ByteArrayOutputStream;
32  import java.nio.ByteBuffer;
33  import java.nio.channels.Channels;
34  import java.nio.channels.ReadableByteChannel;
35  import java.nio.channels.WritableByteChannel;
36  import java.nio.charset.CharacterCodingException;
37  import java.nio.charset.Charset;
38  import java.nio.charset.CharsetDecoder;
39  import java.nio.charset.CharsetEncoder;
40  import java.nio.charset.CodingErrorAction;
41  import java.nio.charset.StandardCharsets;
42  
43  import org.apache.hc.core5.http.MessageConstraintException;
44  import org.apache.hc.core5.http.nio.SessionInputBuffer;
45  import org.apache.hc.core5.http.nio.SessionOutputBuffer;
46  import org.apache.hc.core5.util.CharArrayBuffer;
47  import org.junit.Assert;
48  import org.junit.Test;
49  
50  /**
51   * Simple tests for {@link SessionInputBuffer} and {@link SessionOutputBuffer}.
52   */
53  public class TestSessionInOutBuffers {
54  
55      private static WritableByteChannel newChannel(final ByteArrayOutputStream outStream) {
56          return Channels.newChannel(outStream);
57      }
58  
59      private static ReadableByteChannel newChannel(final byte[] bytes) {
60          return Channels.newChannel(new ByteArrayInputStream(bytes));
61      }
62  
63      private static ReadableByteChannel newChannel(final String s, final Charset charset) {
64          return Channels.newChannel(new ByteArrayInputStream(s.getBytes(charset)));
65      }
66  
67      private static ReadableByteChannel newChannel(final String s) {
68          return newChannel(s, StandardCharsets.US_ASCII);
69      }
70  
71      @Test
72      public void testReadLineChunks() throws Exception {
73          final SessionInputBuffer inbuf = new SessionInputBufferImpl(16, 16);
74  
75          ReadableByteChannel channel = newChannel("One\r\nTwo\r\nThree");
76  
77          inbuf.fill(channel);
78  
79          final CharArrayBuffer line = new CharArrayBuffer(64);
80  
81          line.clear();
82          Assert.assertTrue(inbuf.readLine(line, false));
83          Assert.assertEquals("One", line.toString());
84  
85          line.clear();
86          Assert.assertTrue(inbuf.readLine(line, false));
87          Assert.assertEquals("Two", line.toString());
88  
89          line.clear();
90          Assert.assertFalse(inbuf.readLine(line, false));
91  
92          channel = newChannel("\r\nFour");
93          inbuf.fill(channel);
94  
95          line.clear();
96          Assert.assertTrue(inbuf.readLine(line, false));
97          Assert.assertEquals("Three", line.toString());
98  
99          inbuf.fill(channel);
100 
101         line.clear();
102         Assert.assertTrue(inbuf.readLine(line, true));
103         Assert.assertEquals("Four", line.toString());
104 
105         line.clear();
106         Assert.assertFalse(inbuf.readLine(line, true));
107     }
108 
109     @Test
110     public void testLineLimit() throws Exception {
111         final String s = "LoooooooooooooooooooooooooOOOOOOOOOOOOOOOOOOoooooooooooooooooooooong line\r\n";
112         final CharArrayBuffer line = new CharArrayBuffer(64);
113         final SessionInputBuffer inbuf1 = new SessionInputBufferImpl(128, 128);
114         final ReadableByteChannel channel1 = newChannel(s);
115         inbuf1.fill(channel1);
116 
117         Assert.assertTrue(inbuf1.readLine(line, false));
118 
119         line.clear();
120         final SessionInputBuffer inbuf2 = new SessionInputBufferImpl(128, 128, 10);
121         final ReadableByteChannel channel2 = newChannel(s);
122         inbuf2.fill(channel2);
123         try {
124             inbuf2.readLine(line, false);
125             Assert.fail("MessageConstraintException expected");
126         } catch (final MessageConstraintException ex) {
127         }
128     }
129 
130     @Test
131     public void testLineLimitBufferFull() throws Exception {
132         final String s = "LoooooooooooooooooooooooooOOOOOOOOOOOOOOOOOOoooooooooooooooooooooong line\r\n";
133         final CharArrayBuffer line = new CharArrayBuffer(64);
134         final SessionInputBuffer inbuf1 = new SessionInputBufferImpl(32, 32);
135         final ReadableByteChannel channel1 = newChannel(s);
136         inbuf1.fill(channel1);
137 
138         Assert.assertFalse(inbuf1.readLine(line, false));
139 
140         line.clear();
141         final SessionInputBuffer inbuf2 = new SessionInputBufferImpl(32, 32,10);
142         final ReadableByteChannel channel2 = newChannel(s);
143         inbuf2.fill(channel2);
144         try {
145             inbuf2.readLine(line, false);
146             Assert.fail("MessageConstraintException expected");
147         } catch (final MessageConstraintException ex) {
148         }
149     }
150 
151     @Test
152     public void testWriteLineChunks() throws Exception {
153         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(16, 16);
154         final SessionInputBuffer inbuf = new SessionInputBufferImpl(16, 16, 0);
155 
156         ReadableByteChannel inChannel = newChannel("One\r\nTwo\r\nThree");
157 
158         inbuf.fill(inChannel);
159 
160         final CharArrayBuffer line = new CharArrayBuffer(64);
161 
162         line.clear();
163         Assert.assertTrue(inbuf.readLine(line, false));
164         Assert.assertEquals("One", line.toString());
165 
166         outbuf.writeLine(line);
167 
168         line.clear();
169         Assert.assertTrue(inbuf.readLine(line, false));
170         Assert.assertEquals("Two", line.toString());
171 
172         outbuf.writeLine(line);
173 
174         line.clear();
175         Assert.assertFalse(inbuf.readLine(line, false));
176 
177         inChannel = newChannel("\r\nFour");
178         inbuf.fill(inChannel);
179 
180         line.clear();
181         Assert.assertTrue(inbuf.readLine(line, false));
182         Assert.assertEquals("Three", line.toString());
183 
184         outbuf.writeLine(line);
185 
186         inbuf.fill(inChannel);
187 
188         line.clear();
189         Assert.assertTrue(inbuf.readLine(line, true));
190         Assert.assertEquals("Four", line.toString());
191 
192         outbuf.writeLine(line);
193 
194         line.clear();
195         Assert.assertFalse(inbuf.readLine(line, true));
196 
197         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
198         final WritableByteChannel outChannel = newChannel(outStream);
199         outbuf.flush(outChannel);
200 
201         final String s = new String(outStream.toByteArray(), StandardCharsets.US_ASCII);
202         Assert.assertEquals("One\r\nTwo\r\nThree\r\nFour\r\n", s);
203     }
204 
205     @Test
206     public void testBasicReadWriteLine() throws Exception {
207 
208         final String[] teststrs = new String[5];
209         teststrs[0] = "Hello";
210         teststrs[1] = "This string should be much longer than the size of the line buffer " +
211                 "which is only 16 bytes for this test";
212         final StringBuilder buffer = new StringBuilder();
213         for (int i = 0; i < 15; i++) {
214             buffer.append("123456789 ");
215         }
216         buffer.append("and stuff like that");
217         teststrs[2] = buffer.toString();
218         teststrs[3] = "";
219         teststrs[4] = "And goodbye";
220 
221         final CharArrayBuffer chbuffer = new CharArrayBuffer(32);
222         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 16);
223         for (final String teststr : teststrs) {
224             chbuffer.clear();
225             chbuffer.append(teststr);
226             outbuf.writeLine(chbuffer);
227         }
228         //this write operation should have no effect
229         outbuf.writeLine(null);
230 
231         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
232         final WritableByteChannel outChannel = newChannel(outStream);
233         outbuf.flush(outChannel);
234 
235         final ReadableByteChannel channel = newChannel(outStream.toByteArray());
236 
237         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 16, 0);
238         inbuf.fill(channel);
239 
240         for (final String teststr : teststrs) {
241             chbuffer.clear();
242             inbuf.readLine(chbuffer, true);
243             Assert.assertEquals(teststr, chbuffer.toString());
244         }
245         chbuffer.clear();
246         Assert.assertFalse(inbuf.readLine(chbuffer, true));
247         chbuffer.clear();
248         Assert.assertFalse(inbuf.readLine(chbuffer, true));
249     }
250 
251     @Test
252     public void testComplexReadWriteLine() throws Exception {
253         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 16);
254         outbuf.write(ByteBuffer.wrap(new byte[] {'a', '\n'}));
255         outbuf.write(ByteBuffer.wrap(new byte[] {'\r', '\n'}));
256         outbuf.write(ByteBuffer.wrap(new byte[] {'\r', '\r', '\n'}));
257         outbuf.write(ByteBuffer.wrap(new byte[] {'\n'}));
258 
259         final StringBuilder buffer = new StringBuilder();
260         for (int i = 0; i < 14; i++) {
261             buffer.append("a");
262         }
263         final String s1 = buffer.toString();
264         buffer.append("\r\n");
265         outbuf.write(ByteBuffer.wrap(buffer.toString().getBytes(StandardCharsets.US_ASCII)));
266 
267         buffer.setLength(0);
268         for (int i = 0; i < 15; i++) {
269             buffer.append("a");
270         }
271         final String s2 = buffer.toString();
272         buffer.append("\r\n");
273         outbuf.write(ByteBuffer.wrap(buffer.toString().getBytes(StandardCharsets.US_ASCII)));
274 
275         buffer.setLength(0);
276         for (int i = 0; i < 16; i++) {
277             buffer.append("a");
278         }
279         final String s3 = buffer.toString();
280         buffer.append("\r\n");
281         outbuf.write(ByteBuffer.wrap(buffer.toString().getBytes(StandardCharsets.US_ASCII)));
282 
283         outbuf.write(ByteBuffer.wrap(new byte[] {'a'}));
284 
285         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
286         final WritableByteChannel outChannel = newChannel(outStream);
287         outbuf.flush(outChannel);
288 
289         final ReadableByteChannel channel = newChannel(outStream.toByteArray());
290 
291         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 16, 0);
292         inbuf.fill(channel);
293 
294         final CharArrayBuffer chbuffer = new CharArrayBuffer(32);
295         chbuffer.clear();
296         inbuf.readLine(chbuffer, true);
297         Assert.assertEquals("a", chbuffer.toString());
298         chbuffer.clear();
299         inbuf.readLine(chbuffer, true);
300         Assert.assertEquals("", chbuffer.toString());
301         chbuffer.clear();
302         inbuf.readLine(chbuffer, true);
303         Assert.assertEquals("\r", chbuffer.toString());
304         chbuffer.clear();
305         inbuf.readLine(chbuffer, true);
306         Assert.assertEquals("", chbuffer.toString());
307         chbuffer.clear();
308         inbuf.readLine(chbuffer, true);
309         Assert.assertEquals(s1, chbuffer.toString());
310         chbuffer.clear();
311         inbuf.readLine(chbuffer, true);
312         Assert.assertEquals(s2, chbuffer.toString());
313         chbuffer.clear();
314         inbuf.readLine(chbuffer, true);
315         Assert.assertEquals(s3, chbuffer.toString());
316         chbuffer.clear();
317         inbuf.readLine(chbuffer, true);
318         Assert.assertEquals("a", chbuffer.toString());
319         chbuffer.clear();
320         inbuf.readLine(chbuffer, true);
321         Assert.assertFalse(inbuf.readLine(chbuffer, true));
322         chbuffer.clear();
323         inbuf.readLine(chbuffer, true);
324         Assert.assertFalse(inbuf.readLine(chbuffer, true));
325     }
326 
327     @Test
328     public void testReadOneByte() throws Exception {
329         // make the buffer larger than that of transmitter
330         final byte[] out = new byte[40];
331         for (int i = 0; i < out.length; i++) {
332             out[i] = (byte)('0' + i);
333         }
334         final ReadableByteChannel channel = newChannel(out);
335         final SessionInputBuffer inbuf = new SessionInputBufferImpl(16, 16, 0);
336         while (inbuf.fill(channel) > 0) {
337         }
338 
339         final byte[] in = new byte[40];
340         for (int i = 0; i < in.length; i++) {
341             in[i] = (byte)inbuf.read();
342         }
343         for (int i = 0; i < out.length; i++) {
344             Assert.assertEquals(out[i], in[i]);
345         }
346     }
347 
348     @Test
349     public void testReadByteBuffer() throws Exception {
350         final byte[] pattern = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
351         final ReadableByteChannel channel = newChannel(pattern);
352         final SessionInputBuffer inbuf = new SessionInputBufferImpl(4096, 1024, 0);
353         while (inbuf.fill(channel) > 0) {
354         }
355         final ByteBuffer dst = ByteBuffer.allocate(10);
356         Assert.assertEquals(10, inbuf.read(dst));
357         dst.flip();
358         Assert.assertEquals(dst, ByteBuffer.wrap(pattern, 0, 10));
359         dst.clear();
360         Assert.assertEquals(6, inbuf.read(dst));
361         dst.flip();
362         Assert.assertEquals(dst, ByteBuffer.wrap(pattern, 10, 6));
363     }
364 
365     @Test
366     public void testReadByteBufferWithMaxLen() throws Exception {
367         final byte[] pattern = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
368         final ReadableByteChannel channel = newChannel(pattern);
369         final SessionInputBuffer inbuf = new SessionInputBufferImpl(4096, 1024, 0);
370         while (inbuf.fill(channel) > 0) {
371         }
372         final ByteBuffer dst = ByteBuffer.allocate(16);
373         Assert.assertEquals(10, inbuf.read(dst, 10));
374         dst.flip();
375         Assert.assertEquals(dst, ByteBuffer.wrap(pattern, 0, 10));
376         dst.clear();
377         Assert.assertEquals(3, inbuf.read(dst, 3));
378         dst.flip();
379         Assert.assertEquals(dst, ByteBuffer.wrap(pattern, 10, 3));
380         Assert.assertEquals(3, inbuf.read(dst, 20));
381         dst.flip();
382         Assert.assertEquals(dst, ByteBuffer.wrap(pattern, 13, 3));
383     }
384 
385     @Test
386     public void testReadToChannel() throws Exception {
387         final byte[] pattern = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
388         final ReadableByteChannel channel = newChannel(pattern);
389         final SessionInputBuffer inbuf = new SessionInputBufferImpl(4096, 1024, 0);
390         while (inbuf.fill(channel) > 0) {
391         }
392 
393         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
394         final WritableByteChannel dst = newChannel(outStream);
395 
396         Assert.assertEquals(16, inbuf.read(dst));
397         Assert.assertEquals(ByteBuffer.wrap(pattern), ByteBuffer.wrap(outStream.toByteArray()));
398     }
399 
400     @Test
401     public void testReadToChannelWithMaxLen() throws Exception {
402         final byte[] pattern = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
403         final ReadableByteChannel channel = newChannel(pattern);
404         final SessionInputBuffer inbuf = new SessionInputBufferImpl(4096, 1024, 0);
405         while (inbuf.fill(channel) > 0) {
406         }
407 
408         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
409         final WritableByteChannel dst = newChannel(outStream);
410 
411         Assert.assertEquals(10, inbuf.read(dst, 10));
412         Assert.assertEquals(3, inbuf.read(dst, 3));
413         Assert.assertEquals(3, inbuf.read(dst, 10));
414         Assert.assertEquals(ByteBuffer.wrap(pattern), ByteBuffer.wrap(outStream.toByteArray()));
415     }
416 
417     @Test
418     public void testWriteByteBuffer() throws Exception {
419         final byte[] pattern = "0123456789ABCDEF0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
420 
421         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(4096, 1024);
422         final ReadableByteChannel src = newChannel(pattern);
423         outbuf.write(src);
424 
425         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
426         final WritableByteChannel channel = newChannel(outStream);
427         while (outbuf.flush(channel) > 0) {
428         }
429         Assert.assertEquals(ByteBuffer.wrap(pattern), ByteBuffer.wrap(outStream.toByteArray()));
430     }
431 
432     @Test
433     public void testWriteFromChannel() throws Exception {
434         final byte[] pattern = "0123456789ABCDEF0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
435 
436         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(4096, 1024);
437         outbuf.write(ByteBuffer.wrap(pattern, 0, 16));
438         outbuf.write(ByteBuffer.wrap(pattern, 16, 10));
439         outbuf.write(ByteBuffer.wrap(pattern, 26, 6));
440 
441         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
442         final WritableByteChannel channel = newChannel(outStream);
443         while (outbuf.flush(channel) > 0) {
444         }
445         Assert.assertEquals(ByteBuffer.wrap(pattern), ByteBuffer.wrap(outStream.toByteArray()));
446     }
447 
448     static final int SWISS_GERMAN_HELLO [] = {
449         0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4
450     };
451 
452     static final int RUSSIAN_HELLO [] = {
453         0x412, 0x441, 0x435, 0x43C, 0x5F, 0x43F, 0x440, 0x438,
454         0x432, 0x435, 0x442
455     };
456 
457     private static String constructString(final int [] unicodeChars) {
458         final StringBuilder buffer = new StringBuilder();
459         if (unicodeChars != null) {
460             for (final int unicodeChar : unicodeChars) {
461                 buffer.append((char)unicodeChar);
462             }
463         }
464         return buffer.toString();
465     }
466 
467     @Test
468     public void testMultibyteCodedReadWriteLine() throws Exception {
469         final String s1 = constructString(SWISS_GERMAN_HELLO);
470         final String s2 = constructString(RUSSIAN_HELLO);
471         final String s3 = "Like hello and stuff";
472 
473         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 16,
474                 StandardCharsets.UTF_8.newEncoder());
475 
476         final CharArrayBuffer chbuffer = new CharArrayBuffer(32);
477         for (int i = 0; i < 10; i++) {
478             chbuffer.clear();
479             chbuffer.append(s1);
480             outbuf.writeLine(chbuffer);
481             chbuffer.clear();
482             chbuffer.append(s2);
483             outbuf.writeLine(chbuffer);
484             chbuffer.clear();
485             chbuffer.append(s3);
486             outbuf.writeLine(chbuffer);
487         }
488 
489         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
490         final WritableByteChannel outChannel = newChannel(outStream);
491         outbuf.flush(outChannel);
492 
493         final byte[] tmp = outStream.toByteArray();
494 
495         final ReadableByteChannel channel = newChannel(tmp);
496         final SessionInputBuffer inbuf = new SessionInputBufferImpl(16, 16, 0,
497                 StandardCharsets.UTF_8.newDecoder());
498 
499         while (inbuf.fill(channel) > 0) {
500         }
501 
502         for (int i = 0; i < 10; i++) {
503             chbuffer.clear();
504             inbuf.readLine(chbuffer, true);
505             Assert.assertEquals(s1, chbuffer.toString());
506             chbuffer.clear();
507             inbuf.readLine(chbuffer, true);
508             Assert.assertEquals(s2, chbuffer.toString());
509             chbuffer.clear();
510             inbuf.readLine(chbuffer, true);
511             Assert.assertEquals(s3, chbuffer.toString());
512         }
513     }
514 
515     @Test
516     public void testInputMatchesBufferLength() throws Exception {
517         final String s1 = "abcde";
518         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 5);
519         final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
520         chbuffer.append(s1);
521         outbuf.writeLine(chbuffer);
522     }
523 
524     @Test(expected=CharacterCodingException.class)
525     public void testMalformedInputActionReport() throws Exception {
526         final String s = constructString(SWISS_GERMAN_HELLO);
527         final byte[] tmp = s.getBytes(StandardCharsets.ISO_8859_1);
528 
529         final CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
530         decoder.onMalformedInput(CodingErrorAction.REPORT);
531         decoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
532         final SessionInputBuffer inbuf = new SessionInputBufferImpl(16, 16, 0, decoder);
533         final ReadableByteChannel channel = newChannel(tmp);
534         while (inbuf.fill(channel) > 0) {
535         }
536         final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
537         inbuf.readLine(chbuffer, true);
538     }
539 
540     @Test
541     public void testMalformedInputActionIgnore() throws Exception {
542         final String s = constructString(SWISS_GERMAN_HELLO);
543         final byte[] tmp = s.getBytes(StandardCharsets.ISO_8859_1);
544 
545         final CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
546         decoder.onMalformedInput(CodingErrorAction.IGNORE);
547         decoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
548         final SessionInputBuffer inbuf = new SessionInputBufferImpl(16, 16, 0, decoder);
549         final ReadableByteChannel channel = newChannel(tmp);
550         while (inbuf.fill(channel) > 0) {
551         }
552         final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
553         inbuf.readLine(chbuffer, true);
554         Assert.assertEquals("Grezi_zm", chbuffer.toString());
555     }
556 
557     @Test
558     public void testMalformedInputActionReplace() throws Exception {
559         final String s = constructString(SWISS_GERMAN_HELLO);
560         final byte[] tmp = s.getBytes(StandardCharsets.ISO_8859_1);
561 
562         final CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
563         decoder.onMalformedInput(CodingErrorAction.REPLACE);
564         decoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
565         final SessionInputBuffer inbuf = new SessionInputBufferImpl(16, 16, 0, decoder);
566         final ReadableByteChannel channel = newChannel(tmp);
567         while (inbuf.fill(channel) > 0) {
568         }
569         final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
570         inbuf.readLine(chbuffer, true);
571         Assert.assertEquals("Gr\ufffdezi_z\ufffdm\ufffd", chbuffer.toString());
572     }
573 
574     @Test(expected=CharacterCodingException.class)
575     public void testUnmappableInputActionReport() throws Exception {
576         final String s = "This text contains a circumflex \u0302!!!";
577         final CharsetEncoder encoder = StandardCharsets.ISO_8859_1.newEncoder();
578         encoder.onMalformedInput(CodingErrorAction.IGNORE);
579         encoder.onUnmappableCharacter(CodingErrorAction.REPORT);
580         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 16, encoder);
581         final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
582         chbuffer.append(s);
583         outbuf.writeLine(chbuffer);
584     }
585 
586     @Test
587     public void testUnmappableInputActionIgnore() throws Exception {
588         final String s = "This text contains a circumflex \u0302!!!";
589         final CharsetEncoder encoder = StandardCharsets.ISO_8859_1.newEncoder();
590         encoder.onMalformedInput(CodingErrorAction.IGNORE);
591         encoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
592         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 16, encoder);
593         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
594         final WritableByteChannel channel = newChannel(baos);
595         final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
596         chbuffer.append(s);
597         outbuf.writeLine(chbuffer);
598         outbuf.flush(channel);
599 
600         final String result = new String(baos.toByteArray(), StandardCharsets.US_ASCII);
601         Assert.assertEquals("This text contains a circumflex !!!\r\n", result);
602     }
603 
604     @Test
605     public void testUnmappableInputActionReplace() throws Exception {
606         final String s = "This text contains a circumflex \u0302 !!!";
607         final CharsetEncoder encoder = StandardCharsets.ISO_8859_1.newEncoder();
608         encoder.onMalformedInput(CodingErrorAction.IGNORE);
609         encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
610         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 16, encoder);
611         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
612         final WritableByteChannel channel = newChannel(baos);
613         final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
614         chbuffer.append(s);
615         outbuf.writeLine(chbuffer);
616         outbuf.flush(channel);
617 
618         final String result = new String(baos.toByteArray(), StandardCharsets.US_ASCII);
619         Assert.assertEquals("This text contains a circumflex ? !!!\r\n", result);
620     }
621 
622 }