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.apache.commons.io.test.TestUtils.checkFile;
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertFalse;
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24 import static org.junit.jupiter.api.Assertions.fail;
25 
26 import java.io.File;
27 import java.io.FileWriter;
28 import java.io.IOException;
29 import java.io.OutputStreamWriter;
30 import java.io.Writer;
31 import java.nio.charset.Charset;
32 import java.nio.charset.CharsetEncoder;
33 import java.nio.charset.StandardCharsets;
34 import java.nio.file.Files;
35 
36 import org.junit.jupiter.api.BeforeEach;
37 import org.junit.jupiter.api.Test;
38 import org.junit.jupiter.api.io.TempDir;
39 
40 /**
41  * Tests {@link FileWriterWithEncoding}.
42  */
43 public class FileWriterWithEncodingTest {
44 
45     @TempDir
46     public File temporaryFolder;
47 
48     private String defaultEncoding;
49     private File file1;
50     private File file2;
51     private String textContent;
52     private final char[] anotherTestContent = {'f', 'z', 'x'};
53 
54     @Test
constructor_File_directory()55     public void constructor_File_directory() {
56         assertThrows(IOException.class, () -> {
57             try (Writer writer = new FileWriterWithEncoding(temporaryFolder, defaultEncoding)) {
58                 // empty
59             }
60         });
61         assertFalse(file1.exists());
62         assertThrows(IOException.class, () -> {
63             try (Writer writer = FileWriterWithEncoding.builder().setFile(temporaryFolder).setCharset(defaultEncoding).get()) {
64                 // empty
65             }
66         });
67         assertFalse(file1.exists());
68     }
69 
70     @Test
constructor_File_encoding_badEncoding()71     public void constructor_File_encoding_badEncoding() {
72         assertThrows(IOException.class, () -> {
73             try (Writer writer = new FileWriterWithEncoding(file1, "BAD-ENCODE")) {
74                 // empty
75             }
76         });
77         assertFalse(file1.exists());
78     }
79 
80     @Test
constructor_File_existingFile_withContent()81     public void constructor_File_existingFile_withContent() throws Exception {
82         try (FileWriter fw1 = new FileWriter(file1);) {
83             fw1.write(textContent);
84             fw1.write(65);
85         }
86         assertEquals(1025, file1.length());
87 
88         try (FileWriterWithEncoding fw1 = new FileWriterWithEncoding(file1, defaultEncoding)) {
89             fw1.write("ABcd");
90         }
91 
92         assertEquals(4, file1.length());
93 
94         try (FileWriterWithEncoding fw1 = FileWriterWithEncoding.builder().setFile(file1).setCharset(defaultEncoding).get()) {
95             fw1.write("ABcd");
96         }
97 
98         assertEquals(4, file1.length());
99     }
100 
101     @Test
constructor_File_nullFile()102     public void constructor_File_nullFile() {
103         assertThrows(NullPointerException.class, () -> {
104             try (Writer writer = new FileWriterWithEncoding((File) null, defaultEncoding)) {
105                 // empty
106             }
107         });
108         assertFalse(file1.exists());
109     }
110 
111     @Test
constructor_fileName_nullFile()112     public void constructor_fileName_nullFile() {
113         assertThrows(NullPointerException.class, () -> {
114             try (Writer writer = new FileWriterWithEncoding((String) null, defaultEncoding)) {
115                 // empty
116             }
117         });
118         assertFalse(file1.exists());
119     }
120 
121     @Test
constructorAppend_File_existingFile_withContent()122     public void constructorAppend_File_existingFile_withContent() throws Exception {
123         try (FileWriter fw1 = new FileWriter(file1)) {
124             fw1.write("ABcd");
125         }
126         assertEquals(4, file1.length());
127 
128         try (FileWriterWithEncoding fw1 = new FileWriterWithEncoding(file1, defaultEncoding, true)) {
129             fw1.write("XyZ");
130         }
131 
132         assertEquals(7, file1.length());
133 
134         // @formatter:off
135         try (FileWriterWithEncoding fw1 = FileWriterWithEncoding.builder()
136                 .setFile(file1)
137                 .setCharset(defaultEncoding)
138                 .setAppend(true)
139                 .get()) {
140             fw1.write("XyZ");
141         }
142         // @formatter:on
143 
144         assertEquals(10, file1.length());
145     }
146 
147     @Test
sameEncoding_Charset_constructor()148     public void sameEncoding_Charset_constructor() throws Exception {
149         try (FileWriterWithEncoding writer = new FileWriterWithEncoding(file2, Charset.defaultCharset())) {
150             successfulRun(writer);
151         }
152         // @formatter:off
153         try (FileWriterWithEncoding writer = FileWriterWithEncoding.builder()
154                 .setFile(file2)
155                 .setCharset(Charset.defaultCharset())
156                 .get()) {
157             successfulRun(writer);
158         }
159         // @formatter:on
160     }
161 
162     @Test
sameEncoding_CharsetEncoder_constructor()163     public void sameEncoding_CharsetEncoder_constructor() throws Exception {
164         try (FileWriterWithEncoding writer = new FileWriterWithEncoding(file2, Charset.defaultCharset().newEncoder())) {
165             successfulRun(writer);
166         }
167         // @formatter:off
168         try (FileWriterWithEncoding writer = FileWriterWithEncoding.builder()
169                 .setFile(file2)
170                 .setCharsetEncoder(Charset.defaultCharset().newEncoder())
171                 .get()) {
172             successfulRun(writer);
173         }
174         // @formatter:on
175     }
176 
177     @Test
sameEncoding_null_Charset_constructor()178     public void sameEncoding_null_Charset_constructor() throws Exception {
179         try (FileWriterWithEncoding writer = new FileWriterWithEncoding(file2, (Charset) null)) {
180             successfulRun(writer);
181         }
182     }
183 
184     @Test
sameEncoding_null_CharsetEncoder_constructor()185     public void sameEncoding_null_CharsetEncoder_constructor() throws Exception {
186         try (FileWriterWithEncoding writer = new FileWriterWithEncoding(file2.getPath(), (CharsetEncoder) null)) {
187             successfulRun(writer);
188         }
189         try (FileWriterWithEncoding writer = FileWriterWithEncoding.builder().setFile(file2.getPath()).get()) {
190             successfulRun(writer);
191         }
192         try (FileWriterWithEncoding writer = FileWriterWithEncoding.builder().setFile(file2.getPath()).setCharsetEncoder(null).get()) {
193             successfulRun(writer);
194         }
195     }
196 
197     @Test
sameEncoding_null_CharsetName_constructor()198     public void sameEncoding_null_CharsetName_constructor() throws Exception {
199         try (FileWriterWithEncoding writer = new FileWriterWithEncoding(file2.getPath(), (String) null)) {
200             successfulRun(writer);
201         }
202     }
203 
204     @Test
sameEncoding_string_Charset_constructor()205     public void sameEncoding_string_Charset_constructor() throws Exception {
206         try (FileWriterWithEncoding writer = new FileWriterWithEncoding(file2.getPath(), Charset.defaultCharset())) {
207             successfulRun(writer);
208         }
209         // @formatter:off
210         try (FileWriterWithEncoding writer = FileWriterWithEncoding.builder()
211                 .setFile(file2.getPath())
212                 .setCharset(Charset.defaultCharset())
213                 .get()) {
214             successfulRun(writer);
215         }
216         // @formatter:on
217     }
218 
219     @Test
sameEncoding_string_CharsetEncoder_constructor()220     public void sameEncoding_string_CharsetEncoder_constructor() throws Exception {
221         try (FileWriterWithEncoding writer = new FileWriterWithEncoding(file2.getPath(), Charset.defaultCharset().newEncoder())) {
222             successfulRun(writer);
223         }
224     }
225 
226     @Test
sameEncoding_string_constructor()227     public void sameEncoding_string_constructor() throws Exception {
228         try (FileWriterWithEncoding writer = new FileWriterWithEncoding(file2, defaultEncoding)) {
229             successfulRun(writer);
230         }
231     }
232 
233     @Test
sameEncoding_string_string_constructor()234     public void sameEncoding_string_string_constructor() throws Exception {
235         try (FileWriterWithEncoding writer = new FileWriterWithEncoding(file2.getPath(), defaultEncoding)) {
236             successfulRun(writer);
237         }
238         // @formatter:off
239         try (FileWriterWithEncoding writer = FileWriterWithEncoding.builder()
240                 .setFile(file2.getPath())
241                 .setCharset(defaultEncoding)
242                 .get()) {
243             successfulRun(writer);
244         }
245         // @formatter:on
246     }
247 
248     @BeforeEach
setUp()249     public void setUp() throws Exception {
250         final File encodingFinder = new File(temporaryFolder, "finder.txt");
251         try (OutputStreamWriter out = new OutputStreamWriter(Files.newOutputStream(encodingFinder.toPath()))) {
252             defaultEncoding = out.getEncoding();
253         }
254         file1 = new File(temporaryFolder, "testfile1.txt");
255         file2 = new File(temporaryFolder, "testfile2.txt");
256         final char[] arr = new char[1024];
257         final char[] chars = "ABCDEFGHIJKLMNOPQabcdefgihklmnopq".toCharArray();
258         for (int i = 0; i < arr.length; i++) {
259             arr[i] = chars[i % chars.length];
260         }
261         textContent = new String(arr);
262     }
263 
successfulRun(final FileWriterWithEncoding fw21)264     private void successfulRun(final FileWriterWithEncoding fw21) throws Exception {
265         try (FileWriter fw1 = new FileWriter(file1); // default encoding
266             FileWriterWithEncoding fw2 = fw21) {
267             writeTestPayload(fw1, fw2);
268             checkFile(file1, file2);
269         }
270         assertTrue(file1.exists());
271         assertTrue(file2.exists());
272     }
273 
274     @Test
testDifferentEncoding()275     public void testDifferentEncoding() throws Exception {
276         if (Charset.isSupported(StandardCharsets.UTF_16BE.name())) {
277             try (FileWriter fw1 = new FileWriter(file1); // default encoding
278                 FileWriterWithEncoding fw2 = new FileWriterWithEncoding(file2, defaultEncoding)) {
279                 writeTestPayload(fw1, fw2);
280                 try {
281                     checkFile(file1, file2);
282                     fail();
283                 } catch (final AssertionError ex) {
284                     // success
285                 }
286 
287             }
288             assertTrue(file1.exists());
289             assertTrue(file2.exists());
290         }
291         if (Charset.isSupported(StandardCharsets.UTF_16LE.name())) {
292             try (FileWriter fw1 = new FileWriter(file1); // default encoding
293                 FileWriterWithEncoding fw2 = new FileWriterWithEncoding(file2, defaultEncoding)) {
294                 writeTestPayload(fw1, fw2);
295                 try {
296                     checkFile(file1, file2);
297                     fail();
298                 } catch (final AssertionError ex) {
299                     // success
300                 }
301 
302             }
303             assertTrue(file1.exists());
304             assertTrue(file2.exists());
305         }
306     }
307 
writeTestPayload(final FileWriter fw1, final FileWriterWithEncoding fw2)308     private void writeTestPayload(final FileWriter fw1, final FileWriterWithEncoding fw2) throws IOException {
309         assertTrue(file1.exists());
310         assertTrue(file2.exists());
311 
312         fw1.write(textContent);
313         fw2.write(textContent);
314         fw1.write(65);
315         fw2.write(65);
316         fw1.write(anotherTestContent);
317         fw2.write(anotherTestContent);
318         fw1.write(anotherTestContent, 1, 2);
319         fw2.write(anotherTestContent, 1, 2);
320         fw1.write("CAFE", 1, 2);
321         fw2.write("CAFE", 1, 2);
322 
323         fw1.flush();
324         fw2.flush();
325     }
326 }
327