blob: 96474f4186f8652b6cce51e42f860560e083816a [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/macros.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/token.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/mojom/constants.mojom.h"
#include "services/data_decoder/public/mojom/json_parser.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/mojom/service_manager.mojom.h"
namespace {
using data_decoder::SafeJsonParser;
constexpr char kTestJson[] = "[\"awesome\", \"possum\"]";
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 SafeJsonParserTest : public InProcessBrowserTest {
public:
SafeJsonParserTest() = default;
protected:
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
listener_.Init();
}
// Tests SafeJsonParser::Parse/ParseBatch. Parses |json| using SafeJsonParser
// and verifies that the correct callbacks are called. If |batch_id| is not
// empty, uses SafeJsonParser::ParseBatch to batch multiple parse requests.
void Parse(const std::string& json,
const base::Optional<base::Token>& batch_id = base::nullopt) {
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);
}
if (batch_id) {
SafeJsonParser::ParseBatch(
content::ServiceManagerConnection::GetForProcess()->GetConnector(),
json, success_callback, error_callback, *batch_id);
} else {
SafeJsonParser::Parse(
content::ServiceManagerConnection::GetForProcess()->GetConnector(),
json, success_callback, error_callback);
}
message_loop_runner_->Run();
message_loop_runner_ = nullptr;
}
uint32_t GetServiceStartCount(const std::string& service_name) const {
return listener_.GetServiceStartCount(service_name);
}
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_;
TestServiceManagerListener listener_;
DISALLOW_COPY_AND_ASSIGN(SafeJsonParserTest);
};
} // namespace
IN_PROC_BROWSER_TEST_F(SafeJsonParserTest, Parse) {
Parse("{}");
Parse("choke");
Parse("{\"awesome\": true}");
Parse("\"laser\"");
Parse("false");
Parse("null");
Parse("3.14");
Parse("[");
Parse("\"");
Parse(std::string());
Parse("☃");
Parse("\"☃\"");
Parse("\"\\ufdd0\"");
Parse("\"\\ufffe\"");
Parse("\"\\ud83f\\udffe\"");
}
// Tests that when calling SafeJsonParser::Parse() a new service is started
// every time.
IN_PROC_BROWSER_TEST_F(SafeJsonParserTest, Isolation) {
for (int i = 0; i < 5; i++) {
SCOPED_TRACE(base::StringPrintf("Testing iteration %d", i));
Parse(kTestJson);
EXPECT_EQ(1U + i, GetServiceStartCount(data_decoder::mojom::kServiceName));
}
}
// Tests that using a batch ID allows service reuse.
IN_PROC_BROWSER_TEST_F(SafeJsonParserTest, IsolationWithGroups) {
constexpr base::Token kBatchId1{0, 1};
constexpr base::Token kBatchId2{0, 2};
for (int i = 0; i < 5; i++) {
SCOPED_TRACE(base::StringPrintf("Testing iteration %d", i));
Parse(kTestJson, kBatchId1);
Parse(kTestJson, kBatchId2);
}
EXPECT_EQ(2U, GetServiceStartCount(data_decoder::mojom::kServiceName));
}