1#include "lldb/Utility/DiagnosticsRendering.h"
2#include "lldb/Utility/StreamString.h"
3#include "gtest/gtest.h"
4
5using namespace lldb_private;
6using namespace lldb;
7using llvm::StringRef;
8namespace {
9class ErrorDisplayTest : public ::testing::Test {};
10
11std::string Render(std::vector<DiagnosticDetail> details) {
12 StreamString stream;
13 RenderDiagnosticDetails(stream, offset_in_command: 0, show_inline: true, details);
14 return stream.GetData();
15}
16} // namespace
17
18TEST_F(ErrorDisplayTest, RenderStatus) {
19 using SourceLocation = DiagnosticDetail::SourceLocation;
20 {
21 SourceLocation inline_loc;
22 inline_loc.in_user_input = true;
23 std::string result =
24 Render(details: {DiagnosticDetail{.source_location: inline_loc, .severity: eSeverityError, .message: "foo", .rendered: ""}});
25 ASSERT_TRUE(StringRef(result).contains("error:"));
26 ASSERT_TRUE(StringRef(result).contains("foo"));
27 }
28
29 {
30 // Test that diagnostics on the same column can be handled and all
31 // three errors are diagnosed.
32 SourceLocation loc1 = {.file: FileSpec{"a.c"}, .line: 13, .column: 5, .length: 0, .hidden: false, .in_user_input: true};
33 SourceLocation loc2 = {.file: FileSpec{"a.c"}, .line: 13, .column: 7, .length: 0, .hidden: false, .in_user_input: true};
34 SourceLocation loc3 = {.file: FileSpec{"a.c"}, .line: 13, .column: 9, .length: 0, .hidden: false, .in_user_input: true};
35 std::string result =
36 Render(details: {DiagnosticDetail{.source_location: loc1, .severity: eSeverityError, .message: "1", .rendered: "1"},
37 DiagnosticDetail{.source_location: loc2, .severity: eSeverityError, .message: "2a", .rendered: "2a"},
38 DiagnosticDetail{.source_location: loc2, .severity: eSeverityInfo, .message: "2b", .rendered: "2b"},
39 DiagnosticDetail{.source_location: loc3, .severity: eSeverityError, .message: "3", .rendered: "3"}});
40 llvm::SmallVector<StringRef> lines;
41 StringRef(result).split(A&: lines, Separator: '\n');
42 // 1234567890123
43 ASSERT_EQ(lines[0], " ^ ^ ^");
44 ASSERT_EQ(lines[1], " | | error: 3");
45 ASSERT_EQ(lines[2], " | error: 2a");
46 ASSERT_EQ(lines[3], " | note: 2b");
47 ASSERT_EQ(lines[4], " error: 1");
48 }
49 {
50 // Test that diagnostics in reverse order are emitted correctly.
51 SourceLocation loc1 = {.file: FileSpec{"a.c"}, .line: 1, .column: 20, .length: 0, .hidden: false, .in_user_input: true};
52 SourceLocation loc2 = {.file: FileSpec{"a.c"}, .line: 2, .column: 10, .length: 0, .hidden: false, .in_user_input: true};
53 std::string result =
54 Render(details: {DiagnosticDetail{.source_location: loc2, .severity: eSeverityError, .message: "X", .rendered: "X"},
55 DiagnosticDetail{.source_location: loc1, .severity: eSeverityError, .message: "Y", .rendered: "Y"}});
56 // Unintuitively the later diagnostic appears first in the string:
57 // ^ ^
58 // | second
59 // first
60 ASSERT_GT(StringRef(result).find("Y"), StringRef(result).find("X"));
61 }
62 {
63 // Test that diagnostics in reverse order are emitted correctly.
64 SourceLocation loc1 = {.file: FileSpec{"a.c"}, .line: 1, .column: 10, .length: 0, .hidden: false, .in_user_input: true};
65 SourceLocation loc2 = {.file: FileSpec{"a.c"}, .line: 1, .column: 20, .length: 0, .hidden: false, .in_user_input: true};
66 std::string result =
67 Render(details: {DiagnosticDetail{.source_location: loc2, .severity: eSeverityError, .message: "X", .rendered: "X"},
68 DiagnosticDetail{.source_location: loc1, .severity: eSeverityError, .message: "Y", .rendered: "Y"}});
69 ASSERT_GT(StringRef(result).find("Y"), StringRef(result).find("X"));
70 }
71 {
72 // Test that range diagnostics are emitted correctly.
73 SourceLocation loc1 = {.file: FileSpec{"a.c"}, .line: 1, .column: 1, .length: 3, .hidden: false, .in_user_input: true};
74 SourceLocation loc2 = {.file: FileSpec{"a.c"}, .line: 1, .column: 5, .length: 3, .hidden: false, .in_user_input: true};
75 std::string result =
76 Render(details: {DiagnosticDetail{.source_location: loc1, .severity: eSeverityError, .message: "X", .rendered: "X"},
77 DiagnosticDetail{.source_location: loc2, .severity: eSeverityError, .message: "Y", .rendered: "Y"}});
78 llvm::SmallVector<StringRef> lines;
79 StringRef(result).split(A&: lines, Separator: '\n');
80 // 1234567
81 ASSERT_EQ(lines[0], "^~~ ^~~");
82 ASSERT_EQ(lines[1], "| error: Y");
83 ASSERT_EQ(lines[2], "error: X");
84 }
85 {
86 // Test diagnostics on the same line are emitted correctly.
87 SourceLocation loc1 = {.file: FileSpec{"a.c"}, .line: 1, .column: 2, .length: 0, .hidden: false, .in_user_input: true};
88 SourceLocation loc2 = {.file: FileSpec{"a.c"}, .line: 1, .column: 6, .length: 0, .hidden: false, .in_user_input: true};
89 std::string result =
90 Render(details: {DiagnosticDetail{.source_location: loc1, .severity: eSeverityError, .message: "X", .rendered: "X"},
91 DiagnosticDetail{.source_location: loc2, .severity: eSeverityError, .message: "Y", .rendered: "Y"}});
92 llvm::SmallVector<StringRef> lines;
93 StringRef(result).split(A&: lines, Separator: '\n');
94 // 1234567
95 ASSERT_EQ(lines[0], " ^ ^");
96 ASSERT_EQ(lines[1], " | error: Y");
97 ASSERT_EQ(lines[2], " error: X");
98 }
99}
100

source code of lldb/unittests/Utility/DiagnosticsRenderingTest.cpp