1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/trace_event/traced_value.h"
6
7 #include <cmath>
8 #include <cstddef>
9 #include <string_view>
10 #include <utility>
11
12 #include "base/strings/string_util.h"
13 #include "base/values.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace base {
17 namespace trace_event {
18
TEST(TraceEventArgumentTest,InitializerListCreatedContainers)19 TEST(TraceEventArgumentTest, InitializerListCreatedContainers) {
20 std::string json;
21 TracedValue::Build(
22 {
23 {"empty_array", TracedValue::Array({})},
24 {"empty_dictionary", TracedValue::Dictionary({})},
25 {"nested_array", TracedValue::Array({
26 TracedValue::Array({}),
27 TracedValue::Dictionary({}),
28 true,
29 })},
30 {"nested_dictionary", TracedValue::Dictionary({
31 {"d", TracedValue::Dictionary({})},
32 {"a", TracedValue::Array({})},
33 {"b", true},
34 })},
35 })
36 ->AppendAsTraceFormat(&json);
37 EXPECT_EQ(
38 "{\"empty_array\":[],\"empty_dictionary\":{},"
39 "\"nested_array\":[[],{},true],"
40 "\"nested_dictionary\":{\"d\":{},\"a\":[],\"b\":true}}",
41 json);
42 }
43
TEST(TraceEventArgumentTest,InitializerListCreatedFlatDictionary)44 TEST(TraceEventArgumentTest, InitializerListCreatedFlatDictionary) {
45 std::string json;
46 TracedValue::Build({{"bool_var", true},
47 {"double_var", 3.14},
48 {"int_var", 2020},
49 {"literal_var", "literal"}})
50 ->AppendAsTraceFormat(&json);
51 EXPECT_EQ(
52 "{\"bool_var\":true,\"double_var\":3.14,\"int_var\":2020,\""
53 "literal_var\":\"literal\"}",
54 json);
55 }
56
TEST(TraceEventArgumentTest,ArrayAndDictionaryScope)57 TEST(TraceEventArgumentTest, ArrayAndDictionaryScope) {
58 std::unique_ptr<TracedValue> value(new TracedValue());
59 {
60 auto dictionary = value->BeginDictionaryScoped("dictionary_name");
61 value->SetInteger("my_int", 1);
62 }
63 {
64 auto array = value->BeginArrayScoped("array_name");
65 value->AppendInteger(2);
66 }
67 {
68 auto surround_dictionary =
69 value->BeginDictionaryScoped("outside_dictionary");
70 value->SetBoolean("my_bool", true);
71 {
72 auto inside_array = value->BeginArrayScoped("inside_array");
73 value->AppendBoolean(false);
74 }
75 {
76 auto inside_array = value->BeginDictionaryScoped("inside_dictionary");
77 value->SetBoolean("inner_bool", false);
78 }
79 }
80 {
81 auto surround_array = value->BeginArrayScoped("outside_array");
82 value->AppendBoolean(false);
83 {
84 auto inside_dictionary = value->AppendDictionaryScoped();
85 value->SetBoolean("my_bool", true);
86 }
87 {
88 auto inside_array = value->AppendArrayScoped();
89 value->AppendBoolean(false);
90 }
91 }
92 {
93 auto dictionary = value->BeginDictionaryScopedWithCopiedName(
94 std::string("wonderful_") + std::string("world"));
95 }
96 {
97 auto array = value->BeginArrayScopedWithCopiedName(
98 std::string("wonderful_") + std::string("array"));
99 }
100 std::string json;
101 value->AppendAsTraceFormat(&json);
102 EXPECT_EQ(
103 "{"
104 "\"dictionary_name\":{\"my_int\":1},"
105 "\"array_name\":[2],"
106 "\"outside_dictionary\":{\"my_bool\":true,\"inside_array\":[false],"
107 "\"inside_dictionary\":{\"inner_bool\":false}},"
108 "\"outside_array\":[false,{\"my_bool\":true},[false]],"
109 "\"wonderful_world\":{},"
110 "\"wonderful_array\":[]"
111 "}",
112 json);
113 }
114
SayHello()115 std::string SayHello() {
116 // Create a string by concatenating two strings, so that there is no literal
117 // corresponding to the result.
118 return std::string("hello ") + std::string("world");
119 }
120
TEST(TraceEventArgumentTest,StringAndPointerConstructors)121 TEST(TraceEventArgumentTest, StringAndPointerConstructors) {
122 std::string json;
123 const char* const_char_ptr_var = "const char* value";
124 TracedValue::Build(
125 {
126 {"literal_var", "literal"},
127 {"std_string_var", std::string("std::string value")},
128 {"string_from_function", SayHello()},
129 {"string_from_lambda", []() { return std::string("hello"); }()},
130 {"base_string_piece_var", std::string_view("std::string_view value")},
131 {"const_char_ptr_var", const_char_ptr_var},
132 {"void_nullptr", static_cast<void*>(nullptr)},
133 {"int_nullptr", static_cast<int*>(nullptr)},
134 {"void_1234ptr", reinterpret_cast<void*>(0x1234)},
135 })
136 ->AppendAsTraceFormat(&json);
137 EXPECT_EQ(
138 "{\"literal_var\":\"literal\","
139 "\"std_string_var\":\"std::string value\","
140 "\"string_from_function\":\"hello world\","
141 "\"string_from_lambda\":\"hello\","
142 "\"base_string_piece_var\":\"std::string_view value\","
143 "\"const_char_ptr_var\":\"const char* value\","
144 "\"void_nullptr\":\"0x0\","
145 "\"int_nullptr\":\"0x0\","
146 "\"void_1234ptr\":\"0x1234\"}",
147 json);
148 }
149
TEST(TraceEventArgumentTest,FlatDictionary)150 TEST(TraceEventArgumentTest, FlatDictionary) {
151 std::unique_ptr<TracedValue> value(new TracedValue());
152 value->SetBoolean("bool", true);
153 value->SetDouble("double", 0.0);
154 value->SetInteger("int", 2014);
155 value->SetString("string", "string");
156 value->SetPointer("ptr", reinterpret_cast<void*>(0x1234));
157 std::string json = "PREFIX";
158 value->AppendAsTraceFormat(&json);
159 EXPECT_EQ(
160 "PREFIX{\"bool\":true,\"double\":0.0,\"int\":2014,\"string\":\"string\","
161 "\"ptr\":\"0x1234\"}",
162 json);
163 }
164
TEST(TraceEventArgumentTest,NoDotPathExpansion)165 TEST(TraceEventArgumentTest, NoDotPathExpansion) {
166 std::unique_ptr<TracedValue> value(new TracedValue());
167 value->SetBoolean("bo.ol", true);
168 value->SetDouble("doub.le", 0.0);
169 value->SetInteger("in.t", 2014);
170 value->SetString("str.ing", "str.ing");
171 std::string json;
172 value->AppendAsTraceFormat(&json);
173 EXPECT_EQ(
174 "{\"bo.ol\":true,\"doub.le\":0.0,\"in.t\":2014,\"str.ing\":\"str.ing\"}",
175 json);
176 }
177
TEST(TraceEventArgumentTest,Hierarchy)178 TEST(TraceEventArgumentTest, Hierarchy) {
179 std::unique_ptr<TracedValue> value(new TracedValue());
180 value->BeginArray("a1");
181 value->AppendInteger(1);
182 value->AppendBoolean(true);
183 value->BeginDictionary();
184 value->SetInteger("i2", 3);
185 value->EndDictionary();
186 value->EndArray();
187 value->SetBoolean("b0", true);
188 value->SetDouble("d0", 0.0);
189 value->BeginDictionary("dict1");
190 value->BeginDictionary("dict2");
191 value->SetBoolean("b2", false);
192 value->EndDictionary();
193 value->SetInteger("i1", 2014);
194 value->SetString("s1", "foo");
195 value->EndDictionary();
196 value->SetInteger("i0", 2014);
197 value->SetString("s0", "foo");
198 std::string json;
199 value->AppendAsTraceFormat(&json);
200 EXPECT_EQ(
201 "{\"a1\":[1,true,{\"i2\":3}],\"b0\":true,\"d0\":0.0,\"dict1\":{\"dict2\":"
202 "{\"b2\":false},\"i1\":2014,\"s1\":\"foo\"},\"i0\":2014,\"s0\":"
203 "\"foo\"}",
204 json);
205 }
206
TEST(TraceEventArgumentTest,LongStrings)207 TEST(TraceEventArgumentTest, LongStrings) {
208 std::string kLongString = "supercalifragilisticexpialidocious";
209 std::string kLongString2 = "0123456789012345678901234567890123456789";
210 char kLongString3[4096];
211 for (size_t i = 0; i < sizeof(kLongString3); ++i)
212 kLongString3[i] = 'a' + (i % 25);
213 kLongString3[sizeof(kLongString3) - 1] = '\0';
214
215 std::unique_ptr<TracedValue> value(new TracedValue());
216 value->SetString("a", "short");
217 value->SetString("b", kLongString);
218 value->BeginArray("c");
219 value->AppendString(kLongString2);
220 value->AppendString("");
221 value->BeginDictionary();
222 value->SetString("a", kLongString3);
223 value->EndDictionary();
224 value->EndArray();
225
226 std::string json;
227 value->AppendAsTraceFormat(&json);
228 EXPECT_EQ("{\"a\":\"short\",\"b\":\"" + kLongString + "\",\"c\":[\"" +
229 kLongString2 + "\",\"\",{\"a\":\"" + kLongString3 + "\"}]}",
230 json);
231 }
232
TEST(TraceEventArgumentTest,PassTracedValue)233 TEST(TraceEventArgumentTest, PassTracedValue) {
234 auto dict_value = std::make_unique<TracedValue>();
235 dict_value->SetInteger("a", 1);
236
237 auto nested_dict_value = std::make_unique<TracedValue>();
238 nested_dict_value->SetInteger("b", 2);
239 nested_dict_value->BeginArray("c");
240 nested_dict_value->AppendString("foo");
241 nested_dict_value->EndArray();
242
243 dict_value->SetValue("e", nested_dict_value.get());
244
245 // Check the merged result.
246 std::string json;
247 dict_value->AppendAsTraceFormat(&json);
248 EXPECT_EQ("{\"a\":1,\"e\":{\"b\":2,\"c\":[\"foo\"]}}", json);
249
250 // Check that the passed nestd dict was left unouthced.
251 json = "";
252 nested_dict_value->AppendAsTraceFormat(&json);
253 EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"]}", json);
254
255 // And that it is still usable.
256 nested_dict_value->SetInteger("f", 3);
257 nested_dict_value->BeginDictionary("g");
258 nested_dict_value->EndDictionary();
259 json = "";
260 nested_dict_value->AppendAsTraceFormat(&json);
261 EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"],\"f\":3,\"g\":{}}", json);
262 }
263
TEST(TraceEventArgumentTest,NanAndInfinityJSON)264 TEST(TraceEventArgumentTest, NanAndInfinityJSON) {
265 TracedValueJSON value;
266 value.SetDouble("nan", std::nan(""));
267 value.SetDouble("infinity", INFINITY);
268 value.SetDouble("negInfinity", -INFINITY);
269 std::string json;
270 value.AppendAsTraceFormat(&json);
271 EXPECT_EQ(
272 "{\"nan\":\"NaN\",\"infinity\":\"Infinity\","
273 "\"negInfinity\":\"-Infinity\"}",
274 json);
275
276 std::string formatted_json = value.ToFormattedJSON();
277 // Remove CR and LF to make the result platform-independent.
278 ReplaceChars(formatted_json, "\n\r", "", &formatted_json);
279 EXPECT_EQ(
280 "{"
281 " \"infinity\": \"Infinity\","
282 " \"nan\": \"NaN\","
283 " \"negInfinity\": \"-Infinity\""
284 "}",
285 formatted_json);
286 }
287
288 } // namespace trace_event
289 } // namespace base
290