blob: d30fa11580f771aa0b1d68c8d4d6c660a3edb6df [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include "base/bind.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/run_loop.h"
#include "base/values.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/test_service_manager_listener.h"
#include "content/public/common/service_manager_connection.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "services/data_decoder/public/cpp/safe_json_parser.h"
#include "services/data_decoder/public/interfaces/constants.mojom.h"
#include "services/data_decoder/public/interfaces/json_parser.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/interfaces/service_manager.mojom.h"
namespace {
using data_decoder::SafeJsonParser;
std::string MaybeToJson(const base::Value* value) {
if (!value)
return "(null)";
std::string json;
if (!base::JSONWriter::Write(*value, &json))
return "(invalid value)";
return json;
}
class ParseCallback {
public:
explicit ParseCallback(base::Closure callback) : callback_(callback) {}
void OnSuccess(std::unique_ptr<base::Value> value) {
success_ = true;
callback_.Run();
}
void OnError(const std::string& error) {
success_ = false;
callback_.Run();
}
bool success() const { return success_; }
private:
bool success_ = false;
base::Closure callback_;
DISALLOW_COPY_AND_ASSIGN(ParseCallback);
};
class SafeJsonParserTest : public InProcessBrowserTest {
protected:
void TestParse(const std::string& json) {
SCOPED_TRACE(json);
DCHECK(!message_loop_runner_);
message_loop_runner_ = new content::MessageLoopRunner;
std::string error;
std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
json, base::JSON_PARSE_RFC, nullptr, &error);
SafeJsonParser::SuccessCallback success_callback;
SafeJsonParser::ErrorCallback error_callback;
if (value) {
success_callback =
base::Bind(&SafeJsonParserTest::ExpectValue, base::Unretained(this),
base::Passed(&value));
error_callback = base::Bind(&SafeJsonParserTest::FailWithError,
base::Unretained(this));
} else {
success_callback = base::Bind(&SafeJsonParserTest::FailWithValue,
base::Unretained(this));
error_callback = base::Bind(&SafeJsonParserTest::ExpectError,
base::Unretained(this), error);
}
SafeJsonParser::Parse(
content::ServiceManagerConnection::GetForProcess()->GetConnector(),
json, success_callback, error_callback);
message_loop_runner_->Run();
message_loop_runner_ = nullptr;
}
private:
void ExpectValue(std::unique_ptr<base::Value> expected_value,
std::unique_ptr<base::Value> actual_value) {
EXPECT_EQ(*expected_value, *actual_value)
<< "Expected: " << MaybeToJson(expected_value.get())
<< " Actual: " << MaybeToJson(actual_value.get());
message_loop_runner_->Quit();
}
void ExpectError(const std::string& expected_error,
const std::string& actual_error) {
EXPECT_EQ(expected_error, actual_error);
message_loop_runner_->Quit();
}
void FailWithValue(std::unique_ptr<base::Value> value) {
ADD_FAILURE() << MaybeToJson(value.get());
message_loop_runner_->Quit();
}
void FailWithError(const std::string& error) {
ADD_FAILURE() << error;
message_loop_runner_->Quit();
}
scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
};
class SafeJsonParserImplTest : public InProcessBrowserTest {
public:
SafeJsonParserImplTest() = default;
protected:
// InProcessBrowserTest implementation:
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
// Initialize the TestServiceManagerListener so it starts listening for
// service activity.
listener_.Init();
// The data_decoder service will stop if no connection is bound to it after
// 5 seconds. We bind a connection to it for the duration of the test so it
// is guaranteed the service is always running.
connector()->BindInterface(data_decoder::mojom::kServiceName,
&json_parser_ptr_);
listener_.WaitUntilServiceStarted(data_decoder::mojom::kServiceName);
EXPECT_EQ(
1U, listener_.GetServiceStartCount(data_decoder::mojom::kServiceName));
}
service_manager::Connector* connector() const {
return content::ServiceManagerConnection::GetForProcess()->GetConnector();
}
uint32_t GetServiceStartCount(const std::string& service_name) const {
return listener_.GetServiceStartCount(service_name);
}
private:
data_decoder::mojom::JsonParserPtr json_parser_ptr_;
TestServiceManagerListener listener_;
DISALLOW_COPY_AND_ASSIGN(SafeJsonParserImplTest);
};
} // namespace
IN_PROC_BROWSER_TEST_F(SafeJsonParserTest, Parse) {
TestParse("{}");
TestParse("choke");
TestParse("{\"awesome\": true}");
TestParse("\"laser\"");
TestParse("false");
TestParse("null");
TestParse("3.14");
TestParse("[");
TestParse("\"");
TestParse(std::string());
TestParse("☃");
TestParse("\"☃\"");
TestParse("\"\\ufdd0\"");
TestParse("\"\\ufffe\"");
TestParse("\"\\ud83f\\udffe\"");
}
// Tests that when calling SafeJsonParser::Parse() a new service is started
// every time.
IN_PROC_BROWSER_TEST_F(SafeJsonParserImplTest, Isolation) {
for (int i = 0; i < 5; i++) {
base::RunLoop run_loop;
ParseCallback parse_callback(run_loop.QuitClosure());
SafeJsonParser::Parse(
connector(), "[\"awesome\", \"possum\"]",
base::Bind(&ParseCallback::OnSuccess,
base::Unretained(&parse_callback)),
base::Bind(&ParseCallback::OnError, base::Unretained(&parse_callback)));
run_loop.Run();
EXPECT_TRUE(parse_callback.success());
// 2 + i below because the data_decoder is already running and the index
// starts at 0.
EXPECT_EQ(2U + i, GetServiceStartCount(data_decoder::mojom::kServiceName));
}
}