91 lines · cpp
1#include "support/Cancellation.h"2#include "support/Context.h"3#include "support/Threading.h"4#include "gmock/gmock.h"5#include "gtest/gtest.h"6#include <atomic>7#include <memory>8#include <optional>9#include <thread>10 11namespace clang {12namespace clangd {13namespace {14 15TEST(CancellationTest, CancellationTest) {16 auto Task = cancelableTask();17 WithContext ContextWithCancellation(std::move(Task.first));18 EXPECT_FALSE(isCancelled());19 Task.second();20 EXPECT_TRUE(isCancelled());21}22 23TEST(CancellationTest, CancelerDiesContextLives) {24 std::optional<WithContext> ContextWithCancellation;25 {26 auto Task = cancelableTask();27 ContextWithCancellation.emplace(std::move(Task.first));28 EXPECT_FALSE(isCancelled());29 Task.second();30 EXPECT_TRUE(isCancelled());31 }32 EXPECT_TRUE(isCancelled());33}34 35TEST(CancellationTest, TaskContextDiesHandleLives) {36 auto Task = cancelableTask();37 {38 WithContext ContextWithCancellation(std::move(Task.first));39 EXPECT_FALSE(isCancelled());40 Task.second();41 EXPECT_TRUE(isCancelled());42 }43 // Still should be able to cancel without any problems.44 Task.second();45}46 47struct NestedTasks {48 enum { OuterReason = 1, InnerReason = 2 };49 std::pair<Context, Canceler> Outer, Inner;50 NestedTasks() {51 Outer = cancelableTask(OuterReason);52 {53 WithContext WithOuter(Outer.first.clone());54 Inner = cancelableTask(InnerReason);55 }56 }57};58 59TEST(CancellationTest, Nested) {60 // Cancelling inner task works but leaves outer task unaffected.61 NestedTasks CancelInner;62 CancelInner.Inner.second();63 EXPECT_EQ(NestedTasks::InnerReason, isCancelled(CancelInner.Inner.first));64 EXPECT_FALSE(isCancelled(CancelInner.Outer.first));65 // Cancellation of outer task is inherited by inner task.66 NestedTasks CancelOuter;67 CancelOuter.Outer.second();68 EXPECT_EQ(NestedTasks::OuterReason, isCancelled(CancelOuter.Inner.first));69 EXPECT_EQ(NestedTasks::OuterReason, isCancelled(CancelOuter.Outer.first));70}71 72TEST(CancellationTest, AsynCancellationTest) {73 std::atomic<bool> HasCancelled(false);74 Notification Cancelled;75 auto TaskToBeCancelled = [&](Context Ctx) {76 WithContext ContextGuard(std::move(Ctx));77 Cancelled.wait();78 HasCancelled = isCancelled();79 };80 auto Task = cancelableTask();81 std::thread AsyncTask(TaskToBeCancelled, std::move(Task.first));82 Task.second();83 Cancelled.notify();84 AsyncTask.join();85 86 EXPECT_TRUE(HasCancelled);87}88} // namespace89} // namespace clangd90} // namespace clang91