420 lines · cpp
1//===- SpecialCaseListTest.cpp - Unit tests for SpecialCaseList -----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Support/SpecialCaseList.h"10#include "llvm/Support/FileSystem.h"11#include "llvm/Support/MemoryBuffer.h"12#include "llvm/Support/VirtualFileSystem.h"13#include "gmock/gmock.h"14#include "gtest/gtest.h"15 16using testing::HasSubstr;17using testing::Pair;18using testing::StartsWith;19using namespace llvm;20 21namespace {22 23class SpecialCaseListTest : public ::testing::Test {24protected:25 std::unique_ptr<SpecialCaseList>26 makeSpecialCaseList(StringRef List, std::string &Error, int Version = 0) {27 auto S = List.str();28 if (Version)29 S = (Twine("#!special-case-list-v") + Twine(Version) + "\n" + S).str();30 std::unique_ptr<MemoryBuffer> MB = MemoryBuffer::getMemBuffer(S);31 return SpecialCaseList::create(MB.get(), Error);32 }33 34 std::unique_ptr<SpecialCaseList> makeSpecialCaseList(StringRef List,35 int Version = 0) {36 std::string Error;37 auto SCL = makeSpecialCaseList(List, Error, Version);38 assert(SCL);39 assert(Error == "");40 return SCL;41 }42 43 std::string makeSpecialCaseListFile(StringRef Contents, int Version = 0) {44 int FD;45 SmallString<64> Path;46 sys::fs::createTemporaryFile("SpecialCaseListTest", "temp", FD, Path);47 raw_fd_ostream OF(FD, true, true);48 if (Version)49 OF << "#!special-case-list-v" << Version << "\n";50 OF << Contents;51 OF.close();52 return std::string(Path.str());53 }54};55 56TEST_F(SpecialCaseListTest, Basic) {57 std::unique_ptr<SpecialCaseList> SCL =58 makeSpecialCaseList("# This is a comment.\n"59 "\n"60 "src:hello\n"61 "src:bye\n"62 "src:hi=category\n"63 "src:z*=category\n");64 EXPECT_TRUE(SCL->inSection("", "src", "hello"));65 EXPECT_TRUE(SCL->inSection("", "src", "bye"));66 EXPECT_TRUE(SCL->inSection("", "src", "hi", "category"));67 EXPECT_TRUE(SCL->inSection("", "src", "zzzz", "category"));68 EXPECT_FALSE(SCL->inSection("", "src", "hi"));69 EXPECT_FALSE(SCL->inSection("", "fun", "hello"));70 EXPECT_FALSE(SCL->inSection("", "src", "hello", "category"));71 72 EXPECT_THAT(SCL->inSectionBlame("", "src", "hello"), Pair(0u, 3u));73 EXPECT_THAT(SCL->inSectionBlame("", "src", "bye"), Pair(0u, 4u));74 EXPECT_THAT(SCL->inSectionBlame("", "src", "hi", "category"), Pair(0u, 5u));75 EXPECT_THAT(SCL->inSectionBlame("", "src", "zzzz", "category"), Pair(0u, 6u));76 EXPECT_THAT(SCL->inSectionBlame("", "src", "hi"), Pair(0u, 0u));77 EXPECT_THAT(SCL->inSectionBlame("", "fun", "hello"), Pair(0u, 0u));78 EXPECT_THAT(SCL->inSectionBlame("", "src", "hello", "category"),79 Pair(0u, 0u));80}81 82TEST_F(SpecialCaseListTest, CorrectErrorLineNumberWithBlankLine) {83 std::string Error;84 EXPECT_EQ(nullptr, makeSpecialCaseList("# This is a comment.\n"85 "\n"86 "[not valid\n",87 Error));88 EXPECT_THAT(Error, StartsWith("malformed section header on line 3:"));89 90 EXPECT_EQ(nullptr, makeSpecialCaseList("\n\n\n"91 "[not valid\n",92 Error));93 EXPECT_THAT(Error, StartsWith("malformed section header on line 4:"));94}95 96TEST_F(SpecialCaseListTest, SectionGlobErrorHandling) {97 std::string Error;98 EXPECT_EQ(makeSpecialCaseList("[address", Error), nullptr);99 EXPECT_THAT(Error, StartsWith("malformed section header "));100 101 EXPECT_EQ(makeSpecialCaseList("[[]", Error), nullptr);102 EXPECT_EQ(103 Error,104 "malformed section at line 1: '[': invalid glob pattern, unmatched '['");105 106 EXPECT_EQ(makeSpecialCaseList("src:=", Error), nullptr);107 EXPECT_THAT(Error, HasSubstr("Supplied glob was blank"));108}109 110TEST_F(SpecialCaseListTest, Section) {111 std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:global\n"112 "[{sect1,sect2}]\n"113 "src:test1\n"114 "[sect3*]\n"115 "src:test2\n");116 EXPECT_TRUE(SCL->inSection("arbitrary", "src", "global"));117 EXPECT_TRUE(SCL->inSection("", "src", "global"));118 EXPECT_TRUE(SCL->inSection("sect1", "src", "test1"));119 EXPECT_FALSE(SCL->inSection("sect1-arbitrary", "src", "test1"));120 EXPECT_FALSE(SCL->inSection("sect", "src", "test1"));121 EXPECT_FALSE(SCL->inSection("sect1", "src", "test2"));122 EXPECT_TRUE(SCL->inSection("sect2", "src", "test1"));123 EXPECT_TRUE(SCL->inSection("sect3", "src", "test2"));124 EXPECT_TRUE(SCL->inSection("sect3-arbitrary", "src", "test2"));125 EXPECT_FALSE(SCL->inSection("", "src", "test1"));126 EXPECT_FALSE(SCL->inSection("", "src", "test2"));127}128 129TEST_F(SpecialCaseListTest, GlobalInit) {130 std::unique_ptr<SpecialCaseList> SCL =131 makeSpecialCaseList("global:foo=init\n");132 EXPECT_FALSE(SCL->inSection("", "global", "foo"));133 EXPECT_FALSE(SCL->inSection("", "global", "bar"));134 EXPECT_TRUE(SCL->inSection("", "global", "foo", "init"));135 EXPECT_FALSE(SCL->inSection("", "global", "bar", "init"));136 137 SCL = makeSpecialCaseList("type:t2=init\n");138 EXPECT_FALSE(SCL->inSection("", "type", "t1"));139 EXPECT_FALSE(SCL->inSection("", "type", "t2"));140 EXPECT_FALSE(SCL->inSection("", "type", "t1", "init"));141 EXPECT_TRUE(SCL->inSection("", "type", "t2", "init"));142 143 SCL = makeSpecialCaseList("src:hello=init\n");144 EXPECT_FALSE(SCL->inSection("", "src", "hello"));145 EXPECT_FALSE(SCL->inSection("", "src", "bye"));146 EXPECT_TRUE(SCL->inSection("", "src", "hello", "init"));147 EXPECT_FALSE(SCL->inSection("", "src", "bye", "init"));148}149 150TEST_F(SpecialCaseListTest, Substring) {151 std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:hello\n"152 "fun:foo\n"153 "global:bar\n");154 EXPECT_FALSE(SCL->inSection("", "src", "othello"));155 EXPECT_FALSE(SCL->inSection("", "fun", "tomfoolery"));156 EXPECT_FALSE(SCL->inSection("", "global", "bartender"));157 158 SCL = makeSpecialCaseList("fun:*foo*\n");159 EXPECT_TRUE(SCL->inSection("", "fun", "tomfoolery"));160 EXPECT_TRUE(SCL->inSection("", "fun", "foobar"));161}162 163TEST_F(SpecialCaseListTest, InvalidSpecialCaseList) {164 std::string Error;165 EXPECT_EQ(nullptr, makeSpecialCaseList("badline", Error));166 EXPECT_EQ("malformed line 1: 'badline'", Error);167 EXPECT_EQ(nullptr, makeSpecialCaseList("src:bad[a-", Error));168 EXPECT_EQ(169 "malformed glob in line 1: 'bad[a-': invalid glob pattern, unmatched '['",170 Error);171 std::vector<std::string> Files(1, "unexisting");172 EXPECT_EQ(nullptr,173 SpecialCaseList::create(Files, *vfs::getRealFileSystem(), Error));174 EXPECT_THAT(Error, StartsWith("can't open file 'unexisting':"));175}176 177TEST_F(SpecialCaseListTest, EmptySpecialCaseList) {178 std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("");179 EXPECT_FALSE(SCL->inSection("", "foo", "bar"));180}181 182TEST_F(SpecialCaseListTest, MultipleExclusions) {183 std::vector<std::string> Files;184 Files.push_back(makeSpecialCaseListFile("src:bar\n"185 "src:*foo*\n"186 "src:ban=init\n"));187 Files.push_back(makeSpecialCaseListFile("src:baz\n"188 "src:*fog*\n"));189 auto SCL = SpecialCaseList::createOrDie(Files, *vfs::getRealFileSystem());190 EXPECT_TRUE(SCL->inSection("", "src", "bar"));191 EXPECT_TRUE(SCL->inSection("", "src", "baz"));192 EXPECT_FALSE(SCL->inSection("", "src", "ban"));193 EXPECT_TRUE(SCL->inSection("", "src", "ban", "init"));194 EXPECT_TRUE(SCL->inSection("", "src", "tomfoolery"));195 EXPECT_TRUE(SCL->inSection("", "src", "tomfoglery"));196 for (auto &Path : Files)197 sys::fs::remove(Path);198}199 200TEST_F(SpecialCaseListTest, NoTrigramsInRules) {201 std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:b?r\n"202 "fun:za*az\n");203 EXPECT_TRUE(SCL->inSection("", "fun", "bar"));204 EXPECT_FALSE(SCL->inSection("", "fun", "baz"));205 EXPECT_TRUE(SCL->inSection("", "fun", "zakaz"));206 EXPECT_FALSE(SCL->inSection("", "fun", "zaraza"));207}208 209TEST_F(SpecialCaseListTest, NoTrigramsInARule) {210 std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*bar*\n"211 "fun:za*az\n");212 EXPECT_TRUE(SCL->inSection("", "fun", "abara"));213 EXPECT_FALSE(SCL->inSection("", "fun", "bor"));214 EXPECT_TRUE(SCL->inSection("", "fun", "zakaz"));215 EXPECT_FALSE(SCL->inSection("", "fun", "zaraza"));216}217 218TEST_F(SpecialCaseListTest, RepetitiveRule) {219 std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*bar*bar*bar*bar*\n"220 "fun:bar*\n");221 EXPECT_TRUE(SCL->inSection("", "fun", "bara"));222 EXPECT_FALSE(SCL->inSection("", "fun", "abara"));223 EXPECT_TRUE(SCL->inSection("", "fun", "barbarbarbar"));224 EXPECT_TRUE(SCL->inSection("", "fun", "abarbarbarbar"));225 EXPECT_FALSE(SCL->inSection("", "fun", "abarbarbar"));226}227 228TEST_F(SpecialCaseListTest, SpecialSymbolRule) {229 std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n");230 EXPECT_TRUE(SCL->inSection("", "src", "c++abi"));231 EXPECT_FALSE(SCL->inSection("", "src", "c\\+\\+abi"));232}233 234TEST_F(SpecialCaseListTest, PopularTrigram) {235 std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*aaaaaa*\n"236 "fun:*aaaaa*\n"237 "fun:*aaaa*\n"238 "fun:*aaa*\n");239 EXPECT_TRUE(SCL->inSection("", "fun", "aaa"));240 EXPECT_TRUE(SCL->inSection("", "fun", "aaaa"));241 EXPECT_TRUE(SCL->inSection("", "fun", "aaaabbbaaa"));242}243 244TEST_F(SpecialCaseListTest, EscapedSymbols) {245 std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n"246 "src:*hello\\\\world*\n");247 EXPECT_TRUE(SCL->inSection("", "src", "dir/c++abi"));248 EXPECT_FALSE(SCL->inSection("", "src", "dir/c\\+\\+abi"));249 EXPECT_FALSE(SCL->inSection("", "src", "c\\+\\+abi"));250 EXPECT_TRUE(SCL->inSection("", "src", "C:\\hello\\world"));251 EXPECT_TRUE(SCL->inSection("", "src", "hello\\world"));252 EXPECT_FALSE(SCL->inSection("", "src", "hello\\\\world"));253}254 255TEST_F(SpecialCaseListTest, Version1) {256 std::unique_ptr<SpecialCaseList> SCL =257 makeSpecialCaseList("[sect1|sect2]\n"258 // Does not match foo!259 "fun:foo.*\n"260 "fun:abc|def\n"261 "fun:b.r\n",262 /*Version=*/1);263 264 EXPECT_TRUE(SCL->inSection("sect1", "fun", "fooz"));265 EXPECT_TRUE(SCL->inSection("sect2", "fun", "fooz"));266 EXPECT_FALSE(SCL->inSection("sect3", "fun", "fooz"));267 268 // `foo.*` does not match `foo` because the pattern is translated to `foo..*`269 EXPECT_FALSE(SCL->inSection("sect1", "fun", "foo"));270 271 EXPECT_TRUE(SCL->inSection("sect1", "fun", "abc"));272 EXPECT_TRUE(SCL->inSection("sect2", "fun", "abc"));273 EXPECT_FALSE(SCL->inSection("sect3", "fun", "abc"));274 275 EXPECT_TRUE(SCL->inSection("sect1", "fun", "def"));276 EXPECT_TRUE(SCL->inSection("sect2", "fun", "def"));277 EXPECT_FALSE(SCL->inSection("sect3", "fun", "def"));278 279 EXPECT_TRUE(SCL->inSection("sect1", "fun", "bar"));280 EXPECT_TRUE(SCL->inSection("sect2", "fun", "bar"));281 EXPECT_FALSE(SCL->inSection("sect3", "fun", "bar"));282}283 284TEST_F(SpecialCaseListTest, Version2) {285 std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("[{sect1,sect2}]\n"286 "fun:foo*\n"287 "fun:{abc,def}\n"288 "fun:b?r\n");289 EXPECT_TRUE(SCL->inSection("sect1", "fun", "fooz"));290 EXPECT_TRUE(SCL->inSection("sect2", "fun", "fooz"));291 EXPECT_FALSE(SCL->inSection("sect3", "fun", "fooz"));292 293 EXPECT_TRUE(SCL->inSection("sect1", "fun", "foo"));294 EXPECT_TRUE(SCL->inSection("sect2", "fun", "foo"));295 EXPECT_FALSE(SCL->inSection("sect3", "fun", "foo"));296 297 EXPECT_TRUE(SCL->inSection("sect1", "fun", "abc"));298 EXPECT_TRUE(SCL->inSection("sect2", "fun", "abc"));299 EXPECT_FALSE(SCL->inSection("sect3", "fun", "abc"));300 301 EXPECT_TRUE(SCL->inSection("sect1", "fun", "def"));302 EXPECT_TRUE(SCL->inSection("sect2", "fun", "def"));303 EXPECT_FALSE(SCL->inSection("sect3", "fun", "def"));304 305 EXPECT_TRUE(SCL->inSection("sect1", "fun", "bar"));306 EXPECT_TRUE(SCL->inSection("sect2", "fun", "bar"));307 EXPECT_FALSE(SCL->inSection("sect3", "fun", "bar"));308}309 310TEST_F(SpecialCaseListTest, DotSlash) {311 StringRef IgnoreList = "[dot]\n"312 "fun:./foo\n"313 "src:./bar\n"314 "[not]\n"315 "fun:foo\n"316 "src:bar\n";317 std::unique_ptr<SpecialCaseList> SCL2 = makeSpecialCaseList(IgnoreList);318 std::unique_ptr<SpecialCaseList> SCL3 =319 makeSpecialCaseList(IgnoreList, /*Version=*/3);320 std::unique_ptr<SpecialCaseList> SCL4 = makeSpecialCaseList(IgnoreList,321 /*Version=*/4);322 323 EXPECT_TRUE(SCL2->inSection("dot", "fun", "./foo"));324 EXPECT_TRUE(SCL3->inSection("dot", "fun", "./foo"));325 EXPECT_TRUE(SCL4->inSection("dot", "fun", "./foo"));326 327 EXPECT_FALSE(SCL2->inSection("dot", "fun", "foo"));328 EXPECT_FALSE(SCL3->inSection("dot", "fun", "foo"));329 EXPECT_FALSE(SCL4->inSection("dot", "fun", "foo"));330 331 EXPECT_TRUE(SCL2->inSection("dot", "src", "./bar"));332 EXPECT_FALSE(SCL3->inSection("dot", "src", "./bar"));333 EXPECT_FALSE(SCL4->inSection("dot", "src", "./bar"));334 335 EXPECT_FALSE(SCL2->inSection("dot", "src", "bar"));336 EXPECT_FALSE(SCL3->inSection("dot", "src", "bar"));337 EXPECT_FALSE(SCL4->inSection("dot", "src", "bar"));338 339 EXPECT_FALSE(SCL2->inSection("not", "fun", "./foo"));340 EXPECT_FALSE(SCL3->inSection("not", "fun", "./foo"));341 EXPECT_FALSE(SCL4->inSection("not", "fun", "./foo"));342 343 EXPECT_TRUE(SCL2->inSection("not", "fun", "foo"));344 EXPECT_TRUE(SCL3->inSection("not", "fun", "foo"));345 EXPECT_TRUE(SCL4->inSection("not", "fun", "foo"));346 347 EXPECT_FALSE(SCL2->inSection("not", "src", "./bar"));348 EXPECT_TRUE(SCL3->inSection("not", "src", "./bar"));349 EXPECT_TRUE(SCL4->inSection("not", "src", "./bar"));350 351 EXPECT_TRUE(SCL2->inSection("not", "src", "bar"));352 EXPECT_TRUE(SCL3->inSection("not", "src", "bar"));353 EXPECT_TRUE(SCL4->inSection("not", "src", "bar"));354}355 356TEST_F(SpecialCaseListTest, LinesInSection) {357 std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:foo\n"358 "fun:bar\n"359 "fun:foo\n");360 EXPECT_THAT(SCL->inSectionBlame("sect1", "fun", "foo"), Pair(0u, 3u));361 EXPECT_THAT(SCL->inSectionBlame("sect1", "fun", "bar"), Pair(0u, 2u));362}363 364TEST_F(SpecialCaseListTest, LinesCrossSection) {365 std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:foo\n"366 "fun:bar\n"367 "fun:foo\n"368 "[sect1]\n"369 "fun:bar\n");370 EXPECT_THAT(SCL->inSectionBlame("sect1", "fun", "foo"), Pair(0u, 3u));371 EXPECT_THAT(SCL->inSectionBlame("sect1", "fun", "bar"), Pair(0u, 5u));372}373 374TEST_F(SpecialCaseListTest, Blame) {375 std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("[sect1]\n"376 "src:foo*\n"377 "[sect1]\n"378 "src:bar*\n"379 "src:def\n"380 "[sect2]\n"381 "src:def\n"382 "src:de*\n");383 EXPECT_TRUE(SCL->inSection("sect1", "src", "fooz"));384 EXPECT_TRUE(SCL->inSection("sect1", "src", "barz"));385 EXPECT_FALSE(SCL->inSection("sect2", "src", "fooz"));386 387 EXPECT_TRUE(SCL->inSection("sect2", "src", "def"));388 EXPECT_TRUE(SCL->inSection("sect1", "src", "def"));389 390 EXPECT_THAT(SCL->inSectionBlame("sect1", "src", "fooz"), Pair(0u, 2u));391 EXPECT_THAT(SCL->inSectionBlame("sect1", "src", "barz"), Pair(0u, 4u));392 EXPECT_THAT(SCL->inSectionBlame("sect1", "src", "def"), Pair(0u, 5u));393 EXPECT_THAT(SCL->inSectionBlame("sect2", "src", "def"), Pair(0u, 8u));394 EXPECT_THAT(SCL->inSectionBlame("sect2", "src", "dez"), Pair(0u, 8u));395}396 397TEST_F(SpecialCaseListTest, FileIdx) {398 std::vector<std::string> Files;399 Files.push_back(makeSpecialCaseListFile("src:bar\n"400 "src:*foo*\n"401 "src:ban=init\n"402 "src:baz\n"403 "src:*def\n"));404 Files.push_back(makeSpecialCaseListFile("src:baz\n"405 "src:car\n"406 "src:def*"));407 auto SCL = SpecialCaseList::createOrDie(Files, *vfs::getRealFileSystem());408 EXPECT_THAT(SCL->inSectionBlame("", "src", "bar"), Pair(0u, 1u));409 EXPECT_THAT(SCL->inSectionBlame("", "src", "fooaaaaaa"), Pair(0u, 2u));410 EXPECT_THAT(SCL->inSectionBlame("", "src", "ban", "init"), Pair(0u, 3u));411 EXPECT_THAT(SCL->inSectionBlame("", "src", "baz"), Pair(1u, 1u));412 EXPECT_THAT(SCL->inSectionBlame("", "src", "car"), Pair(1u, 2u));413 EXPECT_THAT(SCL->inSectionBlame("", "src", "aaaadef"), Pair(0u, 5u));414 EXPECT_THAT(SCL->inSectionBlame("", "src", "defaaaaa"), Pair(1u, 3u));415 for (auto &Path : Files)416 sys::fs::remove(Path);417}418 419} // namespace420