19ab99eecSDuncan P. N. Exon Smith //===- unittests/Lex/HeaderMapTest.cpp - HeaderMap tests ----------===// 29ab99eecSDuncan P. N. Exon Smith // 39ab99eecSDuncan P. N. Exon Smith // The LLVM Compiler Infrastructure 49ab99eecSDuncan P. N. Exon Smith // 59ab99eecSDuncan P. N. Exon Smith // This file is distributed under the University of Illinois Open Source 69ab99eecSDuncan P. N. Exon Smith // License. See LICENSE.TXT for details. 79ab99eecSDuncan P. N. Exon Smith // 89ab99eecSDuncan P. N. Exon Smith //===--------------------------------------------------------------===// 99ab99eecSDuncan P. N. Exon Smith 10*08fd70faSDuncan P. N. Exon Smith #include "clang/Basic/CharInfo.h" 119ab99eecSDuncan P. N. Exon Smith #include "clang/Lex/HeaderMap.h" 129ab99eecSDuncan P. N. Exon Smith #include "clang/Lex/HeaderMapTypes.h" 13*08fd70faSDuncan P. N. Exon Smith #include "llvm/ADT/SmallString.h" 149ab99eecSDuncan P. N. Exon Smith #include "llvm/Support/SwapByteOrder.h" 159ab99eecSDuncan P. N. Exon Smith #include "gtest/gtest.h" 16*08fd70faSDuncan P. N. Exon Smith #include <cassert> 179ab99eecSDuncan P. N. Exon Smith 189ab99eecSDuncan P. N. Exon Smith using namespace clang; 199ab99eecSDuncan P. N. Exon Smith using namespace llvm; 209ab99eecSDuncan P. N. Exon Smith 219ab99eecSDuncan P. N. Exon Smith namespace { 229ab99eecSDuncan P. N. Exon Smith 239ab99eecSDuncan P. N. Exon Smith // Lay out a header file for testing. 249ab99eecSDuncan P. N. Exon Smith template <unsigned NumBuckets, unsigned NumBytes> struct MapFile { 259ab99eecSDuncan P. N. Exon Smith HMapHeader Header; 269ab99eecSDuncan P. N. Exon Smith HMapBucket Buckets[NumBuckets]; 279ab99eecSDuncan P. N. Exon Smith unsigned char Bytes[NumBytes]; 289ab99eecSDuncan P. N. Exon Smith 299ab99eecSDuncan P. N. Exon Smith void init() { 309ab99eecSDuncan P. N. Exon Smith memset(this, 0, sizeof(MapFile)); 319ab99eecSDuncan P. N. Exon Smith Header.Magic = HMAP_HeaderMagicNumber; 329ab99eecSDuncan P. N. Exon Smith Header.Version = HMAP_HeaderVersion; 339ab99eecSDuncan P. N. Exon Smith Header.NumBuckets = NumBuckets; 349ab99eecSDuncan P. N. Exon Smith Header.StringsOffset = sizeof(Header) + sizeof(Buckets); 359ab99eecSDuncan P. N. Exon Smith } 369ab99eecSDuncan P. N. Exon Smith 379ab99eecSDuncan P. N. Exon Smith void swapBytes() { 389ab99eecSDuncan P. N. Exon Smith using llvm::sys::getSwappedBytes; 399ab99eecSDuncan P. N. Exon Smith Header.Magic = getSwappedBytes(Header.Magic); 409ab99eecSDuncan P. N. Exon Smith Header.Version = getSwappedBytes(Header.Version); 419ab99eecSDuncan P. N. Exon Smith Header.NumBuckets = getSwappedBytes(Header.NumBuckets); 429ab99eecSDuncan P. N. Exon Smith Header.StringsOffset = getSwappedBytes(Header.StringsOffset); 439ab99eecSDuncan P. N. Exon Smith } 449ab99eecSDuncan P. N. Exon Smith 459ab99eecSDuncan P. N. Exon Smith std::unique_ptr<const MemoryBuffer> getBuffer() const { 469ab99eecSDuncan P. N. Exon Smith return MemoryBuffer::getMemBuffer( 479ab99eecSDuncan P. N. Exon Smith StringRef(reinterpret_cast<const char *>(this), sizeof(MapFile)), 489ab99eecSDuncan P. N. Exon Smith "header", 499ab99eecSDuncan P. N. Exon Smith /* RequresNullTerminator */ false); 509ab99eecSDuncan P. N. Exon Smith } 519ab99eecSDuncan P. N. Exon Smith }; 529ab99eecSDuncan P. N. Exon Smith 53*08fd70faSDuncan P. N. Exon Smith // The header map hash function. 54*08fd70faSDuncan P. N. Exon Smith static inline unsigned getHash(StringRef Str) { 55*08fd70faSDuncan P. N. Exon Smith unsigned Result = 0; 56*08fd70faSDuncan P. N. Exon Smith for (char C : Str) 57*08fd70faSDuncan P. N. Exon Smith Result += toLowercase(C) * 13; 58*08fd70faSDuncan P. N. Exon Smith return Result; 59*08fd70faSDuncan P. N. Exon Smith } 60*08fd70faSDuncan P. N. Exon Smith 61*08fd70faSDuncan P. N. Exon Smith template <class FileTy> struct FileMaker { 62*08fd70faSDuncan P. N. Exon Smith FileTy &File; 63*08fd70faSDuncan P. N. Exon Smith unsigned SI = 1; 64*08fd70faSDuncan P. N. Exon Smith unsigned BI = 0; 65*08fd70faSDuncan P. N. Exon Smith FileMaker(FileTy &File) : File(File) {} 66*08fd70faSDuncan P. N. Exon Smith 67*08fd70faSDuncan P. N. Exon Smith unsigned addString(StringRef S) { 68*08fd70faSDuncan P. N. Exon Smith assert(SI + S.size() + 1 <= sizeof(File.Bytes)); 69*08fd70faSDuncan P. N. Exon Smith std::copy(S.begin(), S.end(), File.Bytes + SI); 70*08fd70faSDuncan P. N. Exon Smith auto OldSI = SI; 71*08fd70faSDuncan P. N. Exon Smith SI += S.size() + 1; 72*08fd70faSDuncan P. N. Exon Smith return OldSI; 73*08fd70faSDuncan P. N. Exon Smith } 74*08fd70faSDuncan P. N. Exon Smith void addBucket(unsigned Hash, unsigned Key, unsigned Prefix, unsigned Suffix) { 75*08fd70faSDuncan P. N. Exon Smith assert(!(File.Header.NumBuckets & (File.Header.NumBuckets - 1))); 76*08fd70faSDuncan P. N. Exon Smith unsigned I = Hash & (File.Header.NumBuckets - 1); 77*08fd70faSDuncan P. N. Exon Smith do { 78*08fd70faSDuncan P. N. Exon Smith if (!File.Buckets[I].Key) { 79*08fd70faSDuncan P. N. Exon Smith File.Buckets[I].Key = Key; 80*08fd70faSDuncan P. N. Exon Smith File.Buckets[I].Prefix = Prefix; 81*08fd70faSDuncan P. N. Exon Smith File.Buckets[I].Suffix = Suffix; 82*08fd70faSDuncan P. N. Exon Smith ++File.Header.NumEntries; 83*08fd70faSDuncan P. N. Exon Smith return; 84*08fd70faSDuncan P. N. Exon Smith } 85*08fd70faSDuncan P. N. Exon Smith ++I; 86*08fd70faSDuncan P. N. Exon Smith I &= File.Header.NumBuckets - 1; 87*08fd70faSDuncan P. N. Exon Smith } while (I != (Hash & (File.Header.NumBuckets - 1))); 88*08fd70faSDuncan P. N. Exon Smith llvm_unreachable("no empty buckets"); 89*08fd70faSDuncan P. N. Exon Smith } 90*08fd70faSDuncan P. N. Exon Smith }; 91*08fd70faSDuncan P. N. Exon Smith 929ab99eecSDuncan P. N. Exon Smith TEST(HeaderMapTest, checkHeaderEmpty) { 939ab99eecSDuncan P. N. Exon Smith bool NeedsSwap; 949ab99eecSDuncan P. N. Exon Smith ASSERT_FALSE(HeaderMapImpl::checkHeader( 959ab99eecSDuncan P. N. Exon Smith *MemoryBuffer::getMemBufferCopy("", "empty"), NeedsSwap)); 969ab99eecSDuncan P. N. Exon Smith ASSERT_FALSE(HeaderMapImpl::checkHeader( 979ab99eecSDuncan P. N. Exon Smith *MemoryBuffer::getMemBufferCopy("", "empty"), NeedsSwap)); 989ab99eecSDuncan P. N. Exon Smith } 999ab99eecSDuncan P. N. Exon Smith 1009ab99eecSDuncan P. N. Exon Smith TEST(HeaderMapTest, checkHeaderMagic) { 1019ab99eecSDuncan P. N. Exon Smith MapFile<1, 1> File; 1029ab99eecSDuncan P. N. Exon Smith File.init(); 1039ab99eecSDuncan P. N. Exon Smith File.Header.Magic = 0; 1049ab99eecSDuncan P. N. Exon Smith bool NeedsSwap; 1059ab99eecSDuncan P. N. Exon Smith ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap)); 1069ab99eecSDuncan P. N. Exon Smith } 1079ab99eecSDuncan P. N. Exon Smith 1089ab99eecSDuncan P. N. Exon Smith TEST(HeaderMapTest, checkHeaderReserved) { 1099ab99eecSDuncan P. N. Exon Smith MapFile<1, 1> File; 1109ab99eecSDuncan P. N. Exon Smith File.init(); 1119ab99eecSDuncan P. N. Exon Smith File.Header.Reserved = 1; 1129ab99eecSDuncan P. N. Exon Smith bool NeedsSwap; 1139ab99eecSDuncan P. N. Exon Smith ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap)); 1149ab99eecSDuncan P. N. Exon Smith } 1159ab99eecSDuncan P. N. Exon Smith 1169ab99eecSDuncan P. N. Exon Smith TEST(HeaderMapTest, checkHeaderVersion) { 1179ab99eecSDuncan P. N. Exon Smith MapFile<1, 1> File; 1189ab99eecSDuncan P. N. Exon Smith File.init(); 1199ab99eecSDuncan P. N. Exon Smith ++File.Header.Version; 1209ab99eecSDuncan P. N. Exon Smith bool NeedsSwap; 1219ab99eecSDuncan P. N. Exon Smith ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap)); 1229ab99eecSDuncan P. N. Exon Smith } 1239ab99eecSDuncan P. N. Exon Smith 1249ab99eecSDuncan P. N. Exon Smith TEST(HeaderMapTest, checkHeaderValidButEmpty) { 1259ab99eecSDuncan P. N. Exon Smith MapFile<1, 1> File; 1269ab99eecSDuncan P. N. Exon Smith File.init(); 1279ab99eecSDuncan P. N. Exon Smith bool NeedsSwap; 1289ab99eecSDuncan P. N. Exon Smith ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap)); 1299ab99eecSDuncan P. N. Exon Smith ASSERT_FALSE(NeedsSwap); 1309ab99eecSDuncan P. N. Exon Smith 1319ab99eecSDuncan P. N. Exon Smith File.swapBytes(); 1329ab99eecSDuncan P. N. Exon Smith ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap)); 1339ab99eecSDuncan P. N. Exon Smith ASSERT_TRUE(NeedsSwap); 1349ab99eecSDuncan P. N. Exon Smith } 1359ab99eecSDuncan P. N. Exon Smith 136dfe85305SDuncan P. N. Exon Smith TEST(HeaderMapTest, checkHeader3Buckets) { 137dfe85305SDuncan P. N. Exon Smith MapFile<3, 1> File; 138dfe85305SDuncan P. N. Exon Smith ASSERT_EQ(3 * sizeof(HMapBucket), sizeof(File.Buckets)); 139dfe85305SDuncan P. N. Exon Smith 140dfe85305SDuncan P. N. Exon Smith File.init(); 141dfe85305SDuncan P. N. Exon Smith bool NeedsSwap; 142dfe85305SDuncan P. N. Exon Smith ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap)); 143dfe85305SDuncan P. N. Exon Smith } 144dfe85305SDuncan P. N. Exon Smith 1458d6a31c0SDuncan P. N. Exon Smith TEST(HeaderMapTest, checkHeaderNotEnoughBuckets) { 1468d6a31c0SDuncan P. N. Exon Smith MapFile<1, 1> File; 1478d6a31c0SDuncan P. N. Exon Smith File.init(); 1488d6a31c0SDuncan P. N. Exon Smith File.Header.NumBuckets = 8; 1498d6a31c0SDuncan P. N. Exon Smith bool NeedsSwap; 1508d6a31c0SDuncan P. N. Exon Smith ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap)); 1518d6a31c0SDuncan P. N. Exon Smith } 1528d6a31c0SDuncan P. N. Exon Smith 153*08fd70faSDuncan P. N. Exon Smith TEST(HeaderMapTest, lookupFilename) { 154*08fd70faSDuncan P. N. Exon Smith typedef MapFile<2, 7> FileTy; 155*08fd70faSDuncan P. N. Exon Smith FileTy File; 156*08fd70faSDuncan P. N. Exon Smith File.init(); 157*08fd70faSDuncan P. N. Exon Smith 158*08fd70faSDuncan P. N. Exon Smith FileMaker<FileTy> Maker(File); 159*08fd70faSDuncan P. N. Exon Smith auto a = Maker.addString("a"); 160*08fd70faSDuncan P. N. Exon Smith auto b = Maker.addString("b"); 161*08fd70faSDuncan P. N. Exon Smith auto c = Maker.addString("c"); 162*08fd70faSDuncan P. N. Exon Smith Maker.addBucket(getHash("a"), a, b, c); 163*08fd70faSDuncan P. N. Exon Smith 164*08fd70faSDuncan P. N. Exon Smith bool NeedsSwap; 165*08fd70faSDuncan P. N. Exon Smith ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap)); 166*08fd70faSDuncan P. N. Exon Smith ASSERT_FALSE(NeedsSwap); 167*08fd70faSDuncan P. N. Exon Smith HeaderMapImpl Map(File.getBuffer(), NeedsSwap); 168*08fd70faSDuncan P. N. Exon Smith 169*08fd70faSDuncan P. N. Exon Smith SmallString<8> DestPath; 170*08fd70faSDuncan P. N. Exon Smith ASSERT_EQ("bc", Map.lookupFilename("a", DestPath)); 171*08fd70faSDuncan P. N. Exon Smith } 172*08fd70faSDuncan P. N. Exon Smith 1739ab99eecSDuncan P. N. Exon Smith } // end namespace 174