blob: 958998540ecaa57473f9936844eb17eff219a1a1 [file] [log] [blame]
/*
* 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();
}
}
}