blob: 222cdacb0ce6c9fbb0d64d052b476e21814b4873 [file] [log] [blame]
// Copyright 2015 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 "chromecast/base/device_capabilities_impl.h"
#include <string>
#include <utility>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/values.h"
#include "chromecast/base/serializers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromecast {
namespace {
const char kSampleDictionaryCapability[] =
"{"
" \"dummy_field_bool\": true,"
" \"dummy_field_int\": 99"
"}";
void GetSampleDefaultCapability(std::string* key,
std::unique_ptr<base::Value>* init_value);
void TestBasicOperations(DeviceCapabilities* capabilities);
// Simple capability manager that implements the Validator interface. Either
// accepts or rejects all proposed changes based on |accept_changes| constructor
// argument.
class FakeCapabilityManagerSimple : public DeviceCapabilities::Validator {
public:
// Registers itself as Validator in constructor. If init_value is not null,
// the capability gets initialized to that value. Else capability remains
// untouched.
FakeCapabilityManagerSimple(DeviceCapabilities* capabilities,
const std::string& key,
std::unique_ptr<base::Value> init_value,
bool accept_changes,
bool validate_private)
: DeviceCapabilities::Validator(capabilities),
key_(key),
accept_changes_(accept_changes),
validate_private_(validate_private) {
capabilities->Register(key, this);
if (init_value) {
if (validate_private_) {
SetPrivateValidatedValue(key, std::move(init_value));
} else {
SetPublicValidatedValue(key, std::move(init_value));
}
}
}
// Unregisters itself as Validator.
~FakeCapabilityManagerSimple() override {
capabilities()->Unregister(key_, this);
}
void Validate(const std::string& path,
std::unique_ptr<base::Value> proposed_value) override {
ASSERT_EQ(path.find(key_), 0ul);
if (!accept_changes_)
return;
if (validate_private_) {
SetPrivateValidatedValue(path, std::move(proposed_value));
} else {
SetPublicValidatedValue(path, std::move(proposed_value));
}
}
private:
const std::string key_;
const bool accept_changes_;
const bool validate_private_;
};
// Used to test that capabilities/validator can be read and written in
// Validate() without encountering deadlocks/unexpected behavior.
class FakeCapabilityManagerComplex : public DeviceCapabilities::Validator {
public:
FakeCapabilityManagerComplex(DeviceCapabilities* capabilities,
const std::string& key)
: DeviceCapabilities::Validator(capabilities), key_(key) {
capabilities->Register(key, this);
}
// Unregisters itself as Validator.
~FakeCapabilityManagerComplex() override {
capabilities()->Unregister(key_, this);
}
// Runs TestBasicOperations().
void Validate(const std::string& path,
std::unique_ptr<base::Value> proposed_value) override {
TestBasicOperations(capabilities());
}
private:
const std::string key_;
};
// Used to test that capabilities/validators can be read and written in
// OnCapabilitiesChanged() without encountering deadlocks/unexpected behavior.
class FakeCapabilitiesObserver : public DeviceCapabilities::Observer {
public:
explicit FakeCapabilitiesObserver(DeviceCapabilities* capabilities)
: capabilities_(capabilities), removed_as_observer(false) {
capabilities_->AddCapabilitiesObserver(this);
}
~FakeCapabilitiesObserver() override {
if (!removed_as_observer)
capabilities_->RemoveCapabilitiesObserver(this);
}
// Runs TestBasicOperations().
void OnCapabilitiesChanged(const std::string& path) override {
TestBasicOperations(capabilities_);
// To prevent infinite loop of SetCapability() -> OnCapabilitiesChanged()
// -> SetCapability() -> OnCapabilitiesChanged() etc.
capabilities_->RemoveCapabilitiesObserver(this);
removed_as_observer = true;
}
private:
DeviceCapabilities* const capabilities_;
bool removed_as_observer;
};
// Used to test that OnCapabilitiesChanged() is called when capabilities are
// modified
class MockCapabilitiesObserver : public DeviceCapabilities::Observer {
public:
MockCapabilitiesObserver() {}
~MockCapabilitiesObserver() override {}
MOCK_METHOD1(OnCapabilitiesChanged, void(const std::string& path));
private:
DISALLOW_COPY_AND_ASSIGN(MockCapabilitiesObserver);
};
// 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) {
DCHECK(key);
DCHECK(init_value);
*key = DeviceCapabilities::kKeyBluetoothSupported;
*init_value = base::MakeUnique<base::FundamentalValue>(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) {
DCHECK(key);
DCHECK(init_value);
*key = "dummy_dynamic_key";
*init_value = base::MakeUnique<base::FundamentalValue>(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 base::MakeUnique<base::FundamentalValue>(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 base::MakeUnique<base::FundamentalValue>(100);
}
// Tests that |json| string matches contents of a DictionaryValue with one entry
// specified by |key| and |value|.
bool JsonStringEquals(const std::string& json,
const std::string& key,
const base::Value& value) {
base::DictionaryValue dict_value;
dict_value.Set(key, value.CreateDeepCopy());
std::unique_ptr<const std::string> dict_json(SerializeToJson(dict_value));
return dict_json.get() && *dict_json == json;
}
// The function runs through the set of basic operations of DeviceCapabilities.
// Register validator for sample default capability, reads capability, writes
// capability, and unregister validator. After it has completed, use
// AssertBasicOperationsSuccessful() to ensure that all operations completed
// successfully. Sample default capability should not be added or registered in
// class before this function is called.
void TestBasicOperations(DeviceCapabilities* capabilities) {
std::string key;
std::unique_ptr<base::Value> init_value;
GetSampleDefaultCapability(&key, &init_value);
ASSERT_FALSE(capabilities->GetCapability(key));
ASSERT_FALSE(capabilities->GetValidator(key));
// Register and write capability
FakeCapabilityManagerSimple* manager(new FakeCapabilityManagerSimple(
capabilities, key, init_value->CreateDeepCopy(), true, false));
// Read Validator
EXPECT_EQ(capabilities->GetValidator(key), manager);
// Read Capability
EXPECT_TRUE(base::Value::Equals(capabilities->GetCapability(key).get(),
init_value.get()));
// 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();
capabilities->SetCapability(key, std::move(new_value));
}
// See TestBasicOperations() comment.
void AssertBasicOperationsSuccessful(const DeviceCapabilities* capabilities) {
base::RunLoop().RunUntilIdle();
std::string key;
std::unique_ptr<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_TRUE(base::Value::Equals(value.get(), new_value.get()));
}
} // namespace
class DeviceCapabilitiesImplTest : public ::testing::Test {
protected:
void SetUp() override {
message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO));
capabilities_ = DeviceCapabilities::Create();
mock_capabilities_observer_.reset(new MockCapabilitiesObserver());
capabilities_->AddCapabilitiesObserver(mock_capabilities_observer_.get());
// We set the default gmock expected calls to any so that tests must
// 'opt in' to checking the calls rather than 'opt out'. This avoids having
// to add explicit calls in test cases that don't care in order to prevent
// lots of useless mock warnings.
EXPECT_CALL(*mock_capabilities_observer_, OnCapabilitiesChanged(testing::_))
.Times(testing::AnyNumber());
}
void TearDown() override {
capabilities_->RemoveCapabilitiesObserver(
mock_capabilities_observer_.get());
mock_capabilities_observer_.reset();
capabilities_.reset();
message_loop_.reset();
}
DeviceCapabilities* capabilities() const { return capabilities_.get(); }
MockCapabilitiesObserver* capabilities_observer() const {
return mock_capabilities_observer_.get();
}
private:
std::unique_ptr<base::MessageLoop> message_loop_;
std::unique_ptr<DeviceCapabilities> capabilities_;
std::unique_ptr<MockCapabilitiesObserver> mock_capabilities_observer_;
};
// Tests that class is in correct state after Create().
TEST_F(DeviceCapabilitiesImplTest, Create) {
std::unique_ptr<const std::string> empty_dict_string(
SerializeToJson(base::DictionaryValue()));
EXPECT_EQ(capabilities()->GetAllData()->json_string(), *empty_dict_string);
EXPECT_TRUE(capabilities()->GetAllData()->dictionary().empty());
}
// Tests Register() of a default capability.
TEST_F(DeviceCapabilitiesImplTest, Register) {
std::string key;
std::unique_ptr<base::Value> init_value;
GetSampleDefaultCapability(&key, &init_value);
EXPECT_CALL(*capabilities_observer(), OnCapabilitiesChanged(key)).Times(0);
FakeCapabilityManagerSimple manager(capabilities(), key, nullptr, true,
false);
EXPECT_EQ(capabilities()->GetValidator(key), &manager);
std::unique_ptr<const std::string> empty_dict_string(
SerializeToJson(base::DictionaryValue()));
EXPECT_EQ(capabilities()->GetAllData()->json_string(), *empty_dict_string);
EXPECT_FALSE(capabilities()->GetCapability(key));
}
// Tests Unregister() of a default capability.
TEST_F(DeviceCapabilitiesImplTest, Unregister) {
std::string key;
std::unique_ptr<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);
delete manager;
EXPECT_FALSE(capabilities()->GetValidator(key));
std::unique_ptr<const std::string> empty_dict_string(
SerializeToJson(base::DictionaryValue()));
EXPECT_EQ(capabilities()->GetAllData()->json_string(), *empty_dict_string);
EXPECT_FALSE(capabilities()->GetCapability(key));
}
// Tests GetCapability() and updating the value through SetCapability().
TEST_F(DeviceCapabilitiesImplTest, GetCapabilityAndSetCapability) {
std::string key;
std::unique_ptr<base::Value> init_value;
GetSampleDefaultCapability(&key, &init_value);
FakeCapabilityManagerSimple manager(
capabilities(), key, init_value->CreateDeepCopy(), true, false);
EXPECT_TRUE(base::Value::Equals(capabilities()->GetCapability(key).get(),
init_value.get()));
std::unique_ptr<base::Value> new_value = GetSampleDefaultCapabilityNewValue();
capabilities()->SetCapability(key, new_value->CreateDeepCopy());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(base::Value::Equals(capabilities()->GetCapability(key).get(),
new_value.get()));
}
// Tests BluetoothSupported() and updating this value through SetCapability().
TEST_F(DeviceCapabilitiesImplTest, BluetoothSupportedAndSetCapability) {
FakeCapabilityManagerSimple manager(
capabilities(), DeviceCapabilities::kKeyBluetoothSupported,
base::WrapUnique(new base::FundamentalValue(true)), true, false);
EXPECT_TRUE(capabilities()->BluetoothSupported());
capabilities()->SetCapability(
DeviceCapabilities::kKeyBluetoothSupported,
base::WrapUnique(new base::FundamentalValue(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::FundamentalValue(true)), true, false);
EXPECT_TRUE(capabilities()->DisplaySupported());
capabilities()->SetCapability(
DeviceCapabilities::kKeyDisplaySupported,
base::WrapUnique(new base::FundamentalValue(false)));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(capabilities()->DisplaySupported());
}
// Tests HiResAudioSupported() and updating this value through SetCapability()
TEST_F(DeviceCapabilitiesImplTest, HiResAudioSupportedAndSetCapability) {
FakeCapabilityManagerSimple manager(
capabilities(), DeviceCapabilities::kKeyHiResAudioSupported,
base::WrapUnique(new base::FundamentalValue(true)), true, false);
EXPECT_TRUE(capabilities()->HiResAudioSupported());
capabilities()->SetCapability(
DeviceCapabilities::kKeyHiResAudioSupported,
base::WrapUnique(new base::FundamentalValue(false)));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(capabilities()->HiResAudioSupported());
}
// Tests AssistantSupported() and updating this value through SetCapability()
TEST_F(DeviceCapabilitiesImplTest, AssistantSupportedAndSetCapability) {
FakeCapabilityManagerSimple manager(
capabilities(), DeviceCapabilities::kKeyAssistantSupported,
base::WrapUnique(new base::FundamentalValue(true)), true, false);
EXPECT_TRUE(capabilities()->AssistantSupported());
capabilities()->SetCapability(
DeviceCapabilities::kKeyAssistantSupported,
base::WrapUnique(new base::FundamentalValue(false)));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(capabilities()->AssistantSupported());
}
// Tests SetCapability() for a default capability when the capability's manager
// rejects the proposed change.
TEST_F(DeviceCapabilitiesImplTest, SetCapabilityInvalid) {
std::string key;
std::unique_ptr<base::Value> init_value;
GetSampleDefaultCapability(&key, &init_value);
FakeCapabilityManagerSimple manager(
capabilities(), key, init_value->CreateDeepCopy(), false, false);
capabilities()->SetCapability(key, GetSampleDefaultCapabilityNewValue());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(base::Value::Equals(capabilities()->GetCapability(key).get(),
init_value.get()));
}
// Test that SetCapability() updates the capabilities string correctly
TEST_F(DeviceCapabilitiesImplTest, SetCapabilityUpdatesString) {
std::string key;
std::unique_ptr<base::Value> init_value;
GetSampleDefaultCapability(&key, &init_value);
FakeCapabilityManagerSimple manager(
capabilities(), key, init_value->CreateDeepCopy(), true, false);
EXPECT_TRUE(JsonStringEquals(capabilities()->GetAllData()->json_string(), key,
*init_value));
std::unique_ptr<base::Value> new_value = GetSampleDefaultCapabilityNewValue();
capabilities()->SetCapability(key, new_value->CreateDeepCopy());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(JsonStringEquals(capabilities()->GetAllData()->json_string(), key,
*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::FundamentalValue(true));
// Dictionary of only public values.
base::DictionaryValue public_dict;
public_dict.Set(key_public, init_value->CreateDeepCopy());
// 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));
}
// 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::FundamentalValue(true));
// Dictionary of only public values.
base::DictionaryValue public_dict;
public_dict.Set(key_public, init_value->CreateDeepCopy());
// 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());
// 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());
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));
}
// 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;
GetSampleDefaultCapability(&key, &init_value);
EXPECT_CALL(*capabilities_observer(), OnCapabilitiesChanged(key)).Times(3);
// 1st call (register)
FakeCapabilityManagerSimple manager(
capabilities(), key, init_value->CreateDeepCopy(), true, false);
// 2nd call
capabilities()->SetCapability(key, GetSampleDefaultCapabilityNewValue());
// Observer should not get called when value does not change
capabilities()->SetCapability(key, GetSampleDefaultCapabilityNewValue());
// 3rd call
capabilities()->SetCapability(key, std::move(init_value));
base::RunLoop().RunUntilIdle();
}
// Test that SetCapability() notifies Observers when a private capability's
// value changes
TEST_F(DeviceCapabilitiesImplTest, SetPrivateCapabilityNotifiesObservers) {
std::string key;
std::unique_ptr<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);
// 2nd call
capabilities()->SetCapability(key, GetSampleDefaultCapabilityNewValue());
// Observer should not get called when value does not change
capabilities()->SetCapability(key, GetSampleDefaultCapabilityNewValue());
// 3rd call
capabilities()->SetCapability(key, std::move(init_value));
base::RunLoop().RunUntilIdle();
}
// Test adding dynamic capabilities
TEST_F(DeviceCapabilitiesImplTest, SetCapabilityDynamic) {
std::string key;
std::unique_ptr<base::Value> init_value;
GetSampleDynamicCapability(&key, &init_value);
ASSERT_FALSE(capabilities()->GetCapability(key));
capabilities()->SetCapability(key, init_value->CreateDeepCopy());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(base::Value::Equals(capabilities()->GetCapability(key).get(),
init_value.get()));
EXPECT_TRUE(JsonStringEquals(capabilities()->GetAllData()->json_string(), key,
*init_value));
std::unique_ptr<base::Value> new_value = GetSampleDynamicCapabilityNewValue();
capabilities()->SetCapability(key, new_value->CreateDeepCopy());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(base::Value::Equals(capabilities()->GetCapability(key).get(),
new_value.get()));
EXPECT_TRUE(JsonStringEquals(capabilities()->GetAllData()->json_string(), key,
*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);
ASSERT_TRUE(init_value);
FakeCapabilityManagerSimple manager(capabilities(), key,
std::move(init_value), true, false);
capabilities()->SetCapability(
"dummy_dictionary_key.dummy_field_bool",
base::WrapUnique(new base::FundamentalValue(false)));
base::RunLoop().RunUntilIdle();
bool value_bool = true;
std::unique_ptr<base::Value> value =
capabilities()->GetCapability("dummy_dictionary_key.dummy_field_bool");
ASSERT_TRUE(value);
EXPECT_TRUE(value->GetAsBoolean(&value_bool));
EXPECT_FALSE(value_bool);
capabilities()->SetCapability(
"dummy_dictionary_key.dummy_field_int",
base::WrapUnique(new base::FundamentalValue(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);
}
// 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);
ASSERT_TRUE(init_value);
FakeCapabilityManagerSimple manager(capabilities(), key,
std::move(init_value), false, false);
capabilities()->SetCapability(
"dummy_dictionary_key.dummy_field_bool",
base::WrapUnique(new base::FundamentalValue(false)));
base::RunLoop().RunUntilIdle();
bool value_bool = false;
std::unique_ptr<base::Value> value =
capabilities()->GetCapability("dummy_dictionary_key.dummy_field_bool");
ASSERT_TRUE(value);
EXPECT_TRUE(value->GetAsBoolean(&value_bool));
EXPECT_TRUE(value_bool);
capabilities()->SetCapability(
"dummy_dictionary_key.dummy_field_int",
base::WrapUnique(new base::FundamentalValue(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);
}
// Test MergeDictionary.
TEST_F(DeviceCapabilitiesImplTest, MergeDictionary) {
std::unique_ptr<base::Value> deserialized_value =
DeserializeFromJson(kSampleDictionaryCapability);
ASSERT_TRUE(deserialized_value);
base::DictionaryValue* dict_value = nullptr;
ASSERT_TRUE(deserialized_value->GetAsDictionary(&dict_value));
ASSERT_TRUE(dict_value);
capabilities()->MergeDictionary(*dict_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;
value = capabilities()->GetCapability("dummy_field_int");
ASSERT_TRUE(value);
EXPECT_TRUE(value->GetAsInteger(&value_int));
EXPECT_EQ(value_int, 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));
capabilities()->MergeDictionary(*dict_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);
value = capabilities()->GetCapability("dummy_field_int");
ASSERT_TRUE(value);
EXPECT_TRUE(value->GetAsInteger(&value_int));
EXPECT_EQ(value_int, 100);
}
// Tests that it is safe to call DeviceCapabilities methods in
// an Observer's OnCapabilitiesChanged() implementation safely with correct
// behavior and without deadlocking.
TEST_F(DeviceCapabilitiesImplTest, OnCapabilitiesChangedSafe) {
FakeCapabilitiesObserver observer(capabilities());
// Trigger FakeCapabilitiesObserver::OnCapabilitiesChanged()
capabilities()->SetCapability(
"dummy_trigger_key", base::WrapUnique(new base::FundamentalValue(true)));
base::RunLoop().RunUntilIdle();
// Check that FakeCapabilitiesObserver::OnCapabilitiesChanged() ran and that
// behavior was successful
AssertBasicOperationsSuccessful(capabilities());
}
// Tests that it is safe to call DeviceCapabilities methods in a Validator's
// Validate() implementation safely with correct behavior and without
// deadlocking.
TEST_F(DeviceCapabilitiesImplTest, ValidateSafe) {
FakeCapabilityManagerComplex manager(capabilities(), "dummy_validate_key");
// Trigger FakeCapabilityManagerComplex::Validate()
capabilities()->SetCapability(
"dummy_validate_key", base::WrapUnique(new base::FundamentalValue(true)));
base::RunLoop().RunUntilIdle();
// Check that FakeCapabilityManagerComplex::Validate() ran and that behavior
// was successful
AssertBasicOperationsSuccessful(capabilities());
}
} // namespace chromecast