Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(173)

Side by Side Diff: components/safe_json/json_sanitizer_unittest.cc

Issue 1203083002: Add a JSON sanitizer. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: x Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
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/bind.h"
6 #include "base/json/json_reader.h"
7 #include "base/json/json_writer.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/values.h"
12 #include "components/safe_json/json_sanitizer.h"
13 #include "components/safe_json/safe_json_parser.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 #if !defined(OS_ANDROID)
17 #include "components/safe_json/testing_json_parser.h"
18 #endif
19
20 namespace safe_json {
21
22 class JsonSanitizerTest : public ::testing::Test {
23 public:
24 void SetUp() override {
25 sanitizer_ = JsonSanitizer::Create(
26 base::Bind(&JsonSanitizerTest::OnSuccess,
27 base::Unretained(this)),
28 base::Bind(&JsonSanitizerTest::OnError, base::Unretained(this)));
29 }
30
31 void TearDown() override {
32 // Flush any tasks from the message loop to avoid leaks.
33 base::RunLoop().RunUntilIdle();
34 }
35
36 protected:
37 void CheckSuccess(const std::string& json);
38 void CheckError(const std::string& json);
39
40 private:
41 enum class State {
42 // ERROR is a #define on Windows, so we prefix the values with STATE_.
43 STATE_IDLE,
44 STATE_SUCCESS,
45 STATE_ERROR,
46 };
47
48 void Sanitize(const std::string& json);
49
50 void OnSuccess(const std::string& json);
51 void OnError(const std::string& error);
52
53 base::MessageLoop message_loop_;
54
55 #if !defined(OS_ANDROID)
56 safe_json::TestingJsonParser::ScopedFactoryOverride factory_override_;
57 #endif
58
59 scoped_ptr<JsonSanitizer> sanitizer_;
60
61 std::string result_;
62 std::string error_;
63 State state_;
64
65 scoped_ptr<base::RunLoop> run_loop_;
66 };
67
68 void JsonSanitizerTest::CheckSuccess(const std::string& json) {
69 SCOPED_TRACE(json);
70 Sanitize(json);
71 scoped_ptr<base::Value> parsed = base::JSONReader::Read(json);
72 ASSERT_TRUE(parsed);
73 EXPECT_EQ(State::STATE_SUCCESS, state_) << "Error: " << error_;
74
75 // The JSON parser should accept the result.
76 int error_code;
77 std::string error;
78 scoped_ptr<base::Value> reparsed = base::JSONReader::ReadAndReturnError(
79 result_, base::JSON_PARSE_RFC, &error_code, &error);
80 EXPECT_TRUE(reparsed)
81 << "Invalid result: " << error;
82
83 // The parsed values should be equal.
84 EXPECT_TRUE(reparsed->Equals(parsed.get()));
85 }
86
87 void JsonSanitizerTest::CheckError(const std::string& json) {
88 SCOPED_TRACE(json);
89 Sanitize(json);
90 EXPECT_EQ(State::STATE_ERROR, state_) << "Result: " << result_;
91 }
92
93 void JsonSanitizerTest::Sanitize(const std::string& json) {
94 state_ = State::STATE_IDLE;
95 result_.clear();
96 error_.clear();
97 run_loop_.reset(new base::RunLoop);
98 sanitizer_->Start(json);
99
100 // We should never get a result immediately.
101 EXPECT_EQ(State::STATE_IDLE, state_);
102 run_loop_->Run();
103 }
104
105 void JsonSanitizerTest::OnSuccess(const std::string& json) {
106 ASSERT_EQ(State::STATE_IDLE, state_);
107 state_ = State::STATE_SUCCESS;
108 result_ = json;
109 run_loop_->Quit();
110 }
111
112 void JsonSanitizerTest::OnError(const std::string& error) {
113 ASSERT_EQ(State::STATE_IDLE, state_);
114 state_ = State::STATE_ERROR;
115 error_ = error;
116 run_loop_->Quit();
117 }
118
119 TEST_F(JsonSanitizerTest, Json) {
120 // Valid JSON:
121 CheckSuccess("{\n \"foo\": \"bar\"\n}");
122 CheckSuccess("[true]");
123 CheckSuccess("[42]");
124 CheckSuccess("[3.14]");
125 CheckSuccess("[4.0]");
126 CheckSuccess("[null]");
127 CheckSuccess("[\"foo\", \"bar\"]");
128
129 // JSON syntax errors:
130 CheckError("");
131 CheckError("[");
132 CheckError("null");
133
134 // Unterminated array.
135 CheckError("[1,2,3,]");
136 }
137
138 TEST_F(JsonSanitizerTest, Nesting) {
139 // 99 nested arrays are fine.
140 std::string nested(99u, '[');
141 nested.append(99u, ']');
142 CheckSuccess(nested);
143
144 // 100 nested arrays is too much.
145 CheckError(std::string(100u, '[') + std::string(100u, ']'));
146 }
147
148 TEST_F(JsonSanitizerTest, Unicode) {
149 // Non-ASCII characters encoded either directly as UTF-8 or escaped as UTF-16:
150 CheckSuccess("[\"☃\"]");
151 CheckSuccess("[\"\\u2603\"]");
152 CheckSuccess("[\"😃\"]");
153 CheckSuccess("[\"\\ud83d\\ude03\"]");
154
155 // Malformed UTF-8:
156 // A continuation byte outside of a sequence.
157 CheckError("[\"\x80\"]");
158
159 // A start byte that is missing a continuation byte.
160 CheckError("[\"\xc0\"]");
161
162 // An invalid byte in UTF-8.
163 CheckError("[\"\xfe\"]");
164
165 // An overlong encoding (of the letter 'A').
166 CheckError("[\"\xc1\x81\"]");
167
168 // U+D83D, a code point reserved for (high) surrogates.
169 CheckError("[\"\xed\xa0\xbd\"]");
170
171 // U+4567890, a code point outside of the valid range for Unicode.
172 CheckError("[\"\xfc\x84\x95\xa7\xa2\x90\"]");
173
174 // Malformed escaped UTF-16:
175 // An unmatched high surrogate.
176 CheckError("[\"\\ud83d\"]");
177
178 // An unmatched low surrogate.
179 CheckError("[\"\\ude03\"]");
180
181 // A low surrogate followed by a high surrogate.
182 CheckError("[\"\\ude03\\ud83d\"]");
183
184 // Valid escaped UTF-16 that encodes non-characters:
185 CheckError("[\"\\ufdd0\"]");
186 CheckError("[\"\\ufffe\"]");
187 CheckError("[\"\\ud83f\\udffe\"]");
188 }
189
190 } // namespace safe_json
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698