1 //===-- DiagnosticEventTest.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 "gtest/gtest.h"
10 
11 #include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
12 #include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h"
13 #include "TestingSupport/SubsystemRAII.h"
14 #include "lldb/Core/Debugger.h"
15 #include "lldb/Core/DebuggerEvents.h"
16 #include "lldb/Host/FileSystem.h"
17 #include "lldb/Host/HostInfo.h"
18 #include "lldb/Utility/Broadcaster.h"
19 #include "lldb/Utility/Event.h"
20 #include "lldb/Utility/Listener.h"
21 #include "lldb/Utility/Reproducer.h"
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 using namespace lldb_private::repro;
26 
27 static const constexpr std::chrono::seconds TIMEOUT(0);
28 static const constexpr size_t DEBUGGERS = 3;
29 
30 static std::once_flag debugger_initialize_flag;
31 
32 namespace {
33 class DiagnosticEventTest : public ::testing::Test {
34 public:
SetUp()35   void SetUp() override {
36     llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
37     FileSystem::Initialize();
38     HostInfo::Initialize();
39     PlatformMacOSX::Initialize();
40     std::call_once(debugger_initialize_flag,
41                    []() { Debugger::Initialize(nullptr); });
42     ArchSpec arch("x86_64-apple-macosx-");
43     Platform::SetHostPlatform(
44         PlatformRemoteMacOSX::CreateInstance(true, &arch));
45   }
TearDown()46   void TearDown() override {
47     PlatformMacOSX::Terminate();
48     HostInfo::Terminate();
49     FileSystem::Terminate();
50     Reproducer::Terminate();
51   }
52 };
53 } // namespace
54 
TEST_F(DiagnosticEventTest,Warning)55 TEST_F(DiagnosticEventTest, Warning) {
56   DebuggerSP debugger_sp = Debugger::CreateInstance();
57 
58   Broadcaster &broadcaster = debugger_sp->GetBroadcaster();
59   ListenerSP listener_sp = Listener::MakeListener("test-listener");
60 
61   listener_sp->StartListeningForEvents(&broadcaster,
62                                        Debugger::eBroadcastBitWarning);
63   EXPECT_TRUE(
64       broadcaster.EventTypeHasListeners(Debugger::eBroadcastBitWarning));
65 
66   Debugger::ReportWarning("foo", debugger_sp->GetID());
67 
68   EventSP event_sp;
69   EXPECT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));
70   ASSERT_TRUE(event_sp);
71 
72   const DiagnosticEventData *data =
73       DiagnosticEventData::GetEventDataFromEvent(event_sp.get());
74   ASSERT_NE(data, nullptr);
75   EXPECT_EQ(data->GetPrefix(), "warning");
76   EXPECT_EQ(data->GetMessage(), "foo");
77 
78   Debugger::Destroy(debugger_sp);
79 }
80 
TEST_F(DiagnosticEventTest,Error)81 TEST_F(DiagnosticEventTest, Error) {
82   DebuggerSP debugger_sp = Debugger::CreateInstance();
83 
84   Broadcaster &broadcaster = debugger_sp->GetBroadcaster();
85   ListenerSP listener_sp = Listener::MakeListener("test-listener");
86 
87   listener_sp->StartListeningForEvents(&broadcaster,
88                                        Debugger::eBroadcastBitError);
89   EXPECT_TRUE(broadcaster.EventTypeHasListeners(Debugger::eBroadcastBitError));
90 
91   Debugger::ReportError("bar", debugger_sp->GetID());
92 
93   EventSP event_sp;
94   EXPECT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));
95   ASSERT_TRUE(event_sp);
96 
97   const DiagnosticEventData *data =
98       DiagnosticEventData::GetEventDataFromEvent(event_sp.get());
99   ASSERT_NE(data, nullptr);
100   EXPECT_EQ(data->GetPrefix(), "error");
101   EXPECT_EQ(data->GetMessage(), "bar");
102 
103   Debugger::Destroy(debugger_sp);
104 }
105 
TEST_F(DiagnosticEventTest,MultipleDebuggers)106 TEST_F(DiagnosticEventTest, MultipleDebuggers) {
107   std::vector<DebuggerSP> debuggers;
108   std::vector<ListenerSP> listeners;
109 
110   for (size_t i = 0; i < DEBUGGERS; ++i) {
111     DebuggerSP debugger = Debugger::CreateInstance();
112     ListenerSP listener = Listener::MakeListener("listener");
113 
114     debuggers.push_back(debugger);
115     listeners.push_back(listener);
116 
117     listener->StartListeningForEvents(&debugger->GetBroadcaster(),
118                                       Debugger::eBroadcastBitError);
119   }
120 
121   Debugger::ReportError("baz");
122 
123   for (size_t i = 0; i < DEBUGGERS; ++i) {
124     EventSP event_sp;
125     EXPECT_TRUE(listeners[i]->GetEvent(event_sp, TIMEOUT));
126     ASSERT_TRUE(event_sp);
127 
128     const DiagnosticEventData *data =
129         DiagnosticEventData::GetEventDataFromEvent(event_sp.get());
130     ASSERT_NE(data, nullptr);
131     EXPECT_EQ(data->GetPrefix(), "error");
132     EXPECT_EQ(data->GetMessage(), "baz");
133   }
134 
135   for (size_t i = 0; i < DEBUGGERS; ++i) {
136     Debugger::Destroy(debuggers[i]);
137   }
138 }
139 
TEST_F(DiagnosticEventTest,WarningOnce)140 TEST_F(DiagnosticEventTest, WarningOnce) {
141   DebuggerSP debugger_sp = Debugger::CreateInstance();
142 
143   Broadcaster &broadcaster = debugger_sp->GetBroadcaster();
144   ListenerSP listener_sp = Listener::MakeListener("test-listener");
145 
146   listener_sp->StartListeningForEvents(&broadcaster,
147                                        Debugger::eBroadcastBitWarning);
148   EXPECT_TRUE(
149       broadcaster.EventTypeHasListeners(Debugger::eBroadcastBitWarning));
150 
151   std::once_flag once;
152   Debugger::ReportWarning("foo", debugger_sp->GetID(), &once);
153 
154   {
155     EventSP event_sp;
156     EXPECT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));
157     ASSERT_TRUE(event_sp);
158 
159     const DiagnosticEventData *data =
160         DiagnosticEventData::GetEventDataFromEvent(event_sp.get());
161     ASSERT_NE(data, nullptr);
162     EXPECT_EQ(data->GetPrefix(), "warning");
163     EXPECT_EQ(data->GetMessage(), "foo");
164   }
165 
166   EventSP second_event_sp;
167   EXPECT_FALSE(listener_sp->GetEvent(second_event_sp, TIMEOUT));
168 
169   Debugger::ReportWarning("foo", debugger_sp->GetID(), &once);
170   EXPECT_FALSE(listener_sp->GetEvent(second_event_sp, TIMEOUT));
171 
172   Debugger::ReportWarning("foo", debugger_sp->GetID());
173   EXPECT_TRUE(listener_sp->GetEvent(second_event_sp, TIMEOUT));
174 
175   Debugger::Destroy(debugger_sp);
176 }
177