Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / safe_json / json_sanitizer_unittest.cc
blob0a75ad35380e1bb63c8402acf8251808e07eabef
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.
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"
16 #if !defined(OS_ANDROID)
17 #include "components/safe_json/testing_json_parser.h"
18 #endif
20 namespace safe_json {
22 class JsonSanitizerTest : public ::testing::Test {
23 public:
24 void TearDown() override {
25 // Flush any tasks from the message loop to avoid leaks.
26 base::RunLoop().RunUntilIdle();
29 protected:
30 void CheckSuccess(const std::string& json);
31 void CheckError(const std::string& json);
33 private:
34 enum class State {
35 // ERROR is a #define on Windows, so we prefix the values with STATE_.
36 STATE_IDLE,
37 STATE_SUCCESS,
38 STATE_ERROR,
41 void Sanitize(const std::string& json);
43 void OnSuccess(const std::string& json);
44 void OnError(const std::string& error);
46 base::MessageLoop message_loop_;
48 #if !defined(OS_ANDROID)
49 safe_json::TestingJsonParser::ScopedFactoryOverride factory_override_;
50 #endif
52 std::string result_;
53 std::string error_;
54 State state_;
56 scoped_ptr<base::RunLoop> run_loop_;
59 void JsonSanitizerTest::CheckSuccess(const std::string& json) {
60 SCOPED_TRACE(json);
61 Sanitize(json);
62 scoped_ptr<base::Value> parsed = base::JSONReader::Read(json);
63 ASSERT_TRUE(parsed);
64 EXPECT_EQ(State::STATE_SUCCESS, state_) << "Error: " << error_;
66 // The JSON parser should accept the result.
67 int error_code;
68 std::string error;
69 scoped_ptr<base::Value> reparsed = base::JSONReader::ReadAndReturnError(
70 result_, base::JSON_PARSE_RFC, &error_code, &error);
71 EXPECT_TRUE(reparsed)
72 << "Invalid result: " << error;
74 // The parsed values should be equal.
75 EXPECT_TRUE(reparsed->Equals(parsed.get()));
78 void JsonSanitizerTest::CheckError(const std::string& json) {
79 SCOPED_TRACE(json);
80 Sanitize(json);
81 EXPECT_EQ(State::STATE_ERROR, state_) << "Result: " << result_;
84 void JsonSanitizerTest::Sanitize(const std::string& json) {
85 state_ = State::STATE_IDLE;
86 result_.clear();
87 error_.clear();
88 run_loop_.reset(new base::RunLoop);
89 JsonSanitizer::Sanitize(
90 json,
91 base::Bind(&JsonSanitizerTest::OnSuccess, base::Unretained(this)),
92 base::Bind(&JsonSanitizerTest::OnError, base::Unretained(this)));
94 // We should never get a result immediately.
95 EXPECT_EQ(State::STATE_IDLE, state_);
96 run_loop_->Run();
99 void JsonSanitizerTest::OnSuccess(const std::string& json) {
100 ASSERT_EQ(State::STATE_IDLE, state_);
101 state_ = State::STATE_SUCCESS;
102 result_ = json;
103 run_loop_->Quit();
106 void JsonSanitizerTest::OnError(const std::string& error) {
107 ASSERT_EQ(State::STATE_IDLE, state_);
108 state_ = State::STATE_ERROR;
109 error_ = error;
110 run_loop_->Quit();
113 TEST_F(JsonSanitizerTest, Json) {
114 // Valid JSON:
115 CheckSuccess("{\n \"foo\": \"bar\"\n}");
116 CheckSuccess("[true]");
117 CheckSuccess("[42]");
118 CheckSuccess("[3.14]");
119 CheckSuccess("[4.0]");
120 CheckSuccess("[null]");
121 CheckSuccess("[\"foo\", \"bar\"]");
123 // JSON syntax errors:
124 CheckError("");
125 CheckError("[");
126 CheckError("null");
128 // Unterminated array.
129 CheckError("[1,2,3,]");
132 TEST_F(JsonSanitizerTest, Nesting) {
133 // 99 nested arrays are fine.
134 std::string nested(99u, '[');
135 nested.append(99u, ']');
136 CheckSuccess(nested);
138 // 100 nested arrays is too much.
139 CheckError(std::string(100u, '[') + std::string(100u, ']'));
142 TEST_F(JsonSanitizerTest, Unicode) {
143 // Non-ASCII characters encoded either directly as UTF-8 or escaped as UTF-16:
144 CheckSuccess("[\"\"]");
145 CheckSuccess("[\"\\u2603\"]");
146 CheckSuccess("[\"😃\"]");
147 CheckSuccess("[\"\\ud83d\\ude03\"]");
149 // Malformed UTF-8:
150 // A continuation byte outside of a sequence.
151 CheckError("[\"\x80\"]");
153 // A start byte that is missing a continuation byte.
154 CheckError("[\"\xc0\"]");
156 // An invalid byte in UTF-8.
157 CheckError("[\"\xfe\"]");
159 // An overlong encoding (of the letter 'A').
160 CheckError("[\"\xc1\x81\"]");
162 // U+D83D, a code point reserved for (high) surrogates.
163 CheckError("[\"\xed\xa0\xbd\"]");
165 // U+4567890, a code point outside of the valid range for Unicode.
166 CheckError("[\"\xfc\x84\x95\xa7\xa2\x90\"]");
168 // Malformed escaped UTF-16:
169 // An unmatched high surrogate.
170 CheckError("[\"\\ud83d\"]");
172 // An unmatched low surrogate.
173 CheckError("[\"\\ude03\"]");
175 // A low surrogate followed by a high surrogate.
176 CheckError("[\"\\ude03\\ud83d\"]");
178 // Valid escaped UTF-16 that encodes non-characters:
179 CheckError("[\"\\ufdd0\"]");
180 CheckError("[\"\\ufffe\"]");
181 CheckError("[\"\\ud83f\\udffe\"]");
184 } // namespace safe_json