blob: 57b51c219e89a5b5c9e15405b87457cfd2d6691e [file] [log] [blame]
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +00001//===- unittests/Lex/HeaderMapTest.cpp - HeaderMap tests ----------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===--------------------------------------------------------------===//
9
Duncan P. N. Exon Smith08fd70f2016-02-20 22:53:22 +000010#include "clang/Basic/CharInfo.h"
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +000011#include "clang/Lex/HeaderMap.h"
12#include "clang/Lex/HeaderMapTypes.h"
Duncan P. N. Exon Smith08fd70f2016-02-20 22:53:22 +000013#include "llvm/ADT/SmallString.h"
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +000014#include "llvm/Support/SwapByteOrder.h"
15#include "gtest/gtest.h"
Duncan P. N. Exon Smith08fd70f2016-02-20 22:53:22 +000016#include <cassert>
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +000017
18using namespace clang;
19using namespace llvm;
20
21namespace {
22
23// Lay out a header file for testing.
24template <unsigned NumBuckets, unsigned NumBytes> struct MapFile {
25 HMapHeader Header;
26 HMapBucket Buckets[NumBuckets];
27 unsigned char Bytes[NumBytes];
28
29 void init() {
30 memset(this, 0, sizeof(MapFile));
31 Header.Magic = HMAP_HeaderMagicNumber;
32 Header.Version = HMAP_HeaderVersion;
33 Header.NumBuckets = NumBuckets;
34 Header.StringsOffset = sizeof(Header) + sizeof(Buckets);
35 }
36
37 void swapBytes() {
38 using llvm::sys::getSwappedBytes;
39 Header.Magic = getSwappedBytes(Header.Magic);
40 Header.Version = getSwappedBytes(Header.Version);
41 Header.NumBuckets = getSwappedBytes(Header.NumBuckets);
42 Header.StringsOffset = getSwappedBytes(Header.StringsOffset);
43 }
44
45 std::unique_ptr<const MemoryBuffer> getBuffer() const {
46 return MemoryBuffer::getMemBuffer(
47 StringRef(reinterpret_cast<const char *>(this), sizeof(MapFile)),
48 "header",
49 /* RequresNullTerminator */ false);
50 }
51};
52
Duncan P. N. Exon Smith08fd70f2016-02-20 22:53:22 +000053// The header map hash function.
54static inline unsigned getHash(StringRef Str) {
55 unsigned Result = 0;
56 for (char C : Str)
57 Result += toLowercase(C) * 13;
58 return Result;
59}
60
61template <class FileTy> struct FileMaker {
62 FileTy &File;
63 unsigned SI = 1;
64 unsigned BI = 0;
65 FileMaker(FileTy &File) : File(File) {}
66
67 unsigned addString(StringRef S) {
68 assert(SI + S.size() + 1 <= sizeof(File.Bytes));
69 std::copy(S.begin(), S.end(), File.Bytes + SI);
70 auto OldSI = SI;
71 SI += S.size() + 1;
72 return OldSI;
73 }
74 void addBucket(unsigned Hash, unsigned Key, unsigned Prefix, unsigned Suffix) {
75 assert(!(File.Header.NumBuckets & (File.Header.NumBuckets - 1)));
76 unsigned I = Hash & (File.Header.NumBuckets - 1);
77 do {
78 if (!File.Buckets[I].Key) {
79 File.Buckets[I].Key = Key;
80 File.Buckets[I].Prefix = Prefix;
81 File.Buckets[I].Suffix = Suffix;
82 ++File.Header.NumEntries;
83 return;
84 }
85 ++I;
86 I &= File.Header.NumBuckets - 1;
87 } while (I != (Hash & (File.Header.NumBuckets - 1)));
88 llvm_unreachable("no empty buckets");
89 }
90};
91
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +000092TEST(HeaderMapTest, checkHeaderEmpty) {
93 bool NeedsSwap;
94 ASSERT_FALSE(HeaderMapImpl::checkHeader(
95 *MemoryBuffer::getMemBufferCopy("", "empty"), NeedsSwap));
96 ASSERT_FALSE(HeaderMapImpl::checkHeader(
97 *MemoryBuffer::getMemBufferCopy("", "empty"), NeedsSwap));
98}
99
100TEST(HeaderMapTest, checkHeaderMagic) {
101 MapFile<1, 1> File;
102 File.init();
103 File.Header.Magic = 0;
104 bool NeedsSwap;
105 ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
106}
107
108TEST(HeaderMapTest, checkHeaderReserved) {
109 MapFile<1, 1> File;
110 File.init();
111 File.Header.Reserved = 1;
112 bool NeedsSwap;
113 ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
114}
115
116TEST(HeaderMapTest, checkHeaderVersion) {
117 MapFile<1, 1> File;
118 File.init();
119 ++File.Header.Version;
120 bool NeedsSwap;
121 ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
122}
123
124TEST(HeaderMapTest, checkHeaderValidButEmpty) {
125 MapFile<1, 1> File;
126 File.init();
127 bool NeedsSwap;
128 ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
129 ASSERT_FALSE(NeedsSwap);
130
131 File.swapBytes();
132 ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
133 ASSERT_TRUE(NeedsSwap);
134}
135
Duncan P. N. Exon Smithdfe85302016-02-20 21:00:58 +0000136TEST(HeaderMapTest, checkHeader3Buckets) {
137 MapFile<3, 1> File;
138 ASSERT_EQ(3 * sizeof(HMapBucket), sizeof(File.Buckets));
139
140 File.init();
141 bool NeedsSwap;
142 ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
143}
144
Duncan P. N. Exon Smith8d6a31c022016-02-20 21:24:31 +0000145TEST(HeaderMapTest, checkHeaderNotEnoughBuckets) {
146 MapFile<1, 1> File;
147 File.init();
148 File.Header.NumBuckets = 8;
149 bool NeedsSwap;
150 ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
151}
152
Duncan P. N. Exon Smith08fd70f2016-02-20 22:53:22 +0000153TEST(HeaderMapTest, lookupFilename) {
154 typedef MapFile<2, 7> FileTy;
155 FileTy File;
156 File.init();
157
158 FileMaker<FileTy> Maker(File);
159 auto a = Maker.addString("a");
160 auto b = Maker.addString("b");
161 auto c = Maker.addString("c");
162 Maker.addBucket(getHash("a"), a, b, c);
163
164 bool NeedsSwap;
165 ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
166 ASSERT_FALSE(NeedsSwap);
167 HeaderMapImpl Map(File.getBuffer(), NeedsSwap);
168
169 SmallString<8> DestPath;
170 ASSERT_EQ("bc", Map.lookupFilename("a", DestPath));
171}
172
Duncan P. N. Exon Smith9ab99ee2016-02-20 20:39:51 +0000173} // end namespace