/*
* Copyright 2016-present Facebook, Inc.
*
* 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.facebook.buck.bsd;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.equalToObject;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import com.facebook.buck.charset.NulTerminatedCharsetDecoder;
import com.google.common.base.Charsets;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import org.junit.Before;
import org.junit.Test;
public class UnixArchiveTest {
private Path tmp;
@Before
public void setUp() throws Exception {
tmp = Files.createTempDirectory("junit-temp-path").toRealPath();
}
@Test
public void testCheckingHeader() throws IOException {
byte[] bytes = "!<arch>\n..........".getBytes(Charsets.UTF_8);
assertThat(
UnixArchive.checkHeader(ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN)), equalTo(true));
bytes = "UNEXPECTED_CONTENTS.......".getBytes(Charsets.UTF_8);
assertThat(
UnixArchive.checkHeader(ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN)),
equalTo(false));
}
@Test
public void testReadingArchive() throws IOException {
Path path = tmp.resolve("test_archive.a");
createArchiveAtPath(path);
UnixArchive archive =
new UnixArchive(
FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE),
new NulTerminatedCharsetDecoder(StandardCharsets.UTF_8.newDecoder()));
assertThat(archive.getEntries().size(), equalTo(3));
assertThat(archive.getEntries().get(0).getFileName(), equalToObject("__.SYMDEF SORTED"));
assertThat(archive.getEntries().get(0).getFileModificationTimestamp(), equalTo(1463146035L));
assertThat(archive.getEntries().get(0).getOwnerId(), equalTo(10727));
assertThat(archive.getEntries().get(0).getGroupId(), equalTo(11706));
assertThat(archive.getEntries().get(0).getFileMode(), equalTo(100644));
assertThat(archive.getEntries().get(1).getFileName(), equalToObject("file1.txt"));
assertThat(archive.getEntries().get(1).getFileModificationTimestamp(), equalTo(1463145840L));
assertThat(archive.getEntries().get(1).getFileSize(), equalTo(16L));
MappedByteBuffer buffer1 = archive.getMapForEntry(archive.getEntries().get(1));
byte[] strBytes1 = new byte[(int) archive.getEntries().get(1).getFileSize()];
buffer1.get(strBytes1, 0, (int) archive.getEntries().get(1).getFileSize());
assertThat(new String(strBytes1), equalToObject("FILE1_CONTENTS\n\n"));
assertThat(archive.getEntries().get(2).getFileName(), equalToObject("file2.txt"));
assertThat(archive.getEntries().get(2).getFileModificationTimestamp(), equalTo(1463145848L));
assertThat(archive.getEntries().get(2).getFileSize(), equalTo(32L));
MappedByteBuffer buffer2 = archive.getMapForEntry(archive.getEntries().get(2));
byte[] strBytes2 = new byte[(int) archive.getEntries().get(2).getFileSize()];
buffer2.get(strBytes2, 0, (int) archive.getEntries().get(2).getFileSize());
assertThat(new String(strBytes2), equalToObject("FILE2_CONTENTS_FILE2_CONTENTS\n\n\n"));
archive.close();
}
@Test
public void testModifyingArchive() throws IOException {
Path path = tmp.resolve("test_archive.a");
createArchiveAtPath(path);
UnixArchive archive =
new UnixArchive(
FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE),
new NulTerminatedCharsetDecoder(StandardCharsets.UTF_8.newDecoder()));
MappedByteBuffer buffer = archive.getMapForEntry(archive.getEntries().get(1));
byte[] bytes = new byte[(int) archive.getEntries().get(1).getFileSize()];
buffer.get(bytes, 0, (int) archive.getEntries().get(1).getFileSize());
assertThat(new String(bytes), equalToObject("FILE1_CONTENTS\n\n"));
buffer.position(0);
buffer.put("NEW_CONTENTS!!!!".getBytes(Charsets.UTF_8));
archive.close();
String updatedContents = new String(Files.readAllBytes(path));
assertThat(updatedContents, not(containsString("FILE1_CONTENTS")));
assertThat(updatedContents, containsString("NEW_CONTENTS!!!!"));
}
private void createArchiveAtPath(Path path) throws IOException {
byte[] magic = {0x60, 0x0A};
String contents = "!<arch>\n";
contents += "#1/20 1463146035 10727 11706 100644 28 ";
contents += new String(magic);
contents +=
"__.SYMDEF SORTED\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
+ "\u0000\u0000";
contents += "#1/20 1463145840 10727 11706 100644 36 ";
contents += new String(magic);
contents += "file1.txt\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000";
contents += "FILE1_CONTENTS\n\n";
contents += "#1/20 1463145848 10727 11706 100644 52 ";
contents += new String(magic);
contents += "file2.txt\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000";
contents += "FILE2_CONTENTS_FILE2_CONTENTS\n\n\n";
FileWriter writer = new FileWriter(path.toFile());
writer.write(contents);
writer.close();
}
@Test
public void testReadingStringDoesNotBreakPositionAndLimit() throws Exception {
byte[] bytes = {66, 66, 66, 66, 66, 66, 66, 66, 66};
ByteBuffer buffer = ByteBuffer.wrap(bytes);
buffer.limit(buffer.capacity() - 4);
UnixArchive.readStringWithLength(buffer, 3, StandardCharsets.UTF_8.newDecoder());
assertThat(buffer.limit(), equalTo(buffer.capacity() - 4));
}
}