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