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