1//===- DependencyScanningFilesystemTest.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 "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h"
10#include "llvm/ADT/SmallString.h"
11#include "llvm/Support/VirtualFileSystem.h"
12#include "gtest/gtest.h"
13
14using namespace clang::tooling::dependencies;
15
16namespace {
17struct InstrumentingFilesystem
18 : llvm::RTTIExtends<InstrumentingFilesystem, llvm::vfs::ProxyFileSystem> {
19 unsigned NumStatusCalls = 0;
20 unsigned NumGetRealPathCalls = 0;
21 unsigned NumExistsCalls = 0;
22
23 using llvm::RTTIExtends<InstrumentingFilesystem,
24 llvm::vfs::ProxyFileSystem>::RTTIExtends;
25
26 llvm::ErrorOr<llvm::vfs::Status> status(const llvm::Twine &Path) override {
27 ++NumStatusCalls;
28 return ProxyFileSystem::status(Path);
29 }
30
31 std::error_code getRealPath(const llvm::Twine &Path,
32 llvm::SmallVectorImpl<char> &Output) override {
33 ++NumGetRealPathCalls;
34 return ProxyFileSystem::getRealPath(Path, Output);
35 }
36
37 bool exists(const llvm::Twine &Path) override {
38 ++NumExistsCalls;
39 return ProxyFileSystem::exists(Path);
40 }
41};
42} // namespace
43
44TEST(DependencyScanningWorkerFilesystem, CacheStatusFailures) {
45 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
46
47 auto InstrumentingFS =
48 llvm::makeIntrusiveRefCnt<InstrumentingFilesystem>(A&: InMemoryFS);
49
50 DependencyScanningFilesystemSharedCache SharedCache;
51 DependencyScanningWorkerFilesystem DepFS(SharedCache, InstrumentingFS);
52 DependencyScanningWorkerFilesystem DepFS2(SharedCache, InstrumentingFS);
53
54 DepFS.status(Path: "/foo.c");
55 EXPECT_EQ(InstrumentingFS->NumStatusCalls, 1u);
56
57 DepFS.status(Path: "/foo.c");
58 EXPECT_EQ(InstrumentingFS->NumStatusCalls, 1u); // Cached, no increase.
59
60 DepFS.status(Path: "/bar.c");
61 EXPECT_EQ(InstrumentingFS->NumStatusCalls, 2u);
62
63 DepFS2.status(Path: "/foo.c");
64 EXPECT_EQ(InstrumentingFS->NumStatusCalls, 2u); // Shared cache.
65}
66
67TEST(DependencyScanningFilesystem, CacheGetRealPath) {
68 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
69 InMemoryFS->setCurrentWorkingDirectory("/");
70 InMemoryFS->addFile(Path: "/foo", ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: ""));
71 InMemoryFS->addFile(Path: "/bar", ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: ""));
72
73 auto InstrumentingFS =
74 llvm::makeIntrusiveRefCnt<InstrumentingFilesystem>(A&: InMemoryFS);
75
76 DependencyScanningFilesystemSharedCache SharedCache;
77 DependencyScanningWorkerFilesystem DepFS(SharedCache, InstrumentingFS);
78 DependencyScanningWorkerFilesystem DepFS2(SharedCache, InstrumentingFS);
79
80 {
81 llvm::SmallString<128> Result;
82 DepFS.getRealPath(Path: "/foo", Output&: Result);
83 EXPECT_EQ(InstrumentingFS->NumGetRealPathCalls, 1u);
84 }
85
86 {
87 llvm::SmallString<128> Result;
88 DepFS.getRealPath(Path: "/foo", Output&: Result);
89 EXPECT_EQ(InstrumentingFS->NumGetRealPathCalls, 1u); // Cached, no increase.
90 }
91
92 {
93 llvm::SmallString<128> Result;
94 DepFS.getRealPath(Path: "/bar", Output&: Result);
95 EXPECT_EQ(InstrumentingFS->NumGetRealPathCalls, 2u);
96 }
97
98 {
99 llvm::SmallString<128> Result;
100 DepFS2.getRealPath(Path: "/foo", Output&: Result);
101 EXPECT_EQ(InstrumentingFS->NumGetRealPathCalls, 2u); // Shared cache.
102 }
103}
104
105TEST(DependencyScanningFilesystem, RealPathAndStatusInvariants) {
106 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
107 InMemoryFS->setCurrentWorkingDirectory("/");
108 InMemoryFS->addFile(Path: "/foo.c", ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: ""));
109 InMemoryFS->addFile(Path: "/bar.c", ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: ""));
110
111 DependencyScanningFilesystemSharedCache SharedCache;
112 DependencyScanningWorkerFilesystem DepFS(SharedCache, InMemoryFS);
113
114 // Success.
115 {
116 DepFS.status(Path: "/foo.c");
117
118 llvm::SmallString<128> Result;
119 DepFS.getRealPath(Path: "/foo.c", Output&: Result);
120 }
121 {
122 llvm::SmallString<128> Result;
123 DepFS.getRealPath(Path: "/bar.c", Output&: Result);
124
125 DepFS.status(Path: "/bar.c");
126 }
127
128 // Failure.
129 {
130 DepFS.status(Path: "/foo.m");
131
132 llvm::SmallString<128> Result;
133 DepFS.getRealPath(Path: "/foo.m", Output&: Result);
134 }
135 {
136 llvm::SmallString<128> Result;
137 DepFS.getRealPath(Path: "/bar.m", Output&: Result);
138
139 DepFS.status(Path: "/bar.m");
140 }
141
142 // Failure without caching.
143 {
144 DepFS.status(Path: "/foo");
145
146 llvm::SmallString<128> Result;
147 DepFS.getRealPath(Path: "/foo", Output&: Result);
148 }
149 {
150 llvm::SmallString<128> Result;
151 DepFS.getRealPath(Path: "/bar", Output&: Result);
152
153 DepFS.status(Path: "/bar");
154 }
155}
156
157TEST(DependencyScanningFilesystem, CacheStatOnExists) {
158 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
159 auto InstrumentingFS =
160 llvm::makeIntrusiveRefCnt<InstrumentingFilesystem>(A&: InMemoryFS);
161 InMemoryFS->setCurrentWorkingDirectory("/");
162 InMemoryFS->addFile(Path: "/foo", ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: ""));
163 InMemoryFS->addFile(Path: "/bar", ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: ""));
164 DependencyScanningFilesystemSharedCache SharedCache;
165 DependencyScanningWorkerFilesystem DepFS(SharedCache, InstrumentingFS);
166
167 DepFS.status(Path: "/foo");
168 DepFS.status(Path: "/foo");
169 DepFS.status(Path: "/bar");
170 EXPECT_EQ(InstrumentingFS->NumStatusCalls, 2u);
171
172 DepFS.exists(Path: "/foo");
173 DepFS.exists(Path: "/bar");
174 EXPECT_EQ(InstrumentingFS->NumStatusCalls, 2u);
175 EXPECT_EQ(InstrumentingFS->NumExistsCalls, 0u);
176}
177

source code of clang/unittests/Tooling/DependencyScanning/DependencyScanningFilesystemTest.cpp