1 //===- unittests/Tooling/DiagnosticsYamlTest.cpp - Serialization tests ---===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Tests for serialization of Diagnostics.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/Tooling/DiagnosticsYaml.h"
15 #include "clang/Tooling/Core/Diagnostic.h"
16 #include "clang/Tooling/ReplacementsYaml.h"
17 #include "gtest/gtest.h"
18 
19 using namespace llvm;
20 using namespace clang::tooling;
21 using clang::tooling::Diagnostic;
22 
23 static Diagnostic makeDiagnostic(StringRef DiagnosticName,
24                                  const std::string &Message, int FileOffset,
25                                  const std::string &FilePath,
26                                  const StringMap<Replacements> &Fix) {
27   DiagnosticMessage DiagMessage;
28   DiagMessage.Message = Message;
29   DiagMessage.FileOffset = FileOffset;
30   DiagMessage.FilePath = FilePath;
31   return Diagnostic(DiagnosticName, DiagMessage, Fix, {}, Diagnostic::Warning,
32                     "path/to/build/directory");
33 }
34 
35 TEST(DiagnosticsYamlTest, serializesDiagnostics) {
36   TranslationUnitDiagnostics TUD;
37   TUD.MainSourceFile = "path/to/source.cpp";
38 
39   StringMap<Replacements> Fix1 = {
40       {"path/to/source.cpp",
41        Replacements({"path/to/source.cpp", 100, 12, "replacement #1"})}};
42   TUD.Diagnostics.push_back(makeDiagnostic("diagnostic#1", "message #1", 55,
43                                            "path/to/source.cpp", Fix1));
44 
45   StringMap<Replacements> Fix2 = {
46       {"path/to/header.h",
47        Replacements({"path/to/header.h", 62, 2, "replacement #2"})}};
48   TUD.Diagnostics.push_back(makeDiagnostic("diagnostic#2", "message #2", 60,
49                                            "path/to/header.h", Fix2));
50 
51   TUD.Diagnostics.push_back(makeDiagnostic("diagnostic#3", "message #3", 72,
52                                            "path/to/source2.cpp", {}));
53 
54   std::string YamlContent;
55   raw_string_ostream YamlContentStream(YamlContent);
56 
57   yaml::Output YAML(YamlContentStream);
58   YAML << TUD;
59 
60   EXPECT_EQ("---\n"
61             "MainSourceFile:  'path/to/source.cpp'\n"
62             "Diagnostics:     \n"
63             "  - DiagnosticName:  'diagnostic#1\'\n"
64             "    Message:         'message #1'\n"
65             "    FileOffset:      55\n"
66             "    FilePath:        'path/to/source.cpp'\n"
67             "    Replacements:    \n"
68             "      - FilePath:        'path/to/source.cpp'\n"
69             "        Offset:          100\n"
70             "        Length:          12\n"
71             "        ReplacementText: 'replacement #1'\n"
72             "  - DiagnosticName:  'diagnostic#2'\n"
73             "    Message:         'message #2'\n"
74             "    FileOffset:      60\n"
75             "    FilePath:        'path/to/header.h'\n"
76             "    Replacements:    \n"
77             "      - FilePath:        'path/to/header.h'\n"
78             "        Offset:          62\n"
79             "        Length:          2\n"
80             "        ReplacementText: 'replacement #2'\n"
81             "  - DiagnosticName:  'diagnostic#3'\n"
82             "    Message:         'message #3'\n"
83             "    FileOffset:      72\n"
84             "    FilePath:        'path/to/source2.cpp'\n"
85             "    Replacements:    \n"
86             "...\n",
87             YamlContentStream.str());
88 }
89 
90 TEST(DiagnosticsYamlTest, deserializesDiagnostics) {
91   std::string YamlContent = "---\n"
92                             "MainSourceFile:  path/to/source.cpp\n"
93                             "Diagnostics:     \n"
94                             "  - DiagnosticName:  'diagnostic#1'\n"
95                             "    Message:         'message #1'\n"
96                             "    FileOffset:      55\n"
97                             "    FilePath:        path/to/source.cpp\n"
98                             "    Replacements:    \n"
99                             "      - FilePath:        path/to/source.cpp\n"
100                             "        Offset:          100\n"
101                             "        Length:          12\n"
102                             "        ReplacementText: 'replacement #1'\n"
103                             "  - DiagnosticName:  'diagnostic#2'\n"
104                             "    Message:         'message #2'\n"
105                             "    FileOffset:      60\n"
106                             "    FilePath:        path/to/header.h\n"
107                             "    Replacements:    \n"
108                             "      - FilePath:        path/to/header.h\n"
109                             "        Offset:          62\n"
110                             "        Length:          2\n"
111                             "        ReplacementText: 'replacement #2'\n"
112                             "  - DiagnosticName:  'diagnostic#3'\n"
113                             "    Message:         'message #3'\n"
114                             "    FileOffset:      98\n"
115                             "    FilePath:        path/to/source.cpp\n"
116                             "    Replacements:    \n"
117                             "...\n";
118   TranslationUnitDiagnostics TUDActual;
119   yaml::Input YAML(YamlContent);
120   YAML >> TUDActual;
121 
122   ASSERT_FALSE(YAML.error());
123   ASSERT_EQ(3u, TUDActual.Diagnostics.size());
124   EXPECT_EQ("path/to/source.cpp", TUDActual.MainSourceFile);
125 
126   auto getFixes = [](const StringMap<Replacements> &Fix) {
127     std::vector<Replacement> Fixes;
128     for (auto &Replacements : Fix) {
129       for (auto &Replacement : Replacements.second) {
130         Fixes.push_back(Replacement);
131       }
132     }
133     return Fixes;
134   };
135 
136   Diagnostic D1 = TUDActual.Diagnostics[0];
137   EXPECT_EQ("diagnostic#1", D1.DiagnosticName);
138   EXPECT_EQ("message #1", D1.Message.Message);
139   EXPECT_EQ(55u, D1.Message.FileOffset);
140   EXPECT_EQ("path/to/source.cpp", D1.Message.FilePath);
141   std::vector<Replacement> Fixes1 = getFixes(D1.Fix);
142   ASSERT_EQ(1u, Fixes1.size());
143   EXPECT_EQ("path/to/source.cpp", Fixes1[0].getFilePath());
144   EXPECT_EQ(100u, Fixes1[0].getOffset());
145   EXPECT_EQ(12u, Fixes1[0].getLength());
146   EXPECT_EQ("replacement #1", Fixes1[0].getReplacementText());
147 
148   Diagnostic D2 = TUDActual.Diagnostics[1];
149   EXPECT_EQ("diagnostic#2", D2.DiagnosticName);
150   EXPECT_EQ("message #2", D2.Message.Message);
151   EXPECT_EQ(60u, D2.Message.FileOffset);
152   EXPECT_EQ("path/to/header.h", D2.Message.FilePath);
153   std::vector<Replacement> Fixes2 = getFixes(D2.Fix);
154   ASSERT_EQ(1u, Fixes2.size());
155   EXPECT_EQ("path/to/header.h", Fixes2[0].getFilePath());
156   EXPECT_EQ(62u, Fixes2[0].getOffset());
157   EXPECT_EQ(2u, Fixes2[0].getLength());
158   EXPECT_EQ("replacement #2", Fixes2[0].getReplacementText());
159 
160   Diagnostic D3 = TUDActual.Diagnostics[2];
161   EXPECT_EQ("diagnostic#3", D3.DiagnosticName);
162   EXPECT_EQ("message #3", D3.Message.Message);
163   EXPECT_EQ(98u, D3.Message.FileOffset);
164   EXPECT_EQ("path/to/source.cpp", D3.Message.FilePath);
165   std::vector<Replacement> Fixes3 = getFixes(D3.Fix);
166   EXPECT_TRUE(Fixes3.empty());
167 }
168