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 check(remarks::SerializerMode Mode, ArrayRef<remarks::Remark> Rs,
26                   StringRef ExpectedR, Optional<StringRef> ExpectedMeta,
27                   bool UseStrTab = false,
28                   Optional<remarks::StringTable> StrTab = None) {
29   std::string Buf;
30   raw_string_ostream OS(Buf);
31   Expected<std::unique_ptr<remarks::RemarkSerializer>> MaybeS = [&] {
32     if (UseStrTab) {
33       if (StrTab)
34         return createRemarkSerializer(remarks::Format::YAMLStrTab, Mode, OS,
35                                       std::move(*StrTab));
36       else
37         return createRemarkSerializer(remarks::Format::YAMLStrTab, Mode, OS);
38     } else
39       return createRemarkSerializer(remarks::Format::YAML, Mode, OS);
40   }();
41   EXPECT_FALSE(errorToBool(MaybeS.takeError()));
42   std::unique_ptr<remarks::RemarkSerializer> S = std::move(*MaybeS);
43 
44   for (const remarks::Remark &R : Rs)
45     S->emit(R);
46   EXPECT_EQ(OS.str(), ExpectedR);
47 
48   if (ExpectedMeta) {
49     Buf.clear();
50     std::unique_ptr<remarks::MetaSerializer> MS =
51         S->metaSerializer(OS, StringRef(EXTERNALFILETESTPATH));
52     MS->emit();
53     EXPECT_EQ(OS.str(), *ExpectedMeta);
54   }
55 }
56 
57 static void check(const remarks::Remark &R, StringRef ExpectedR,
58                   StringRef ExpectedMeta, bool UseStrTab = false,
59                   Optional<remarks::StringTable> StrTab = None) {
60   return check(remarks::SerializerMode::Separate, makeArrayRef(&R, &R + 1), ExpectedR, ExpectedMeta,
61                UseStrTab, std::move(StrTab));
62 }
63 
64 static void checkStandalone(const remarks::Remark &R, StringRef ExpectedR,
65                             Optional<remarks::StringTable> StrTab = None) {
66   bool UseStrTab = StrTab.hasValue();
67   return check(remarks::SerializerMode::Standalone, makeArrayRef(&R, &R +1), ExpectedR,
68                /*ExpectedMeta=*/None, UseStrTab, 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{"path", 3, 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{"argpath", 6, 7};
86   check(R,
87         "--- !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         StringRef("REMARKS\0"
99                   "\0\0\0\0\0\0\0\0"
100                   "\0\0\0\0\0\0\0\0"
101                   EXTERNALFILETESTPATH"\0",
102                   38));
103 }
104 
105 TEST(YAMLRemarks, SerializerRemarkStandalone) {
106   remarks::Remark R;
107   R.RemarkType = remarks::Type::Missed;
108   R.PassName = "pass";
109   R.RemarkName = "name";
110   R.FunctionName = "func";
111   R.Loc = remarks::RemarkLocation{"path", 3, 4};
112   R.Hotness = 5;
113   R.Args.emplace_back();
114   R.Args.back().Key = "key";
115   R.Args.back().Val = "value";
116   R.Args.emplace_back();
117   R.Args.back().Key = "keydebug";
118   R.Args.back().Val = "valuedebug";
119   R.Args.back().Loc = remarks::RemarkLocation{"argpath", 6, 7};
120   checkStandalone(
121       R,
122       StringRef("--- !Missed\n"
123                 "Pass:            pass\n"
124                 "Name:            name\n"
125                 "DebugLoc:        { File: path, Line: 3, Column: 4 }\n"
126                 "Function:        func\n"
127                 "Hotness:         5\n"
128                 "Args:\n"
129                 "  - key:             value\n"
130                 "  - keydebug:        valuedebug\n"
131                 "    DebugLoc:        { File: argpath, Line: 6, Column: 7 }\n"
132                 "...\n"));
133 }
134 
135 TEST(YAMLRemarks, SerializerRemarkStrTab) {
136   remarks::Remark R;
137   R.RemarkType = remarks::Type::Missed;
138   R.PassName = "pass";
139   R.RemarkName = "name";
140   R.FunctionName = "func";
141   R.Loc = remarks::RemarkLocation{"path", 3, 4};
142   R.Hotness = 5;
143   R.Args.emplace_back();
144   R.Args.back().Key = "key";
145   R.Args.back().Val = "value";
146   R.Args.emplace_back();
147   R.Args.back().Key = "keydebug";
148   R.Args.back().Val = "valuedebug";
149   R.Args.back().Loc = remarks::RemarkLocation{"argpath", 6, 7};
150   check(R,
151         "--- !Missed\n"
152         "Pass:            0\n"
153         "Name:            1\n"
154         "DebugLoc:        { File: 3, Line: 3, Column: 4 }\n"
155         "Function:        2\n"
156         "Hotness:         5\n"
157         "Args:\n"
158         "  - key:             4\n"
159         "  - keydebug:        5\n"
160         "    DebugLoc:        { File: 6, Line: 6, Column: 7 }\n"
161         "...\n",
162         StringRef("REMARKS\0"
163                   "\0\0\0\0\0\0\0\0"
164                   "\x2d\0\0\0\0\0\0\0"
165                   "pass\0name\0func\0path\0value\0valuedebug\0argpath\0"
166                   EXTERNALFILETESTPATH"\0",
167                   83),
168         /*UseStrTab=*/true);
169 }
170 
171 TEST(YAMLRemarks, SerializerRemarkParsedStrTab) {
172   StringRef StrTab("pass\0name\0func\0path\0value\0valuedebug\0argpath\0", 45);
173   remarks::Remark R;
174   R.RemarkType = remarks::Type::Missed;
175   R.PassName = "pass";
176   R.RemarkName = "name";
177   R.FunctionName = "func";
178   R.Loc = remarks::RemarkLocation{"path", 3, 4};
179   R.Hotness = 5;
180   R.Args.emplace_back();
181   R.Args.back().Key = "key";
182   R.Args.back().Val = "value";
183   R.Args.emplace_back();
184   R.Args.back().Key = "keydebug";
185   R.Args.back().Val = "valuedebug";
186   R.Args.back().Loc = remarks::RemarkLocation{"argpath", 6, 7};
187   check(R,
188         "--- !Missed\n"
189         "Pass:            0\n"
190         "Name:            1\n"
191         "DebugLoc:        { File: 3, Line: 3, Column: 4 }\n"
192         "Function:        2\n"
193         "Hotness:         5\n"
194         "Args:\n"
195         "  - key:             4\n"
196         "  - keydebug:        5\n"
197         "    DebugLoc:        { File: 6, Line: 6, Column: 7 }\n"
198         "...\n",
199         StringRef("REMARKS\0"
200                   "\0\0\0\0\0\0\0\0"
201                   "\x2d\0\0\0\0\0\0\0"
202                   "pass\0name\0func\0path\0value\0valuedebug\0argpath\0"
203                   EXTERNALFILETESTPATH"\0",
204                   83),
205         /*UseStrTab=*/true,
206         remarks::StringTable(remarks::ParsedStringTable(StrTab)));
207 }
208 
209 TEST(YAMLRemarks, SerializerRemarkParsedStrTabStandalone) {
210   StringRef StrTab("pass\0name\0func\0path\0value\0valuedebug\0argpath\0", 45);
211   remarks::ParsedStringTable ParsedStrTab(StrTab);
212   remarks::StringTable PreFilledStrTab(ParsedStrTab);
213   remarks::Remark R;
214   R.RemarkType = remarks::Type::Missed;
215   R.PassName = "pass";
216   R.RemarkName = "name";
217   R.FunctionName = "func";
218   R.Loc = remarks::RemarkLocation{"path", 3, 4};
219   R.Hotness = 5;
220   R.Args.emplace_back();
221   R.Args.back().Key = "key";
222   R.Args.back().Val = "value";
223   R.Args.emplace_back();
224   R.Args.back().Key = "keydebug";
225   R.Args.back().Val = "valuedebug";
226   R.Args.back().Loc = remarks::RemarkLocation{"argpath", 6, 7};
227   checkStandalone(
228       R,
229       StringRef("REMARKS\0"
230                 "\0\0\0\0\0\0\0\0"
231                 "\x2d\0\0\0\0\0\0\0"
232                 "pass\0name\0func\0path\0value\0valuedebug\0argpath\0"
233                 "--- !Missed\n"
234                 "Pass:            0\n"
235                 "Name:            1\n"
236                 "DebugLoc:        { File: 3, Line: 3, Column: 4 }\n"
237                 "Function:        2\n"
238                 "Hotness:         5\n"
239                 "Args:\n"
240                 "  - key:             4\n"
241                 "  - keydebug:        5\n"
242                 "    DebugLoc:        { File: 6, Line: 6, Column: 7 }\n"
243                 "...\n",
244                 315),
245       std::move(PreFilledStrTab));
246 }
247 
248 TEST(YAMLRemarks, SerializerRemarkParsedStrTabStandaloneMultipleRemarks) {
249   StringRef StrTab("pass\0name\0func\0path\0value\0valuedebug\0argpath\0", 45);
250   remarks::ParsedStringTable ParsedStrTab(StrTab);
251   remarks::StringTable PreFilledStrTab(ParsedStrTab);
252   SmallVector<remarks::Remark, 2> Rs;
253   remarks::Remark R;
254   R.RemarkType = remarks::Type::Missed;
255   R.PassName = "pass";
256   R.RemarkName = "name";
257   R.FunctionName = "func";
258   R.Loc = remarks::RemarkLocation{"path", 3, 4};
259   R.Hotness = 5;
260   R.Args.emplace_back();
261   R.Args.back().Key = "key";
262   R.Args.back().Val = "value";
263   R.Args.emplace_back();
264   R.Args.back().Key = "keydebug";
265   R.Args.back().Val = "valuedebug";
266   R.Args.back().Loc = remarks::RemarkLocation{"argpath", 6, 7};
267   Rs.emplace_back(R.clone());
268   Rs.emplace_back(std::move(R));
269   check(remarks::SerializerMode::Standalone, Rs,
270         StringRef("REMARKS\0"
271                   "\0\0\0\0\0\0\0\0"
272                   "\x2d\0\0\0\0\0\0\0"
273                   "pass\0name\0func\0path\0value\0valuedebug\0argpath\0"
274                   "--- !Missed\n"
275                   "Pass:            0\n"
276                   "Name:            1\n"
277                   "DebugLoc:        { File: 3, Line: 3, Column: 4 }\n"
278                   "Function:        2\n"
279                   "Hotness:         5\n"
280                   "Args:\n"
281                   "  - key:             4\n"
282                   "  - keydebug:        5\n"
283                   "    DebugLoc:        { File: 6, Line: 6, Column: 7 }\n"
284                   "...\n"
285                   "--- !Missed\n"
286                   "Pass:            0\n"
287                   "Name:            1\n"
288                   "DebugLoc:        { File: 3, Line: 3, Column: 4 }\n"
289                   "Function:        2\n"
290                   "Hotness:         5\n"
291                   "Args:\n"
292                   "  - key:             4\n"
293                   "  - keydebug:        5\n"
294                   "    DebugLoc:        { File: 6, Line: 6, Column: 7 }\n"
295                   "...\n",
296                   561),
297         /*ExpectedMeta=*/None,
298         /*UseStrTab=*/true, std::move(PreFilledStrTab));
299 }
300