xref: /aosp_15_r20/external/cronet/base/json/json_writer_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 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/json/json_writer.h"
6 
7 #include <optional>
8 
9 #include "base/containers/span.h"
10 #include "base/json/json_reader.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/test/gmock_expected_support.h"
13 #include "base/values.h"
14 #include "build/build_config.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 #if BUILDFLAG(IS_WIN)
18 #include "base/strings/string_util.h"
19 #endif
20 
21 namespace base {
22 
23 namespace {
24 
FixNewlines(const std::string & json)25 std::string FixNewlines(const std::string& json) {
26   // The pretty-printer uses a different newline style on Windows than on
27   // other platforms.
28 #if BUILDFLAG(IS_WIN)
29   std::string result;
30   ReplaceChars(json, "\n", "\r\n", &result);
31   return result;
32 #else
33   return json;
34 #endif
35 }
36 
37 }  // namespace
38 
TEST(JsonWriterTest,BasicTypes)39 TEST(JsonWriterTest, BasicTypes) {
40   // Test null.
41   EXPECT_EQ(WriteJson(Value()), "null");
42 
43   // Test empty dict.
44   EXPECT_EQ(WriteJson(Value(Value::Type::DICT)), "{}");
45 
46   // Test empty list.
47   EXPECT_EQ(WriteJson(Value(Value::Type::LIST)), "[]");
48 
49   // Test integer values.
50   EXPECT_EQ(WriteJson(Value(42)), "42");
51 
52   // Test boolean values.
53   EXPECT_EQ(WriteJson(Value(true)), "true");
54 
55   // Test Real values should always have a decimal or an 'e'.
56   EXPECT_EQ(WriteJson(Value(1.0)), "1.0");
57 
58   // Test Real values in the range (-1, 1) must have leading zeros
59   EXPECT_EQ(WriteJson(Value(0.2)), "0.2");
60 
61   // Test Real values in the range (-1, 1) must have leading zeros
62   EXPECT_EQ(WriteJson(Value(-0.8)), "-0.8");
63 
64   // Test String values.
65   EXPECT_EQ(WriteJson(Value("foo")), "\"foo\"");
66 }
67 
TEST(JsonWriterTest,NestedTypes)68 TEST(JsonWriterTest, NestedTypes) {
69   // Writer unittests like empty list/dict nesting,
70   // list list nesting, etc.
71   auto dict =
72       Value::Dict().Set("list", Value::List()
73                                     .Append(Value::Dict().Set("inner int", 10))
74                                     .Append(Value::Dict())
75                                     .Append(Value::List())
76                                     .Append(true));
77 
78   EXPECT_EQ(WriteJson(dict), "{\"list\":[{\"inner int\":10},{},[],true]}");
79 
80   // Test the pretty-printer.
81   EXPECT_EQ(WriteJsonWithOptions(dict, JSONWriter::OPTIONS_PRETTY_PRINT),
82             FixNewlines(R"({
83    "list": [ {
84       "inner int": 10
85    }, {
86    }, [  ], true ]
87 }
88 )"));
89 }
90 
TEST(JsonWriterTest,KeysWithPeriods)91 TEST(JsonWriterTest, KeysWithPeriods) {
92   EXPECT_EQ(WriteJson(Value::Dict()  //
93                           .Set("a.b", 3)
94                           .Set("c", 2)
95                           .Set("d.e.f", Value::Dict().Set("g.h.i.j", 1))),
96             R"({"a.b":3,"c":2,"d.e.f":{"g.h.i.j":1}})");
97 
98   EXPECT_EQ(WriteJson(Value::Dict()  //
99                           .SetByDottedPath("a.b", 2)
100                           .Set("a.b", 1)),
101             R"({"a":{"b":2},"a.b":1})");
102 }
103 
TEST(JsonWriterTest,BinaryValues)104 TEST(JsonWriterTest, BinaryValues) {
105   const auto kBinaryData = base::as_bytes(base::make_span("asdf", 4u));
106 
107   // Binary values should return errors unless suppressed via the
108   // `OPTIONS_OMIT_BINARY_VALUES` flag.
109   EXPECT_EQ(WriteJson(Value(kBinaryData)), std::nullopt);
110   EXPECT_EQ(WriteJsonWithOptions(Value(kBinaryData),
111                                  JsonOptions::OPTIONS_OMIT_BINARY_VALUES),
112             "");
113 
114   auto binary_list = Value::List()
115                          .Append(Value(kBinaryData))
116                          .Append(5)
117                          .Append(Value(kBinaryData))
118                          .Append(2)
119                          .Append(Value(kBinaryData));
120   EXPECT_EQ(WriteJson(binary_list), std::nullopt);
121   EXPECT_EQ(
122       WriteJsonWithOptions(binary_list, JSONWriter::OPTIONS_OMIT_BINARY_VALUES),
123       "[5,2]");
124 
125   auto binary_dict = Value::Dict()
126                          .Set("a", Value(kBinaryData))
127                          .Set("b", 5)
128                          .Set("c", Value(kBinaryData))
129                          .Set("d", 2)
130                          .Set("e", Value(kBinaryData));
131   EXPECT_EQ(WriteJson(binary_dict), std::nullopt);
132   EXPECT_EQ(
133       WriteJsonWithOptions(binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES),
134       R"({"b":5,"d":2})");
135 }
136 
TEST(JsonWriterTest,DoublesAsInts)137 TEST(JsonWriterTest, DoublesAsInts) {
138   // Test allowing a double with no fractional part to be written as an integer.
139   Value double_value(1e10);
140   EXPECT_EQ(
141       WriteJsonWithOptions(double_value,
142                            JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION),
143       "10000000000");
144 }
145 
TEST(JsonWriterTest,StackOverflow)146 TEST(JsonWriterTest, StackOverflow) {
147   Value::List deep_list;
148   const size_t max_depth = 100000;
149 
150   for (size_t i = 0; i < max_depth; ++i) {
151     Value::List new_top_list;
152     new_top_list.Append(std::move(deep_list));
153     deep_list = std::move(new_top_list);
154   }
155 
156   Value deep_list_value(std::move(deep_list));
157   EXPECT_EQ(WriteJson(deep_list_value), std::nullopt);
158   EXPECT_EQ(
159       WriteJsonWithOptions(deep_list_value, JSONWriter::OPTIONS_PRETTY_PRINT),
160       std::nullopt);
161 
162   // We cannot just let `deep_list` tear down since it
163   // would cause a stack overflow. Therefore, we tear
164   // down the deep list manually.
165   deep_list = std::move(deep_list_value).TakeList();
166   while (!deep_list.empty()) {
167     DCHECK_EQ(deep_list.size(), 1u);
168     Value::List inner_list = std::move(deep_list[0]).TakeList();
169     deep_list = std::move(inner_list);
170   }
171 }
172 
TEST(JsonWriterTest,TestMaxDepthWithValidNodes)173 TEST(JsonWriterTest, TestMaxDepthWithValidNodes) {
174   // Create JSON to the max depth - 1.  Nodes at that depth are still valid
175   // for writing which matches the JSONParser logic.
176   std::string nested_json;
177   for (int i = 0; i < 199; ++i) {
178     std::string node = "[";
179     for (int j = 0; j < 5; j++) {
180       node.append(StringPrintf("%d,", j));
181     }
182     nested_json.insert(0, node);
183     nested_json.append("]");
184   }
185 
186   // Ensure we can read and write the JSON
187   ASSERT_OK_AND_ASSIGN(Value value,
188                        JSONReader::ReadAndReturnValueWithError(
189                            nested_json, JSON_ALLOW_TRAILING_COMMAS));
190   EXPECT_TRUE(WriteJson(std::move(value)).has_value());
191 }
192 
193 // Test that the JSONWriter::Write method still works.
TEST(JsonWriterTest,JSONWriterWriteSuccess)194 TEST(JsonWriterTest, JSONWriterWriteSuccess) {
195   std::string output_js;
196 
197   EXPECT_TRUE(
198       JSONWriter::Write(base::Value::Dict().Set("key", "value"), &output_js));
199   EXPECT_EQ(output_js, R"({"key":"value"})");
200 }
201 
202 // Test that the JSONWriter::Write method still works.
TEST(JsonWriterTest,JSONWriterWriteFailure)203 TEST(JsonWriterTest, JSONWriterWriteFailure) {
204   std::string output_js;
205 
206   EXPECT_FALSE(JSONWriter::Write(
207       base::Value::Dict()  //
208           .Set("key",
209                base::Value::Dict().Set("nested-key", base::Value::Dict())),
210       &output_js, /*max_depth=*/1));
211 }
212 
213 // Test that the JSONWriter::WriteWithOptions method still works.
TEST(JsonWriterTest,JSONWriterWriteWithOptionsSuccess)214 TEST(JsonWriterTest, JSONWriterWriteWithOptionsSuccess) {
215   std::string output_js;
216   EXPECT_TRUE(JSONWriter::WriteWithOptions(
217       base::Value::Dict().Set("key", "value"), JSONWriter::OPTIONS_PRETTY_PRINT,
218       &output_js));
219   EXPECT_EQ(output_js, FixNewlines(R"({
220    "key": "value"
221 }
222 )"));
223 }
224 
225 // Test that the JSONWriter::WriteWithOptions method still works.
TEST(JsonWriterTest,JSONWriterWriteWithOptionsFailure)226 TEST(JsonWriterTest, JSONWriterWriteWithOptionsFailure) {
227   std::string output_js;
228 
229   EXPECT_FALSE(JSONWriter::WriteWithOptions(
230       base::Value::Dict().Set(
231           "key", base::Value::Dict().Set("nested-key", base::Value::Dict())),
232       JSONWriter::OPTIONS_PRETTY_PRINT, &output_js, /*max_depth=*/1));
233 }
234 
235 }  // namespace base
236