23 #include "clang/Basic/DiagnosticDriver.h"
24 #include "llvm/ADT/ArrayRef.h"
25 #include "llvm/ADT/FunctionExtras.h"
26 #include "llvm/ADT/STLExtras.h"
27 #include "llvm/ADT/ScopeExit.h"
28 #include "llvm/ADT/StringExtras.h"
29 #include "llvm/ADT/StringMap.h"
30 #include "llvm/ADT/StringRef.h"
31 #include "gmock/gmock.h"
32 #include "gtest/gtest.h"
45 using ::testing::AnyOf;
46 using ::testing::Each;
47 using ::testing::ElementsAre;
49 using ::testing::Field;
50 using ::testing::IsEmpty;
51 using ::testing::Pointee;
52 using ::testing::SizeIs;
53 using ::testing::UnorderedElementsAre;
55 MATCHER_P2(TUState, PreambleActivity, ASTActivity,
"") {
56 if (arg.PreambleActivity != PreambleActivity) {
57 *result_listener <<
"preamblestate is "
58 << static_cast<uint8_t>(arg.PreambleActivity);
61 if (arg.ASTActivity.K != ASTActivity) {
62 *result_listener <<
"aststate is " << arg.ASTActivity.K;
69 static Key<std::string> BoundPath;
73 llvm::StringRef boundPath() {
75 return V ? *V : llvm::StringRef(
"");
78 TUScheduler::Options optsForTest() {
80 Opts.ContextProvider = bindPath;
84 class TUSchedulerTests :
public ::testing::Test {
91 Inputs.Opts = ParseOptions();
95 void updateWithCallback(TUScheduler &S,
PathRef File,
97 llvm::unique_function<
void()> CB) {
104 llvm::unique_function<
void()> CB) {
105 WithContextValue
Ctx(llvm::make_scope_exit(std::move(CB)));
109 static Key<llvm::unique_function<void(
PathRef File, std::vector<Diag>)>>
114 static std::unique_ptr<ParsingCallbacks> captureDiags() {
115 class CaptureDiags :
public ParsingCallbacks {
117 void onMainAST(
PathRef File, ParsedAST &
AST, PublishFn Publish)
override {
118 reportDiagnostics(
File,
AST.getDiagnostics(), Publish);
121 void onFailedAST(
PathRef File, llvm::StringRef Version,
122 std::vector<Diag>
Diags, PublishFn Publish)
override {
134 llvm::unique_function<
void(
PathRef, std::vector<Diag>)
> &> (*D)(
139 return std::make_unique<CaptureDiags>();
147 llvm::unique_function<
void(std::vector<Diag>)> CB) {
150 [OrigFile, CB = std::move(CB)](
152 assert(
File == OrigFile);
153 CB(std::move(
Diags));
160 llvm::unique_function<
void(std::vector<Diag>)> CB) {
166 MockCompilationDatabase
CDB;
169 Key<llvm::unique_function<void(
PathRef File, std::vector<Diag>)>>
172 TEST_F(TUSchedulerTests, MissingFiles) {
173 TUScheduler S(
CDB, optsForTest());
186 [&](Expected<InputsAndAST> AST) {
EXPECT_ERROR(AST); });
194 S.runWithAST(
"", Added,
195 [&](Expected<InputsAndAST> AST) { EXPECT_TRUE(
bool(AST)); });
197 [&](Expected<InputsAndPreamble>
Preamble) {
203 S.runWithAST(
"", Added,
204 [&](Expected<InputsAndAST> AST) {
EXPECT_ERROR(AST); });
206 [&](Expected<InputsAndPreamble>
Preamble) {
208 llvm::consumeError(
Preamble.takeError());
215 std::atomic<int> CallbackCount(0);
220 TUScheduler S(
CDB, optsForTest(), captureDiags());
223 [&](std::vector<Diag>) { Ready.wait(); });
225 [&](std::vector<Diag>) { ++CallbackCount; });
227 [&](std::vector<Diag>) {
229 <<
"auto should have been cancelled by auto";
232 [&](std::vector<Diag>) {
233 ADD_FAILURE() <<
"no diags should not be called back";
236 [&](std::vector<Diag>) { ++CallbackCount; });
241 EXPECT_EQ(2, CallbackCount);
244 TEST_F(TUSchedulerTests, Debounce) {
245 std::atomic<int> CallbackCount(0);
247 auto Opts = optsForTest();
249 TUScheduler S(
CDB, Opts, captureDiags());
253 [&](std::vector<Diag>) {
255 <<
"auto should have been debounced and canceled";
257 std::this_thread::sleep_for(std::chrono::milliseconds(200));
259 [&](std::vector<Diag>) { ++CallbackCount; });
260 std::this_thread::sleep_for(std::chrono::seconds(2));
262 [&](std::vector<Diag>) { ++CallbackCount; });
266 EXPECT_EQ(2, CallbackCount);
269 TEST_F(TUSchedulerTests, Cancellation) {
279 std::vector<std::string> DiagsSeen, ReadsSeen, ReadsCanceled;
281 Notification Proceed;
282 TUScheduler S(
CDB, optsForTest(), captureDiags());
285 auto Update = [&](std::string ID) ->
Canceler {
287 WithContext C(std::move(T.first));
290 [&, ID](std::vector<Diag>
Diags) { DiagsSeen.push_back(ID); });
291 return std::move(T.second);
296 WithContext C(std::move(T.first));
297 S.runWithAST(ID,
Path, [&, ID](llvm::Expected<InputsAndAST>
E) {
298 if (
auto Err =
E.takeError()) {
299 if (Err.isA<CancelledError>()) {
300 ReadsCanceled.push_back(ID);
301 consumeError(std::move(Err));
303 ADD_FAILURE() <<
"Non-cancelled error for " << ID <<
": "
307 ReadsSeen.push_back(ID);
310 return std::move(T.second);
314 [&]() { Proceed.wait(); });
327 EXPECT_THAT(DiagsSeen, ElementsAre(
"U2",
"U3"))
328 <<
"U1 and all dependent reads were cancelled. "
329 "U2 has a dependent read R2A. "
330 "U3 was not cancelled.";
331 EXPECT_THAT(ReadsSeen, ElementsAre(
"R2B"))
332 <<
"All reads other than R2B were cancelled";
333 EXPECT_THAT(ReadsCanceled, ElementsAre(
"R1",
"R2A",
"R3"))
334 <<
"All reads other than R2B were cancelled";
337 TEST_F(TUSchedulerTests, InvalidationNoCrash) {
339 TUScheduler S(
CDB, optsForTest(), captureDiags());
341 Notification StartedRunning;
342 Notification ScheduledChange;
348 "invalidatable-but-running",
Path,
349 [&](llvm::Expected<InputsAndAST> AST) {
350 StartedRunning.notify();
351 ScheduledChange.wait();
352 ASSERT_TRUE(
bool(AST));
355 StartedRunning.wait();
357 ScheduledChange.notify();
361 TEST_F(TUSchedulerTests, Invalidation) {
363 TUScheduler S(
CDB, optsForTest(), captureDiags());
364 std::atomic<int> Builds(0), Actions(0);
372 "invalidatable",
Path,
373 [&](llvm::Expected<InputsAndAST> AST) {
375 EXPECT_FALSE(
bool(AST));
377 EXPECT_TRUE(
E.isA<CancelledError>());
378 handleAllErrors(std::move(
E), [&](
const CancelledError &
E) {
384 "not-invalidatable",
Path,
385 [&](llvm::Expected<InputsAndAST> AST) {
387 EXPECT_TRUE(
bool(AST));
392 ADD_FAILURE() <<
"Shouldn't build, all dependents invalidated";
395 "invalidatable",
Path,
396 [&](llvm::Expected<InputsAndAST> AST) {
398 EXPECT_FALSE(
bool(AST));
400 EXPECT_TRUE(
E.isA<CancelledError>());
401 consumeError(std::move(
E));
405 [&](std::vector<Diag>) { ++Builds; });
407 "invalidatable",
Path,
408 [&](llvm::Expected<InputsAndAST> AST) {
410 EXPECT_TRUE(
bool(AST)) <<
"Shouldn't be invalidated, no update follows";
416 EXPECT_EQ(2, Builds.load()) <<
"Middle build should be skipped";
417 EXPECT_EQ(4, Actions.load()) <<
"All actions should run (some with error)";
420 TEST_F(TUSchedulerTests, ManyUpdates) {
421 const int FilesCount = 3;
422 const int UpdatesPerFile = 10;
425 int TotalASTReads = 0;
426 int TotalPreambleReads = 0;
427 int TotalUpdates = 0;
428 llvm::StringMap<int> LatestDiagVersion;
432 auto Opts = optsForTest();
434 TUScheduler S(
CDB, Opts, captureDiags());
436 std::vector<std::string> Files;
437 for (
int I = 0; I < FilesCount; ++I) {
438 std::string
Name =
"foo" + std::to_string(I) +
".cpp";
440 this->
FS.
Files[Files.back()] =
"";
443 StringRef Contents1 = R
"cpp(int a;)cpp";
444 StringRef Contents2 = R"cpp(int main() { return 1; })cpp";
445 StringRef Contents3 = R"cpp(int a; int b; int sum() { return a + b; })cpp";
447 StringRef AllContents[] = {Contents1, Contents2, Contents3};
448 const int AllContentsSize = 3;
452 static Key<int> NonceKey;
455 for (
int FileI = 0; FileI < FilesCount; ++FileI) {
456 for (
int UpdateI = 0; UpdateI < UpdatesPerFile; ++UpdateI) {
457 auto Contents = AllContents[(FileI + UpdateI) % AllContentsSize];
459 auto File = Files[FileI];
462 WithContextValue WithNonce(NonceKey, ++Nonce);
467 &LatestDiagVersion](std::vector<Diag>) {
468 EXPECT_THAT(Context::current().get(NonceKey), Pointee(Nonce));
469 EXPECT_EQ(File, boundPath());
471 std::lock_guard<std::mutex> Lock(Mut);
473 EXPECT_EQ(File, *TUScheduler::getFileBeingProcessedInContext());
475 auto It = LatestDiagVersion.try_emplace(File, -1);
476 const int PrevVersion = It.first->second;
478 ASSERT_TRUE(llvm::to_integer(Version, CurVersion, 10));
479 EXPECT_LT(PrevVersion, CurVersion);
480 It.first->getValue() = CurVersion;
484 WithContextValue WithNonce(NonceKey, ++Nonce);
487 [File,
Inputs, Nonce, &Mut,
488 &TotalASTReads](Expected<InputsAndAST> AST) {
490 EXPECT_EQ(File, boundPath());
492 ASSERT_TRUE((
bool)AST);
497 std::lock_guard<std::mutex> Lock(Mut);
504 WithContextValue WithNonce(NonceKey, ++Nonce);
507 [File,
Inputs, Nonce, &Mut,
508 &TotalPreambleReads](Expected<InputsAndPreamble>
Preamble) {
510 EXPECT_EQ(File, boundPath());
515 std::lock_guard<std::mutex> Lock(Mut);
516 ++TotalPreambleReads;
525 std::lock_guard<std::mutex> Lock(Mut);
528 EXPECT_GE(TotalUpdates, FilesCount);
529 EXPECT_LE(TotalUpdates, FilesCount * UpdatesPerFile);
531 for (
const auto &
Entry : LatestDiagVersion)
532 EXPECT_EQ(
Entry.second, UpdatesPerFile - 1);
533 EXPECT_EQ(TotalASTReads, FilesCount * UpdatesPerFile);
534 EXPECT_EQ(TotalPreambleReads, FilesCount * UpdatesPerFile);
537 TEST_F(TUSchedulerTests, EvictedAST) {
538 std::atomic<int> BuiltASTCounter(0);
539 auto Opts = optsForTest();
540 Opts.AsyncThreadsCount = 1;
541 Opts.RetentionPolicy.MaxRetainedASTs = 2;
543 TUScheduler S(
CDB, Opts);
545 llvm::StringLiteral SourceContents = R
"cpp(
549 llvm::StringLiteral OtherSourceContents = R"cpp(
558 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_diag",
"hit"), SizeIs(0));
559 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_diag",
"miss"), SizeIs(0));
563 [&BuiltASTCounter]() { ++BuiltASTCounter; });
565 ASSERT_EQ(BuiltASTCounter.load(), 1);
566 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_diag",
"hit"), SizeIs(0));
567 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_diag",
"miss"), SizeIs(1));
572 [&BuiltASTCounter]() { ++BuiltASTCounter; });
574 [&BuiltASTCounter]() { ++BuiltASTCounter; });
576 ASSERT_EQ(BuiltASTCounter.load(), 3);
577 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_diag",
"hit"), SizeIs(0));
578 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_diag",
"miss"), SizeIs(2));
581 ASSERT_THAT(S.getFilesWithCachedAST(), UnorderedElementsAre(Bar, Baz));
585 [&BuiltASTCounter]() { ++BuiltASTCounter; });
587 ASSERT_EQ(BuiltASTCounter.load(), 4);
588 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_diag",
"hit"), SizeIs(0));
589 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_diag",
"miss"), SizeIs(1));
593 EXPECT_THAT(S.getFilesWithCachedAST(),
594 UnorderedElementsAre(Foo, AnyOf(Bar, Baz)));
600 TEST_F(TUSchedulerTests, NoopChangesDontThrashCache) {
601 auto Opts = optsForTest();
602 Opts.RetentionPolicy.MaxRetainedASTs = 1;
603 TUScheduler S(
CDB, Opts);
606 auto FooInputs = getInputs(Foo,
"int x=1;");
608 auto BarInputs = getInputs(Bar,
"int x=2;");
615 ASSERT_THAT(S.getFilesWithCachedAST(), ElementsAre(Bar));
622 ASSERT_THAT(S.getFilesWithCachedAST(), ElementsAre(Bar));
624 ASSERT_EQ(S.fileStats().lookup(Foo).ASTBuilds, 1u);
625 ASSERT_EQ(S.fileStats().lookup(Bar).ASTBuilds, 1u);
628 TEST_F(TUSchedulerTests, EmptyPreamble) {
629 TUScheduler S(
CDB, optsForTest());
634 FS.
Files[Header] =
"void foo()";
636 auto WithPreamble = R
"cpp(
640 auto WithEmptyPreamble = R
"cpp(int main() {})cpp";
644 [&](Expected<InputsAndPreamble>
Preamble) {
659 [&](Expected<InputsAndPreamble>
Preamble) {
667 TEST_F(TUSchedulerTests, RunWaitsForPreamble) {
670 TUScheduler S(
CDB, optsForTest());
672 auto NonEmptyPreamble = R
"cpp(
678 constexpr int ReadsToSchedule = 10;
679 std::mutex PreamblesMut;
680 std::vector<const void *> Preambles(ReadsToSchedule,
nullptr);
682 for (
int I = 0; I < ReadsToSchedule; ++I) {
685 [I, &PreamblesMut, &Preambles](Expected<InputsAndPreamble> IP) {
686 std::lock_guard<std::mutex> Lock(PreamblesMut);
687 Preambles[I] = cantFail(std::move(IP)).Preamble;
692 std::lock_guard<std::mutex> Lock(PreamblesMut);
693 ASSERT_NE(Preambles[0],
nullptr);
694 ASSERT_THAT(Preambles, Each(Preambles[0]));
697 TEST_F(TUSchedulerTests, NoopOnEmptyChanges) {
698 TUScheduler S(
CDB, optsForTest(), captureDiags());
706 std::string SourceContents = R
"cpp(
712 auto DoUpdate = [&](std::string
Contents) ->
bool {
713 std::atomic<bool> Updated(
false);
716 [&Updated](std::vector<Diag>) { Updated =
true; });
719 ADD_FAILURE() <<
"Updated has not finished in one second. Threading bug?";
724 ASSERT_TRUE(DoUpdate(SourceContents));
725 ASSERT_EQ(S.fileStats().lookup(Source).ASTBuilds, 1u);
726 ASSERT_EQ(S.fileStats().lookup(Source).PreambleBuilds, 1u);
727 ASSERT_FALSE(DoUpdate(SourceContents));
728 ASSERT_EQ(S.fileStats().lookup(Source).ASTBuilds, 1u);
729 ASSERT_EQ(S.fileStats().lookup(Source).PreambleBuilds, 1u);
733 ASSERT_TRUE(DoUpdate(SourceContents));
734 ASSERT_FALSE(DoUpdate(SourceContents));
735 ASSERT_EQ(S.fileStats().lookup(Source).ASTBuilds, 2u);
736 ASSERT_EQ(S.fileStats().lookup(Source).PreambleBuilds, 2u);
739 SourceContents +=
"\nint c = b;";
740 ASSERT_TRUE(DoUpdate(SourceContents));
741 ASSERT_FALSE(DoUpdate(SourceContents));
742 ASSERT_EQ(S.fileStats().lookup(Source).ASTBuilds, 3u);
743 ASSERT_EQ(S.fileStats().lookup(Source).PreambleBuilds, 2u);
747 ASSERT_TRUE(DoUpdate(SourceContents));
748 ASSERT_FALSE(DoUpdate(SourceContents));
749 ASSERT_EQ(S.fileStats().lookup(Source).ASTBuilds, 4u);
750 ASSERT_EQ(S.fileStats().lookup(Source).PreambleBuilds, 3u);
756 TEST_F(TUSchedulerTests, MissingHeader) {
760 FS.
Files.try_emplace(
"a/__unused__");
761 FS.
Files.try_emplace(
"b/__unused__");
762 TUScheduler S(
CDB, optsForTest(), captureDiags());
768 auto SourceContents = R
"cpp(
773 ParseInputs Inputs = getInputs(Source, SourceContents);
774 std::atomic<size_t> DiagCount(0);
780 [&DiagCount](std::vector<Diag>
Diags) {
785 "use of undeclared identifier 'b'")));
794 [&DiagCount](std::vector<Diag>
Diags) {
796 EXPECT_THAT(
Diags, IsEmpty());
807 [&DiagCount](std::vector<Diag>
Diags) {
810 <<
"Didn't expect new diagnostics when adding a/foo.h";
817 [&DiagCount](std::vector<Diag>
Diags) {
823 EXPECT_EQ(DiagCount, 3U);
826 TEST_F(TUSchedulerTests, NoChangeDiags) {
828 TUScheduler S(
CDB, optsForTest(), captureDiags());
831 const auto *
Contents =
"int a; int b;";
833 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_read",
"hit"), SizeIs(0));
834 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_read",
"miss"), SizeIs(0));
835 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_diag",
"hit"), SizeIs(0));
836 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_diag",
"miss"), SizeIs(0));
839 [](std::vector<Diag>) { ADD_FAILURE() <<
"Should not be called."; });
840 S.runWithAST(
"touchAST", FooCpp, [](Expected<InputsAndAST> IA) {
842 cantFail(std::move(IA));
845 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_read",
"hit"), SizeIs(0));
846 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_read",
"miss"), SizeIs(1));
850 std::atomic<bool> SeenDiags(
false);
852 [&](std::vector<Diag>) { SeenDiags =
true; });
854 ASSERT_TRUE(SeenDiags);
855 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_diag",
"hit"), SizeIs(1));
856 EXPECT_THAT(
Tracer.takeMetric(
"ast_access_diag",
"miss"), SizeIs(0));
862 [&](std::vector<Diag>) { ADD_FAILURE() <<
"Should not be called."; });
866 TEST_F(TUSchedulerTests, Run) {
867 auto Opts = optsForTest();
868 Opts.ContextProvider = bindPath;
869 TUScheduler S(
CDB, Opts);
871 S.run(
"add 1",
"", [&] { ++
Counter; });
872 S.run(
"add 2",
"", [&] {
Counter += 2; });
876 Notification TaskRun;
878 WithContextValue CtxWithKey(TestKey, 10);
879 const char *
Path =
"somepath";
880 S.run(
"props context",
Path, [&] {
882 EXPECT_EQ(
Path, boundPath());
888 TEST_F(TUSchedulerTests, TUStatus) {
889 class CaptureTUStatus :
public ClangdServer::Callbacks {
891 void onFileUpdated(
PathRef File,
const TUStatus &Status)
override {
892 auto ASTAction = Status.ASTActivity.K;
894 std::lock_guard<std::mutex> Lock(Mutex);
901 if (ASTActions.empty() || ASTActions.back() != ASTAction)
902 ASTActions.push_back(ASTAction);
903 if (PreambleActions.empty() || PreambleActions.back() !=
PreambleAction)
907 std::vector<PreambleAction> preambleStatuses() {
908 std::lock_guard<std::mutex> Lock(Mutex);
909 return PreambleActions;
912 std::vector<ASTAction::Kind> astStatuses() {
913 std::lock_guard<std::mutex> Lock(Mutex);
919 std::vector<ASTAction::Kind> ASTActions;
920 std::vector<PreambleAction> PreambleActions;
923 MockCompilationDatabase
CDB;
925 Annotations
Code(
"int m^ain () {}");
929 Server.addDocument(
testPath(
"foo.cpp"),
Code.code(),
"1",
931 ASSERT_TRUE(Server.blockUntilIdleForTest());
932 Server.locateSymbolAt(
testPath(
"foo.cpp"),
Code.point(),
933 [](Expected<std::vector<LocatedSymbol>> Result) {
934 ASSERT_TRUE((
bool)Result);
936 ASSERT_TRUE(Server.blockUntilIdleForTest());
938 EXPECT_THAT(CaptureTUStatus.preambleStatuses(),
949 EXPECT_THAT(CaptureTUStatus.astStatuses(),
965 TEST_F(TUSchedulerTests, CommandLineErrors) {
972 TUScheduler S(
CDB, optsForTest(), captureDiags());
973 std::vector<Diag> Diagnostics;
974 updateWithDiags(S,
testPath(
"foo.cpp"),
"void test() {}",
976 Diagnostics = std::move(D);
989 TEST_F(TUSchedulerTests, CommandLineWarnings) {
996 TUScheduler S(
CDB, optsForTest(), captureDiags());
997 std::vector<Diag> Diagnostics;
998 updateWithDiags(S,
testPath(
"foo.cpp"),
"void test() {}",
1000 Diagnostics = std::move(D);
1005 EXPECT_THAT(Diagnostics, IsEmpty());
1008 TEST(DebouncePolicy, Compute) {
1009 namespace c = std::chrono;
1010 std::vector<DebouncePolicy::clock::duration> History = {
1016 DebouncePolicy Policy;
1017 Policy.Min = c::seconds(3);
1018 Policy.Max = c::seconds(25);
1020 auto Compute = [&](llvm::ArrayRef<DebouncePolicy::clock::duration> History) {
1021 using FloatingSeconds = c::duration<float, c::seconds::period>;
1022 return static_cast<float>(Policy.compute(History) / FloatingSeconds(1));
1024 EXPECT_NEAR(10, Compute(History), 0.01) <<
"(upper) median = 10";
1025 Policy.RebuildRatio = 1.5;
1026 EXPECT_NEAR(15, Compute(History), 0.01) <<
"median = 10, ratio = 1.5";
1027 Policy.RebuildRatio = 3;
1028 EXPECT_NEAR(25, Compute(History), 0.01) <<
"constrained by max";
1029 Policy.RebuildRatio = 0;
1030 EXPECT_NEAR(3, Compute(History), 0.01) <<
"constrained by min";
1031 EXPECT_NEAR(25, Compute({}), 0.01) <<
"no history -> max";
1034 TEST_F(TUSchedulerTests, AsyncPreambleThread) {
1037 class BlockPreambleThread :
public ParsingCallbacks {
1039 BlockPreambleThread(llvm::StringRef BlockVersion, Notification &N)
1040 : BlockVersion(BlockVersion), N(N) {}
1041 void onPreambleAST(
PathRef Path, llvm::StringRef Version, ASTContext &
Ctx,
1042 std::shared_ptr<clang::Preprocessor>
PP,
1043 const CanonicalIncludes &)
override {
1044 if (Version == BlockVersion)
1049 llvm::StringRef BlockVersion;
1053 static constexpr llvm::StringLiteral InputsV0 =
"v0";
1054 static constexpr llvm::StringLiteral InputsV1 =
"v1";
1056 TUScheduler S(
CDB, optsForTest(),
1057 std::make_unique<BlockPreambleThread>(InputsV1, Ready));
1060 auto PI = getInputs(File,
"");
1061 PI.Version = InputsV0.str();
1066 PI.Version = InputsV1.str();
1070 Notification RunASTAction;
1073 S.runWithAST(
"test", File, [&](Expected<InputsAndAST> AST) {
1074 ASSERT_TRUE(
bool(AST));
1078 EXPECT_THAT(AST->Inputs.Version, InputsV1.str());
1079 RunASTAction.notify();
1081 RunASTAction.wait();