Report warnings and errors through events instead of printing directly the to the debugger's error stream. By using events, IDEs such as Xcode can report these issues in the UI instead of having them show up in the debugger console. The new diagnostic events are handled by the default event loop. If a diagnostic is reported while nobody is listening for the new event types, it is printed directly to the debugger's error stream. Differential revision: https://reviews.llvm.org/D121511
177 lines
5.5 KiB
C++
177 lines
5.5 KiB
C++
//===-- DiagnosticEventTest.cpp -------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
|
|
#include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h"
|
|
#include "TestingSupport/SubsystemRAII.h"
|
|
#include "lldb/Core/Debugger.h"
|
|
#include "lldb/Core/DebuggerEvents.h"
|
|
#include "lldb/Host/FileSystem.h"
|
|
#include "lldb/Host/HostInfo.h"
|
|
#include "lldb/Utility/Broadcaster.h"
|
|
#include "lldb/Utility/Event.h"
|
|
#include "lldb/Utility/Listener.h"
|
|
#include "lldb/Utility/Reproducer.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::repro;
|
|
|
|
static const constexpr std::chrono::seconds TIMEOUT(0);
|
|
static const constexpr size_t DEBUGGERS = 3;
|
|
|
|
static std::once_flag debugger_initialize_flag;
|
|
|
|
namespace {
|
|
class DiagnosticEventTest : public ::testing::Test {
|
|
public:
|
|
void SetUp() override {
|
|
llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
|
|
FileSystem::Initialize();
|
|
HostInfo::Initialize();
|
|
PlatformMacOSX::Initialize();
|
|
std::call_once(debugger_initialize_flag,
|
|
[]() { Debugger::Initialize(nullptr); });
|
|
ArchSpec arch("x86_64-apple-macosx-");
|
|
Platform::SetHostPlatform(
|
|
PlatformRemoteMacOSX::CreateInstance(true, &arch));
|
|
}
|
|
void TearDown() override {
|
|
PlatformMacOSX::Terminate();
|
|
HostInfo::Terminate();
|
|
FileSystem::Terminate();
|
|
Reproducer::Terminate();
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
TEST_F(DiagnosticEventTest, Warning) {
|
|
DebuggerSP debugger_sp = Debugger::CreateInstance();
|
|
|
|
Broadcaster &broadcaster = debugger_sp->GetBroadcaster();
|
|
ListenerSP listener_sp = Listener::MakeListener("test-listener");
|
|
|
|
listener_sp->StartListeningForEvents(&broadcaster,
|
|
Debugger::eBroadcastBitWarning);
|
|
EXPECT_TRUE(
|
|
broadcaster.EventTypeHasListeners(Debugger::eBroadcastBitWarning));
|
|
|
|
Debugger::ReportWarning("foo", debugger_sp->GetID());
|
|
|
|
EventSP event_sp;
|
|
EXPECT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));
|
|
ASSERT_TRUE(event_sp);
|
|
|
|
const DiagnosticEventData *data =
|
|
DiagnosticEventData::GetEventDataFromEvent(event_sp.get());
|
|
ASSERT_NE(data, nullptr);
|
|
EXPECT_EQ(data->GetPrefix(), "warning");
|
|
EXPECT_EQ(data->GetMessage(), "foo");
|
|
|
|
Debugger::Destroy(debugger_sp);
|
|
}
|
|
|
|
TEST_F(DiagnosticEventTest, Error) {
|
|
DebuggerSP debugger_sp = Debugger::CreateInstance();
|
|
|
|
Broadcaster &broadcaster = debugger_sp->GetBroadcaster();
|
|
ListenerSP listener_sp = Listener::MakeListener("test-listener");
|
|
|
|
listener_sp->StartListeningForEvents(&broadcaster,
|
|
Debugger::eBroadcastBitError);
|
|
EXPECT_TRUE(broadcaster.EventTypeHasListeners(Debugger::eBroadcastBitError));
|
|
|
|
Debugger::ReportError("bar", debugger_sp->GetID());
|
|
|
|
EventSP event_sp;
|
|
EXPECT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));
|
|
ASSERT_TRUE(event_sp);
|
|
|
|
const DiagnosticEventData *data =
|
|
DiagnosticEventData::GetEventDataFromEvent(event_sp.get());
|
|
ASSERT_NE(data, nullptr);
|
|
EXPECT_EQ(data->GetPrefix(), "error");
|
|
EXPECT_EQ(data->GetMessage(), "bar");
|
|
|
|
Debugger::Destroy(debugger_sp);
|
|
}
|
|
|
|
TEST_F(DiagnosticEventTest, MultipleDebuggers) {
|
|
std::vector<DebuggerSP> debuggers;
|
|
std::vector<ListenerSP> listeners;
|
|
|
|
for (size_t i = 0; i < DEBUGGERS; ++i) {
|
|
DebuggerSP debugger = Debugger::CreateInstance();
|
|
ListenerSP listener = Listener::MakeListener("listener");
|
|
|
|
debuggers.push_back(debugger);
|
|
listeners.push_back(listener);
|
|
|
|
listener->StartListeningForEvents(&debugger->GetBroadcaster(),
|
|
Debugger::eBroadcastBitError);
|
|
}
|
|
|
|
Debugger::ReportError("baz");
|
|
|
|
for (size_t i = 0; i < DEBUGGERS; ++i) {
|
|
EventSP event_sp;
|
|
EXPECT_TRUE(listeners[i]->GetEvent(event_sp, TIMEOUT));
|
|
ASSERT_TRUE(event_sp);
|
|
|
|
const DiagnosticEventData *data =
|
|
DiagnosticEventData::GetEventDataFromEvent(event_sp.get());
|
|
ASSERT_NE(data, nullptr);
|
|
EXPECT_EQ(data->GetPrefix(), "error");
|
|
EXPECT_EQ(data->GetMessage(), "baz");
|
|
}
|
|
|
|
for (size_t i = 0; i < DEBUGGERS; ++i) {
|
|
Debugger::Destroy(debuggers[i]);
|
|
}
|
|
}
|
|
|
|
TEST_F(DiagnosticEventTest, WarningOnce) {
|
|
DebuggerSP debugger_sp = Debugger::CreateInstance();
|
|
|
|
Broadcaster &broadcaster = debugger_sp->GetBroadcaster();
|
|
ListenerSP listener_sp = Listener::MakeListener("test-listener");
|
|
|
|
listener_sp->StartListeningForEvents(&broadcaster,
|
|
Debugger::eBroadcastBitWarning);
|
|
EXPECT_TRUE(
|
|
broadcaster.EventTypeHasListeners(Debugger::eBroadcastBitWarning));
|
|
|
|
std::once_flag once;
|
|
Debugger::ReportWarning("foo", debugger_sp->GetID(), &once);
|
|
|
|
{
|
|
EventSP event_sp;
|
|
EXPECT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));
|
|
ASSERT_TRUE(event_sp);
|
|
|
|
const DiagnosticEventData *data =
|
|
DiagnosticEventData::GetEventDataFromEvent(event_sp.get());
|
|
ASSERT_NE(data, nullptr);
|
|
EXPECT_EQ(data->GetPrefix(), "warning");
|
|
EXPECT_EQ(data->GetMessage(), "foo");
|
|
}
|
|
|
|
EventSP second_event_sp;
|
|
EXPECT_FALSE(listener_sp->GetEvent(second_event_sp, TIMEOUT));
|
|
|
|
Debugger::ReportWarning("foo", debugger_sp->GetID(), &once);
|
|
EXPECT_FALSE(listener_sp->GetEvent(second_event_sp, TIMEOUT));
|
|
|
|
Debugger::ReportWarning("foo", debugger_sp->GetID());
|
|
EXPECT_TRUE(listener_sp->GetEvent(second_event_sp, TIMEOUT));
|
|
|
|
Debugger::Destroy(debugger_sp);
|
|
}
|