// 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.assertEquals; import static org.junit.Assert.fail; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /** * 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) { assertEquals(msg + " - value, ", (byte) off, buf.get(0)); } } byte[] fileData(int count) { byte[] bytes = new byte[count]; for (int i = 0; i < count; i++) { bytes[i] = (byte) i; } return bytes; } }