1 //===-- FileCacheTests.cpp ------------------------------------------------===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "support/FileCache.h"
10 
11 #include "TestFS.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
14 #include <atomic>
15 #include <chrono>
16 
17 namespace clang {
18 namespace clangd {
19 namespace config {
20 namespace {
21 
22 class TestCache : public FileCache {
23   MockFS FS;
24   mutable std::string Value;
25 
26 public:
TestCache()27   TestCache() : FileCache(testPath("foo.cc")) {}
28 
setContents(const char * C)29   void setContents(const char *C) {
30     if (C)
31       FS.Files[testPath("foo.cc")] = C;
32     else
33       FS.Files.erase(testPath("foo.cc"));
34   }
35 
get(std::chrono::steady_clock::time_point FreshTime,bool ExpectParse) const36   std::string get(std::chrono::steady_clock::time_point FreshTime,
37                   bool ExpectParse) const {
38     bool GotParse = false;
39     bool GotRead;
40     std::string Result;
41     read(
42         FS, FreshTime,
43         [&](llvm::Optional<llvm::StringRef> Data) {
44           GotParse = true;
45           Value = Data.getValueOr("").str();
46         },
47         [&]() {
48           GotRead = true;
49           Result = Value;
50         });
51     EXPECT_EQ(GotParse, ExpectParse);
52     EXPECT_TRUE(GotRead);
53     return Result;
54   }
55 };
56 
TEST(FileCacheTest,Invalidation)57 TEST(FileCacheTest, Invalidation) {
58   TestCache C;
59 
60   auto StaleOK = std::chrono::steady_clock::now();
61   auto MustBeFresh = StaleOK + std::chrono::hours(1);
62 
63   C.setContents("a");
64   EXPECT_EQ("a", C.get(StaleOK, /*ExpectParse=*/true)) << "Parsed first time";
65   EXPECT_EQ("a", C.get(StaleOK, /*ExpectParse=*/false)) << "Cached (time)";
66   EXPECT_EQ("a", C.get(MustBeFresh, /*ExpectParse=*/false)) << "Cached (stat)";
67   C.setContents("bb");
68   EXPECT_EQ("a", C.get(StaleOK, /*ExpectParse=*/false)) << "Cached (time)";
69   EXPECT_EQ("bb", C.get(MustBeFresh, /*ExpectParse=*/true)) << "Size changed";
70   EXPECT_EQ("bb", C.get(MustBeFresh, /*ExpectParse=*/true)) << "Cached (stat)";
71   C.setContents(nullptr);
72   EXPECT_EQ("bb", C.get(StaleOK, /*ExpectParse=*/false)) << "Cached (time)";
73   EXPECT_EQ("", C.get(MustBeFresh, /*ExpectParse=*/true)) << "Stat failed";
74   EXPECT_EQ("", C.get(MustBeFresh, /*ExpectParse=*/false)) << "Cached (404)";
75   C.setContents("bb"); // Match the previous stat values!
76   EXPECT_EQ("", C.get(StaleOK, /*ExpectParse=*/false)) << "Cached (time)";
77   EXPECT_EQ("bb", C.get(MustBeFresh, /*ExpectParse=*/true)) << "Size changed";
78 }
79 
80 } // namespace
81 } // namespace config
82 } // namespace clangd
83 } // namespace clang
84