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