1 | //===- unittest/Support/YAMLRemarksSerializerTest.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 "llvm/Remarks/Remark.h" |
10 | #include "llvm/Remarks/RemarkParser.h" |
11 | #include "llvm/Remarks/YAMLRemarkSerializer.h" |
12 | #include "llvm/Support/Error.h" |
13 | #include "gtest/gtest.h" |
14 | |
15 | // We need to supprt Windows paths as well. In order to have paths with the same |
16 | // length, use a different path according to the platform. |
17 | #ifdef _WIN32 |
18 | #define EXTERNALFILETESTPATH "C:/externalfi" |
19 | #else |
20 | #define EXTERNALFILETESTPATH "/externalfile" |
21 | #endif |
22 | |
23 | using namespace llvm; |
24 | |
25 | static void (remarks::Format SerializerFormat, |
26 | remarks::SerializerMode Mode, ArrayRef<remarks::Remark> Rs, |
27 | StringRef ExpectedR, std::optional<StringRef> ExpectedMeta, |
28 | std::optional<remarks::StringTable> StrTab = std::nullopt) { |
29 | std::string Buf; |
30 | raw_string_ostream OS(Buf); |
31 | Expected<std::unique_ptr<remarks::RemarkSerializer>> MaybeS = [&] { |
32 | if (StrTab) |
33 | return createRemarkSerializer(RemarksFormat: SerializerFormat, Mode, OS, |
34 | StrTab: std::move(*StrTab)); |
35 | else |
36 | return createRemarkSerializer(RemarksFormat: SerializerFormat, Mode, OS); |
37 | }(); |
38 | EXPECT_FALSE(errorToBool(MaybeS.takeError())); |
39 | std::unique_ptr<remarks::RemarkSerializer> S = std::move(*MaybeS); |
40 | |
41 | for (const remarks::Remark &R : Rs) |
42 | S->emit(Remark: R); |
43 | EXPECT_EQ(OS.str(), ExpectedR); |
44 | |
45 | if (ExpectedMeta) { |
46 | Buf.clear(); |
47 | std::unique_ptr<remarks::MetaSerializer> MS = |
48 | S->metaSerializer(OS, ExternalFilename: StringRef(EXTERNALFILETESTPATH)); |
49 | MS->emit(); |
50 | EXPECT_EQ(OS.str(), *ExpectedMeta); |
51 | } |
52 | } |
53 | |
54 | static void (remarks::Format SerializerFormat, const remarks::Remark &R, |
55 | StringRef ExpectedR, StringRef ExpectedMeta, |
56 | std::optional<remarks::StringTable> StrTab = std::nullopt) { |
57 | return check(SerializerFormat, Mode: remarks::SerializerMode::Separate, |
58 | Rs: ArrayRef(&R, &R + 1), ExpectedR, ExpectedMeta, |
59 | StrTab: std::move(StrTab)); |
60 | } |
61 | |
62 | static void |
63 | checkStandalone(remarks::Format SerializerFormat, const remarks::Remark &R, |
64 | StringRef ExpectedR, |
65 | std::optional<remarks::StringTable> StrTab = std::nullopt) { |
66 | return check(SerializerFormat, Mode: remarks::SerializerMode::Standalone, |
67 | Rs: ArrayRef(&R, &R + 1), ExpectedR, |
68 | /*ExpectedMeta=*/std::nullopt, StrTab: std::move(StrTab)); |
69 | } |
70 | |
71 | TEST(YAMLRemarks, SerializerRemark) { |
72 | remarks::Remark R; |
73 | R.RemarkType = remarks::Type::Missed; |
74 | R.PassName = "pass" ; |
75 | R.RemarkName = "name" ; |
76 | R.FunctionName = "func" ; |
77 | R.Loc = remarks::RemarkLocation{.SourceFilePath: "path" , .SourceLine: 3, .SourceColumn: 4}; |
78 | R.Hotness = 5; |
79 | R.Args.emplace_back(); |
80 | R.Args.back().Key = "key" ; |
81 | R.Args.back().Val = "value" ; |
82 | R.Args.emplace_back(); |
83 | R.Args.back().Key = "keydebug" ; |
84 | R.Args.back().Val = "valuedebug" ; |
85 | R.Args.back().Loc = remarks::RemarkLocation{.SourceFilePath: "argpath" , .SourceLine: 6, .SourceColumn: 7}; |
86 | check(SerializerFormat: remarks::Format::YAML, R, |
87 | ExpectedR: "--- !Missed\n" |
88 | "Pass: pass\n" |
89 | "Name: name\n" |
90 | "DebugLoc: { File: path, Line: 3, Column: 4 }\n" |
91 | "Function: func\n" |
92 | "Hotness: 5\n" |
93 | "Args:\n" |
94 | " - key: value\n" |
95 | " - keydebug: valuedebug\n" |
96 | " DebugLoc: { File: argpath, Line: 6, Column: 7 }\n" |
97 | "...\n" , |
98 | ExpectedMeta: StringRef("REMARKS\0" |
99 | "\0\0\0\0\0\0\0\0" |
100 | "\0\0\0\0\0\0\0\0" EXTERNALFILETESTPATH "\0" , |
101 | 38)); |
102 | } |
103 | |
104 | TEST(YAMLRemarks, SerializerRemarkStandalone) { |
105 | remarks::Remark R; |
106 | R.RemarkType = remarks::Type::Missed; |
107 | R.PassName = "pass" ; |
108 | R.RemarkName = "name" ; |
109 | R.FunctionName = "func" ; |
110 | R.Loc = remarks::RemarkLocation{.SourceFilePath: "path" , .SourceLine: 3, .SourceColumn: 4}; |
111 | R.Hotness = 5; |
112 | R.Args.emplace_back(); |
113 | R.Args.back().Key = "key" ; |
114 | R.Args.back().Val = "value" ; |
115 | R.Args.emplace_back(); |
116 | R.Args.back().Key = "keydebug" ; |
117 | R.Args.back().Val = "valuedebug" ; |
118 | R.Args.back().Loc = remarks::RemarkLocation{.SourceFilePath: "argpath" , .SourceLine: 6, .SourceColumn: 7}; |
119 | checkStandalone( |
120 | SerializerFormat: remarks::Format::YAML, R, |
121 | ExpectedR: StringRef("--- !Missed\n" |
122 | "Pass: pass\n" |
123 | "Name: name\n" |
124 | "DebugLoc: { File: path, Line: 3, Column: 4 }\n" |
125 | "Function: func\n" |
126 | "Hotness: 5\n" |
127 | "Args:\n" |
128 | " - key: value\n" |
129 | " - keydebug: valuedebug\n" |
130 | " DebugLoc: { File: argpath, Line: 6, Column: 7 }\n" |
131 | "...\n" )); |
132 | } |
133 | |
134 | TEST(YAMLRemarks, SerializerRemarkStrTab) { |
135 | remarks::Remark R; |
136 | R.RemarkType = remarks::Type::Missed; |
137 | R.PassName = "pass" ; |
138 | R.RemarkName = "name" ; |
139 | R.FunctionName = "func" ; |
140 | R.Loc = remarks::RemarkLocation{.SourceFilePath: "path" , .SourceLine: 3, .SourceColumn: 4}; |
141 | R.Hotness = 5; |
142 | R.Args.emplace_back(); |
143 | R.Args.back().Key = "key" ; |
144 | R.Args.back().Val = "value" ; |
145 | R.Args.emplace_back(); |
146 | R.Args.back().Key = "keydebug" ; |
147 | R.Args.back().Val = "valuedebug" ; |
148 | R.Args.back().Loc = remarks::RemarkLocation{.SourceFilePath: "argpath" , .SourceLine: 6, .SourceColumn: 7}; |
149 | check(SerializerFormat: remarks::Format::YAMLStrTab, R, |
150 | ExpectedR: "--- !Missed\n" |
151 | "Pass: 0\n" |
152 | "Name: 1\n" |
153 | "DebugLoc: { File: 3, Line: 3, Column: 4 }\n" |
154 | "Function: 2\n" |
155 | "Hotness: 5\n" |
156 | "Args:\n" |
157 | " - key: 4\n" |
158 | " - keydebug: 5\n" |
159 | " DebugLoc: { File: 6, Line: 6, Column: 7 }\n" |
160 | "...\n" , |
161 | ExpectedMeta: StringRef("REMARKS\0" |
162 | "\0\0\0\0\0\0\0\0" |
163 | "\x2d\0\0\0\0\0\0\0" |
164 | "pass\0name\0func\0path\0value\0valuedebug\0argpath" |
165 | "\0" EXTERNALFILETESTPATH "\0" , |
166 | 83)); |
167 | } |
168 | |
169 | TEST(YAMLRemarks, SerializerRemarkParsedStrTab) { |
170 | StringRef StrTab("pass\0name\0func\0path\0value\0valuedebug\0argpath\0" , 45); |
171 | remarks::Remark R; |
172 | R.RemarkType = remarks::Type::Missed; |
173 | R.PassName = "pass" ; |
174 | R.RemarkName = "name" ; |
175 | R.FunctionName = "func" ; |
176 | R.Loc = remarks::RemarkLocation{.SourceFilePath: "path" , .SourceLine: 3, .SourceColumn: 4}; |
177 | R.Hotness = 5; |
178 | R.Args.emplace_back(); |
179 | R.Args.back().Key = "key" ; |
180 | R.Args.back().Val = "value" ; |
181 | R.Args.emplace_back(); |
182 | R.Args.back().Key = "keydebug" ; |
183 | R.Args.back().Val = "valuedebug" ; |
184 | R.Args.back().Loc = remarks::RemarkLocation{.SourceFilePath: "argpath" , .SourceLine: 6, .SourceColumn: 7}; |
185 | check(SerializerFormat: remarks::Format::YAMLStrTab, R, |
186 | ExpectedR: "--- !Missed\n" |
187 | "Pass: 0\n" |
188 | "Name: 1\n" |
189 | "DebugLoc: { File: 3, Line: 3, Column: 4 }\n" |
190 | "Function: 2\n" |
191 | "Hotness: 5\n" |
192 | "Args:\n" |
193 | " - key: 4\n" |
194 | " - keydebug: 5\n" |
195 | " DebugLoc: { File: 6, Line: 6, Column: 7 }\n" |
196 | "...\n" , |
197 | ExpectedMeta: StringRef("REMARKS\0" |
198 | "\0\0\0\0\0\0\0\0" |
199 | "\x2d\0\0\0\0\0\0\0" |
200 | "pass\0name\0func\0path\0value\0valuedebug\0argpath" |
201 | "\0" EXTERNALFILETESTPATH "\0" , |
202 | 83), |
203 | StrTab: remarks::StringTable(remarks::ParsedStringTable(StrTab))); |
204 | } |
205 | |
206 | TEST(YAMLRemarks, SerializerRemarkParsedStrTabStandaloneNoStrTab) { |
207 | // Check that we don't use the string table even if it was provided. |
208 | StringRef StrTab("pass\0name\0func\0path\0value\0valuedebug\0argpath\0" , 45); |
209 | remarks::ParsedStringTable ParsedStrTab(StrTab); |
210 | remarks::StringTable PreFilledStrTab(ParsedStrTab); |
211 | remarks::Remark R; |
212 | R.RemarkType = remarks::Type::Missed; |
213 | R.PassName = "pass" ; |
214 | R.RemarkName = "name" ; |
215 | R.FunctionName = "func" ; |
216 | R.Loc = remarks::RemarkLocation{.SourceFilePath: "path" , .SourceLine: 3, .SourceColumn: 4}; |
217 | R.Hotness = 5; |
218 | R.Args.emplace_back(); |
219 | R.Args.back().Key = "key" ; |
220 | R.Args.back().Val = "value" ; |
221 | R.Args.emplace_back(); |
222 | R.Args.back().Key = "keydebug" ; |
223 | R.Args.back().Val = "valuedebug" ; |
224 | R.Args.back().Loc = remarks::RemarkLocation{.SourceFilePath: "argpath" , .SourceLine: 6, .SourceColumn: 7}; |
225 | checkStandalone( |
226 | SerializerFormat: remarks::Format::YAML, R, |
227 | ExpectedR: StringRef("--- !Missed\n" |
228 | "Pass: pass\n" |
229 | "Name: name\n" |
230 | "DebugLoc: { File: path, Line: 3, Column: 4 }\n" |
231 | "Function: func\n" |
232 | "Hotness: 5\n" |
233 | "Args:\n" |
234 | " - key: value\n" |
235 | " - keydebug: valuedebug\n" |
236 | " DebugLoc: { File: argpath, Line: 6, Column: 7 }\n" |
237 | "...\n" ), |
238 | StrTab: std::move(PreFilledStrTab)); |
239 | } |
240 | |
241 | TEST(YAMLRemarks, SerializerRemarkParsedStrTabStandalone) { |
242 | StringRef StrTab("pass\0name\0func\0path\0value\0valuedebug\0argpath\0" , 45); |
243 | remarks::ParsedStringTable ParsedStrTab(StrTab); |
244 | remarks::StringTable PreFilledStrTab(ParsedStrTab); |
245 | remarks::Remark R; |
246 | R.RemarkType = remarks::Type::Missed; |
247 | R.PassName = "pass" ; |
248 | R.RemarkName = "name" ; |
249 | R.FunctionName = "func" ; |
250 | R.Loc = remarks::RemarkLocation{.SourceFilePath: "path" , .SourceLine: 3, .SourceColumn: 4}; |
251 | R.Hotness = 5; |
252 | R.Args.emplace_back(); |
253 | R.Args.back().Key = "key" ; |
254 | R.Args.back().Val = "value" ; |
255 | R.Args.emplace_back(); |
256 | R.Args.back().Key = "keydebug" ; |
257 | R.Args.back().Val = "valuedebug" ; |
258 | R.Args.back().Loc = remarks::RemarkLocation{.SourceFilePath: "argpath" , .SourceLine: 6, .SourceColumn: 7}; |
259 | checkStandalone( |
260 | SerializerFormat: remarks::Format::YAMLStrTab, R, |
261 | ExpectedR: StringRef("REMARKS\0" |
262 | "\0\0\0\0\0\0\0\0" |
263 | "\x2d\0\0\0\0\0\0\0" |
264 | "pass\0name\0func\0path\0value\0valuedebug\0argpath\0" |
265 | "--- !Missed\n" |
266 | "Pass: 0\n" |
267 | "Name: 1\n" |
268 | "DebugLoc: { File: 3, Line: 3, Column: 4 }\n" |
269 | "Function: 2\n" |
270 | "Hotness: 5\n" |
271 | "Args:\n" |
272 | " - key: 4\n" |
273 | " - keydebug: 5\n" |
274 | " DebugLoc: { File: 6, Line: 6, Column: 7 }\n" |
275 | "...\n" , |
276 | 315), |
277 | StrTab: std::move(PreFilledStrTab)); |
278 | } |
279 | |
280 | TEST(YAMLRemarks, SerializerRemarkParsedStrTabStandaloneMultipleRemarks) { |
281 | StringRef StrTab("pass\0name\0func\0path\0value\0valuedebug\0argpath\0" , 45); |
282 | remarks::ParsedStringTable ParsedStrTab(StrTab); |
283 | remarks::StringTable PreFilledStrTab(ParsedStrTab); |
284 | SmallVector<remarks::Remark, 2> Rs; |
285 | remarks::Remark R; |
286 | R.RemarkType = remarks::Type::Missed; |
287 | R.PassName = "pass" ; |
288 | R.RemarkName = "name" ; |
289 | R.FunctionName = "func" ; |
290 | R.Loc = remarks::RemarkLocation{.SourceFilePath: "path" , .SourceLine: 3, .SourceColumn: 4}; |
291 | R.Hotness = 5; |
292 | R.Args.emplace_back(); |
293 | R.Args.back().Key = "key" ; |
294 | R.Args.back().Val = "value" ; |
295 | R.Args.emplace_back(); |
296 | R.Args.back().Key = "keydebug" ; |
297 | R.Args.back().Val = "valuedebug" ; |
298 | R.Args.back().Loc = remarks::RemarkLocation{.SourceFilePath: "argpath" , .SourceLine: 6, .SourceColumn: 7}; |
299 | Rs.emplace_back(Args: R.clone()); |
300 | Rs.emplace_back(Args: std::move(R)); |
301 | check(SerializerFormat: remarks::Format::YAMLStrTab, Mode: remarks::SerializerMode::Standalone, Rs, |
302 | ExpectedR: StringRef("REMARKS\0" |
303 | "\0\0\0\0\0\0\0\0" |
304 | "\x2d\0\0\0\0\0\0\0" |
305 | "pass\0name\0func\0path\0value\0valuedebug\0argpath\0" |
306 | "--- !Missed\n" |
307 | "Pass: 0\n" |
308 | "Name: 1\n" |
309 | "DebugLoc: { File: 3, Line: 3, Column: 4 }\n" |
310 | "Function: 2\n" |
311 | "Hotness: 5\n" |
312 | "Args:\n" |
313 | " - key: 4\n" |
314 | " - keydebug: 5\n" |
315 | " DebugLoc: { File: 6, Line: 6, Column: 7 }\n" |
316 | "...\n" |
317 | "--- !Missed\n" |
318 | "Pass: 0\n" |
319 | "Name: 1\n" |
320 | "DebugLoc: { File: 3, Line: 3, Column: 4 }\n" |
321 | "Function: 2\n" |
322 | "Hotness: 5\n" |
323 | "Args:\n" |
324 | " - key: 4\n" |
325 | " - keydebug: 5\n" |
326 | " DebugLoc: { File: 6, Line: 6, Column: 7 }\n" |
327 | "...\n" , |
328 | 561), |
329 | /*ExpectedMeta=*/std::nullopt, StrTab: std::move(PreFilledStrTab)); |
330 | } |
331 | |