/* | |
* Copyright (C) 2014 The Android Open Source Project | |
* | |
* Licensed under the Eclipse Public License, Version 1.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.eclipse.org/org/documents/epl-v10.php | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package com.android.io; | |
import com.android.annotations.NonNull; | |
import com.android.io.NonClosingInputStream.CloseBehavior; | |
import com.google.common.base.Charsets; | |
import java.io.BufferedInputStream; | |
import java.io.ByteArrayInputStream; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.util.Locale; | |
import junit.framework.TestCase; | |
/** | |
* | |
*/ | |
public class NonClosingInputStreamTest extends TestCase { | |
private File mFile; | |
@Override | |
protected void setUp() throws Exception { | |
super.setUp(); | |
mFile = File.createTempFile("test", "txt"); | |
FileWrapper fw = new FileWrapper(mFile); | |
fw.setContents(new ByteArrayInputStream("1234".getBytes(Charsets.UTF_8))); | |
} | |
@Override | |
protected void tearDown() throws Exception { | |
super.tearDown(); | |
if (!mFile.delete()) { | |
mFile.deleteOnExit(); | |
} | |
} | |
/** | |
* Tests the normal case where a method parses a stream closes it. | |
* Next parser/reset operation fails with an IOException since the stream is closed. | |
*/ | |
public void testFailure() throws IOException { | |
InputStream is = loadResource(); | |
try { | |
assertEquals('1', parseAndClose(is)); | |
try { | |
assertEquals('2', parse(is)); | |
fail("Expected: IOException 'stream closed'; Actual: no error."); | |
} catch (IOException e) { | |
assertEquals("Stream closed", e.getMessage()); | |
} | |
} finally { | |
// Stream should have been closed already. | |
// This is to prevent from keeping a stream open in case the test fails. | |
if (is != null) { | |
is.close(); | |
} | |
} | |
} | |
/** | |
* Tests with a NonClosingInputStream using CLOSE behavior. | |
* This should do exactly like in the previous testFailure case. | |
*/ | |
public void testCloseBehavior() throws IOException { | |
InputStream is = loadResource(); | |
try { | |
InputStream ncis = new NonClosingInputStream(is); | |
assertEquals('1', parseAndClose(ncis)); | |
try { | |
assertEquals('2', parse(ncis)); | |
fail("Expected: IOException 'stream closed'; Actual: no error."); | |
} catch (IOException e) { | |
assertEquals("stream closed", e.getMessage().toLowerCase(Locale.US)); | |
} | |
} finally { | |
// Stream should have been closed already. | |
// This is to prevent from keeping a stream open in case the test fails. | |
// | |
// Note that to really close, we need to invoke the original stream | |
if (is != null) { | |
is.close(); | |
} | |
} | |
} | |
/** | |
* Tests with a NonClosingInputStream using IGNORE behavior. | |
* In this case, when the parser tries to close the stream, nothing happens. | |
*/ | |
public void testIgnoreBehavior() throws IOException { | |
InputStream is = loadResource(); | |
try { | |
InputStream ncis = new NonClosingInputStream(is); | |
((NonClosingInputStream) ncis).setCloseBehavior(CloseBehavior.IGNORE); | |
assertTrue(ncis.markSupported()); | |
assertEquals('1', parseAndClose(ncis)); | |
// the first parser's close should have done nothing | |
assertEquals('2', parse(ncis)); | |
// closing does nothing | |
ncis.close(); | |
assertEquals('3', parse(ncis)); | |
assertEquals('4', parse(ncis)); | |
// we can change the closing behavior to really close the stream | |
((NonClosingInputStream) ncis).setCloseBehavior(CloseBehavior.CLOSE); | |
try { | |
ncis.close(); | |
assertEquals('5', parse(ncis)); | |
fail("Expected: IOException 'stream closed'; Actual: no error."); | |
} catch (IOException e) { | |
assertEquals("stream closed", e.getMessage().toLowerCase(Locale.US)); | |
} | |
} finally { | |
// Stream should have been closed already. | |
// This is to prevent from keeping a stream open in case the test fails. | |
// | |
// Note that to really close, we need to invoke the original stream | |
if (is != null) { | |
is.close(); | |
} | |
} | |
} | |
/** | |
* Tests with a NonClosingInputStream using RESET behavior. | |
* In this case, when the parser tries to close the stream, it actually | |
* calls reset and reverts it the last marked position. | |
*/ | |
public void testResetBehavior() throws IOException { | |
InputStream is = loadResource(); | |
try { | |
InputStream ncis = new NonClosingInputStream(is); | |
((NonClosingInputStream) ncis).setCloseBehavior(CloseBehavior.RESET); | |
assertTrue(ncis.markSupported()); | |
ncis.mark(10); | |
assertEquals('1', parseAndClose(ncis)); | |
// the first parser's close should have reset to the beginning | |
assertEquals('1', parse(ncis)); | |
assertEquals('2', parse(ncis)); | |
// a reset takes us back to the beginning | |
is.reset(); | |
assertEquals('1', parse(ncis)); | |
assertEquals('2', parse(ncis)); | |
// a direct close on the wrapper also resets | |
ncis.close(); | |
assertEquals('1', parse(ncis)); | |
assertEquals('2', parse(ncis)); | |
// we can change the closing behavior to really close the stream | |
((NonClosingInputStream) ncis).setCloseBehavior(CloseBehavior.CLOSE); | |
try { | |
ncis.close(); | |
assertEquals('3', parse(ncis)); | |
fail("Expected: IOException 'stream closed'; Actual: no error."); | |
} catch (IOException e) { | |
assertEquals("stream closed", e.getMessage().toLowerCase(Locale.US)); | |
} | |
} finally { | |
// Stream should have been closed already. | |
// This is to prevent from keeping a stream open in case the test fails. | |
// | |
// Note that to really close, we need to invoke the original stream | |
if (is != null) { | |
is.close(); | |
} | |
} | |
} | |
//--- | |
private InputStream loadResource() throws FileNotFoundException { | |
InputStream is = new BufferedInputStream(new FileInputStream(mFile)); | |
assertNotNull("test.txt not found", is); | |
return is; | |
} | |
private char parse(@NonNull InputStream is) throws IOException { | |
return (char) is.read(); | |
} | |
private char parseAndClose(@NonNull InputStream is) throws IOException { | |
try { | |
return (char) is.read(); | |
} finally { | |
is.close(); | |
} | |
} | |
} |