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