Commit c7a025a7 authored by Junbo Ke's avatar Junbo Ke Committed by Chromium LUCI CQ

[Chromecast] Avoid using heap allocated base::Value in DeviceCapabilities.

Also migrated off base::DictionaryValue.

Bug: internal b/156555613
Merge-With: eureka-internal/514526
Merge-With: eureka-internal/514525
Merge-With: eureka-internal/514524
Merge-With: eureka-internal/514186
Merge-With: eureka-internal/513401
Merge-With: eureka-internal/513298
Merge-With: eureka-internal/513381
Merge-With: eureka-internal/513294
Merge-With: eureka-internal/513296
Merge-With: eureka-internal/513299
Test: cast_base_unittests
Change-Id: If06e412cd0d8eab2374e6567a87832d6a225d9a7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2612108
Commit-Queue: Junbo Ke <juke@chromium.org>
Reviewed-by: default avatarSean Topping <seantopping@chromium.org>
Reviewed-by: default avatarLuke Halliwell (slow) <halliwell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#846411}
parent 2ea79437
......@@ -10,11 +10,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
namespace base {
class DictionaryValue;
class Value;
}
#include "base/values.h"
namespace chromecast {
......@@ -84,7 +80,7 @@ class DeviceCapabilities {
// to it must be handled serially. Returns response through
// SetPublicValidatedValue() or SetPrivateValidatedValue().
virtual void Validate(const std::string& path,
std::unique_ptr<base::Value> proposed_value) = 0;
base::Value proposed_value) = 0;
protected:
explicit Validator(DeviceCapabilities* capabilities);
......@@ -99,9 +95,9 @@ class DeviceCapabilities {
// TODO(seantopping): Change this interface so that Validators are not the
// only means of accessing private capabilities.
void SetPublicValidatedValue(const std::string& path,
std::unique_ptr<base::Value> new_value) const;
base::Value new_value) const;
void SetPrivateValidatedValue(const std::string& path,
std::unique_ptr<base::Value> new_value) const;
base::Value new_value) const;
private:
DeviceCapabilities* const capabilities_;
......@@ -115,9 +111,7 @@ class DeviceCapabilities {
class Data : public base::RefCountedThreadSafe<Data> {
public:
// Accessor for complete capabilities in dictionary format.
const base::DictionaryValue& dictionary() const {
return *dictionary_.get();
}
const base::Value& dictionary() const { return dictionary_; }
// Accessor for complete capabilities string in JSON format.
const std::string& json_string() const { return json_string_; }
......@@ -131,11 +125,11 @@ class DeviceCapabilities {
// Constructs empty dictionary with no capabilities.
Data();
// Uses |dictionary| as capabilities dictionary.
explicit Data(std::unique_ptr<const base::DictionaryValue> dictionary);
explicit Data(base::Value dictionary);
~Data();
const std::unique_ptr<const base::DictionaryValue> dictionary_;
const std::string json_string_;
const base::Value dictionary_;
std::string json_string_;
DISALLOW_COPY_AND_ASSIGN(Data);
};
......@@ -196,8 +190,7 @@ class DeviceCapabilities {
// Returns a deep copy of the value at |path|. If the capability at |path|
// does not exist, a null scoped_ptr is returned.
virtual std::unique_ptr<base::Value> GetCapability(
const std::string& path) const = 0;
virtual base::Value GetCapability(const std::string& path) const = 0;
// Use this method to access dictionary and JSON string. No deep copying is
// performed, so this method is inexpensive. Note that any capability updates
......@@ -223,11 +216,11 @@ class DeviceCapabilities {
// classify the value as public or private via SetPublicValidatedValue() or
// SetPrivateValidatedValue() respectively.
virtual void SetCapability(const std::string& path,
std::unique_ptr<base::Value> proposed_value) = 0;
base::Value proposed_value) = 0;
// Iterates through entries in |dict_value| and calls SetCapability() for
// each one. This method is asynchronous.
virtual void MergeDictionary(const base::DictionaryValue& dict_value) = 0;
virtual void MergeDictionary(const base::Value& dict_value) = 0;
// Adds/removes an observer. It doesn't take the ownership of |observer|.
virtual void AddCapabilitiesObserver(Observer* observer) = 0;
......@@ -241,20 +234,17 @@ class DeviceCapabilities {
// Creates empty dictionary with no capabilities.
static scoped_refptr<Data> CreateData();
// Uses |dictionary| as capabilities dictionary.
static scoped_refptr<Data> CreateData(
std::unique_ptr<const base::DictionaryValue> dictionary);
static scoped_refptr<Data> CreateData(base::Value dictionary);
private:
// Internally update the capability residing at |path| to |new_value|. This
// capability will be visible in GetAllData() and GetPublicData().
virtual void SetPublicValidatedValue(
const std::string& path,
std::unique_ptr<base::Value> new_value) = 0;
virtual void SetPublicValidatedValue(const std::string& path,
base::Value new_value) = 0;
// Similar to SetPublicValidatedValue(), but this capability will only be
// visible in GetAllData().
virtual void SetPrivateValidatedValue(
const std::string& path,
std::unique_ptr<base::Value> new_value) = 0;
virtual void SetPrivateValidatedValue(const std::string& path,
base::Value new_value) = 0;
DISALLOW_COPY_AND_ASSIGN(DeviceCapabilities);
};
......
......@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
......@@ -64,14 +65,10 @@ std::unique_ptr<DeviceCapabilities> DeviceCapabilities::Create() {
// static
std::unique_ptr<DeviceCapabilities> DeviceCapabilities::CreateForTesting() {
DeviceCapabilities* capabilities = new DeviceCapabilitiesImpl;
capabilities->SetCapability(kKeyBluetoothSupported,
std::make_unique<base::Value>(false));
capabilities->SetCapability(kKeyDisplaySupported,
std::make_unique<base::Value>(true));
capabilities->SetCapability(kKeyHiResAudioSupported,
std::make_unique<base::Value>(false));
capabilities->SetCapability(kKeyAssistantSupported,
std::make_unique<base::Value>(true));
capabilities->SetCapability(kKeyBluetoothSupported, base::Value(false));
capabilities->SetCapability(kKeyDisplaySupported, base::Value(true));
capabilities->SetCapability(kKeyHiResAudioSupported, base::Value(false));
capabilities->SetCapability(kKeyAssistantSupported, base::Value(true));
return base::WrapUnique(capabilities);
}
......@@ -80,8 +77,8 @@ scoped_refptr<DeviceCapabilities::Data> DeviceCapabilities::CreateData() {
}
scoped_refptr<DeviceCapabilities::Data> DeviceCapabilities::CreateData(
std::unique_ptr<const base::DictionaryValue> dictionary) {
DCHECK(dictionary.get());
base::Value dictionary) {
DCHECK(dictionary.is_dict());
return base::WrapRefCounted(new Data(std::move(dictionary)));
}
......@@ -92,25 +89,24 @@ DeviceCapabilities::Validator::Validator(DeviceCapabilities* capabilities)
void DeviceCapabilities::Validator::SetPublicValidatedValue(
const std::string& path,
std::unique_ptr<base::Value> new_value) const {
base::Value new_value) const {
capabilities_->SetPublicValidatedValue(path, std::move(new_value));
}
void DeviceCapabilities::Validator::SetPrivateValidatedValue(
const std::string& path,
std::unique_ptr<base::Value> new_value) const {
base::Value new_value) const {
capabilities_->SetPrivateValidatedValue(path, std::move(new_value));
}
DeviceCapabilities::Data::Data()
: dictionary_(new base::DictionaryValue),
json_string_(*SerializeToJson(*dictionary_)) {}
DeviceCapabilities::Data::Data() : dictionary_(base::Value::Type::DICTIONARY) {
base::JSONWriter::Write(dictionary_, &json_string_);
}
DeviceCapabilities::Data::Data(
std::unique_ptr<const base::DictionaryValue> dictionary)
: dictionary_(std::move(dictionary)),
json_string_(*SerializeToJson(*dictionary_)) {
DCHECK(dictionary_.get());
DeviceCapabilities::Data::Data(base::Value dictionary)
: dictionary_(std::move(dictionary)) {
DCHECK(dictionary_.is_dict());
base::JSONWriter::Write(dictionary_, &json_string_);
}
DeviceCapabilitiesImpl::Data::~Data() {}
......@@ -129,7 +125,7 @@ DeviceCapabilitiesImpl::ValidatorInfo::~ValidatorInfo() {
void DeviceCapabilitiesImpl::ValidatorInfo::Validate(
const std::string& path,
std::unique_ptr<base::Value> proposed_value) const {
base::Value proposed_value) const {
// Check that we are running Validate on the same thread that ValidatorInfo
// was constructed on.
DCHECK(task_runner_->BelongsToCurrentThread());
......@@ -195,46 +191,41 @@ DeviceCapabilities::Validator* DeviceCapabilitiesImpl::GetValidator(
bool DeviceCapabilitiesImpl::BluetoothSupported() const {
scoped_refptr<Data> data_ref = GetAllData();
bool bluetooth_supported = false;
bool found_key = data_ref->dictionary().GetBoolean(kKeyBluetoothSupported,
&bluetooth_supported);
DCHECK(found_key);
return bluetooth_supported;
auto bluetooth_supported =
data_ref->dictionary().FindBoolKey(kKeyBluetoothSupported);
DCHECK(bluetooth_supported);
return *bluetooth_supported;
}
bool DeviceCapabilitiesImpl::DisplaySupported() const {
scoped_refptr<Data> data_ref = GetAllData();
bool display_supported = false;
bool found_key = data_ref->dictionary().GetBoolean(kKeyDisplaySupported,
&display_supported);
DCHECK(found_key);
return display_supported;
auto display_supported =
data_ref->dictionary().FindBoolKey(kKeyDisplaySupported);
DCHECK(display_supported);
return *display_supported;
}
bool DeviceCapabilitiesImpl::HiResAudioSupported() const {
scoped_refptr<Data> data_ref = GetAllData();
bool hi_res_audio_supported = false;
bool found_key = data_ref->dictionary().GetBoolean(kKeyHiResAudioSupported,
&hi_res_audio_supported);
DCHECK(found_key);
return hi_res_audio_supported;
auto hi_res_audio_supported =
data_ref->dictionary().FindBoolKey(kKeyHiResAudioSupported);
DCHECK(hi_res_audio_supported);
return *hi_res_audio_supported;
}
bool DeviceCapabilitiesImpl::AssistantSupported() const {
scoped_refptr<Data> data_ref = GetAllData();
bool assistant_supported = false;
bool found_key = data_ref->dictionary().GetBoolean(kKeyAssistantSupported,
&assistant_supported);
DCHECK(found_key);
return assistant_supported;
auto assistant_supported =
data_ref->dictionary().FindBoolKey(kKeyAssistantSupported);
DCHECK(assistant_supported);
return *assistant_supported;
}
std::unique_ptr<base::Value> DeviceCapabilitiesImpl::GetCapability(
base::Value DeviceCapabilitiesImpl::GetCapability(
const std::string& path) const {
scoped_refptr<Data> data_ref = GetAllData();
const base::Value* value = nullptr;
bool found_path = data_ref->dictionary().Get(path, &value);
return found_path ? value->CreateDeepCopy() : std::unique_ptr<base::Value>();
const base::Value* value = data_ref->dictionary().FindPath(path);
return value ? value->Clone() : base::Value();
}
scoped_refptr<DeviceCapabilities::Data> DeviceCapabilitiesImpl::GetAllData()
......@@ -255,10 +246,8 @@ scoped_refptr<DeviceCapabilities::Data> DeviceCapabilitiesImpl::GetPublicData()
return public_data_;
}
void DeviceCapabilitiesImpl::SetCapability(
const std::string& path,
std::unique_ptr<base::Value> proposed_value) {
DCHECK(proposed_value.get());
void DeviceCapabilitiesImpl::SetCapability(const std::string& path,
base::Value proposed_value) {
if (!IsValidPath(path)) {
LOG(DFATAL) << "Invalid capability path encountered for SetCapability()";
return;
......@@ -290,11 +279,10 @@ void DeviceCapabilitiesImpl::SetCapability(
SetPublicValidatedValue(path, std::move(proposed_value));
}
void DeviceCapabilitiesImpl::MergeDictionary(
const base::DictionaryValue& dict_value) {
for (base::DictionaryValue::Iterator it(dict_value); !it.IsAtEnd();
it.Advance()) {
SetCapability(it.key(), it.value().CreateDeepCopy());
void DeviceCapabilitiesImpl::MergeDictionary(const base::Value& dict_value) {
DCHECK(dict_value.is_dict());
for (const auto& kv : dict_value.DictItems()) {
SetCapability(kv.first, kv.second.Clone());
}
}
......@@ -308,9 +296,8 @@ void DeviceCapabilitiesImpl::RemoveCapabilitiesObserver(Observer* observer) {
observer_list_->RemoveObserver(observer);
}
void DeviceCapabilitiesImpl::SetPublicValidatedValue(
const std::string& path,
std::unique_ptr<base::Value> new_value) {
void DeviceCapabilitiesImpl::SetPublicValidatedValue(const std::string& path,
base::Value new_value) {
// All internal writes/modifications of capabilities must occur on same
// thread to avoid race conditions.
if (!task_runner_for_writes_->BelongsToCurrentThread()) {
......@@ -322,13 +309,12 @@ void DeviceCapabilitiesImpl::SetPublicValidatedValue(
}
DCHECK(IsValidPath(path));
DCHECK(new_value.get());
// If the capability exists, it must be public (present in all_data_ and
// public_data_). We cannot change the privacy of an already existing
// capability.
bool is_private = all_data_->dictionary().HasKey(path) &&
!public_data_->dictionary().HasKey(path);
bool is_private = all_data_->dictionary().FindKey(path) &&
!public_data_->dictionary().FindKey(path);
if (is_private) {
NOTREACHED() << "Cannot make a private capability '" << path << "' public.";
return;
......@@ -337,10 +323,8 @@ void DeviceCapabilitiesImpl::SetPublicValidatedValue(
// We don't need to acquire lock here when reading public_data_ because we
// know that all writes to public_data_ must occur serially on thread that
// we're on.
const base::Value* cur_value = nullptr;
bool capability_unchanged =
public_data_->dictionary().Get(path, &cur_value) &&
cur_value->Equals(new_value.get());
const base::Value* cur_value = public_data_->dictionary().FindPath(path);
bool capability_unchanged = cur_value && *cur_value == new_value;
if (capability_unchanged) {
DVLOG(1) << "Ignoring unchanged public capability: " << path;
return;
......@@ -352,7 +336,7 @@ void DeviceCapabilitiesImpl::SetPublicValidatedValue(
// dictionary directly, there may be expensive writes that block other
// threads.
scoped_refptr<Data> new_public_data = GenerateDataWithNewValue(
public_data_->dictionary(), path, new_value->CreateDeepCopy());
public_data_->dictionary(), path, new_value.Clone());
scoped_refptr<Data> new_data = GenerateDataWithNewValue(
all_data_->dictionary(), path, std::move(new_value));
......@@ -371,9 +355,8 @@ void DeviceCapabilitiesImpl::SetPublicValidatedValue(
observer_list_->Notify(FROM_HERE, &Observer::OnCapabilitiesChanged, path);
}
void DeviceCapabilitiesImpl::SetPrivateValidatedValue(
const std::string& path,
std::unique_ptr<base::Value> new_value) {
void DeviceCapabilitiesImpl::SetPrivateValidatedValue(const std::string& path,
base::Value new_value) {
// All internal writes/modifications of capabilities must occur on same
// thread to avoid race conditions.
if (!task_runner_for_writes_->BelongsToCurrentThread()) {
......@@ -385,11 +368,10 @@ void DeviceCapabilitiesImpl::SetPrivateValidatedValue(
}
DCHECK(IsValidPath(path));
DCHECK(new_value.get());
// If the capability exists, it must be private (present in all_data_ only).
// We cannot change the privacy of an already existing capability.
bool is_public = public_data_->dictionary().HasKey(path);
const auto* is_public = public_data_->dictionary().FindKey(path);
if (is_public) {
NOTREACHED() << "Cannot make a public capability '" << path << "' private.";
return;
......@@ -397,9 +379,8 @@ void DeviceCapabilitiesImpl::SetPrivateValidatedValue(
// We don't need to acquire lock here when reading all_data_ because we know
// that all writes to all_data_ must occur serially on thread that we're on.
const base::Value* cur_value = nullptr;
bool capability_unchanged = all_data_->dictionary().Get(path, &cur_value) &&
cur_value->Equals(new_value.get());
const base::Value* cur_value = all_data_->dictionary().FindPath(path);
bool capability_unchanged = cur_value && *cur_value == new_value;
if (capability_unchanged) {
DVLOG(1) << "Ignoring unchanged capability: " << path;
return;
......@@ -428,12 +409,11 @@ void DeviceCapabilitiesImpl::SetPrivateValidatedValue(
}
scoped_refptr<DeviceCapabilities::Data>
DeviceCapabilitiesImpl::GenerateDataWithNewValue(
const base::DictionaryValue& dict,
const std::string& path,
std::unique_ptr<base::Value> new_value) {
std::unique_ptr<base::DictionaryValue> dict_deep_copy(dict.CreateDeepCopy());
dict_deep_copy->Set(path, std::move(new_value));
DeviceCapabilitiesImpl::GenerateDataWithNewValue(const base::Value& dict,
const std::string& path,
base::Value new_value) {
base::Value dict_deep_copy(dict.Clone());
dict_deep_copy.SetPath(path, std::move(new_value));
return CreateData(std::move(dict_deep_copy));
}
......
......@@ -33,13 +33,12 @@ class DeviceCapabilitiesImpl : public DeviceCapabilities {
bool BluetoothSupported() const override;
bool DisplaySupported() const override;
bool HiResAudioSupported() const override;
std::unique_ptr<base::Value> GetCapability(
const std::string& path) const override;
base::Value GetCapability(const std::string& path) const override;
scoped_refptr<Data> GetAllData() const override;
scoped_refptr<Data> GetPublicData() const override;
void SetCapability(const std::string& path,
std::unique_ptr<base::Value> proposed_value) override;
void MergeDictionary(const base::DictionaryValue& dict_value) override;
base::Value proposed_value) override;
void MergeDictionary(const base::Value& dict_value) override;
void AddCapabilitiesObserver(Observer* observer) override;
void RemoveCapabilitiesObserver(Observer* observer) override;
......@@ -55,8 +54,7 @@ class DeviceCapabilitiesImpl : public DeviceCapabilities {
return task_runner_;
}
void Validate(const std::string& path,
std::unique_ptr<base::Value> proposed_value) const;
void Validate(const std::string& path, base::Value proposed_value) const;
private:
Validator* const validator_;
......@@ -78,17 +76,15 @@ class DeviceCapabilitiesImpl : public DeviceCapabilities {
DeviceCapabilitiesImpl();
void SetPublicValidatedValue(const std::string& path,
std::unique_ptr<base::Value> new_value) override;
void SetPrivateValidatedValue(
const std::string& path,
std::unique_ptr<base::Value> new_value) override;
base::Value new_value) override;
void SetPrivateValidatedValue(const std::string& path,
base::Value new_value) override;
void SetValidatedValueInternal(const std::string& path,
std::unique_ptr<base::Value> new_value);
base::Value new_value);
scoped_refptr<Data> GenerateDataWithNewValue(
const base::DictionaryValue& dict,
const std::string& path,
std::unique_ptr<base::Value> new_value);
scoped_refptr<Data> GenerateDataWithNewValue(const base::Value& dict,
const std::string& path,
base::Value new_value);
// Lock for reading/writing all_data_ or public_data_ pointers
mutable base::Lock data_lock_;
......
......@@ -7,6 +7,8 @@
#include <string>
#include <utility>
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_pump_type.h"
......@@ -14,7 +16,6 @@
#include "base/single_thread_task_runner.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "chromecast/base/serializers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -28,8 +29,7 @@ const char kSampleDictionaryCapability[] =
" \"dummy_field_int\": 99"
"}";
void GetSampleDefaultCapability(std::string* key,
std::unique_ptr<base::Value>* init_value);
void GetSampleDefaultCapability(std::string* key, base::Value* init_value);
void TestBasicOperations(DeviceCapabilities* capabilities);
// Simple capability manager that implements the Validator interface. Either
......@@ -42,7 +42,7 @@ class FakeCapabilityManagerSimple : public DeviceCapabilities::Validator {
// untouched.
FakeCapabilityManagerSimple(DeviceCapabilities* capabilities,
const std::string& key,
std::unique_ptr<base::Value> init_value,
base::Value init_value,
bool accept_changes,
bool validate_private)
: DeviceCapabilities::Validator(capabilities),
......@@ -50,7 +50,7 @@ class FakeCapabilityManagerSimple : public DeviceCapabilities::Validator {
accept_changes_(accept_changes),
validate_private_(validate_private) {
capabilities->Register(key, this);
if (init_value) {
if (!init_value.is_none()) {
if (validate_private_) {
SetPrivateValidatedValue(key, std::move(init_value));
} else {
......@@ -64,8 +64,7 @@ class FakeCapabilityManagerSimple : public DeviceCapabilities::Validator {
capabilities()->Unregister(key_, this);
}
void Validate(const std::string& path,
std::unique_ptr<base::Value> proposed_value) override {
void Validate(const std::string& path, base::Value proposed_value) override {
ASSERT_EQ(path.find(key_), 0ul);
if (!accept_changes_)
return;
......@@ -98,8 +97,7 @@ class FakeCapabilityManagerComplex : public DeviceCapabilities::Validator {
}
// Runs TestBasicOperations().
void Validate(const std::string& path,
std::unique_ptr<base::Value> proposed_value) override {
void Validate(const std::string& path, base::Value proposed_value) override {
TestBasicOperations(capabilities());
}
......@@ -150,36 +148,34 @@ class MockCapabilitiesObserver : public DeviceCapabilities::Observer {
// Test fixtures needs an example default capability to test DeviceCapabilities
// methods. Gets a sample key and initial value.
void GetSampleDefaultCapability(std::string* key,
std::unique_ptr<base::Value>* init_value) {
void GetSampleDefaultCapability(std::string* key, base::Value* init_value) {
DCHECK(key);
DCHECK(init_value);
*key = DeviceCapabilities::kKeyBluetoothSupported;
*init_value = std::make_unique<base::Value>(true);
*init_value = base::Value(true);
}
// For test fixtures that test dynamic capabilities, gets a sample key
// and initial value.
void GetSampleDynamicCapability(std::string* key,
std::unique_ptr<base::Value>* init_value) {
void GetSampleDynamicCapability(std::string* key, base::Value* init_value) {
DCHECK(key);
DCHECK(init_value);
*key = "dummy_dynamic_key";
*init_value = std::make_unique<base::Value>(99);
*init_value = base::Value(99);
}
// Gets a value for sample default capability different from |init_value|
// returned in GetSampleDefaultCapability(). Must be of same type as
// |init_value| of course.
std::unique_ptr<base::Value> GetSampleDefaultCapabilityNewValue() {
return std::make_unique<base::Value>(false);
base::Value GetSampleDefaultCapabilityNewValue() {
return base::Value(false);
}
// Gets a value for sample dynamic capability different from |init_value|
// returned in GetSampleDynamicCapability(). Must be of same type as
// |init_value| of course.
std::unique_ptr<base::Value> GetSampleDynamicCapabilityNewValue() {
return std::make_unique<base::Value>(100);
base::Value GetSampleDynamicCapabilityNewValue() {
return base::Value(100);
}
// Tests that |json| string matches contents of a DictionaryValue with one entry
......@@ -187,10 +183,10 @@ std::unique_ptr<base::Value> GetSampleDynamicCapabilityNewValue() {
bool JsonStringEquals(const std::string& json,
const std::string& key,
const base::Value& value) {
base::DictionaryValue dict_value;
dict_value.Set(key, value.CreateDeepCopy());
base::Optional<std::string> dict_json = SerializeToJson(dict_value);
return dict_json && *dict_json == json;
base::Value dict_value(base::Value::Type::DICTIONARY);
dict_value.SetKey(key, value.Clone());
std::string dict_json;
return base::JSONWriter::Write(dict_value, &dict_json) && dict_json == json;
}
// The function runs through the set of basic operations of DeviceCapabilities.
......@@ -201,25 +197,25 @@ bool JsonStringEquals(const std::string& json,
// class before this function is called.
void TestBasicOperations(DeviceCapabilities* capabilities) {
std::string key;
std::unique_ptr<base::Value> init_value;
base::Value init_value;
GetSampleDefaultCapability(&key, &init_value);
ASSERT_FALSE(capabilities->GetCapability(key));
ASSERT_TRUE(capabilities->GetCapability(key).is_none());
ASSERT_FALSE(capabilities->GetValidator(key));
// Register and write capability
FakeCapabilityManagerSimple* manager(new FakeCapabilityManagerSimple(
capabilities, key, init_value->CreateDeepCopy(), true, false));
capabilities, key, init_value.Clone(), true, false));
// Read Validator
EXPECT_EQ(capabilities->GetValidator(key), manager);
// Read Capability
EXPECT_EQ(*capabilities->GetCapability(key), *init_value);
EXPECT_EQ(capabilities->GetCapability(key), init_value);
// Unregister
delete manager;
// Write capability again. Provides way of checking that this function
// ran and was successful.
std::unique_ptr<base::Value> new_value = GetSampleDefaultCapabilityNewValue();
base::Value new_value = GetSampleDefaultCapabilityNewValue();
capabilities->SetCapability(key, std::move(new_value));
}
......@@ -227,12 +223,11 @@ void TestBasicOperations(DeviceCapabilities* capabilities) {
void AssertBasicOperationsSuccessful(const DeviceCapabilities* capabilities) {
base::RunLoop().RunUntilIdle();
std::string key;
std::unique_ptr<base::Value> init_value;
base::Value init_value;
GetSampleDefaultCapability(&key, &init_value);
std::unique_ptr<base::Value> value = capabilities->GetCapability(key);
ASSERT_TRUE(value);
std::unique_ptr<base::Value> new_value = GetSampleDefaultCapabilityNewValue();
EXPECT_EQ(*value, *new_value);
base::Value value = capabilities->GetCapability(key);
base::Value new_value = GetSampleDefaultCapabilityNewValue();
EXPECT_EQ(value, new_value);
}
} // namespace
......@@ -273,83 +268,89 @@ class DeviceCapabilitiesImplTest : public ::testing::Test {
// Tests that class is in correct state after Create().
TEST_F(DeviceCapabilitiesImplTest, Create) {
std::string empty_dict_string = *SerializeToJson(base::DictionaryValue());
std::string empty_dict_string;
base::JSONWriter::Write(base::Value(base::Value::Type::DICTIONARY),
&empty_dict_string);
EXPECT_EQ(capabilities()->GetAllData()->json_string(), empty_dict_string);
EXPECT_TRUE(capabilities()->GetAllData()->dictionary().empty());
EXPECT_TRUE(capabilities()->GetAllData()->dictionary().DictEmpty());
}
// Tests Register() of a default capability.
TEST_F(DeviceCapabilitiesImplTest, Register) {
std::string key;
std::unique_ptr<base::Value> init_value;
base::Value init_value;
GetSampleDefaultCapability(&key, &init_value);
EXPECT_CALL(*capabilities_observer(), OnCapabilitiesChanged(key)).Times(0);
FakeCapabilityManagerSimple manager(capabilities(), key, nullptr, true,
FakeCapabilityManagerSimple manager(capabilities(), key, base::Value(), true,
false);
EXPECT_EQ(capabilities()->GetValidator(key), &manager);
std::string empty_dict_string = *SerializeToJson(base::DictionaryValue());
std::string empty_dict_string;
base::JSONWriter::Write(base::Value(base::Value::Type::DICTIONARY),
&empty_dict_string);
EXPECT_EQ(capabilities()->GetAllData()->json_string(), empty_dict_string);
EXPECT_FALSE(capabilities()->GetCapability(key));
EXPECT_TRUE(capabilities()->GetCapability(key).is_none());
}
// Tests Unregister() of a default capability.
TEST_F(DeviceCapabilitiesImplTest, Unregister) {
std::string key;
std::unique_ptr<base::Value> init_value;
base::Value init_value;
GetSampleDefaultCapability(&key, &init_value);
EXPECT_CALL(*capabilities_observer(), OnCapabilitiesChanged(key)).Times(0);
FakeCapabilityManagerSimple* manager = new FakeCapabilityManagerSimple(
capabilities(), key, nullptr, true, false);
capabilities(), key, base::Value(), true, false);
delete manager;
EXPECT_FALSE(capabilities()->GetValidator(key));
std::string empty_dict_string = *SerializeToJson(base::DictionaryValue());
std::string empty_dict_string;
base::JSONWriter::Write(base::Value(base::Value::Type::DICTIONARY),
&empty_dict_string);
EXPECT_EQ(capabilities()->GetAllData()->json_string(), empty_dict_string);
EXPECT_FALSE(capabilities()->GetCapability(key));
EXPECT_TRUE(capabilities()->GetCapability(key).is_none());
}
// Tests GetCapability() and updating the value through SetCapability().
TEST_F(DeviceCapabilitiesImplTest, GetCapabilityAndSetCapability) {
std::string key;
std::unique_ptr<base::Value> init_value;
base::Value init_value;
GetSampleDefaultCapability(&key, &init_value);
FakeCapabilityManagerSimple manager(
capabilities(), key, init_value->CreateDeepCopy(), true, false);
FakeCapabilityManagerSimple manager(capabilities(), key, init_value.Clone(),
true, false);
EXPECT_EQ(*capabilities()->GetCapability(key), *init_value);
EXPECT_EQ(capabilities()->GetCapability(key), init_value);
std::unique_ptr<base::Value> new_value = GetSampleDefaultCapabilityNewValue();
capabilities()->SetCapability(key, new_value->CreateDeepCopy());
base::Value new_value = GetSampleDefaultCapabilityNewValue();
capabilities()->SetCapability(key, new_value.Clone());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(*capabilities()->GetCapability(key), *new_value);
EXPECT_EQ(capabilities()->GetCapability(key), new_value);
}
// Tests BluetoothSupported() and updating this value through SetCapability().
TEST_F(DeviceCapabilitiesImplTest, BluetoothSupportedAndSetCapability) {
FakeCapabilityManagerSimple manager(
capabilities(), DeviceCapabilities::kKeyBluetoothSupported,
base::WrapUnique(new base::Value(true)), true, false);
base::Value(true), true, false);
EXPECT_TRUE(capabilities()->BluetoothSupported());
capabilities()->SetCapability(DeviceCapabilities::kKeyBluetoothSupported,
base::WrapUnique(new base::Value(false)));
base::Value(false));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(capabilities()->BluetoothSupported());
}
// Tests DisplaySupported() and updating this value through SetCapability().
TEST_F(DeviceCapabilitiesImplTest, DisplaySupportedAndSetCapability) {
FakeCapabilityManagerSimple manager(
capabilities(), DeviceCapabilities::kKeyDisplaySupported,
base::WrapUnique(new base::Value(true)), true, false);
FakeCapabilityManagerSimple manager(capabilities(),
DeviceCapabilities::kKeyDisplaySupported,
base::Value(true), true, false);
EXPECT_TRUE(capabilities()->DisplaySupported());
capabilities()->SetCapability(DeviceCapabilities::kKeyDisplaySupported,
base::WrapUnique(new base::Value(false)));
base::Value(false));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(capabilities()->DisplaySupported());
}
......@@ -358,11 +359,11 @@ TEST_F(DeviceCapabilitiesImplTest, DisplaySupportedAndSetCapability) {
TEST_F(DeviceCapabilitiesImplTest, HiResAudioSupportedAndSetCapability) {
FakeCapabilityManagerSimple manager(
capabilities(), DeviceCapabilities::kKeyHiResAudioSupported,
base::WrapUnique(new base::Value(true)), true, false);
base::Value(true), true, false);
EXPECT_TRUE(capabilities()->HiResAudioSupported());
capabilities()->SetCapability(DeviceCapabilities::kKeyHiResAudioSupported,
base::WrapUnique(new base::Value(false)));
base::Value(false));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(capabilities()->HiResAudioSupported());
}
......@@ -371,11 +372,11 @@ TEST_F(DeviceCapabilitiesImplTest, HiResAudioSupportedAndSetCapability) {
TEST_F(DeviceCapabilitiesImplTest, AssistantSupportedAndSetCapability) {
FakeCapabilityManagerSimple manager(
capabilities(), DeviceCapabilities::kKeyAssistantSupported,
base::WrapUnique(new base::Value(true)), true, false);
base::Value(true), true, false);
EXPECT_TRUE(capabilities()->AssistantSupported());
capabilities()->SetCapability(DeviceCapabilities::kKeyAssistantSupported,
base::WrapUnique(new base::Value(false)));
base::Value(false));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(capabilities()->AssistantSupported());
}
......@@ -384,97 +385,95 @@ TEST_F(DeviceCapabilitiesImplTest, AssistantSupportedAndSetCapability) {
// rejects the proposed change.
TEST_F(DeviceCapabilitiesImplTest, SetCapabilityInvalid) {
std::string key;
std::unique_ptr<base::Value> init_value;
base::Value init_value;
GetSampleDefaultCapability(&key, &init_value);
FakeCapabilityManagerSimple manager(
capabilities(), key, init_value->CreateDeepCopy(), false, false);
FakeCapabilityManagerSimple manager(capabilities(), key, init_value.Clone(),
false, false);
capabilities()->SetCapability(key, GetSampleDefaultCapabilityNewValue());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(*capabilities()->GetCapability(key), *init_value);
EXPECT_EQ(capabilities()->GetCapability(key), init_value);
}
// Test that SetCapability() updates the capabilities string correctly
TEST_F(DeviceCapabilitiesImplTest, SetCapabilityUpdatesString) {
std::string key;
std::unique_ptr<base::Value> init_value;
base::Value init_value;
GetSampleDefaultCapability(&key, &init_value);
FakeCapabilityManagerSimple manager(
capabilities(), key, init_value->CreateDeepCopy(), true, false);
FakeCapabilityManagerSimple manager(capabilities(), key, init_value.Clone(),
true, false);
EXPECT_TRUE(JsonStringEquals(capabilities()->GetAllData()->json_string(), key,
*init_value));
init_value));
std::unique_ptr<base::Value> new_value = GetSampleDefaultCapabilityNewValue();
capabilities()->SetCapability(key, new_value->CreateDeepCopy());
base::Value new_value = GetSampleDefaultCapabilityNewValue();
capabilities()->SetCapability(key, new_value.Clone());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(JsonStringEquals(capabilities()->GetAllData()->json_string(), key,
*new_value));
new_value));
}
// Tests that GetPublicData() does not include private capabilities
TEST_F(DeviceCapabilitiesImplTest, SetPublicPrivateCapabilities) {
std::string key_private = "private";
std::string key_public = "public";
std::unique_ptr<base::Value> init_value(new base::Value(true));
base::Value init_value(true);
// Dictionary of only public values.
base::DictionaryValue public_dict;
public_dict.Set(key_public, init_value->CreateDeepCopy());
base::Value public_dict(base::Value::Type::DICTIONARY);
public_dict.SetKey(key_public, init_value.Clone());
// Dictionary of public and private values.
base::DictionaryValue full_dict;
full_dict.Set(key_public, init_value->CreateDeepCopy());
full_dict.Set(key_private, init_value->CreateDeepCopy());
FakeCapabilityManagerSimple public_manager(
capabilities(), key_public, init_value->CreateDeepCopy(), true, false);
FakeCapabilityManagerSimple private_manager(
capabilities(), key_private, init_value->CreateDeepCopy(), true, true);
EXPECT_TRUE(capabilities()->GetAllData()->dictionary().Equals(&full_dict));
EXPECT_TRUE(
capabilities()->GetPublicData()->dictionary().Equals(&public_dict));
base::Value full_dict(base::Value::Type::DICTIONARY);
full_dict.SetKey(key_public, init_value.Clone());
full_dict.SetKey(key_private, init_value.Clone());
FakeCapabilityManagerSimple public_manager(capabilities(), key_public,
init_value.Clone(), true, false);
FakeCapabilityManagerSimple private_manager(capabilities(), key_private,
init_value.Clone(), true, true);
EXPECT_EQ(capabilities()->GetAllData()->dictionary(), full_dict);
EXPECT_EQ(capabilities()->GetPublicData()->dictionary(), public_dict);
}
// Tests that SetCapability() defaults to making a capability public
TEST_F(DeviceCapabilitiesImplTest, NoValidatorDefaultsToPublicCapability) {
std::string key_private = "private";
std::string key_public = "public";
std::unique_ptr<base::Value> init_value(new base::Value(true));
base::Value init_value(true);
// Dictionary of only public values.
base::DictionaryValue public_dict;
public_dict.Set(key_public, init_value->CreateDeepCopy());
base::Value public_dict(base::Value::Type::DICTIONARY);
public_dict.SetKey(key_public, init_value.Clone());
// Dictionary of public and private values.
base::DictionaryValue full_dict;
full_dict.Set(key_public, init_value->CreateDeepCopy());
full_dict.Set(key_private, init_value->CreateDeepCopy());
base::Value full_dict(base::Value::Type::DICTIONARY);
full_dict.SetKey(key_public, init_value.Clone());
full_dict.SetKey(key_private, init_value.Clone());
// We will not create a validator for the public capability; instead we will
// set the capability directly. It will be registered as a public capability.
capabilities()->SetCapability(key_public, init_value->CreateDeepCopy());
capabilities()->SetCapability(key_public, init_value.Clone());
FakeCapabilityManagerSimple private_manager(
capabilities(), key_private, init_value->CreateDeepCopy(), true, true);
FakeCapabilityManagerSimple private_manager(capabilities(), key_private,
init_value.Clone(), true, true);
EXPECT_TRUE(capabilities()->GetAllData()->dictionary().Equals(&full_dict));
EXPECT_TRUE(
capabilities()->GetPublicData()->dictionary().Equals(&public_dict));
EXPECT_EQ(capabilities()->GetAllData()->dictionary(), full_dict);
EXPECT_EQ(capabilities()->GetPublicData()->dictionary(), public_dict);
}
// Test that SetCapability() notifies Observers when the capability's value
// changes
TEST_F(DeviceCapabilitiesImplTest, SetCapabilityNotifiesObservers) {
std::string key;
std::unique_ptr<base::Value> init_value;
base::Value init_value;
GetSampleDefaultCapability(&key, &init_value);
EXPECT_CALL(*capabilities_observer(), OnCapabilitiesChanged(key)).Times(3);
// 1st call (register)
FakeCapabilityManagerSimple manager(
capabilities(), key, init_value->CreateDeepCopy(), true, false);
FakeCapabilityManagerSimple manager(capabilities(), key, init_value.Clone(),
true, false);
// 2nd call
capabilities()->SetCapability(key, GetSampleDefaultCapabilityNewValue());
......@@ -491,15 +490,15 @@ TEST_F(DeviceCapabilitiesImplTest, SetCapabilityNotifiesObservers) {
// value changes
TEST_F(DeviceCapabilitiesImplTest, SetPrivateCapabilityNotifiesObservers) {
std::string key;
std::unique_ptr<base::Value> init_value;
base::Value init_value;
GetSampleDefaultCapability(&key, &init_value);
EXPECT_CALL(*capabilities_observer(), OnCapabilitiesChanged(key)).Times(3);
// 1st call (register), this manager validates and sets the capability
// privately.
FakeCapabilityManagerSimple manager(capabilities(), key,
init_value->CreateDeepCopy(), true, true);
FakeCapabilityManagerSimple manager(capabilities(), key, init_value.Clone(),
true, true);
// 2nd call
capabilities()->SetCapability(key, GetSampleDefaultCapabilityNewValue());
......@@ -515,129 +514,108 @@ TEST_F(DeviceCapabilitiesImplTest, SetPrivateCapabilityNotifiesObservers) {
// Test adding dynamic capabilities
TEST_F(DeviceCapabilitiesImplTest, SetCapabilityDynamic) {
std::string key;
std::unique_ptr<base::Value> init_value;
base::Value init_value;
GetSampleDynamicCapability(&key, &init_value);
ASSERT_FALSE(capabilities()->GetCapability(key));
capabilities()->SetCapability(key, init_value->CreateDeepCopy());
ASSERT_TRUE(capabilities()->GetCapability(key).is_none());
capabilities()->SetCapability(key, init_value.Clone());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(*capabilities()->GetCapability(key), *init_value);
EXPECT_EQ(capabilities()->GetCapability(key), init_value);
EXPECT_TRUE(JsonStringEquals(capabilities()->GetAllData()->json_string(), key,
*init_value));
init_value));
std::unique_ptr<base::Value> new_value = GetSampleDynamicCapabilityNewValue();
capabilities()->SetCapability(key, new_value->CreateDeepCopy());
base::Value new_value = GetSampleDynamicCapabilityNewValue();
capabilities()->SetCapability(key, new_value.Clone());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(*capabilities()->GetCapability(key), *new_value);
EXPECT_EQ(capabilities()->GetCapability(key), new_value);
EXPECT_TRUE(JsonStringEquals(capabilities()->GetAllData()->json_string(), key,
*new_value));
new_value));
}
// Tests that SetCapability() works with expanded paths when there is a
// capability of type DictionaryValue.
TEST_F(DeviceCapabilitiesImplTest, SetCapabilityDictionary) {
std::string key("dummy_dictionary_key");
std::unique_ptr<base::Value> init_value =
DeserializeFromJson(kSampleDictionaryCapability);
auto init_value = base::JSONReader::Read(kSampleDictionaryCapability);
ASSERT_TRUE(init_value);
FakeCapabilityManagerSimple manager(capabilities(), key,
std::move(init_value), true, false);
std::move(*init_value), true, false);
capabilities()->SetCapability("dummy_dictionary_key.dummy_field_bool",
base::WrapUnique(new base::Value(false)));
base::Value(false));
base::RunLoop().RunUntilIdle();
bool value_bool = true;
std::unique_ptr<base::Value> value =
base::Value value =
capabilities()->GetCapability("dummy_dictionary_key.dummy_field_bool");
ASSERT_TRUE(value);
EXPECT_TRUE(value->GetAsBoolean(&value_bool));
EXPECT_FALSE(value_bool);
ASSERT_TRUE(value.is_bool());
EXPECT_FALSE(value.GetBool());
capabilities()->SetCapability("dummy_dictionary_key.dummy_field_int",
base::WrapUnique(new base::Value(100)));
base::Value(100));
base::RunLoop().RunUntilIdle();
int value_int = 0;
value = capabilities()->GetCapability("dummy_dictionary_key.dummy_field_int");
ASSERT_TRUE(value);
EXPECT_TRUE(value->GetAsInteger(&value_int));
EXPECT_EQ(value_int, 100);
ASSERT_TRUE(value.is_int());
EXPECT_EQ(value.GetInt(), 100);
}
// Tests that SetCapability() works with expanded paths when there is a
// capability of type DictionaryValue and invalid changes are proposed.
TEST_F(DeviceCapabilitiesImplTest, SetCapabilityDictionaryInvalid) {
std::string key("dummy_dictionary_key");
std::unique_ptr<base::Value> init_value =
DeserializeFromJson(kSampleDictionaryCapability);
auto init_value = base::JSONReader::Read(kSampleDictionaryCapability);
ASSERT_TRUE(init_value);
FakeCapabilityManagerSimple manager(capabilities(), key,
std::move(init_value), false, false);
std::move(*init_value), false, false);
capabilities()->SetCapability("dummy_dictionary_key.dummy_field_bool",
base::WrapUnique(new base::Value(false)));
base::Value(false));
base::RunLoop().RunUntilIdle();
bool value_bool = false;
std::unique_ptr<base::Value> value =
base::Value value =
capabilities()->GetCapability("dummy_dictionary_key.dummy_field_bool");
ASSERT_TRUE(value);
EXPECT_TRUE(value->GetAsBoolean(&value_bool));
EXPECT_TRUE(value_bool);
ASSERT_TRUE(value.is_bool());
EXPECT_TRUE(value.GetBool());
capabilities()->SetCapability("dummy_dictionary_key.dummy_field_int",
base::WrapUnique(new base::Value(100)));
base::Value(100));
base::RunLoop().RunUntilIdle();
int value_int = 0;
value = capabilities()->GetCapability("dummy_dictionary_key.dummy_field_int");
ASSERT_TRUE(value);
EXPECT_TRUE(value->GetAsInteger(&value_int));
EXPECT_EQ(value_int, 99);
ASSERT_TRUE(value.is_int());
EXPECT_EQ(value.GetInt(), 99);
}
// Test MergeDictionary.
TEST_F(DeviceCapabilitiesImplTest, MergeDictionary) {
std::unique_ptr<base::Value> deserialized_value =
DeserializeFromJson(kSampleDictionaryCapability);
auto deserialized_value = base::JSONReader::Read(kSampleDictionaryCapability);
ASSERT_TRUE(deserialized_value);
base::DictionaryValue* dict_value = nullptr;
ASSERT_TRUE(deserialized_value->GetAsDictionary(&dict_value));
ASSERT_TRUE(dict_value);
ASSERT_TRUE(deserialized_value->is_dict());
capabilities()->MergeDictionary(*dict_value);
capabilities()->MergeDictionary(*deserialized_value);
base::RunLoop().RunUntilIdle();
// First make sure that capabilities get created if they do not exist
bool value_bool = false;
std::unique_ptr<base::Value> value =
capabilities()->GetCapability("dummy_field_bool");
ASSERT_TRUE(value);
EXPECT_TRUE(value->GetAsBoolean(&value_bool));
EXPECT_TRUE(value_bool);
int value_int = 0;
base::Value value = capabilities()->GetCapability("dummy_field_bool");
ASSERT_TRUE(value.is_bool());
EXPECT_TRUE(value.GetBool());
value = capabilities()->GetCapability("dummy_field_int");
ASSERT_TRUE(value);
EXPECT_TRUE(value->GetAsInteger(&value_int));
EXPECT_EQ(value_int, 99);
ASSERT_TRUE(value.is_int());
EXPECT_EQ(value.GetInt(), 99);
// Now just update one of the fields. Make sure the updated value is changed
// in DeviceCapabilities and the other field remains untouched.
dict_value->SetInteger("dummy_field_int", 100);
ASSERT_TRUE(dict_value->Remove("dummy_field_bool", nullptr));
deserialized_value->SetIntKey("dummy_field_int", 100);
ASSERT_TRUE(deserialized_value->RemoveKey("dummy_field_bool"));
capabilities()->MergeDictionary(*dict_value);
capabilities()->MergeDictionary(*deserialized_value);
base::RunLoop().RunUntilIdle();
value_bool = false;
value = capabilities()->GetCapability("dummy_field_bool");
ASSERT_TRUE(value);
EXPECT_TRUE(value->GetAsBoolean(&value_bool));
EXPECT_TRUE(value_bool);
ASSERT_TRUE(value.is_bool());
EXPECT_TRUE(value.GetBool());
value = capabilities()->GetCapability("dummy_field_int");
ASSERT_TRUE(value);
EXPECT_TRUE(value->GetAsInteger(&value_int));
EXPECT_EQ(value_int, 100);
ASSERT_TRUE(value.is_int());
EXPECT_EQ(value.GetInt(), 100);
}
// Tests that it is safe to call DeviceCapabilities methods in
......@@ -647,8 +625,7 @@ TEST_F(DeviceCapabilitiesImplTest, OnCapabilitiesChangedSafe) {
FakeCapabilitiesObserver observer(capabilities());
// Trigger FakeCapabilitiesObserver::OnCapabilitiesChanged()
capabilities()->SetCapability("dummy_trigger_key",
base::WrapUnique(new base::Value(true)));
capabilities()->SetCapability("dummy_trigger_key", base::Value(true));
base::RunLoop().RunUntilIdle();
// Check that FakeCapabilitiesObserver::OnCapabilitiesChanged() ran and that
......@@ -663,8 +640,7 @@ TEST_F(DeviceCapabilitiesImplTest, ValidateSafe) {
FakeCapabilityManagerComplex manager(capabilities(), "dummy_validate_key");
// Trigger FakeCapabilityManagerComplex::Validate()
capabilities()->SetCapability("dummy_validate_key",
base::WrapUnique(new base::Value(true)));
capabilities()->SetCapability("dummy_validate_key", base::Value(true));
base::RunLoop().RunUntilIdle();
// Check that FakeCapabilityManagerComplex::Validate() ran and that behavior
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment