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