blob: 75ee0d0a0e2681188f428c641eac2925391baf05 [file] [log] [blame]
// Copyright 2015 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
//
// 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.google.devtools.build.android.ziputils;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertThrows;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link BufferedFile}. */
@RunWith(JUnit4.class)
public class BufferedFileTest {
private static final FakeFileSystem fileSystem = new FakeFileSystem();
@Test
public void testBufferedFile() throws Exception {
int fileSize = 64;
String filename = "bytes64";
byte[] bytes = fileData(fileSize);
fileSystem.addFile(filename, bytes);
FileChannel file = fileSystem.getInputChannel(filename);
int maxAlloc = 16;
int regionOff = 0;
assertException("channel null",
null, regionOff, fileSize, maxAlloc, NullPointerException.class);
assertException("region offset negative",
file, -1, fileSize, maxAlloc, IllegalArgumentException.class);
assertException("region size negative",
file, regionOff, -1, maxAlloc, IllegalArgumentException.class);
assertException("maxAlloc negative",
file, regionOff, fileSize, -1, IllegalArgumentException.class);
assertException("region exceeds file",
file, regionOff, fileSize + 1, maxAlloc, IllegalArgumentException.class);
assertException("region too long from offset",
file, regionOff + 1, fileSize, maxAlloc, IllegalArgumentException.class);
assertException("region short, still too long",
file, regionOff + 50, fileSize - 49, maxAlloc, IllegalArgumentException.class);
new BufferedFile(file, regionOff, fileSize, 0); // alloc minimal buffers for request
new BufferedFile(file, regionOff, fileSize, fileSize); // alloc for full region
}
@Test
public void testGetBufferThrows() throws Exception {
BufferedFile instance;
int fileSize = 64;
String filename = "bytes64";
byte[] bytes = fileData(fileSize);
fileSystem.addFile(filename, bytes);
FileChannel file = fileSystem.getInputChannel(filename);
int regionOff = 4;
int regionSize = 50;
int maxAlloc = 16;
instance = new BufferedFile(file, regionOff, regionSize, maxAlloc);
assertException("buffer negative size",
instance, regionOff, -1, IllegalArgumentException.class);
assertException("buffer lower bound",
instance, regionOff - 1, regionSize, IllegalArgumentException.class);
assertException("buffer upper bound",
instance, regionOff + regionSize + 1, 1, IllegalArgumentException.class);
assertException("buffer upper bound zero read",
instance, regionOff + regionSize + 1, 0, IllegalArgumentException.class);
assertException("buffer beyond region non zero read",
instance, regionOff + regionSize, 1, IllegalArgumentException.class);
}
@Test
public void testGetBufferAllocationLimits() throws Exception {
BufferedFile instance;
int fileSize = 64;
String filename = "bytes64";
byte[] bytes = fileData(fileSize);
fileSystem.addFile(filename, bytes);
FileChannel file = fileSystem.getInputChannel(filename);
int regionOff = 4;
int regionSize = 50;
int maxAlloc = 16;
instance = new BufferedFile(file, regionOff, regionSize, maxAlloc);
assertCase("buffer, empty, start", instance, regionOff, 0, 0, maxAlloc);
assertWithMessage("buffer, empty, start").that(regionOff + regionSize)
.isEqualTo(instance.limit());
instance = new BufferedFile(file, regionOff, regionSize, maxAlloc);
assertCase("buffer, empty, end", instance, regionOff + regionSize, 0, 0, 0);
instance = new BufferedFile(file, regionOff, regionSize, maxAlloc);
assertCase("buffer, one, end", instance, regionOff + regionSize - 1, 1, 1, 1);
assertWithMessage("buffer, one, end").that(regionOff + regionSize)
.isEqualTo(instance.limit());
instance = new BufferedFile(file, regionOff, regionSize, maxAlloc);
assertCase("buffer, small, end", instance, regionOff + regionSize - 2, 2, 2, 2);
assertWithMessage("buffer, small, end").that(regionOff + regionSize)
.isEqualTo(instance.limit());
instance = new BufferedFile(file, regionOff, regionSize, maxAlloc);
assertCase("buffer, small, start", instance, regionOff, 2, 2, maxAlloc);
assertWithMessage("buffer, small, start").that(regionOff + regionSize)
.isEqualTo(instance.limit());
instance = new BufferedFile(file, regionOff, regionSize, maxAlloc);
assertCase("buffer, all region", instance, regionOff, regionSize, regionSize, regionSize);
assertWithMessage("buffer, all region").that(regionOff + regionSize)
.isEqualTo(instance.limit());
instance = new BufferedFile(file, regionOff, regionSize, maxAlloc);
assertCase("buffer, request more",
instance, regionOff + 5, regionSize, regionSize - 5, regionSize - 5);
assertWithMessage("buffer, request more").that(regionOff + regionSize)
.isEqualTo(instance.limit());
}
@Test
public void testGetBufferInCache() throws Exception {
BufferedFile instance;
int fileSize = 64;
String filename = "bytes64";
byte[] bytes = fileData(fileSize);
fileSystem.addFile(filename, bytes);
FileChannel file = fileSystem.getInputChannel(filename);
int regionOff = 5;
int regionSize = 50;
int maxAlloc = 20;
int cacheOff = regionOff + 5;
instance = new BufferedFile(file, regionOff, regionSize, maxAlloc);
instance.getBuffer(cacheOff, maxAlloc);
assertCase("Cached zero buf", instance, cacheOff, 0, 0, maxAlloc);
assertCase("Cached at front", instance, cacheOff, 5, 5, maxAlloc);
assertCase("Cached at end", instance, cacheOff + 2, 5, 5, maxAlloc - 2);
assertCase("Cached", instance, cacheOff, maxAlloc, maxAlloc, maxAlloc);
}
@Test
public void testGetBufferReadMore() throws Exception {
BufferedFile instance;
int fileSize = 64;
String filename = "bytes64";
byte[] bytes = fileData(fileSize);
fileSystem.addFile(filename, bytes);
FileChannel file = fileSystem.getInputChannel(filename);
int regionOff = 5;
int regionSize = 50;
int maxAlloc = 20;
int cacheOff = regionOff + 5;
int initialRead = maxAlloc / 2;
instance = new BufferedFile(file, regionOff, regionSize, maxAlloc);
instance.getBuffer(cacheOff, initialRead);
assertCase("Read more overlap",
instance, cacheOff + 1, initialRead, initialRead, maxAlloc - 1);
assertCase("Read more jump",
instance, cacheOff + initialRead + 5, 5, 5, maxAlloc - initialRead - 5);
}
@Test
public void testGetBufferReallocate() throws Exception {
BufferedFile instance;
int fileSize = 64;
String filename = "bytes64";
byte[] bytes = fileData(fileSize);
fileSystem.addFile(filename, bytes);
FileChannel file = fileSystem.getInputChannel(filename);
int regionOff = 5;
int regionSize = 50;
int maxAlloc = 20;
int cacheOff = regionOff + 5;
instance = new BufferedFile(file, regionOff, regionSize, maxAlloc);
instance.getBuffer(cacheOff, maxAlloc);
assertCase("Realloc after", instance, cacheOff + maxAlloc, maxAlloc, maxAlloc, maxAlloc);
assertCase("Realloc before", instance, cacheOff, maxAlloc, maxAlloc, maxAlloc);
assertCase("Realloc just after", instance, cacheOff + 5, maxAlloc, maxAlloc, maxAlloc);
assertCase("Realloc just before", instance, cacheOff, maxAlloc, maxAlloc, maxAlloc);
assertCase("Realloc supersize", instance, cacheOff, maxAlloc + 5, maxAlloc + 5, maxAlloc + 5);
}
void assertException(String msg, FileChannel file, long off, long len, int maxAlloc,
Class<?> expect) {
Exception ex =
assertThrows(
msg + " - no exception",
Exception.class,
() -> new BufferedFile(file, off, len, maxAlloc));
assertWithMessage(msg + " - exception, ").that(expect).isSameInstanceAs(ex.getClass());
}
void assertException(String msg, BufferedFile instance, long off, int len, Class<?> expect) {
Exception ex =
assertThrows(msg + " - no exception", Exception.class, () -> instance.getBuffer(off, len));
assertWithMessage(msg + " - exception, ").that(expect).isSameInstanceAs(ex.getClass());
}
void assertCase(String msg, BufferedFile instance, long off, int len, int expectLimit,
int capacityBound) throws IOException {
ByteBuffer buf = instance.getBuffer(off, len);
assertWithMessage(msg + " - position, ").that(0).isEqualTo(buf.position());
assertWithMessage(msg + " - limit, ").that(expectLimit).isEqualTo(buf.limit());
assertWithMessage(msg + " - capacity, ").that(buf.capacity()).isAtLeast(expectLimit);
assertWithMessage(msg + " - capacity, ").that(buf.capacity()).isAtMost(capacityBound);
if (len > 0 && expectLimit > 0) {
assertWithMessage(msg + " - value, ").that(buf.get(0)).isEqualTo((byte) off);
}
}
byte[] fileData(int count) {
byte[] bytes = new byte[count];
for (int i = 0; i < count; i++) {
bytes[i] = (byte) i;
}
return bytes;
}
}