blob: 1160ae5eb8332cdb4ea63679fc43c981398040ea [file] [log] [blame]
// Copyright 2020 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/ash/crostini/crostini_shelf_utils.h"
#include <iterator>
#include <memory>
#include "base/stl_util.h"
#include "base/values.h"
#include "chrome/browser/ash/crostini/crostini_test_helper.h"
#include "chrome/browser/ash/guest_os/guest_os_pref_names.h"
#include "chrome/browser/ash/guest_os/guest_os_registry_service.h"
#include "chrome/test/base/testing_profile.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace crostini {
namespace {
struct App {
std::string desktop_file_id;
std::string vm_name = "vm";
std::string container_name = "container";
std::string app_name;
absl::optional<std::string> startup_wm_class;
absl::optional<bool> startup_notify;
absl::optional<bool> no_display;
};
struct WindowIds {
absl::optional<std::string> app_id;
absl::optional<std::string> startup_id;
};
std::string GenAppId(const App& app) {
return CrostiniTestHelper::GenerateAppId(app.desktop_file_id, app.vm_name,
app.container_name);
}
} // namespace
class CrostiniShelfUtilsTest : public testing::Test {
public:
std::string GetShelfAppId(WindowIds window_ids) const {
return GetCrostiniShelfAppId(
&testing_profile_, base::OptionalOrNullptr(window_ids.app_id),
base::OptionalOrNullptr(window_ids.startup_id));
}
void SetGuestOsRegistry(std::vector<App> apps) {
using AppLists = std::map<std::pair<std::string, std::string>,
vm_tools::apps::ApplicationList>;
AppLists app_lists;
for (App& in_app : apps) {
AppLists::key_type key(std::move(in_app.vm_name),
std::move(in_app.container_name));
AppLists::iterator app_list_it = app_lists.find(key);
if (app_list_it == app_lists.cend()) {
vm_tools::apps::ApplicationList app_list;
app_list.set_vm_name(key.first);
app_list.set_container_name(key.second);
app_list_it = app_lists.emplace_hint(app_list_it, std::move(key),
std::move(app_list));
}
vm_tools::apps::App& out_app = *app_list_it->second.add_apps();
out_app.set_desktop_file_id(std::move(in_app.desktop_file_id));
out_app.mutable_name()->add_values()->set_value(
std::move(in_app.app_name));
if (in_app.startup_wm_class)
out_app.set_startup_wm_class(std::move(*in_app.startup_wm_class));
if (in_app.startup_notify)
out_app.set_startup_notify(*in_app.startup_notify);
if (in_app.no_display)
out_app.set_no_display(*in_app.no_display);
}
guest_os::GuestOsRegistryService service(&testing_profile_);
for (AppLists::value_type& value : app_lists) {
service.UpdateApplicationList(std::move(value.second));
}
}
private:
content::BrowserTaskEnvironment task_environment_;
TestingProfile testing_profile_;
};
TEST_F(CrostiniShelfUtilsTest,
GetCrostiniShelfAppIdReturnsEmptyIdWhenCalledWithoutAnyParametersSet) {
SetGuestOsRegistry({});
EXPECT_EQ(GetShelfAppId(WindowIds()), "");
}
TEST_F(CrostiniShelfUtilsTest,
GetCrostiniShelfAppIdFindsAppWithEitherWindowIdOrAppId) {
SetGuestOsRegistry({
{.desktop_file_id = "cool.app"},
});
// App is found using wm app_id.
EXPECT_EQ(GetShelfAppId({.app_id = "org.chromium.termina.wmclass.cool.app"}),
GenAppId({.desktop_file_id = "cool.app"}));
// App is found using app_id.
EXPECT_EQ(GetShelfAppId({.app_id = "cool.app"}),
GenAppId({.desktop_file_id = "cool.app"}));
}
TEST_F(CrostiniShelfUtilsTest, GetCrostiniShelfAppIdIgnoresWindowAppIdsCase) {
SetGuestOsRegistry({
{.desktop_file_id = "app"},
});
// App is found using capitalized App.
EXPECT_EQ(GetShelfAppId({.app_id = "org.chromium.termina.wmclass.App"}),
GenAppId({.desktop_file_id = "app"}));
}
TEST_F(
CrostiniShelfUtilsTest,
GetCrostiniShelfAppIdCantFindAppWhenMultipleAppsInDifferentVmsShareDesktopFileIds) {
SetGuestOsRegistry({
{.desktop_file_id = "super"},
{.desktop_file_id = "super", .vm_name = "vm 2"},
});
// Neither app is found, as they can't be disambiguated.
EXPECT_EQ(GetShelfAppId({.app_id = "org.chromium.termina.wmclass.super"}),
"crostini:org.chromium.termina.wmclass.super");
}
TEST_F(CrostiniShelfUtilsTest,
GetCrostiniShelfAppIdDoesntFindAppWhenGivenUnregisteredAppIds) {
SetGuestOsRegistry({});
EXPECT_EQ(
GetShelfAppId({.app_id = "org.chromium.termina.wmclientleader.1234"}),
"crostini:org.chromium.termina.wmclientleader.1234");
EXPECT_EQ(GetShelfAppId({.app_id = "org.chromium.termina.xid.654321"}),
"crostini:org.chromium.termina.xid.654321");
EXPECT_EQ(GetShelfAppId({.app_id = "fancy.app"}), "crostini:fancy.app");
}
TEST_F(CrostiniShelfUtilsTest,
GetCrostiniShelfAppIdCanFindAppUsingItsStartupWmClass) {
SetGuestOsRegistry({
{.desktop_file_id = "app", .startup_wm_class = "app_start"},
});
// App is found using it's startup_wm_class.
EXPECT_EQ(GetShelfAppId({.app_id = "org.chromium.termina.wmclass.app_start"}),
GenAppId({.desktop_file_id = "app"}));
}
TEST_F(
CrostiniShelfUtilsTest,
GetCrostiniShelfAppIdCantFindAppIfMultipleAppsStartupWmClassesAreTheSame) {
SetGuestOsRegistry({
{.desktop_file_id = "app2", .startup_wm_class = "app2"},
{.desktop_file_id = "app3", .startup_wm_class = "app2"},
});
// Neither app is found, as they can't be disambiguated.
EXPECT_EQ(GetShelfAppId({.app_id = "org.chromium.termina.wmclass.app2"}),
"crostini:org.chromium.termina.wmclass.app2");
}
TEST_F(CrostiniShelfUtilsTest,
GetCrostiniShelfAppIdCanFindAppUsingStartupIdIfStartupNotifyIsTrue) {
SetGuestOsRegistry({
{.desktop_file_id = "app", .startup_notify = true},
{.desktop_file_id = "app2", .startup_notify = false},
});
// App's startup_notify is true, so it can be found using startup_id.
EXPECT_EQ(GetShelfAppId({.startup_id = "app"}),
GenAppId({.desktop_file_id = "app"}));
// App's startup_notify is true, so it can be found using startup_id, even if
// app_id is set.
EXPECT_EQ(GetShelfAppId({.app_id = "unknown_app_id", .startup_id = "app"}),
GenAppId({.desktop_file_id = "app"}));
// App's startup_notify is false, so startup_id is ignored and no app was
// found.
EXPECT_EQ(GetShelfAppId({.app_id = "unknown_app_id", .startup_id = "app2"}),
"crostini:unknown_app_id");
}
TEST_F(CrostiniShelfUtilsTest, GetCrostiniShelfAppIdCanFindAppsByName) {
SetGuestOsRegistry({
{.desktop_file_id = "app", .app_name = "name"},
});
// App found by app_name: "name".
EXPECT_EQ(GetShelfAppId({.app_id = "org.chromium.termina.wmclass.name"}),
GenAppId({.desktop_file_id = "app"}));
}
TEST_F(CrostiniShelfUtilsTest,
GetCrostiniShelfAppIdDoesntFindAppsByNameIfTheyHaveNoDisplaySet) {
// One no_display app.
SetGuestOsRegistry({
{.desktop_file_id = "another_app",
.app_name = "name",
.no_display = true},
});
// No app is found.
EXPECT_EQ(GetShelfAppId({.app_id = "org.chromium.termina.wmclass.name"}),
"crostini:org.chromium.termina.wmclass.name");
// Two apps with the same name, where one is no_display.
SetGuestOsRegistry({
{.desktop_file_id = "app", .app_name = "name"},
{.desktop_file_id = "another_app",
.app_name = "name",
.no_display = true},
});
// The app without no_display set is found.
EXPECT_EQ(GetShelfAppId({.app_id = "org.chromium.termina.wmclass.name"}),
GenAppId({.desktop_file_id = "app"}));
}
} // namespace crostini