1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/importers/json/json_trace_tokenizer.h"
18
19 #include <json/value.h>
20
21 #include "src/trace_processor/importers/json/json_utils.h"
22 #include "test/gtest_and_gmock.h"
23
24 namespace perfetto {
25 namespace trace_processor {
26 namespace {
27
TEST(JsonTraceTokenizerTest,ReadDictSuccess)28 TEST(JsonTraceTokenizerTest, ReadDictSuccess) {
29 const char* start = R"({ "foo": "bar" })";
30 const char* end = start + strlen(start);
31 const char* next = nullptr;
32 base::StringView value;
33 ReadDictRes result = ReadOneJsonDict(start, end, &value, &next);
34
35 ASSERT_EQ(result, ReadDictRes::kFoundDict);
36 ASSERT_EQ(next, end);
37
38 Json::Value parsed = *json::ParseJsonString(value);
39 ASSERT_EQ(parsed["foo"].asString(), "bar");
40 }
41
TEST(JsonTraceTokenizerTest,ReadDictQuotedBraces)42 TEST(JsonTraceTokenizerTest, ReadDictQuotedBraces) {
43 const char* start = R"({ "foo": "}\"bar{\\" })";
44 const char* end = start + strlen(start);
45 const char* next = nullptr;
46 base::StringView value;
47 ReadDictRes result = ReadOneJsonDict(start, end, &value, &next);
48
49 ASSERT_EQ(result, ReadDictRes::kFoundDict);
50 ASSERT_EQ(next, end);
51
52 Json::Value parsed = *json::ParseJsonString(value);
53 ASSERT_EQ(parsed["foo"].asString(), "}\"bar{\\");
54 }
55
TEST(JsonTraceTokenizerTest,ReadDictTwoDicts)56 TEST(JsonTraceTokenizerTest, ReadDictTwoDicts) {
57 const char* start = R"({"foo": 1}, {"bar": 2})";
58 const char* middle = start + strlen(R"({"foo": 1})");
59 const char* end = start + strlen(start);
60 const char* next = nullptr;
61 base::StringView value;
62
63 ASSERT_EQ(ReadOneJsonDict(start, end, &value, &next),
64 ReadDictRes::kFoundDict);
65 ASSERT_EQ(next, middle);
66
67 Json::Value parsed = *json::ParseJsonString(value);
68 ASSERT_EQ(parsed["foo"].asInt(), 1);
69
70 ASSERT_EQ(ReadOneJsonDict(next, end, &value, &next), ReadDictRes::kFoundDict);
71 ASSERT_EQ(next, end);
72
73 parsed = *json::ParseJsonString(value);
74 ASSERT_EQ(parsed["bar"].asInt(), 2);
75 }
76
TEST(JsonTraceTokenizerTest,ReadDictNeedMoreData)77 TEST(JsonTraceTokenizerTest, ReadDictNeedMoreData) {
78 const char* start = R"({"foo": 1)";
79 const char* end = start + strlen(start);
80 const char* next = nullptr;
81 base::StringView value;
82
83 ASSERT_EQ(ReadOneJsonDict(start, end, &value, &next),
84 ReadDictRes::kNeedsMoreData);
85 ASSERT_EQ(next, nullptr);
86 }
87
TEST(JsonTraceTokenizerTest,ReadKeyIntValue)88 TEST(JsonTraceTokenizerTest, ReadKeyIntValue) {
89 const char* start = R"("Test": 01234, )";
90 const char* middle = start + strlen(R"("Test": )");
91 const char* end = start + strlen(start);
92 const char* next = nullptr;
93 std::string key;
94
95 ASSERT_EQ(ReadOneJsonKey(start, end, &key, &next), ReadKeyRes::kFoundKey);
96 ASSERT_EQ(next, middle);
97 ASSERT_EQ(key, "Test");
98 }
99
TEST(JsonTraceTokenizerTest,ReadKeyArrayValue)100 TEST(JsonTraceTokenizerTest, ReadKeyArrayValue) {
101 const char* start = R"(, "key": [test], )";
102 const char* middle = start + strlen(R"(, "key": )");
103 const char* end = start + strlen(start);
104 const char* next = nullptr;
105 std::string key;
106
107 ASSERT_EQ(ReadOneJsonKey(start, end, &key, &next), ReadKeyRes::kFoundKey);
108 ASSERT_EQ(next, middle);
109 ASSERT_EQ(key, "key");
110 }
111
TEST(JsonTraceTokenizerTest,ReadKeyDictValue)112 TEST(JsonTraceTokenizerTest, ReadKeyDictValue) {
113 const char* start = R"("key2": {}})";
114 const char* middle = start + strlen(R"("key2": )");
115 const char* end = start + strlen(start);
116 const char* next = nullptr;
117 std::string key;
118
119 ASSERT_EQ(ReadOneJsonKey(start, end, &key, &next), ReadKeyRes::kFoundKey);
120 ASSERT_EQ(next, middle);
121 ASSERT_EQ(key, "key2");
122 }
123
TEST(JsonTraceTokenizerTest,ReadKeyEscaped)124 TEST(JsonTraceTokenizerTest, ReadKeyEscaped) {
125 const char* start = R"("key\n2": {}})";
126 const char* middle = start + strlen(R"("key\n2": )");
127 const char* end = start + strlen(start);
128 const char* next = nullptr;
129 std::string key;
130
131 ASSERT_EQ(ReadOneJsonKey(start, end, &key, &next), ReadKeyRes::kFoundKey);
132 ASSERT_EQ(next, middle);
133 ASSERT_EQ(key, "key\n2");
134 }
135
TEST(JsonTraceTokenizerTest,ReadKeyNeedMoreDataStartString)136 TEST(JsonTraceTokenizerTest, ReadKeyNeedMoreDataStartString) {
137 const char* start = R"(")";
138 const char* end = start + strlen(start);
139 const char* next = nullptr;
140 std::string key;
141
142 ASSERT_EQ(ReadOneJsonKey(start, end, &key, &next),
143 ReadKeyRes::kNeedsMoreData);
144 ASSERT_EQ(next, nullptr);
145 }
146
147 TEST(JsonTraceTokenizerTest, ReadKeyNeedMoreDataMiddleString) {
148 const char* start = R"("key)";
149 const char* end = start + strlen(start);
150 const char* next = nullptr;
151 std::string key;
152
153 ASSERT_EQ(ReadOneJsonKey(start, end, &key, &next),
154 ReadKeyRes::kNeedsMoreData);
155 ASSERT_EQ(next, nullptr);
156 }
157
TEST(JsonTraceTokenizerTest,ReadKeyNeedMoreDataNoValue)158 TEST(JsonTraceTokenizerTest, ReadKeyNeedMoreDataNoValue) {
159 const char* start = R"("key": )";
160 const char* end = start + strlen(start);
161 const char* next = nullptr;
162 std::string key;
163
164 ASSERT_EQ(ReadOneJsonKey(start, end, &key, &next),
165 ReadKeyRes::kNeedsMoreData);
166 ASSERT_EQ(next, nullptr);
167 }
168
TEST(JsonTraceTokenizerTest,ReadKeyEndOfDict)169 TEST(JsonTraceTokenizerTest, ReadKeyEndOfDict) {
170 const char* start = R"( })";
171 const char* end = start + strlen(start);
172 const char* next = nullptr;
173 std::string key;
174
175 ASSERT_EQ(ReadOneJsonKey(start, end, &key, &next),
176 ReadKeyRes::kEndOfDictionary);
177 ASSERT_EQ(next, end);
178 }
179
TEST(JsonTraceTokenizerTest,ReadSystraceLine)180 TEST(JsonTraceTokenizerTest, ReadSystraceLine) {
181 const char* start = R"(test one two\n test again\n)";
182 const char* middle = start + strlen(R"(test one two\n)");
183 const char* end = start + strlen(start);
184 const char* next = nullptr;
185 std::string line;
186
187 ASSERT_EQ(ReadOneSystemTraceLine(start, end, &line, &next),
188 ReadSystemLineRes::kFoundLine);
189 ASSERT_EQ(next, middle);
190 ASSERT_EQ(line, "test one two");
191 }
192
TEST(JsonTraceTokenizerTest,ReadSystraceLineEscaped)193 TEST(JsonTraceTokenizerTest, ReadSystraceLineEscaped) {
194 const char* start = R"(test\t one two\n test again\n)";
195 const char* middle = start + strlen(R"(test\t one two\n)");
196 const char* end = start + strlen(start);
197 const char* next = nullptr;
198 std::string line;
199
200 ASSERT_EQ(ReadOneSystemTraceLine(start, end, &line, &next),
201 ReadSystemLineRes::kFoundLine);
202 ASSERT_EQ(next, middle);
203 ASSERT_EQ(line, "test\t one two");
204 }
205
TEST(JsonTraceTokenizerTest,ReadSystraceNeedMoreDataOnlyEscape)206 TEST(JsonTraceTokenizerTest, ReadSystraceNeedMoreDataOnlyEscape) {
207 const char* start = R"(test one two\)";
208 const char* end = start + strlen(start);
209 const char* next = nullptr;
210 std::string line;
211
212 ASSERT_EQ(ReadOneSystemTraceLine(start, end, &line, &next),
213 ReadSystemLineRes::kNeedsMoreData);
214 ASSERT_EQ(next, nullptr);
215 }
216
TEST(JsonTraceTokenizerTest,ReadSystraceEndOfData)217 TEST(JsonTraceTokenizerTest, ReadSystraceEndOfData) {
218 const char* start = R"(")";
219 const char* end = start + strlen(start);
220 const char* next = nullptr;
221 std::string line;
222
223 ASSERT_EQ(ReadOneSystemTraceLine(start, end, &line, &next),
224 ReadSystemLineRes::kEndOfSystemTrace);
225 ASSERT_EQ(next, end);
226 }
227
228 TEST(JsonTraceTokenizerTest, ExtractValueForJsonKey) {
229 base::Optional<std::string> line;
230
231 ASSERT_TRUE(ExtractValueForJsonKey(R"({"ts": 149029})", "ts", &line).ok());
232 ASSERT_EQ(*line, "149029");
233
234 ASSERT_TRUE(ExtractValueForJsonKey(R"(
235 {
236 "lots_of": "whitespace"
237 }
238 )",
239 "lots_of", &line)
240 .ok());
241 ASSERT_EQ(*line, "whitespace");
242
243 ASSERT_TRUE(ExtractValueForJsonKey(R"(
244 {
245 "lots_of": "whitespace" ,
246 "other": "value"
247 }
248 )",
249 "other", &line)
250 .ok());
251 ASSERT_EQ(*line, "value");
252
253 ASSERT_TRUE(ExtractValueForJsonKey(R"({
254 "ts": 149029, "foo": "bar"
255 })",
256 "ts", &line)
257 .ok());
258 ASSERT_EQ(*line, "149029");
259
260 ASSERT_TRUE(ExtractValueForJsonKey(R"({
261 "ts": 149029, "foo": "bar"
262 })",
263 "foo", &line)
264 .ok());
265 ASSERT_EQ(*line, "bar");
266
267 ASSERT_TRUE(ExtractValueForJsonKey(R"({
268 "nested": {"ts": 149029, "foo": "bar"}
269 })",
270 "nested", &line)
271 .ok());
272 ASSERT_EQ(*line, R"({"ts": 149029, "foo": "bar"})");
273 }
274
275 } // namespace
276 } // namespace trace_processor
277 } // namespace perfetto
278