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 | |
14 | using namespace clang::tooling::dependencies; |
15 | |
16 | namespace { |
17 | struct 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 | |
44 | TEST(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 | |
67 | TEST(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 | |
105 | TEST(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 | |
157 | TEST(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 | |