Duncan P. N. Exon Smith | 9ab99ee | 2016-02-20 20:39:51 +0000 | [diff] [blame] | 1 | //===- 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 Smith | 08fd70f | 2016-02-20 22:53:22 +0000 | [diff] [blame^] | 10 | #include "clang/Basic/CharInfo.h" |
Duncan P. N. Exon Smith | 9ab99ee | 2016-02-20 20:39:51 +0000 | [diff] [blame] | 11 | #include "clang/Lex/HeaderMap.h" |
| 12 | #include "clang/Lex/HeaderMapTypes.h" |
Duncan P. N. Exon Smith | 08fd70f | 2016-02-20 22:53:22 +0000 | [diff] [blame^] | 13 | #include "llvm/ADT/SmallString.h" |
Duncan P. N. Exon Smith | 9ab99ee | 2016-02-20 20:39:51 +0000 | [diff] [blame] | 14 | #include "llvm/Support/SwapByteOrder.h" |
| 15 | #include "gtest/gtest.h" |
Duncan P. N. Exon Smith | 08fd70f | 2016-02-20 22:53:22 +0000 | [diff] [blame^] | 16 | #include <cassert> |
Duncan P. N. Exon Smith | 9ab99ee | 2016-02-20 20:39:51 +0000 | [diff] [blame] | 17 | |
| 18 | using namespace clang; |
| 19 | using namespace llvm; |
| 20 | |
| 21 | namespace { |
| 22 | |
| 23 | // Lay out a header file for testing. |
| 24 | template <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 Smith | 08fd70f | 2016-02-20 22:53:22 +0000 | [diff] [blame^] | 53 | // The header map hash function. |
| 54 | static inline unsigned getHash(StringRef Str) { |
| 55 | unsigned Result = 0; |
| 56 | for (char C : Str) |
| 57 | Result += toLowercase(C) * 13; |
| 58 | return Result; |
| 59 | } |
| 60 | |
| 61 | template <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 Smith | 9ab99ee | 2016-02-20 20:39:51 +0000 | [diff] [blame] | 92 | TEST(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 | |
| 100 | TEST(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 | |
| 108 | TEST(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 | |
| 116 | TEST(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 | |
| 124 | TEST(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 Smith | dfe8530 | 2016-02-20 21:00:58 +0000 | [diff] [blame] | 136 | TEST(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 Smith | 8d6a31c02 | 2016-02-20 21:24:31 +0000 | [diff] [blame] | 145 | TEST(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 Smith | 08fd70f | 2016-02-20 22:53:22 +0000 | [diff] [blame^] | 153 | TEST(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 Smith | 9ab99ee | 2016-02-20 20:39:51 +0000 | [diff] [blame] | 173 | } // end namespace |