1 //===-- DiagnosticManagerTest.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 "lldb/Expression/DiagnosticManager.h" 10 #include "gtest/gtest.h" 11 12 using namespace lldb_private; 13 14 static const uint32_t custom_diag_id = 42; 15 16 namespace { 17 class FixItDiag : public Diagnostic { 18 bool m_has_fixits; 19 20 public: 21 FixItDiag(llvm::StringRef msg, bool has_fixits) 22 : Diagnostic(DiagnosticOrigin::eDiagnosticOriginLLDB, custom_diag_id, 23 DiagnosticDetail{{}, lldb::eSeverityError, msg.str(), {}}), 24 m_has_fixits(has_fixits) {} 25 bool HasFixIts() const override { return m_has_fixits; } 26 }; 27 } // namespace 28 29 namespace { 30 class TextDiag : public Diagnostic { 31 public: 32 TextDiag(llvm::StringRef msg, lldb::Severity severity) 33 : Diagnostic(DiagnosticOrigin::eDiagnosticOriginLLDB, custom_diag_id, 34 DiagnosticDetail{{}, severity, msg.str(), msg.str()}) {} 35 }; 36 } // namespace 37 38 TEST(DiagnosticManagerTest, AddDiagnostic) { 39 DiagnosticManager mgr; 40 EXPECT_EQ(0U, mgr.Diagnostics().size()); 41 42 std::string msg = "foo bar has happened"; 43 lldb::Severity severity = lldb::eSeverityError; 44 DiagnosticOrigin origin = DiagnosticOrigin::eDiagnosticOriginLLDB; 45 auto diag = std::make_unique<Diagnostic>( 46 origin, custom_diag_id, DiagnosticDetail{{}, severity, msg, {}}); 47 mgr.AddDiagnostic(std::move(diag)); 48 EXPECT_EQ(1U, mgr.Diagnostics().size()); 49 const Diagnostic *got = mgr.Diagnostics().front().get(); 50 EXPECT_EQ(DiagnosticOrigin::eDiagnosticOriginLLDB, got->getKind()); 51 EXPECT_EQ(msg, got->GetMessage()); 52 EXPECT_EQ(severity, got->GetSeverity()); 53 EXPECT_EQ(custom_diag_id, got->GetCompilerID()); 54 EXPECT_EQ(false, got->HasFixIts()); 55 } 56 57 TEST(DiagnosticManagerTest, HasFixits) { 58 DiagnosticManager mgr; 59 // By default we shouldn't have any fixits. 60 EXPECT_FALSE(mgr.HasFixIts()); 61 // Adding a diag without fixits shouldn't make HasFixIts return true. 62 mgr.AddDiagnostic(std::make_unique<FixItDiag>("no fixit", false)); 63 EXPECT_FALSE(mgr.HasFixIts()); 64 // Adding a diag with fixits will mark the manager as containing fixits. 65 mgr.AddDiagnostic(std::make_unique<FixItDiag>("fixit", true)); 66 EXPECT_TRUE(mgr.HasFixIts()); 67 // Adding another diag without fixit shouldn't make it return false. 68 mgr.AddDiagnostic(std::make_unique<FixItDiag>("no fixit", false)); 69 EXPECT_TRUE(mgr.HasFixIts()); 70 // Adding a diag with fixits. The manager should still return true. 71 mgr.AddDiagnostic(std::make_unique<FixItDiag>("fixit", true)); 72 EXPECT_TRUE(mgr.HasFixIts()); 73 } 74 75 static std::string toString(DiagnosticManager &mgr) { 76 // The error code doesn't really matter since we just convert the 77 // diagnostics to a string. 78 auto result = lldb::eExpressionCompleted; 79 return llvm::toString(mgr.GetAsError(result)); 80 } 81 82 TEST(DiagnosticManagerTest, GetStringNoDiags) { 83 DiagnosticManager mgr; 84 EXPECT_EQ("", toString(mgr)); 85 std::unique_ptr<Diagnostic> empty; 86 mgr.AddDiagnostic(std::move(empty)); 87 EXPECT_EQ("", toString(mgr)); 88 } 89 90 TEST(DiagnosticManagerTest, GetStringBasic) { 91 DiagnosticManager mgr; 92 mgr.AddDiagnostic(std::make_unique<TextDiag>("abc", lldb::eSeverityError)); 93 EXPECT_EQ("error: abc\n", toString(mgr)); 94 } 95 96 TEST(DiagnosticManagerTest, GetStringMultiline) { 97 DiagnosticManager mgr; 98 99 // Multiline diagnostics should only get one severity label. 100 mgr.AddDiagnostic(std::make_unique<TextDiag>("b\nc", lldb::eSeverityError)); 101 EXPECT_EQ("error: b\nc\n", toString(mgr)); 102 } 103 104 TEST(DiagnosticManagerTest, GetStringMultipleDiags) { 105 DiagnosticManager mgr; 106 mgr.AddDiagnostic(std::make_unique<TextDiag>("abc", lldb::eSeverityError)); 107 EXPECT_EQ("error: abc\n", toString(mgr)); 108 mgr.AddDiagnostic(std::make_unique<TextDiag>("def", lldb::eSeverityError)); 109 EXPECT_EQ("error: abc\nerror: def\n", toString(mgr)); 110 } 111 112 TEST(DiagnosticManagerTest, GetStringSeverityLabels) { 113 DiagnosticManager mgr; 114 115 // Different severities should cause different labels. 116 mgr.AddDiagnostic(std::make_unique<TextDiag>("foo", lldb::eSeverityError)); 117 mgr.AddDiagnostic(std::make_unique<TextDiag>("bar", lldb::eSeverityWarning)); 118 // Remarks have no labels. 119 mgr.AddDiagnostic(std::make_unique<TextDiag>("baz", lldb::eSeverityInfo)); 120 EXPECT_EQ("error: foo\nwarning: bar\nbaz\n", toString(mgr)); 121 } 122 123 TEST(DiagnosticManagerTest, GetStringPreserveOrder) { 124 DiagnosticManager mgr; 125 126 // Make sure we preserve the diagnostic order and do not sort them in any way. 127 mgr.AddDiagnostic(std::make_unique<TextDiag>("baz", lldb::eSeverityInfo)); 128 mgr.AddDiagnostic(std::make_unique<TextDiag>("bar", lldb::eSeverityWarning)); 129 mgr.AddDiagnostic(std::make_unique<TextDiag>("foo", lldb::eSeverityError)); 130 EXPECT_EQ("baz\nwarning: bar\nerror: foo\n", toString(mgr)); 131 } 132 133 TEST(DiagnosticManagerTest, AppendMessageNoDiag) { 134 DiagnosticManager mgr; 135 136 // FIXME: This *really* should not just fail silently. 137 mgr.AppendMessageToDiagnostic("no diag has been pushed yet"); 138 EXPECT_EQ(0U, mgr.Diagnostics().size()); 139 } 140 141 TEST(DiagnosticManagerTest, AppendMessageAttachToLastDiag) { 142 DiagnosticManager mgr; 143 144 mgr.AddDiagnostic(std::make_unique<TextDiag>("foo", lldb::eSeverityError)); 145 mgr.AddDiagnostic(std::make_unique<TextDiag>("bar", lldb::eSeverityError)); 146 // This should append to 'bar' and not to 'foo'. 147 mgr.AppendMessageToDiagnostic("message text"); 148 149 EXPECT_EQ("error: foo\nerror: bar\nmessage text\n", toString(mgr)); 150 } 151 152 TEST(DiagnosticManagerTest, AppendMessageSubsequentDiags) { 153 DiagnosticManager mgr; 154 155 mgr.AddDiagnostic(std::make_unique<TextDiag>("bar", lldb::eSeverityError)); 156 mgr.AppendMessageToDiagnostic("message text"); 157 // Pushing another diag after the message should work fine. 158 mgr.AddDiagnostic(std::make_unique<TextDiag>("foo", lldb::eSeverityError)); 159 160 EXPECT_EQ("error: bar\nmessage text\nerror: foo\n", toString(mgr)); 161 } 162 163 TEST(DiagnosticManagerTest, PutString) { 164 DiagnosticManager mgr; 165 166 mgr.PutString(lldb::eSeverityError, "foo"); 167 EXPECT_EQ(1U, mgr.Diagnostics().size()); 168 EXPECT_EQ(eDiagnosticOriginLLDB, mgr.Diagnostics().front()->getKind()); 169 EXPECT_EQ("error: foo\n", toString(mgr)); 170 } 171 172 TEST(DiagnosticManagerTest, PutStringMultiple) { 173 DiagnosticManager mgr; 174 175 // Multiple PutString should behave like multiple diagnostics. 176 mgr.PutString(lldb::eSeverityError, "foo"); 177 mgr.PutString(lldb::eSeverityError, "bar"); 178 EXPECT_EQ(2U, mgr.Diagnostics().size()); 179 EXPECT_EQ("error: foo\nerror: bar\n", toString(mgr)); 180 } 181 182 TEST(DiagnosticManagerTest, PutStringSeverities) { 183 DiagnosticManager mgr; 184 185 // Multiple PutString with different severities should behave like we 186 // created multiple diagnostics. 187 mgr.PutString(lldb::eSeverityError, "foo"); 188 mgr.PutString(lldb::eSeverityWarning, "bar"); 189 EXPECT_EQ(2U, mgr.Diagnostics().size()); 190 EXPECT_EQ("error: foo\nwarning: bar\n", toString(mgr)); 191 } 192 193 TEST(DiagnosticManagerTest, FixedExpression) { 194 DiagnosticManager mgr; 195 196 // By default there should be no fixed expression. 197 EXPECT_EQ("", mgr.GetFixedExpression()); 198 199 // Setting the fixed expression should change it. 200 mgr.SetFixedExpression("foo"); 201 EXPECT_EQ("foo", mgr.GetFixedExpression()); 202 203 // Setting the fixed expression again should also change it. 204 mgr.SetFixedExpression("bar"); 205 EXPECT_EQ("bar", mgr.GetFixedExpression()); 206 } 207 208 TEST(DiagnosticManagerTest, StatusConversion) { 209 DiagnosticManager mgr; 210 mgr.AddDiagnostic(std::make_unique<TextDiag>("abc", lldb::eSeverityError)); 211 mgr.AddDiagnostic(std::make_unique<TextDiag>("def", lldb::eSeverityWarning)); 212 Status status = 213 Status::FromError(mgr.GetAsError(lldb::eExpressionParseError)); 214 EXPECT_EQ(std::string("error: abc\nwarning: def\n"), 215 std::string(status.AsCString())); 216 } 217