bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 1 | // Copyright 2014 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 | |
dcheng | 4af4858 | 2016-04-19 00:29:35 | [diff] [blame] | 5 | #include <memory> |
| 6 | |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 7 | #include "base/bind.h" |
| 8 | #include "base/json/json_reader.h" |
| 9 | #include "base/json/json_writer.h" |
Gabriel Charette | b164afef | 2017-11-21 20:59:31 | [diff] [blame] | 10 | #include "base/run_loop.h" |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 11 | #include "base/values.h" |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 12 | #include "chrome/test/base/in_process_browser_test.h" |
Jay Civelli | 90a4cb1 | 2017-11-28 21:04:52 | [diff] [blame] | 13 | #include "chrome/test/base/test_service_manager_listener.h" |
Jay Civelli | ab99a9c | 2017-10-13 17:48:23 | [diff] [blame] | 14 | #include "content/public/common/service_manager_connection.h" |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 15 | #include "content/public/test/test_browser_thread_bundle.h" |
| 16 | #include "content/public/test/test_utils.h" |
Jay Civelli | ab99a9c | 2017-10-13 17:48:23 | [diff] [blame] | 17 | #include "services/data_decoder/public/cpp/safe_json_parser.h" |
Ken Rockot | 19db638 | 2018-02-10 01:41:02 | [diff] [blame] | 18 | #include "services/data_decoder/public/mojom/constants.mojom.h" |
| 19 | #include "services/data_decoder/public/mojom/json_parser.mojom.h" |
Jay Civelli | d8dc7c6 | 2017-11-02 02:10:41 | [diff] [blame] | 20 | #include "services/service_manager/public/cpp/connector.h" |
Ken Rockot | 543f5e3 | 2018-02-04 02:13:50 | [diff] [blame] | 21 | #include "services/service_manager/public/mojom/service_manager.mojom.h" |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 22 | |
| 23 | namespace { |
| 24 | |
Jay Civelli | ab99a9c | 2017-10-13 17:48:23 | [diff] [blame] | 25 | using data_decoder::SafeJsonParser; |
eranm | b795155 | 2015-06-03 08:38:13 | [diff] [blame] | 26 | |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 27 | std::string MaybeToJson(const base::Value* value) { |
| 28 | if (!value) |
| 29 | return "(null)"; |
| 30 | |
| 31 | std::string json; |
estade | 8d04646 | 2015-05-16 01:02:34 | [diff] [blame] | 32 | if (!base::JSONWriter::Write(*value, &json)) |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 33 | return "(invalid value)"; |
| 34 | |
| 35 | return json; |
| 36 | } |
| 37 | |
Jay Civelli | d8dc7c6 | 2017-11-02 02:10:41 | [diff] [blame] | 38 | class ParseCallback { |
| 39 | public: |
| 40 | explicit ParseCallback(base::Closure callback) : callback_(callback) {} |
| 41 | |
| 42 | void OnSuccess(std::unique_ptr<base::Value> value) { |
| 43 | success_ = true; |
| 44 | callback_.Run(); |
| 45 | } |
| 46 | |
| 47 | void OnError(const std::string& error) { |
| 48 | success_ = false; |
| 49 | callback_.Run(); |
| 50 | } |
| 51 | |
| 52 | bool success() const { return success_; } |
| 53 | |
| 54 | private: |
| 55 | bool success_ = false; |
| 56 | base::Closure callback_; |
| 57 | |
| 58 | DISALLOW_COPY_AND_ASSIGN(ParseCallback); |
| 59 | }; |
Jay Civelli | d8dc7c6 | 2017-11-02 02:10:41 | [diff] [blame] | 60 | |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 61 | class SafeJsonParserTest : public InProcessBrowserTest { |
| 62 | protected: |
| 63 | void TestParse(const std::string& json) { |
| 64 | SCOPED_TRACE(json); |
| 65 | DCHECK(!message_loop_runner_); |
| 66 | message_loop_runner_ = new content::MessageLoopRunner; |
| 67 | |
| 68 | std::string error; |
dcheng | 4af4858 | 2016-04-19 00:29:35 | [diff] [blame] | 69 | std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError( |
estade | b09312b | 2015-05-22 16:30:13 | [diff] [blame] | 70 | json, base::JSON_PARSE_RFC, nullptr, &error); |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 71 | |
| 72 | SafeJsonParser::SuccessCallback success_callback; |
| 73 | SafeJsonParser::ErrorCallback error_callback; |
| 74 | if (value) { |
| 75 | success_callback = |
| 76 | base::Bind(&SafeJsonParserTest::ExpectValue, base::Unretained(this), |
| 77 | base::Passed(&value)); |
| 78 | error_callback = base::Bind(&SafeJsonParserTest::FailWithError, |
| 79 | base::Unretained(this)); |
| 80 | } else { |
| 81 | success_callback = base::Bind(&SafeJsonParserTest::FailWithValue, |
| 82 | base::Unretained(this)); |
| 83 | error_callback = base::Bind(&SafeJsonParserTest::ExpectError, |
| 84 | base::Unretained(this), error); |
| 85 | } |
Jay Civelli | ab99a9c | 2017-10-13 17:48:23 | [diff] [blame] | 86 | SafeJsonParser::Parse( |
| 87 | content::ServiceManagerConnection::GetForProcess()->GetConnector(), |
| 88 | json, success_callback, error_callback); |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 89 | |
| 90 | message_loop_runner_->Run(); |
| 91 | message_loop_runner_ = nullptr; |
| 92 | } |
| 93 | |
| 94 | private: |
dcheng | 4af4858 | 2016-04-19 00:29:35 | [diff] [blame] | 95 | void ExpectValue(std::unique_ptr<base::Value> expected_value, |
| 96 | std::unique_ptr<base::Value> actual_value) { |
jdoerrie | 8551f92 | 2017-07-25 10:55:13 | [diff] [blame] | 97 | EXPECT_EQ(*expected_value, *actual_value) |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 98 | << "Expected: " << MaybeToJson(expected_value.get()) |
| 99 | << " Actual: " << MaybeToJson(actual_value.get()); |
| 100 | message_loop_runner_->Quit(); |
| 101 | } |
| 102 | |
| 103 | void ExpectError(const std::string& expected_error, |
| 104 | const std::string& actual_error) { |
| 105 | EXPECT_EQ(expected_error, actual_error); |
| 106 | message_loop_runner_->Quit(); |
| 107 | } |
| 108 | |
dcheng | 4af4858 | 2016-04-19 00:29:35 | [diff] [blame] | 109 | void FailWithValue(std::unique_ptr<base::Value> value) { |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 110 | ADD_FAILURE() << MaybeToJson(value.get()); |
| 111 | message_loop_runner_->Quit(); |
| 112 | } |
| 113 | |
| 114 | void FailWithError(const std::string& error) { |
| 115 | ADD_FAILURE() << error; |
| 116 | message_loop_runner_->Quit(); |
| 117 | } |
| 118 | |
| 119 | scoped_refptr<content::MessageLoopRunner> message_loop_runner_; |
| 120 | }; |
| 121 | |
Jay Civelli | d8dc7c6 | 2017-11-02 02:10:41 | [diff] [blame] | 122 | class SafeJsonParserImplTest : public InProcessBrowserTest { |
| 123 | public: |
| 124 | SafeJsonParserImplTest() = default; |
| 125 | |
| 126 | protected: |
| 127 | // InProcessBrowserTest implementation: |
| 128 | void SetUpOnMainThread() override { |
| 129 | InProcessBrowserTest::SetUpOnMainThread(); |
| 130 | |
Jay Civelli | 90a4cb1 | 2017-11-28 21:04:52 | [diff] [blame] | 131 | // Initialize the TestServiceManagerListener so it starts listening for |
| 132 | // service activity. |
| 133 | listener_.Init(); |
Jay Civelli | d8dc7c6 | 2017-11-02 02:10:41 | [diff] [blame] | 134 | |
| 135 | // The data_decoder service will stop if no connection is bound to it after |
| 136 | // 5 seconds. We bind a connection to it for the duration of the test so it |
| 137 | // is guaranteed the service is always running. |
Jay Civelli | 90a4cb1 | 2017-11-28 21:04:52 | [diff] [blame] | 138 | connector()->BindInterface(data_decoder::mojom::kServiceName, |
| 139 | &json_parser_ptr_); |
Jay Civelli | d8dc7c6 | 2017-11-02 02:10:41 | [diff] [blame] | 140 | listener_.WaitUntilServiceStarted(data_decoder::mojom::kServiceName); |
| 141 | EXPECT_EQ( |
| 142 | 1U, listener_.GetServiceStartCount(data_decoder::mojom::kServiceName)); |
| 143 | } |
| 144 | |
Jay Civelli | 90a4cb1 | 2017-11-28 21:04:52 | [diff] [blame] | 145 | service_manager::Connector* connector() const { |
| 146 | return content::ServiceManagerConnection::GetForProcess()->GetConnector(); |
| 147 | } |
Jay Civelli | d8dc7c6 | 2017-11-02 02:10:41 | [diff] [blame] | 148 | |
| 149 | uint32_t GetServiceStartCount(const std::string& service_name) const { |
| 150 | return listener_.GetServiceStartCount(service_name); |
| 151 | } |
| 152 | |
| 153 | private: |
| 154 | data_decoder::mojom::JsonParserPtr json_parser_ptr_; |
Jay Civelli | d8dc7c6 | 2017-11-02 02:10:41 | [diff] [blame] | 155 | TestServiceManagerListener listener_; |
Jay Civelli | d8dc7c6 | 2017-11-02 02:10:41 | [diff] [blame] | 156 | |
| 157 | DISALLOW_COPY_AND_ASSIGN(SafeJsonParserImplTest); |
| 158 | }; |
Jay Civelli | d8dc7c6 | 2017-11-02 02:10:41 | [diff] [blame] | 159 | |
Jay Civelli | 90a4cb1 | 2017-11-28 21:04:52 | [diff] [blame] | 160 | } // namespace |
| 161 | |
Jay Civelli | ab99a9c | 2017-10-13 17:48:23 | [diff] [blame] | 162 | IN_PROC_BROWSER_TEST_F(SafeJsonParserTest, Parse) { |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 163 | TestParse("{}"); |
| 164 | TestParse("choke"); |
| 165 | TestParse("{\"awesome\": true}"); |
| 166 | TestParse("\"laser\""); |
| 167 | TestParse("false"); |
| 168 | TestParse("null"); |
| 169 | TestParse("3.14"); |
| 170 | TestParse("["); |
| 171 | TestParse("\""); |
| 172 | TestParse(std::string()); |
| 173 | TestParse("☃"); |
| 174 | TestParse("\"☃\""); |
bauerb | d7de09a | 2015-07-02 16:20:44 | [diff] [blame] | 175 | TestParse("\"\\ufdd0\""); |
| 176 | TestParse("\"\\ufffe\""); |
| 177 | TestParse("\"\\ud83f\\udffe\""); |
bauerb | 4c2863e | 2015-01-06 00:26:30 | [diff] [blame] | 178 | } |
Jay Civelli | d8dc7c6 | 2017-11-02 02:10:41 | [diff] [blame] | 179 | |
Jay Civelli | d8dc7c6 | 2017-11-02 02:10:41 | [diff] [blame] | 180 | // Tests that when calling SafeJsonParser::Parse() a new service is started |
| 181 | // every time. |
| 182 | IN_PROC_BROWSER_TEST_F(SafeJsonParserImplTest, Isolation) { |
| 183 | for (int i = 0; i < 5; i++) { |
| 184 | base::RunLoop run_loop; |
| 185 | ParseCallback parse_callback(run_loop.QuitClosure()); |
| 186 | SafeJsonParser::Parse( |
| 187 | connector(), "[\"awesome\", \"possum\"]", |
| 188 | base::Bind(&ParseCallback::OnSuccess, |
| 189 | base::Unretained(&parse_callback)), |
| 190 | base::Bind(&ParseCallback::OnError, base::Unretained(&parse_callback))); |
| 191 | run_loop.Run(); |
| 192 | EXPECT_TRUE(parse_callback.success()); |
| 193 | // 2 + i below because the data_decoder is already running and the index |
| 194 | // starts at 0. |
| 195 | EXPECT_EQ(2U + i, GetServiceStartCount(data_decoder::mojom::kServiceName)); |
| 196 | } |
| 197 | } |