// Copyright (c) 2012 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 "chrome/browser/extensions/extension_sync_data.h" #include "base/files/file_path.h" #include "base/memory/scoped_ptr.h" #include "base/version.h" #include "extensions/common/extension.h" #include "sync/api/string_ordinal.h" #include "sync/protocol/app_specifics.pb.h" #include "sync/protocol/extension_specifics.pb.h" #include "sync/protocol/sync.pb.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" namespace extensions { namespace { const char kValidId[] = "abcdefghijklmnopabcdefghijklmnop"; const char kVersion[] = "1.0.0.1"; const char kValidUpdateUrl[] = "https://clients2.google.com/service/update2/crx"; const int kValidDisableReasons = Extension::DISABLE_USER_ACTION; const char kName[] = "MyExtension"; // Serializes a protobuf structure (entity specifics) into an ExtensionSyncData // and back again, and confirms that the input is the same as the output. void ProtobufToSyncDataEqual(const sync_pb::EntitySpecifics& entity) { syncer::SyncData sync_data = syncer::SyncData::CreateLocalData("sync_tag", "non_unique_title", entity); scoped_ptr extension_sync_data = ExtensionSyncData::CreateFromSyncData(sync_data); ASSERT_TRUE(extension_sync_data.get()); syncer::SyncData output_sync_data = extension_sync_data->GetSyncData(); const sync_pb::ExtensionSpecifics& output = output_sync_data.GetSpecifics().extension(); const sync_pb::ExtensionSpecifics& input = entity.extension(); // Check for field-by-field quality. It'd be nice if we could use // AssertionResults here (instead of EXPECT_EQ) so that we could get valid // line numbers, but it's not worth the ugliness of the verbose comparison. EXPECT_EQ(input.id(), output.id()); EXPECT_EQ(input.name(), output.name()); EXPECT_EQ(input.version(), output.version()); EXPECT_EQ(input.update_url(), output.update_url()); EXPECT_EQ(input.enabled(), output.enabled()); EXPECT_EQ(input.incognito_enabled(), output.incognito_enabled()); EXPECT_EQ(input.remote_install(), output.remote_install()); EXPECT_EQ(input.installed_by_custodian(), output.installed_by_custodian()); EXPECT_EQ(input.has_all_urls_enabled(), output.has_all_urls_enabled()); if (input.has_all_urls_enabled()) EXPECT_EQ(input.all_urls_enabled(), output.all_urls_enabled()); } // Serializes an ExtensionSyncData into a protobuf structure and back again, and // confirms that the input is the same as the output. void SyncDataToProtobufEqual(const ExtensionSyncData& input) { syncer::SyncData sync_data = input.GetSyncData(); scoped_ptr output = ExtensionSyncData::CreateFromSyncData(sync_data); ASSERT_TRUE(output.get()); EXPECT_EQ(input.id(), output->id()); EXPECT_EQ(input.uninstalled(), output->uninstalled()); EXPECT_EQ(input.enabled(), output->enabled()); EXPECT_EQ(input.incognito_enabled(), output->incognito_enabled()); EXPECT_EQ(input.remote_install(), output->remote_install()); EXPECT_EQ(input.installed_by_custodian(), output->installed_by_custodian()); EXPECT_EQ(input.all_urls_enabled(), output->all_urls_enabled()); EXPECT_EQ(input.version(), output->version()); EXPECT_EQ(input.update_url(), output->update_url()); EXPECT_EQ(input.name(), output->name()); } } // namespace class ExtensionSyncDataTest : public testing::Test { }; // Tests the conversion process from a protobuf to an ExtensionSyncData and vice // versa. TEST_F(ExtensionSyncDataTest, ExtensionSyncDataForExtension) { sync_pb::EntitySpecifics entity; sync_pb::ExtensionSpecifics* extension_specifics = entity.mutable_extension(); extension_specifics->set_id(kValidId); extension_specifics->set_update_url(kValidUpdateUrl); extension_specifics->set_enabled(false); extension_specifics->set_incognito_enabled(true); extension_specifics->set_remote_install(false); extension_specifics->set_installed_by_custodian(false); extension_specifics->set_all_urls_enabled(true); extension_specifics->set_version(kVersion); extension_specifics->set_name(kName); // Check the serialize-deserialize process for proto to ExtensionSyncData. ProtobufToSyncDataEqual(entity); // Explicitly test that conversion to an ExtensionSyncData gets the correct // result (otherwise we just know that conversion to/from a proto gives us // the same result, but don't know that it's right). ExtensionSyncData extension_sync_data; extension_sync_data.PopulateFromExtensionSpecifics(*extension_specifics); EXPECT_EQ(kValidId, extension_sync_data.id()); EXPECT_EQ(GURL(kValidUpdateUrl), extension_sync_data.update_url()); EXPECT_FALSE(extension_sync_data.enabled()); EXPECT_EQ(true, extension_sync_data.incognito_enabled()); EXPECT_FALSE(extension_sync_data.remote_install()); EXPECT_EQ(ExtensionSyncData::BOOLEAN_TRUE, extension_sync_data.all_urls_enabled()); EXPECT_EQ(Version(kVersion), extension_sync_data.version()); EXPECT_EQ(std::string(kName), extension_sync_data.name()); // Check the serialize-deserialize process for ExtensionSyncData to proto. SyncDataToProtobufEqual(extension_sync_data); // The most important thing to test is the "all urls" bit, since it is a // tri-state boolean (and thus has more logic). Also flip another bit for a // sanity check. extension_specifics->set_all_urls_enabled(false); extension_specifics->set_incognito_enabled(false); ProtobufToSyncDataEqual(entity); extension_sync_data.PopulateFromExtensionSpecifics(*extension_specifics); EXPECT_EQ(ExtensionSyncData::BOOLEAN_FALSE, extension_sync_data.all_urls_enabled()); EXPECT_FALSE(extension_sync_data.incognito_enabled()); SyncDataToProtobufEqual(extension_sync_data); extension_specifics->clear_all_urls_enabled(); ProtobufToSyncDataEqual(entity); extension_sync_data.PopulateFromExtensionSpecifics(*extension_specifics); EXPECT_FALSE(extension_specifics->has_all_urls_enabled()); EXPECT_EQ(ExtensionSyncData::BOOLEAN_UNSET, extension_sync_data.all_urls_enabled()); SyncDataToProtobufEqual(extension_sync_data); } class AppSyncDataTest : public testing::Test { public: AppSyncDataTest() {} ~AppSyncDataTest() override {} void SetRequiredExtensionValues( sync_pb::ExtensionSpecifics* extension_specifics) { extension_specifics->set_id(kValidId); extension_specifics->set_update_url(kValidUpdateUrl); extension_specifics->set_version(kVersion); extension_specifics->set_enabled(false); extension_specifics->set_disable_reasons(kValidDisableReasons); extension_specifics->set_incognito_enabled(true); extension_specifics->set_remote_install(false); extension_specifics->set_all_urls_enabled(true); extension_specifics->set_installed_by_custodian(false); extension_specifics->set_name(kName); } }; TEST_F(AppSyncDataTest, SyncDataToExtensionSyncDataForApp) { sync_pb::EntitySpecifics entity; sync_pb::AppSpecifics* app_specifics = entity.mutable_app(); app_specifics->set_app_launch_ordinal( syncer::StringOrdinal::CreateInitialOrdinal().ToInternalValue()); app_specifics->set_page_ordinal( syncer::StringOrdinal::CreateInitialOrdinal().ToInternalValue()); SetRequiredExtensionValues(app_specifics->mutable_extension()); syncer::SyncData sync_data = syncer::SyncData::CreateLocalData("sync_tag", "non_unique_title", entity); scoped_ptr app_sync_data = ExtensionSyncData::CreateFromSyncData(sync_data); ASSERT_TRUE(app_sync_data.get()); EXPECT_EQ(app_specifics->app_launch_ordinal(), app_sync_data->app_launch_ordinal().ToInternalValue()); EXPECT_EQ(app_specifics->page_ordinal(), app_sync_data->page_ordinal().ToInternalValue()); } TEST_F(AppSyncDataTest, ExtensionSyncDataToSyncDataForApp) { sync_pb::EntitySpecifics entity; sync_pb::AppSpecifics* input_specifics = entity.mutable_app(); input_specifics->set_app_launch_ordinal( syncer::StringOrdinal::CreateInitialOrdinal().ToInternalValue()); input_specifics->set_page_ordinal( syncer::StringOrdinal::CreateInitialOrdinal().ToInternalValue()); SetRequiredExtensionValues(input_specifics->mutable_extension()); syncer::SyncData sync_data = syncer::SyncData::CreateLocalData("sync_tag", "non_unique_title", entity); scoped_ptr app_sync_data = ExtensionSyncData::CreateFromSyncData(sync_data); ASSERT_TRUE(app_sync_data.get()); syncer::SyncData output_sync_data = app_sync_data->GetSyncData(); EXPECT_TRUE(sync_data.GetSpecifics().has_app()); const sync_pb::AppSpecifics& output_specifics = output_sync_data.GetSpecifics().app(); EXPECT_EQ(input_specifics->SerializeAsString(), output_specifics.SerializeAsString()); } // Ensures that invalid StringOrdinals don't break ExtensionSyncData. TEST_F(AppSyncDataTest, ExtensionSyncDataInvalidOrdinal) { sync_pb::EntitySpecifics entity; sync_pb::AppSpecifics* app_specifics = entity.mutable_app(); // Set the ordinals as invalid. app_specifics->set_app_launch_ordinal(""); app_specifics->set_page_ordinal(""); SetRequiredExtensionValues(app_specifics->mutable_extension()); syncer::SyncData sync_data = syncer::SyncData::CreateLocalData("sync_tag", "non_unique_title", entity); // There should be no issue loading the sync data. scoped_ptr app_sync_data = ExtensionSyncData::CreateFromSyncData(sync_data); ASSERT_TRUE(app_sync_data.get()); app_sync_data->GetSyncData(); } } // namespace extensions