blob: d4efc5d55e1e04f47fb6ec3e15082894813afd5c [file] [log] [blame]
/*
* Copyright 2014-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.apple.clang;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Path;
import java.nio.file.Paths;
public class HeaderMapTest {
private void assertThatHeaderMapsAreEqual(final HeaderMap hmap1, final HeaderMap hmap2) {
hmap1.visit(
new HeaderMap.HeaderMapVisitor() {
@Override
public void apply(String str, String prefix, String suffix) {
assertEquals(prefix + suffix, hmap2.lookup(str));
}
});
if (hmap1 == hmap2) {
return;
}
assertEquals(hmap1.getNumBuckets(), hmap2.getNumBuckets());
assertEquals(hmap1.getNumEntries(), hmap2.getNumEntries());
assertEquals(hmap1.getMaxValueLength(), hmap2.getMaxValueLength());
hmap2.visit(
new HeaderMap.HeaderMapVisitor() {
@Override
public void apply(String str, String prefix, String suffix) {
assertEquals(prefix + suffix, hmap1.lookup(str));
}
});
}
@Test
public void testAddLookup() {
int n = 11;
HeaderMap.Builder builder = HeaderMap.builder();
for (int i = 0; i < n; i++) {
assertTrue(builder.add("foo" + i, "", "value of foo" + i));
}
assertFalse(builder.add("foo1", "", "another value for foo1??"));
HeaderMap hmap = builder.build();
for (int i = 0; i < n; i++) {
assertEquals("value of foo" + i, hmap.lookup("foo" + i));
}
for (int i = 0; i < n; i++) {
assertEquals("value of foo" + i, hmap.lookup("FOO" + i));
}
assertEquals(null, hmap.lookup("BAR"));
assertEquals(n, hmap.getNumEntries());
assertEquals("value of foo10".length(), hmap.getMaxValueLength());
assertThatHeaderMapsAreEqual(hmap, hmap);
}
@Test
public void testAddAndToString() {
HeaderMap.Builder builder = HeaderMap.builder();
assertTrue(builder.add("foo", "value of ", "foo"));
assertTrue(builder.add("bar", "value of ", "bar"));
HeaderMap hmap = builder.build();
assertEquals(
"\"foo\" -> \"value of foo\"\n" +
"\"bar\" -> \"value of bar\"\n",
hmap.toString());
}
// sample hmap generated by xcode on a toy project
final int[] testData = {
0x686d6170, 0x00000001, 0x00000318, 0x00000003, 0x00000040, 0x0000004b,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x0000004b, 0x00000013, 0x0000004b, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000060, 0x00000013, 0x00000060,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000013, 0x00000001,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x69755100, 0x7070417a, 0x656c6544, 0x65746167, 0x2f00682e, 0x72657355,
0x616d2f73, 0x65696874, 0x75616275, 0x2f746564, 0x75636f44, 0x746e656d,
0x63582f73, 0x5065646f, 0x656a6f72, 0x2f737463, 0x7a697551, 0x6975512f,
0x51002f7a, 0x567a6975, 0x43776569, 0x72746e6f, 0x656c6c6f, 0x00682e72,
0x7a697551, 0x6572502d, 0x2e786966, 0x00686370
};
private byte[] getDataBytes(int[] data){
byte[] bytes = new byte[data.length * 4];
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
for (int i = 0; i < data.length; i++) {
buffer.putInt(data[i]);
}
return bytes;
}
@Test
public void testReadFromXcodeData() {
byte[] bytes = getDataBytes(testData);
// the original file was 904 bytes long and started with "pamh" = 70 61 6d 68
assertEquals(904, bytes.length);
assertEquals(0x70, bytes[0]);
assertEquals(0x61, bytes[1]);
assertEquals(0x6d, bytes[2]);
assertEquals(0x68, bytes[3]);
HeaderMap hmap = HeaderMap.deserialize(bytes);
assertNotNull(hmap);
assertEquals(testData[3], hmap.getNumEntries());
assertEquals(testData[4], hmap.getNumBuckets());
assertEquals(testData[5], hmap.getMaxValueLength());
assertEquals(
"\"QuizViewController.h\" -> " +
"\"/Users/mathieubaudet/Documents/XcodeProjects/Quiz/Quiz/QuizViewController.h\"\n" +
"\"Quiz-Prefix.pch\" -> " +
"\"/Users/mathieubaudet/Documents/XcodeProjects/Quiz/Quiz/Quiz-Prefix.pch\"\n" +
"\"QuizAppDelegate.h\" -> " +
"\"/Users/mathieubaudet/Documents/XcodeProjects/Quiz/Quiz/QuizAppDelegate.h\"\n",
hmap.toString());
assertEquals(hmap.lookup("QuizViewController.h").length(), hmap.getMaxValueLength());
}
@Test
public void testReserializeFromXcodeData() {
byte[] bytes = getDataBytes(testData);
HeaderMap hmap = HeaderMap.deserialize(bytes);
assertNotNull(hmap);
byte[] bytes1 = hmap.getBytes();
HeaderMap hmap1 = HeaderMap.deserialize(bytes1);
assertNotNull(hmap1);
// Note: The ordering and number of buckets does not change when reserializing maps as we do.
assertArrayEquals(bytes1, hmap1.getBytes());
assertThatHeaderMapsAreEqual(hmap, hmap1);
}
@Test
public void testReserializeVeryLongTable() {
int n = 1001;
HeaderMap.Builder builder = HeaderMap.builder();
for (int i = 0; i < n; i++) {
assertTrue(builder.add("foo" + i, "value of foo", (new Integer(i)).toString()));
}
HeaderMap hmap = builder.build();
assertEquals(n, hmap.getNumEntries());
assertEquals(2048, hmap.getNumBuckets());
assertEquals("value of foo1000".length(), hmap.getMaxValueLength());
byte[] bytes = hmap.getBytes();
HeaderMap hmap1 = HeaderMap.deserialize(bytes);
assertNotNull(hmap1);
assertThatHeaderMapsAreEqual(hmap, hmap1);
assertArrayEquals(bytes, hmap1.getBytes());
}
private void assertThatSplitPathWorksOnPath(Path path) {
String[] result = HeaderMap.Builder.splitPath(path);
assertNotNull(result);
assertEquals(2, result.length);
assertNotNull(result[0]);
assertNotNull(result[1]);
assertEquals(path.toString(), result[0] + result[1]);
}
@Test
public void splitPathIsCorrect() {
assertThatSplitPathWorksOnPath(Paths.get(""));
assertThatSplitPathWorksOnPath(Paths.get("."));
assertThatSplitPathWorksOnPath(Paths.get("/"));
assertThatSplitPathWorksOnPath(Paths.get("./"));
assertThatSplitPathWorksOnPath(Paths.get("../."));
assertThatSplitPathWorksOnPath(Paths.get("./.."));
assertThatSplitPathWorksOnPath(Paths.get("/asdf/fdgh"));
assertThatSplitPathWorksOnPath(Paths.get("asdf/fdgh"));
assertThatSplitPathWorksOnPath(Paths.get("asdf/fdgh/dsfg"));
}
@Test
public void addPathWorks() {
int n = 11;
HeaderMap.Builder builder = HeaderMap.builder();
for (int i = 0; i < n; i++) {
assertTrue(builder.add("foo" + i, Paths.get("bar", "file" + i)));
}
HeaderMap hmap = builder.build();
for (int i = 0; i < n; i++) {
assertEquals("bar/file" + i, hmap.lookup("foo" + i));
}
}
@Test
public void loadFactorDoesNotExceedLimit() {
{
int n = 384; // 384 / 512 = 0.750, ok
HeaderMap.Builder builder = HeaderMap.builder();
for (int i = 0; i < n; i++) {
assertTrue(builder.add("foo" + i, "value of foo", (new Integer(i)).toString()));
}
HeaderMap hmap = builder.build();
assertEquals(n, hmap.getNumEntries());
assertEquals(512, hmap.getNumBuckets());
}
{
int n = 385; // 385 / 512 = 0.752, should expand
HeaderMap.Builder builder = HeaderMap.builder();
for (int i = 0; i < n; i++) {
assertTrue(builder.add("foo" + i, "value of foo", (new Integer(i)).toString()));
}
HeaderMap hmap = builder.build();
assertEquals(n, hmap.getNumEntries());
assertEquals(1024, hmap.getNumBuckets());
}
}
}