| // 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.fail; |
| |
| 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) { |
| try { |
| new BufferedFile(file, off, len, maxAlloc); |
| fail(msg + " - no exception"); |
| } catch (Exception ex) { |
| assertWithMessage(msg + " - exception, ").that(expect).isSameAs(ex.getClass()); |
| } |
| } |
| |
| void assertException(String msg, BufferedFile instance, long off, int len, Class<?> expect) { |
| try { |
| instance.getBuffer(off, len); |
| fail(msg + " - no exception"); |
| } catch (Exception ex) { |
| assertWithMessage(msg + " - exception, ").that(expect).isSameAs(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; |
| } |
| } |