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 | TEST(DependencyScanningWorkerFilesystem, CacheStatusFailures) { |
17 | auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); |
18 | |
19 | auto InstrumentingFS = |
20 | llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(A&: InMemoryFS); |
21 | |
22 | DependencyScanningFilesystemSharedCache SharedCache; |
23 | DependencyScanningWorkerFilesystem DepFS(SharedCache, InstrumentingFS); |
24 | DependencyScanningWorkerFilesystem DepFS2(SharedCache, InstrumentingFS); |
25 | |
26 | DepFS.status(Path: "/foo.c" ); |
27 | EXPECT_EQ(InstrumentingFS->NumStatusCalls, 1u); |
28 | |
29 | DepFS.status(Path: "/foo.c" ); |
30 | EXPECT_EQ(InstrumentingFS->NumStatusCalls, 1u); // Cached, no increase. |
31 | |
32 | DepFS.status(Path: "/bar.c" ); |
33 | EXPECT_EQ(InstrumentingFS->NumStatusCalls, 2u); |
34 | |
35 | DepFS2.status(Path: "/foo.c" ); |
36 | EXPECT_EQ(InstrumentingFS->NumStatusCalls, 2u); // Shared cache. |
37 | } |
38 | |
39 | TEST(DependencyScanningFilesystem, CacheGetRealPath) { |
40 | auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); |
41 | InMemoryFS->setCurrentWorkingDirectory("/" ); |
42 | InMemoryFS->addFile(Path: "/foo" , ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "" )); |
43 | InMemoryFS->addFile(Path: "/bar" , ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "" )); |
44 | |
45 | auto InstrumentingFS = |
46 | llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(A&: InMemoryFS); |
47 | |
48 | DependencyScanningFilesystemSharedCache SharedCache; |
49 | DependencyScanningWorkerFilesystem DepFS(SharedCache, InstrumentingFS); |
50 | DependencyScanningWorkerFilesystem DepFS2(SharedCache, InstrumentingFS); |
51 | |
52 | { |
53 | llvm::SmallString<128> Result; |
54 | DepFS.getRealPath(Path: "/foo" , Output&: Result); |
55 | EXPECT_EQ(InstrumentingFS->NumGetRealPathCalls, 1u); |
56 | } |
57 | |
58 | { |
59 | llvm::SmallString<128> Result; |
60 | DepFS.getRealPath(Path: "/foo" , Output&: Result); |
61 | EXPECT_EQ(InstrumentingFS->NumGetRealPathCalls, 1u); // Cached, no increase. |
62 | } |
63 | |
64 | { |
65 | llvm::SmallString<128> Result; |
66 | DepFS.getRealPath(Path: "/bar" , Output&: Result); |
67 | EXPECT_EQ(InstrumentingFS->NumGetRealPathCalls, 2u); |
68 | } |
69 | |
70 | { |
71 | llvm::SmallString<128> Result; |
72 | DepFS2.getRealPath(Path: "/foo" , Output&: Result); |
73 | EXPECT_EQ(InstrumentingFS->NumGetRealPathCalls, 2u); // Shared cache. |
74 | } |
75 | } |
76 | |
77 | TEST(DependencyScanningFilesystem, RealPathAndStatusInvariants) { |
78 | auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); |
79 | InMemoryFS->setCurrentWorkingDirectory("/" ); |
80 | InMemoryFS->addFile(Path: "/foo.c" , ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "" )); |
81 | InMemoryFS->addFile(Path: "/bar.c" , ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "" )); |
82 | |
83 | DependencyScanningFilesystemSharedCache SharedCache; |
84 | DependencyScanningWorkerFilesystem DepFS(SharedCache, InMemoryFS); |
85 | |
86 | // Success. |
87 | { |
88 | DepFS.status(Path: "/foo.c" ); |
89 | |
90 | llvm::SmallString<128> Result; |
91 | DepFS.getRealPath(Path: "/foo.c" , Output&: Result); |
92 | } |
93 | { |
94 | llvm::SmallString<128> Result; |
95 | DepFS.getRealPath(Path: "/bar.c" , Output&: Result); |
96 | |
97 | DepFS.status(Path: "/bar.c" ); |
98 | } |
99 | |
100 | // Failure. |
101 | { |
102 | DepFS.status(Path: "/foo.m" ); |
103 | |
104 | llvm::SmallString<128> Result; |
105 | DepFS.getRealPath(Path: "/foo.m" , Output&: Result); |
106 | } |
107 | { |
108 | llvm::SmallString<128> Result; |
109 | DepFS.getRealPath(Path: "/bar.m" , Output&: Result); |
110 | |
111 | DepFS.status(Path: "/bar.m" ); |
112 | } |
113 | |
114 | // Failure without caching. |
115 | { |
116 | DepFS.status(Path: "/foo" ); |
117 | |
118 | llvm::SmallString<128> Result; |
119 | DepFS.getRealPath(Path: "/foo" , Output&: Result); |
120 | } |
121 | { |
122 | llvm::SmallString<128> Result; |
123 | DepFS.getRealPath(Path: "/bar" , Output&: Result); |
124 | |
125 | DepFS.status(Path: "/bar" ); |
126 | } |
127 | } |
128 | |
129 | TEST(DependencyScanningFilesystem, CacheStatOnExists) { |
130 | auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); |
131 | auto InstrumentingFS = |
132 | llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(A&: InMemoryFS); |
133 | InMemoryFS->setCurrentWorkingDirectory("/" ); |
134 | InMemoryFS->addFile(Path: "/foo" , ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "" )); |
135 | InMemoryFS->addFile(Path: "/bar" , ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "" )); |
136 | DependencyScanningFilesystemSharedCache SharedCache; |
137 | DependencyScanningWorkerFilesystem DepFS(SharedCache, InstrumentingFS); |
138 | |
139 | DepFS.status(Path: "/foo" ); |
140 | DepFS.status(Path: "/foo" ); |
141 | DepFS.status(Path: "/bar" ); |
142 | EXPECT_EQ(InstrumentingFS->NumStatusCalls, 2u); |
143 | |
144 | DepFS.exists(Path: "/foo" ); |
145 | DepFS.exists(Path: "/bar" ); |
146 | EXPECT_EQ(InstrumentingFS->NumStatusCalls, 2u); |
147 | EXPECT_EQ(InstrumentingFS->NumExistsCalls, 0u); |
148 | } |
149 | |
150 | TEST(DependencyScanningFilesystem, CacheStatFailures) { |
151 | auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); |
152 | InMemoryFS->setCurrentWorkingDirectory("/" ); |
153 | InMemoryFS->addFile(Path: "/dir/vector" , ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "" )); |
154 | InMemoryFS->addFile(Path: "/cache/a.pcm" , ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "" )); |
155 | |
156 | auto InstrumentingFS = |
157 | llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(A&: InMemoryFS); |
158 | |
159 | DependencyScanningFilesystemSharedCache SharedCache; |
160 | DependencyScanningWorkerFilesystem DepFS(SharedCache, InstrumentingFS); |
161 | |
162 | DepFS.status(Path: "/dir" ); |
163 | DepFS.status(Path: "/dir" ); |
164 | EXPECT_EQ(InstrumentingFS->NumStatusCalls, 1u); |
165 | |
166 | DepFS.status(Path: "/dir/vector" ); |
167 | DepFS.status(Path: "/dir/vector" ); |
168 | EXPECT_EQ(InstrumentingFS->NumStatusCalls, 2u); |
169 | |
170 | DepFS.setBypassedPathPrefix("/cache" ); |
171 | DepFS.exists(Path: "/cache/a.pcm" ); |
172 | EXPECT_EQ(InstrumentingFS->NumStatusCalls, 3u); |
173 | DepFS.exists(Path: "/cache/a.pcm" ); |
174 | EXPECT_EQ(InstrumentingFS->NumStatusCalls, 4u); |
175 | |
176 | DepFS.resetBypassedPathPrefix(); |
177 | DepFS.exists(Path: "/cache/a.pcm" ); |
178 | DepFS.exists(Path: "/cache/a.pcm" ); |
179 | EXPECT_EQ(InstrumentingFS->NumStatusCalls, 5u); |
180 | } |
181 | |
182 | TEST(DependencyScanningFilesystem, DiagnoseStaleStatFailures) { |
183 | auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); |
184 | InMemoryFS->setCurrentWorkingDirectory("/" ); |
185 | |
186 | DependencyScanningFilesystemSharedCache SharedCache; |
187 | DependencyScanningWorkerFilesystem DepFS(SharedCache, InMemoryFS); |
188 | |
189 | bool Path1Exists = DepFS.exists(Path: "/path1.suffix" ); |
190 | EXPECT_EQ(Path1Exists, false); |
191 | |
192 | // Adding a file that has been stat-ed, |
193 | InMemoryFS->addFile(Path: "/path1.suffix" , ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "" )); |
194 | Path1Exists = DepFS.exists(Path: "/path1.suffix" ); |
195 | // Due to caching in SharedCache, path1 should not exist in |
196 | // DepFS's eyes. |
197 | EXPECT_EQ(Path1Exists, false); |
198 | |
199 | std::vector<llvm::StringRef> InvalidPaths = |
200 | SharedCache.getInvalidNegativeStatCachedPaths(UnderlyingFS&: *InMemoryFS); |
201 | |
202 | EXPECT_EQ(InvalidPaths.size(), 1u); |
203 | ASSERT_STREQ("/path1.suffix" , InvalidPaths[0].str().c_str()); |
204 | } |
205 | |