1 /* 2 * Copyright (C) 2008 The Guava Authors 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 17 package com.google.common.io; 18 19 import static com.google.common.base.StandardSystemProperty.JAVA_IO_TMPDIR; 20 import static com.google.common.base.StandardSystemProperty.OS_NAME; 21 import static com.google.common.truth.Truth.assertThat; 22 import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; 23 import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; 24 import static org.junit.Assert.assertThrows; 25 26 import java.io.File; 27 import java.io.IOException; 28 import java.io.OutputStream; 29 import java.nio.file.attribute.PosixFileAttributeView; 30 import java.nio.file.attribute.PosixFileAttributes; 31 import java.util.Arrays; 32 33 /** 34 * Unit tests for {@link FileBackedOutputStream}. 35 * 36 * <p>For a tiny bit more testing, see {@link FileBackedOutputStreamAndroidIncompatibleTest}. 37 * 38 * @author Chris Nokleberg 39 */ 40 public class FileBackedOutputStreamTest extends IoTestCase { 41 42 testThreshold()43 public void testThreshold() throws Exception { 44 testThreshold(0, 100, true, false); 45 testThreshold(10, 100, true, false); 46 testThreshold(100, 100, true, false); 47 testThreshold(1000, 100, true, false); 48 testThreshold(0, 100, false, false); 49 testThreshold(10, 100, false, false); 50 testThreshold(100, 100, false, false); 51 testThreshold(1000, 100, false, false); 52 } 53 testThreshold( int fileThreshold, int dataSize, boolean singleByte, boolean resetOnFinalize)54 private void testThreshold( 55 int fileThreshold, int dataSize, boolean singleByte, boolean resetOnFinalize) 56 throws IOException { 57 byte[] data = newPreFilledByteArray(dataSize); 58 FileBackedOutputStream out = new FileBackedOutputStream(fileThreshold, resetOnFinalize); 59 ByteSource source = out.asByteSource(); 60 int chunk1 = Math.min(dataSize, fileThreshold); 61 int chunk2 = dataSize - chunk1; 62 63 // Write just enough to not trip the threshold 64 if (chunk1 > 0) { 65 write(out, data, 0, chunk1, singleByte); 66 assertTrue(ByteSource.wrap(data).slice(0, chunk1).contentEquals(source)); 67 } 68 File file = out.getFile(); 69 assertNull(file); 70 71 // Write data to go over the threshold 72 if (chunk2 > 0) { 73 if (JAVA_IO_TMPDIR.value().equals("/sdcard")) { 74 assertThrows(IOException.class, () -> write(out, data, chunk1, chunk2, singleByte)); 75 return; 76 } 77 write(out, data, chunk1, chunk2, singleByte); 78 file = out.getFile(); 79 assertEquals(dataSize, file.length()); 80 assertTrue(file.exists()); 81 assertThat(file.getName()).contains("FileBackedOutputStream"); 82 if (!isAndroid() && !isWindows()) { 83 PosixFileAttributes attributes = 84 java.nio.file.Files.getFileAttributeView(file.toPath(), PosixFileAttributeView.class) 85 .readAttributes(); 86 assertThat(attributes.permissions()).containsExactly(OWNER_READ, OWNER_WRITE); 87 } 88 } 89 out.close(); 90 91 // Check that source returns the right data 92 assertTrue(Arrays.equals(data, source.read())); 93 94 // Make sure that reset deleted the file 95 out.reset(); 96 if (file != null) { 97 assertFalse(file.exists()); 98 } 99 } 100 101 testThreshold_resetOnFinalize()102 public void testThreshold_resetOnFinalize() throws Exception { 103 testThreshold(0, 100, true, true); 104 testThreshold(10, 100, true, true); 105 testThreshold(100, 100, true, true); 106 testThreshold(1000, 100, true, true); 107 testThreshold(0, 100, false, true); 108 testThreshold(10, 100, false, true); 109 testThreshold(100, 100, false, true); 110 testThreshold(1000, 100, false, true); 111 } 112 write(OutputStream out, byte[] b, int off, int len, boolean singleByte)113 static void write(OutputStream out, byte[] b, int off, int len, boolean singleByte) 114 throws IOException { 115 if (singleByte) { 116 for (int i = off; i < off + len; i++) { 117 out.write(b[i]); 118 } 119 } else { 120 out.write(b, off, len); 121 } 122 out.flush(); // for coverage 123 } 124 125 // TODO(chrisn): only works if we ensure we have crossed file threshold 126 testWriteErrorAfterClose()127 public void testWriteErrorAfterClose() throws Exception { 128 byte[] data = newPreFilledByteArray(100); 129 FileBackedOutputStream out = new FileBackedOutputStream(50); 130 ByteSource source = out.asByteSource(); 131 132 if (JAVA_IO_TMPDIR.value().equals("/sdcard")) { 133 assertThrows(IOException.class, () -> out.write(data)); 134 return; 135 } 136 out.write(data); 137 assertTrue(Arrays.equals(data, source.read())); 138 139 out.close(); 140 assertThrows(IOException.class, () -> out.write(42)); 141 142 // Verify that write had no effect 143 assertTrue(Arrays.equals(data, source.read())); 144 out.reset(); 145 } 146 testReset()147 public void testReset() throws Exception { 148 byte[] data = newPreFilledByteArray(100); 149 FileBackedOutputStream out = new FileBackedOutputStream(Integer.MAX_VALUE); 150 ByteSource source = out.asByteSource(); 151 152 out.write(data); 153 assertTrue(Arrays.equals(data, source.read())); 154 155 out.reset(); 156 assertTrue(Arrays.equals(new byte[0], source.read())); 157 158 out.write(data); 159 assertTrue(Arrays.equals(data, source.read())); 160 161 out.close(); 162 } 163 isAndroid()164 private static boolean isAndroid() { 165 return System.getProperty("java.runtime.name", "").contains("Android"); 166 } 167 isWindows()168 private static boolean isWindows() { 169 return OS_NAME.value().startsWith("Windows"); 170 } 171 } 172