| // 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 |