blob: 7d9479675d3342a4708fc914dd0e4dd73415358f [file] [log] [blame]
// Copyright 2018 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/web_applications/web_app_registrar.h"
#include <set>
#include <string>
#include <utility>
#include "base/bind_helpers.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/web_applications/components/web_app_helpers.h"
#include "chrome/browser/web_applications/test/test_web_app_database.h"
#include "chrome/browser/web_applications/test/web_app_test.h"
#include "chrome/browser/web_applications/web_app.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace web_app {
namespace {
Registry CreateRegistryForTesting(const std::string& base_url, int num_apps) {
Registry registry;
for (int i = 0; i < num_apps; ++i) {
const auto url = base_url + base::NumberToString(i);
const AppId app_id = GenerateAppIdFromURL(GURL(url));
auto web_app = std::make_unique<WebApp>(app_id);
registry.emplace(app_id, std::move(web_app));
}
return registry;
}
} // namespace
class WebAppRegistrarTest : public WebAppTest {
public:
void SetUp() override {
WebAppTest::SetUp();
database_ = std::make_unique<TestWebAppDatabase>();
registrar_ = std::make_unique<WebAppRegistrar>(profile(), database_.get());
}
protected:
TestWebAppDatabase& database() { return *database_; }
WebAppRegistrar& registrar() { return *registrar_; }
std::set<AppId> RegisterAppsForTesting(Registry registry) {
std::set<AppId> ids;
for (auto& kv : registry) {
ids.insert(kv.first);
registrar().RegisterApp(std::move(kv.second));
}
return ids;
}
std::set<AppId> InitRegistrarWithApps(const std::string& base_url,
int num_apps) {
std::set<AppId> app_ids;
registrar().Init(base::DoNothing());
DCHECK(registrar().is_empty());
Registry registry = CreateRegistryForTesting(base_url, num_apps);
for (auto& kv : registry)
app_ids.insert(kv.second->app_id());
database().TakeOpenDatabaseCallback().Run(std::move(registry));
return app_ids;
}
void DestroySubsystems() {
registrar_.reset();
database_.reset();
}
private:
std::unique_ptr<TestWebAppDatabase> database_;
std::unique_ptr<WebAppRegistrar> registrar_;
};
TEST_F(WebAppRegistrarTest, CreateRegisterUnregister) {
EXPECT_EQ(nullptr, registrar().GetAppById(AppId()));
EXPECT_FALSE(registrar().GetAppById(AppId()));
const GURL launch_url = GURL("https://example.com/path");
const AppId app_id = GenerateAppIdFromURL(launch_url);
const std::string name = "Name";
const std::string description = "Description";
const GURL scope = GURL("https://example.com/scope");
const base::Optional<SkColor> theme_color = 0xAABBCCDD;
const GURL launch_url2 = GURL("https://example.com/path2");
const AppId app_id2 = GenerateAppIdFromURL(launch_url2);
auto web_app = std::make_unique<WebApp>(app_id);
auto web_app2 = std::make_unique<WebApp>(app_id2);
web_app->SetName(name);
web_app->SetDescription(description);
web_app->SetLaunchUrl(launch_url);
web_app->SetScope(scope);
web_app->SetThemeColor(theme_color);
EXPECT_EQ(nullptr, registrar().GetAppById(app_id));
EXPECT_EQ(nullptr, registrar().GetAppById(app_id2));
EXPECT_TRUE(registrar().is_empty());
registrar().RegisterApp(std::move(web_app));
EXPECT_TRUE(registrar().IsInstalled(app_id));
WebApp* app = registrar().GetAppById(app_id);
EXPECT_EQ(app_id, app->app_id());
EXPECT_EQ(name, app->name());
EXPECT_EQ(description, app->description());
EXPECT_EQ(launch_url, app->launch_url());
EXPECT_EQ(scope, app->scope());
EXPECT_EQ(theme_color, app->theme_color());
EXPECT_EQ(nullptr, registrar().GetAppById(app_id2));
EXPECT_FALSE(registrar().is_empty());
registrar().RegisterApp(std::move(web_app2));
EXPECT_TRUE(registrar().IsInstalled(app_id2));
WebApp* app2 = registrar().GetAppById(app_id2);
EXPECT_EQ(app_id2, app2->app_id());
EXPECT_FALSE(registrar().is_empty());
registrar().UnregisterApp(app_id);
EXPECT_FALSE(registrar().IsInstalled(app_id));
EXPECT_EQ(nullptr, registrar().GetAppById(app_id));
EXPECT_FALSE(registrar().is_empty());
// Check that app2 is still registered.
app2 = registrar().GetAppById(app_id2);
EXPECT_TRUE(registrar().IsInstalled(app_id2));
EXPECT_EQ(app_id2, app2->app_id());
registrar().UnregisterApp(app_id2);
EXPECT_FALSE(registrar().IsInstalled(app_id2));
EXPECT_EQ(nullptr, registrar().GetAppById(app_id2));
EXPECT_TRUE(registrar().is_empty());
}
TEST_F(WebAppRegistrarTest, DestroyRegistrarOwningRegisteredApps) {
const AppId app_id = GenerateAppIdFromURL(GURL("https://example.com/path"));
const AppId app_id2 = GenerateAppIdFromURL(GURL("https://example.com/path2"));
auto web_app = std::make_unique<WebApp>(app_id);
registrar().RegisterApp(std::move(web_app));
auto web_app2 = std::make_unique<WebApp>(app_id2);
registrar().RegisterApp(std::move(web_app2));
DestroySubsystems();
}
TEST_F(WebAppRegistrarTest, InitRegistrarAndDoForEachApp) {
std::set<AppId> ids = InitRegistrarWithApps("https://example.com/path", 100);
for (const WebApp& web_app : registrar().AllApps()) {
const size_t num_removed = ids.erase(web_app.app_id());
EXPECT_EQ(1U, num_removed);
}
EXPECT_TRUE(ids.empty());
}
TEST_F(WebAppRegistrarTest, DoForEachAndUnregisterAllApps) {
Registry registry = CreateRegistryForTesting("https://example.com/path", 100);
auto ids = RegisterAppsForTesting(std::move(registry));
EXPECT_EQ(100UL, ids.size());
for (WebApp& web_app : registrar().AllApps()) {
const size_t num_removed = ids.erase(web_app.app_id());
EXPECT_EQ(1U, num_removed);
}
EXPECT_TRUE(ids.empty());
EXPECT_FALSE(registrar().is_empty());
registrar().UnregisterAll();
EXPECT_TRUE(registrar().is_empty());
}
TEST_F(WebAppRegistrarTest, AbstractWebAppDatabase) {
std::set<AppId> ids = InitRegistrarWithApps("https://example.com/path", 100);
// Add 1 app after Init.
const AppId app_id = GenerateAppIdFromURL(GURL("https://example.com/path"));
auto web_app = std::make_unique<WebApp>(app_id);
registrar().RegisterApp(std::move(web_app));
EXPECT_EQ(app_id, database().write_web_app_id());
EXPECT_EQ(101UL, registrar().registry_for_testing().size());
// Remove 1 app after Init.
registrar().UnregisterApp(app_id);
EXPECT_EQ(100UL, registrar().registry_for_testing().size());
EXPECT_EQ(1UL, database().delete_web_app_ids().size());
EXPECT_EQ(app_id, database().delete_web_app_ids()[0]);
// Remove 100 apps after Init.
registrar().UnregisterAll();
for (auto& app_id : database().delete_web_app_ids())
ids.erase(app_id);
EXPECT_TRUE(ids.empty());
EXPECT_TRUE(registrar().is_empty());
}
TEST_F(WebAppRegistrarTest, GetAppDataFields) {
const GURL launch_url = GURL("https://example.com/path");
const AppId app_id = GenerateAppIdFromURL(launch_url);
const std::string name = "Name";
const std::string description = "Description";
const base::Optional<SkColor> theme_color = 0xAABBCCDD;
const auto launch_container = LaunchContainer::kWindow;
EXPECT_EQ(std::string(), registrar().GetAppShortName(app_id));
EXPECT_EQ(GURL(), registrar().GetAppLaunchURL(app_id));
auto web_app = std::make_unique<WebApp>(app_id);
WebApp* web_app_ptr = web_app.get();
web_app->SetName(name);
web_app->SetDescription(description);
web_app->SetThemeColor(theme_color);
web_app->SetLaunchUrl(launch_url);
web_app->SetLaunchContainer(launch_container);
web_app->SetIsLocallyInstalled(/*is_locally_installed*/ false);
registrar().RegisterApp(std::move(web_app));
EXPECT_EQ(name, registrar().GetAppShortName(app_id));
EXPECT_EQ(description, registrar().GetAppDescription(app_id));
EXPECT_EQ(theme_color, registrar().GetAppThemeColor(app_id));
EXPECT_EQ(launch_url, registrar().GetAppLaunchURL(app_id));
EXPECT_EQ(launch_container, registrar().GetAppLaunchContainer(app_id));
EXPECT_FALSE(registrar().IsLocallyInstalled(app_id));
EXPECT_EQ(LaunchContainer::kDefault,
registrar().GetAppLaunchContainer("unknown"));
web_app_ptr->SetLaunchContainer(LaunchContainer::kTab);
EXPECT_EQ(LaunchContainer::kTab, registrar().GetAppLaunchContainer(app_id));
EXPECT_FALSE(registrar().IsLocallyInstalled("unknown"));
web_app_ptr->SetIsLocallyInstalled(/*is_locally_installed*/ true);
EXPECT_TRUE(registrar().IsLocallyInstalled(app_id));
}
TEST_F(WebAppRegistrarTest, CanFindAppsInScope) {
const GURL origin_scope("https://example.com/");
const GURL app1_scope("https://example.com/app");
const GURL app2_scope("https://example.com/app-two");
const GURL app3_scope("https://not-example.com/app");
std::vector<web_app::AppId> in_scope =
registrar().FindAppsInScope(origin_scope);
EXPECT_EQ(0u, in_scope.size());
auto app1 = std::make_unique<WebApp>("1");
app1->SetScope(app1_scope);
registrar().RegisterApp(std::move(app1));
in_scope = registrar().FindAppsInScope(origin_scope);
EXPECT_THAT(in_scope, testing::UnorderedElementsAre("1"));
in_scope = registrar().FindAppsInScope(app1_scope);
EXPECT_THAT(in_scope, testing::UnorderedElementsAre("1"));
auto app2 = std::make_unique<WebApp>("2");
app2->SetScope(app2_scope);
registrar().RegisterApp(std::move(app2));
in_scope = registrar().FindAppsInScope(origin_scope);
EXPECT_THAT(in_scope, testing::UnorderedElementsAre("1", "2"));
in_scope = registrar().FindAppsInScope(app1_scope);
EXPECT_THAT(in_scope, testing::UnorderedElementsAre("1", "2"));
in_scope = registrar().FindAppsInScope(app2_scope);
EXPECT_THAT(in_scope, testing::UnorderedElementsAre("2"));
auto app3 = std::make_unique<WebApp>("3");
app3->SetScope(app3_scope);
registrar().RegisterApp(std::move(app3));
in_scope = registrar().FindAppsInScope(origin_scope);
EXPECT_THAT(in_scope, testing::UnorderedElementsAre("1", "2"));
in_scope = registrar().FindAppsInScope(app3_scope);
EXPECT_THAT(in_scope, testing::UnorderedElementsAre("3"));
}
} // namespace web_app