//===-- DiagnosticManagerTest.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 "lldb/Expression/DiagnosticManager.h" #include "gtest/gtest.h" using namespace lldb_private; static const uint32_t custom_diag_id = 42; namespace { class FixItDiag : public Diagnostic { bool m_has_fixits; public: FixItDiag(llvm::StringRef msg, bool has_fixits) : Diagnostic(DiagnosticOrigin::eDiagnosticOriginLLDB, custom_diag_id, DiagnosticDetail{{}, lldb::eSeverityError, msg.str(), {}}), m_has_fixits(has_fixits) {} bool HasFixIts() const override { return m_has_fixits; } }; } // namespace namespace { class TextDiag : public Diagnostic { public: TextDiag(llvm::StringRef msg, lldb::Severity severity) : Diagnostic(DiagnosticOrigin::eDiagnosticOriginLLDB, custom_diag_id, DiagnosticDetail{{}, severity, msg.str(), msg.str()}) {} }; } // namespace TEST(DiagnosticManagerTest, AddDiagnostic) { DiagnosticManager mgr; EXPECT_EQ(0U, mgr.Diagnostics().size()); std::string msg = "foo bar has happened"; lldb::Severity severity = lldb::eSeverityError; DiagnosticOrigin origin = DiagnosticOrigin::eDiagnosticOriginLLDB; auto diag = std::make_unique( origin, custom_diag_id, DiagnosticDetail{{}, severity, msg, {}}); mgr.AddDiagnostic(std::move(diag)); EXPECT_EQ(1U, mgr.Diagnostics().size()); const Diagnostic *got = mgr.Diagnostics().front().get(); EXPECT_EQ(DiagnosticOrigin::eDiagnosticOriginLLDB, got->getKind()); EXPECT_EQ(msg, got->GetMessage()); EXPECT_EQ(severity, got->GetSeverity()); EXPECT_EQ(custom_diag_id, got->GetCompilerID()); EXPECT_EQ(false, got->HasFixIts()); } TEST(DiagnosticManagerTest, HasFixits) { DiagnosticManager mgr; // By default we shouldn't have any fixits. EXPECT_FALSE(mgr.HasFixIts()); // Adding a diag without fixits shouldn't make HasFixIts return true. mgr.AddDiagnostic(std::make_unique("no fixit", false)); EXPECT_FALSE(mgr.HasFixIts()); // Adding a diag with fixits will mark the manager as containing fixits. mgr.AddDiagnostic(std::make_unique("fixit", true)); EXPECT_TRUE(mgr.HasFixIts()); // Adding another diag without fixit shouldn't make it return false. mgr.AddDiagnostic(std::make_unique("no fixit", false)); EXPECT_TRUE(mgr.HasFixIts()); // Adding a diag with fixits. The manager should still return true. mgr.AddDiagnostic(std::make_unique("fixit", true)); EXPECT_TRUE(mgr.HasFixIts()); } static std::string toString(DiagnosticManager &mgr) { // The error code doesn't really matter since we just convert the // diagnostics to a string. auto result = lldb::eExpressionCompleted; return llvm::toString(mgr.GetAsError(result)); } TEST(DiagnosticManagerTest, GetStringNoDiags) { DiagnosticManager mgr; EXPECT_EQ("", toString(mgr)); std::unique_ptr empty; mgr.AddDiagnostic(std::move(empty)); EXPECT_EQ("", toString(mgr)); } TEST(DiagnosticManagerTest, GetStringBasic) { DiagnosticManager mgr; mgr.AddDiagnostic(std::make_unique("abc", lldb::eSeverityError)); EXPECT_EQ("error: abc\n", toString(mgr)); } TEST(DiagnosticManagerTest, GetStringMultiline) { DiagnosticManager mgr; // Multiline diagnostics should only get one severity label. mgr.AddDiagnostic(std::make_unique("b\nc", lldb::eSeverityError)); EXPECT_EQ("error: b\nc\n", toString(mgr)); } TEST(DiagnosticManagerTest, GetStringMultipleDiags) { DiagnosticManager mgr; mgr.AddDiagnostic(std::make_unique("abc", lldb::eSeverityError)); EXPECT_EQ("error: abc\n", toString(mgr)); mgr.AddDiagnostic(std::make_unique("def", lldb::eSeverityError)); EXPECT_EQ("error: abc\nerror: def\n", toString(mgr)); } TEST(DiagnosticManagerTest, GetStringSeverityLabels) { DiagnosticManager mgr; // Different severities should cause different labels. mgr.AddDiagnostic(std::make_unique("foo", lldb::eSeverityError)); mgr.AddDiagnostic(std::make_unique("bar", lldb::eSeverityWarning)); // Remarks have no labels. mgr.AddDiagnostic(std::make_unique("baz", lldb::eSeverityInfo)); EXPECT_EQ("error: foo\nwarning: bar\nbaz\n", toString(mgr)); } TEST(DiagnosticManagerTest, GetStringPreserveOrder) { DiagnosticManager mgr; // Make sure we preserve the diagnostic order and do not sort them in any way. mgr.AddDiagnostic(std::make_unique("baz", lldb::eSeverityInfo)); mgr.AddDiagnostic(std::make_unique("bar", lldb::eSeverityWarning)); mgr.AddDiagnostic(std::make_unique("foo", lldb::eSeverityError)); EXPECT_EQ("baz\nwarning: bar\nerror: foo\n", toString(mgr)); } TEST(DiagnosticManagerTest, AppendMessageNoDiag) { DiagnosticManager mgr; // FIXME: This *really* should not just fail silently. mgr.AppendMessageToDiagnostic("no diag has been pushed yet"); EXPECT_EQ(0U, mgr.Diagnostics().size()); } TEST(DiagnosticManagerTest, AppendMessageAttachToLastDiag) { DiagnosticManager mgr; mgr.AddDiagnostic(std::make_unique("foo", lldb::eSeverityError)); mgr.AddDiagnostic(std::make_unique("bar", lldb::eSeverityError)); // This should append to 'bar' and not to 'foo'. mgr.AppendMessageToDiagnostic("message text"); EXPECT_EQ("error: foo\nerror: bar\nmessage text\n", toString(mgr)); } TEST(DiagnosticManagerTest, AppendMessageSubsequentDiags) { DiagnosticManager mgr; mgr.AddDiagnostic(std::make_unique("bar", lldb::eSeverityError)); mgr.AppendMessageToDiagnostic("message text"); // Pushing another diag after the message should work fine. mgr.AddDiagnostic(std::make_unique("foo", lldb::eSeverityError)); EXPECT_EQ("error: bar\nmessage text\nerror: foo\n", toString(mgr)); } TEST(DiagnosticManagerTest, PutString) { DiagnosticManager mgr; mgr.PutString(lldb::eSeverityError, "foo"); EXPECT_EQ(1U, mgr.Diagnostics().size()); EXPECT_EQ(eDiagnosticOriginLLDB, mgr.Diagnostics().front()->getKind()); EXPECT_EQ("error: foo\n", toString(mgr)); } TEST(DiagnosticManagerTest, PutStringMultiple) { DiagnosticManager mgr; // Multiple PutString should behave like multiple diagnostics. mgr.PutString(lldb::eSeverityError, "foo"); mgr.PutString(lldb::eSeverityError, "bar"); EXPECT_EQ(2U, mgr.Diagnostics().size()); EXPECT_EQ("error: foo\nerror: bar\n", toString(mgr)); } TEST(DiagnosticManagerTest, PutStringSeverities) { DiagnosticManager mgr; // Multiple PutString with different severities should behave like we // created multiple diagnostics. mgr.PutString(lldb::eSeverityError, "foo"); mgr.PutString(lldb::eSeverityWarning, "bar"); EXPECT_EQ(2U, mgr.Diagnostics().size()); EXPECT_EQ("error: foo\nwarning: bar\n", toString(mgr)); } TEST(DiagnosticManagerTest, FixedExpression) { DiagnosticManager mgr; // By default there should be no fixed expression. EXPECT_EQ("", mgr.GetFixedExpression()); // Setting the fixed expression should change it. mgr.SetFixedExpression("foo"); EXPECT_EQ("foo", mgr.GetFixedExpression()); // Setting the fixed expression again should also change it. mgr.SetFixedExpression("bar"); EXPECT_EQ("bar", mgr.GetFixedExpression()); } TEST(DiagnosticManagerTest, StatusConversion) { DiagnosticManager mgr; mgr.AddDiagnostic(std::make_unique("abc", lldb::eSeverityError)); mgr.AddDiagnostic(std::make_unique("def", lldb::eSeverityWarning)); Status status = Status::FromError(mgr.GetAsError(lldb::eExpressionParseError)); EXPECT_EQ(std::string("error: abc\nwarning: def\n"), std::string(status.AsCString())); }