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
17package com.google.common.io;
18
19import com.google.common.testing.GcFinalization;
20
21import java.io.File;
22import java.io.IOException;
23import java.io.InputStream;
24import java.io.OutputStream;
25import java.util.Arrays;
26
27/**
28 * Unit tests for {@link FileBackedOutputStream}.
29 *
30 * @author Chris Nokleberg
31 */
32public class FileBackedOutputStreamTest extends IoTestCase {
33
34  public void testThreshold() throws Exception {
35    testThreshold(0, 100, true, false);
36    testThreshold(10, 100, true, false);
37    testThreshold(100, 100, true, false);
38    testThreshold(1000, 100, true, false);
39    testThreshold(0, 100, false, false);
40    testThreshold(10, 100, false, false);
41    testThreshold(100, 100, false, false);
42    testThreshold(1000, 100, false, false);
43  }
44
45  public void testFinalizeDeletesFile() throws Exception {
46    byte[] data = newPreFilledByteArray(100);
47    FileBackedOutputStream out = new FileBackedOutputStream(0, true);
48
49    write(out, data, 0, 100, true);
50    final File file = out.getFile();
51    assertEquals(100, file.length());
52    assertTrue(file.exists());
53    out.close();
54
55    // Make sure that finalize deletes the file
56    out = null;
57
58    // times out and throws RuntimeException on failure
59    GcFinalization.awaitDone(new GcFinalization.FinalizationPredicate() {
60      @Override
61      public boolean isDone() {
62        return !file.exists();
63      }
64    });
65  }
66
67  public void testThreshold_resetOnFinalize() throws Exception {
68    testThreshold(0, 100, true, true);
69    testThreshold(10, 100, true, true);
70    testThreshold(100, 100, true, true);
71    testThreshold(1000, 100, true, true);
72    testThreshold(0, 100, false, true);
73    testThreshold(10, 100, false, true);
74    testThreshold(100, 100, false, true);
75    testThreshold(1000, 100, false, true);
76  }
77
78  private void testThreshold(int fileThreshold, int dataSize, boolean singleByte,
79      boolean resetOnFinalize) throws IOException {
80    byte[] data = newPreFilledByteArray(dataSize);
81    FileBackedOutputStream out = new FileBackedOutputStream(fileThreshold, resetOnFinalize);
82    InputSupplier<InputStream> supplier = out.getSupplier();
83    int chunk1 = Math.min(dataSize, fileThreshold);
84    int chunk2 = dataSize - chunk1;
85
86    // Write just enough to not trip the threshold
87    if (chunk1 > 0) {
88      write(out, data, 0, chunk1, singleByte);
89      assertTrue(ByteStreams.equal(
90          ByteStreams.newInputStreamSupplier(data, 0, chunk1), supplier));
91    }
92    File file = out.getFile();
93    assertNull(file);
94
95    // Write data to go over the threshold
96    if (chunk2 > 0) {
97      write(out, data, chunk1, chunk2, singleByte);
98      file = out.getFile();
99      assertEquals(dataSize, file.length());
100      assertTrue(file.exists());
101    }
102    out.close();
103
104    // Check that supplier returns the right data
105    assertTrue(Arrays.equals(data, ByteStreams.toByteArray(supplier)));
106
107    // Make sure that reset deleted the file
108    out.reset();
109    if (file != null) {
110      assertFalse(file.exists());
111    }
112  }
113
114  private static void write(
115      OutputStream out, byte[] b, int off, int len, boolean singleByte)
116      throws IOException {
117    if (singleByte) {
118      for (int i = off; i < off + len; i++) {
119        out.write(b[i]);
120      }
121    } else {
122      out.write(b, off, len);
123    }
124    out.flush(); // for coverage
125  }
126
127  // TODO(chrisn): only works if we ensure we have crossed file threshold
128
129  public void testWriteErrorAfterClose() throws Exception {
130    byte[] data = newPreFilledByteArray(100);
131    FileBackedOutputStream out = new FileBackedOutputStream(50);
132    InputSupplier<InputStream> supplier = out.getSupplier();
133
134    out.write(data);
135    assertTrue(Arrays.equals(data, ByteStreams.toByteArray(supplier)));
136
137    out.close();
138    try {
139      out.write(42);
140      fail("expected exception");
141    } catch (IOException expected) {
142      // expected
143    }
144
145    // Verify that write had no effect
146    assertTrue(Arrays.equals(data, ByteStreams.toByteArray(supplier)));
147    out.reset();
148  }
149
150  public void testReset() throws Exception {
151    byte[] data = newPreFilledByteArray(100);
152    FileBackedOutputStream out = new FileBackedOutputStream(Integer.MAX_VALUE);
153    InputSupplier<InputStream> supplier = out.getSupplier();
154
155    out.write(data);
156    assertTrue(Arrays.equals(data, ByteStreams.toByteArray(supplier)));
157
158    out.reset();
159    assertTrue(Arrays.equals(new byte[0], ByteStreams.toByteArray(supplier)));
160
161    out.write(data);
162    assertTrue(Arrays.equals(data, ByteStreams.toByteArray(supplier)));
163
164    out.close();
165  }
166}
167