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.io.output;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.fail;
21  
22  import java.io.IOException;
23  import java.io.StringWriter;
24  import java.nio.charset.Charset;
25  import java.nio.charset.CharsetDecoder;
26  import java.nio.charset.StandardCharsets;
27  import java.nio.file.StandardOpenOption;
28  import java.util.Random;
29  
30  import org.apache.commons.io.Charsets;
31  import org.apache.commons.io.charset.CharsetDecoders;
32  import org.junit.jupiter.api.Test;
33  
34  /**
35   * Tests {@link WriterOutputStream}.
36   */
37  public class WriterOutputStreamTest {
38  
39      private static final String UTF_16LE = StandardCharsets.UTF_16LE.name();
40      private static final String UTF_16BE = StandardCharsets.UTF_16BE.name();
41      private static final String UTF_16 = StandardCharsets.UTF_16.name();
42      private static final String UTF_8 = StandardCharsets.UTF_8.name();
43      private static final String TEST_STRING = "\u00e0 peine arriv\u00e9s nous entr\u00e2mes dans sa chambre";
44      private static final String LARGE_TEST_STRING;
45  
46      static {
47          final StringBuilder buffer = new StringBuilder();
48          for (int i=0; i<100; i++) {
49              buffer.append(TEST_STRING);
50          }
51          LARGE_TEST_STRING = buffer.toString();
52      }
53  
54      private final Random random = new Random();
55  
56      @Test
57      public void testFlush() throws IOException {
58          final StringWriter writer = new StringWriter();
59          try (WriterOutputStream out = new WriterOutputStream(writer, "us-ascii", 1024, false)) {
60              out.write("abc".getBytes(StandardCharsets.US_ASCII));
61              assertEquals(0, writer.getBuffer().length());
62              out.flush();
63              assertEquals("abc", writer.toString());
64          }
65      }
66  
67      @Test
68      public void testLargeUTF8CharsetWithBufferedWrite() throws IOException {
69          testWithBufferedWrite(LARGE_TEST_STRING, UTF_8);
70      }
71  
72      @Test
73      public void testLargeUTF8CharsetWithSingleByteWrite() throws IOException {
74          testWithSingleByteWrite(LARGE_TEST_STRING, StandardCharsets.UTF_8);
75      }
76  
77      @Test
78      public void testLargeUTF8WithBufferedWrite() throws IOException {
79          testWithBufferedWrite(LARGE_TEST_STRING, UTF_8);
80      }
81  
82      @Test
83      public void testLargeUTF8WithSingleByteWrite() throws IOException {
84          testWithSingleByteWrite(LARGE_TEST_STRING, UTF_8);
85      }
86  
87      @Test
88      public void testNullCharsetDecoderWithSingleByteWrite() throws IOException {
89          testWithSingleByteWrite(TEST_STRING, (CharsetDecoder) null);
90      }
91  
92      @Test
93      public void testNullCharsetNameWithSingleByteWrite() throws IOException {
94          testWithSingleByteWrite(TEST_STRING, (String) null);
95      }
96  
97      @Test
98      public void testNullCharsetWithSingleByteWrite() throws IOException {
99          testWithSingleByteWrite(TEST_STRING, (Charset) null);
100     }
101 
102     @Test
103     public void testUTF16BEWithBufferedWrite() throws IOException {
104         testWithBufferedWrite(TEST_STRING, UTF_16BE);
105     }
106 
107     @Test
108     public void testUTF16BEWithSingleByteWrite() throws IOException {
109         testWithSingleByteWrite(TEST_STRING, UTF_16BE);
110     }
111 
112     @Test
113     public void testUTF16LEWithBufferedWrite() throws IOException {
114         testWithBufferedWrite(TEST_STRING, UTF_16LE);
115     }
116 
117     @Test
118     public void testUTF16LEWithSingleByteWrite() throws IOException {
119         testWithSingleByteWrite(TEST_STRING, UTF_16LE);
120     }
121 
122     @Test
123     public void testUTF16WithBufferedWrite() throws IOException {
124         try {
125             testWithBufferedWrite(TEST_STRING, UTF_16);
126         } catch (final UnsupportedOperationException e) {
127             if (!System.getProperty("java.vendor").contains("IBM")) {
128                 fail("This test should only throw UOE on IBM JDKs with broken UTF-16");
129             }
130         }
131     }
132 
133     @Test
134     public void testUTF16WithSingleByteWrite() throws IOException {
135         try {
136             testWithSingleByteWrite(TEST_STRING, UTF_16);
137         } catch (final UnsupportedOperationException e){
138             if (!System.getProperty("java.vendor").contains("IBM")){
139                 fail("This test should only throw UOE on IBM JDKs with broken UTF-16");
140             }
141         }
142     }
143 
144     @Test
145     public void testUTF8WithBufferedWrite() throws IOException {
146         testWithBufferedWrite(TEST_STRING, UTF_8);
147     }
148 
149     @Test
150     public void testUTF8WithSingleByteWrite() throws IOException {
151         testWithSingleByteWrite(TEST_STRING, UTF_8);
152     }
153 
154     private void testWithBufferedWrite(final String testString, final String charsetName) throws IOException {
155         final byte[] expected = testString.getBytes(charsetName);
156         final StringWriter writer = new StringWriter();
157         try (WriterOutputStream out = WriterOutputStream.builder().setWriter(writer).setCharset(charsetName).get()) {
158             int offset = 0;
159             while (offset < expected.length) {
160                 final int length = Math.min(random.nextInt(128), expected.length - offset);
161                 out.write(expected, offset, length);
162                 offset += length;
163             }
164         }
165         assertEquals(testString, writer.toString());
166     }
167 
168     private void testWithSingleByteWrite(final String testString, final Charset charset) throws IOException {
169         final byte[] bytes = testString.getBytes(Charsets.toCharset(charset));
170         StringWriter writer = new StringWriter();
171         try (WriterOutputStream out = new WriterOutputStream(writer, charset)) {
172             writeOneAtATime(bytes, out);
173         }
174         assertEquals(testString, writer.toString());
175         //
176         writer = new StringWriter();
177         try (WriterOutputStream out = WriterOutputStream.builder().setWriter(writer).setCharset(charset).get()) {
178             writeOneAtATime(bytes, out);
179         }
180         assertEquals(testString, writer.toString());
181     }
182 
183     private void testWithSingleByteWrite(final String testString, final CharsetDecoder charsetDecoder) throws IOException {
184         final byte[] bytes = testString.getBytes(CharsetDecoders.toCharsetDecoder(charsetDecoder).charset());
185         StringWriter writer = new StringWriter();
186         try (WriterOutputStream out = new WriterOutputStream(writer, charsetDecoder)) {
187             writeOneAtATime(bytes, out);
188         }
189         assertEquals(testString, writer.toString());
190         //
191         writer = new StringWriter();
192         try (WriterOutputStream out = WriterOutputStream.builder().setWriter(writer).setCharsetDecoder(charsetDecoder).get()) {
193             writeOneAtATime(bytes, out);
194         }
195         assertEquals(testString, writer.toString());
196     }
197 
198     private void testWithSingleByteWrite(final String testString, final String charsetName) throws IOException {
199         final byte[] bytes = testString.getBytes(Charsets.toCharset(charsetName));
200         StringWriter writer = new StringWriter();
201         try (WriterOutputStream out = new WriterOutputStream(writer, charsetName)) {
202             writeOneAtATime(bytes, out);
203         }
204         assertEquals(testString, writer.toString());
205         //
206         writer = new StringWriter();
207         try (WriterOutputStream out = WriterOutputStream.builder().setWriter(writer).setCharset(charsetName).get()) {
208             writeOneAtATime(bytes, out);
209         }
210         assertEquals(testString, writer.toString());
211     }
212 
213     @Test
214     public void testWriteImmediately() throws IOException {
215         final StringWriter writer = new StringWriter();
216         try (WriterOutputStream out = new WriterOutputStream(writer, "us-ascii", 1024, true)) {
217             out.write("abc".getBytes(StandardCharsets.US_ASCII));
218             assertEquals("abc", writer.toString());
219         }
220         // @formatter:off
221         try (WriterOutputStream out = WriterOutputStream.builder()
222                 .setWriter(writer)
223                 .setCharset("us-ascii")
224                 .setBufferSize(1024)
225                 .setWriteImmediately(true)
226                 .setOpenOptions(StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)
227                 .get()) {
228             // @formatter:on
229             out.write("abc".getBytes(StandardCharsets.US_ASCII));
230             assertEquals("abcabc", writer.toString());
231         }
232     }
233 
234     private void writeOneAtATime(final byte[] bytes, final WriterOutputStream out) throws IOException {
235         for (final byte b : bytes) {
236             out.write(b);
237         }
238     }
239 }