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