1/*
2 * Copyright (C) 2007 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 static org.easymock.EasyMock.createStrictMock;
20import static org.easymock.EasyMock.expectLastCall;
21import static org.easymock.EasyMock.replay;
22import static org.easymock.EasyMock.reset;
23import static org.easymock.EasyMock.verify;
24
25import junit.framework.TestCase;
26
27import java.io.Closeable;
28import java.io.Flushable;
29import java.io.IOException;
30
31/**
32 * Unit tests for {@link Closeables} and {@link Flushables}.
33 *
34 * <p>Checks proper closing and flushing behavior, and ensures that
35 * IOExceptions on Closeable.close() or Flushable.flush() are not
36 * propagated out from the {@link Closeables#close} method if {@code
37 * swallowException} is true.
38 *
39 * @author Michael Lancaster
40 */
41public class CloseablesTest extends TestCase {
42  private Closeable mockCloseable;
43  private Flushable mockFlushable;
44
45  public void testClose_closeableClean() throws IOException {
46    // make sure that no exception is thrown regardless of value of
47    // 'swallowException' when the mock does not throw an exception.
48    setupCloseable(false);
49    doClose(mockCloseable, false, false);
50
51    setupCloseable(false);
52    doClose(mockCloseable, true, false);
53  }
54
55  public void testClose_closeableWithEatenException() throws IOException {
56    // make sure that no exception is thrown if 'swallowException' is true
57    // when the mock does throw an exception.
58    setupCloseable(true);
59    doClose(mockCloseable, true);
60  }
61
62  public void testClose_closeableWithThrownException() throws IOException {
63    // make sure that the exception is thrown if 'swallowException' is false
64    // when the mock does throw an exception.
65    setupCloseable(true);
66    doClose(mockCloseable, false);
67  }
68
69  public void testCloseQuietly_closeableWithEatenException()
70      throws IOException {
71    // make sure that no exception is thrown by CloseQuietly when the mock does
72    // throw an exception, either on close, on flush, or both.
73    setupCloseable(true);
74    Closeables.closeQuietly(mockCloseable);
75  }
76
77  public void testFlush_clean() throws IOException {
78    // make sure that no exception is thrown regardless of value of
79    // 'swallowException' when the mock does not throw an exception.
80    setupFlushable(false);
81    doFlush(mockFlushable, false, false);
82
83    setupFlushable(false);
84    doFlush(mockFlushable, true, false);
85  }
86
87  public void testFlush_flushableWithEatenException() throws IOException {
88    // make sure that no exception is thrown if 'swallowException' is true
89    // when the mock does throw an exception on flush.
90    setupFlushable(true);
91    doFlush(mockFlushable, true, false);
92  }
93
94  public void testFlush_flushableWithThrownException() throws IOException {
95    // make sure that the exception is thrown if 'swallowException' is false
96    // when the mock does throw an exception on flush.
97    setupFlushable(true);
98    doFlush(mockFlushable, false, true);
99  }
100
101  public void testFlushQuietly_flushableWithEatenException()
102      throws IOException {
103    // make sure that no exception is thrown by CloseQuietly when the mock does
104    // throw an exception on flush.
105    setupFlushable(true);
106    Flushables.flushQuietly(mockFlushable);
107  }
108
109  public void testCloseNull() throws IOException {
110    Closeables.close(null, true);
111    Closeables.close(null, false);
112    Closeables.closeQuietly(null);
113  }
114
115  @Override protected void setUp() throws Exception {
116    mockCloseable = createStrictMock(Closeable.class);
117    mockFlushable = createStrictMock(Flushable.class);
118  }
119
120  private void expectThrown() {
121    expectLastCall().andThrow(new IOException("This should only appear in the "
122        + "logs. It should not be rethrown."));
123  }
124
125  // Set up a closeable to expect to be closed, and optionally to throw an
126  // exception.
127  private void setupCloseable(boolean shouldThrow) throws IOException {
128    reset(mockCloseable);
129    mockCloseable.close();
130    if (shouldThrow) {
131      expectThrown();
132    }
133    replay(mockCloseable);
134  }
135
136  // Set up a flushable to expect to be flushed and closed, and optionally to
137  // throw an exception.
138  private void setupFlushable(boolean shouldThrowOnFlush) throws IOException {
139    reset(mockFlushable);
140    mockFlushable.flush();
141    if (shouldThrowOnFlush) {
142      expectThrown();
143    }
144    replay(mockFlushable);
145  }
146
147  private void doClose(Closeable closeable, boolean swallowException) {
148    doClose(closeable, swallowException, !swallowException);
149  }
150
151  // Close the closeable using the Closeables, passing in the swallowException
152  // parameter. expectThrown determines whether we expect an exception to
153  // be thrown by Closeables.close;
154  private void doClose(Closeable closeable, boolean swallowException,
155      boolean expectThrown) {
156    try {
157      Closeables.close(closeable, swallowException);
158      if (expectThrown) {
159        fail("Didn't throw exception.");
160      }
161    } catch (IOException e) {
162      if (!expectThrown) {
163        fail("Threw exception");
164      }
165    }
166    verify(closeable);
167  }
168
169  // Flush the flushable using the Flushables, passing in the swallowException
170  // parameter. expectThrown determines whether we expect an exception to
171  // be thrown by Flushables.flush;
172  private void doFlush(Flushable flushable, boolean swallowException,
173      boolean expectThrown) {
174    try {
175      Flushables.flush(flushable, swallowException);
176      if (expectThrown) {
177        fail("Didn't throw exception.");
178      }
179    } catch (IOException e) {
180      if (!expectThrown) {
181        fail("Threw exception");
182      }
183    }
184    verify(flushable);
185  }
186}
187