#include "chrome/browser/browsing_data/counters/hosted_apps_counter.h"
#include <algorithm>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/uuid.h"
#include "base/values.h"
#include "chrome/test/base/testing_profile.h"
#include "components/browsing_data/core/browsing_data_utils.h"
#include "components/browsing_data/core/pref_names.h"
#include "components/crx_file/id_util.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension_builder.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class HostedAppsCounterTest : public testing::Test {
public:
void SetUp() override {
profile_ = std::make_unique<TestingProfile>();
extension_registry_ = extensions::ExtensionRegistry::Get(profile_.get());
SetHostedAppsDeletionPref(true);
SetDeletionPeriodPref(browsing_data::TimePeriod::ALL_TIME);
}
std::string AddExtension() {
return AddItem(base::Uuid::GenerateRandomV4().AsLowercaseString(),
std::nullopt);
}
std::string AddPackagedApp() {
return AddItem(
base::Uuid::GenerateRandomV4().AsLowercaseString(),
base::Value::Dict().Set(
"launch", base::Value::Dict().Set("local_path", "index.html")));
}
std::string AddHostedApp() {
return AddHostedAppWithName(
base::Uuid::GenerateRandomV4().AsLowercaseString());
}
std::string AddHostedAppWithName(const std::string& name) {
return AddItem(
name,
base::Value::Dict()
.Set("urls", base::Value::List().Append("https://example.com"))
.Set("launch",
base::Value::Dict().Set("web_url", "https://example.com")));
}
std::string AddItem(const std::string& name,
std::optional<base::Value::Dict> app_manifest) {
auto manifest_builder = base::Value::Dict()
.Set("manifest_version", 2)
.Set("name", name)
.Set("version", "1");
if (app_manifest) {
manifest_builder.Set("app", std::move(*app_manifest));
}
scoped_refptr<const extensions::Extension> item =
extensions::ExtensionBuilder()
.SetManifest(std::move(manifest_builder))
.SetID(crx_file::id_util::GenerateId(name))
.Build();
extension_registry_->AddEnabled(item.get());
return item->id();
}
void RemoveItem(const std::string& id) {
extension_registry_->RemoveEnabled(id);
}
void SetHostedAppsDeletionPref(bool value) {
GetProfile()->GetPrefs()->SetBoolean(
browsing_data::prefs::kDeleteHostedAppsData, value);
}
void SetDeletionPeriodPref(browsing_data::TimePeriod period) {
GetProfile()->GetPrefs()->SetInteger(
browsing_data::prefs::kDeleteTimePeriod, static_cast<int>(period));
}
browsing_data::BrowsingDataCounter::ResultInt GetNumHostedApps() {
DCHECK(finished_);
return num_apps_;
}
const std::vector<std::string>& GetExamples() {
DCHECK(finished_);
return examples_;
}
void Callback(
std::unique_ptr<browsing_data::BrowsingDataCounter::Result> result) {
finished_ = result->Finished();
if (finished_) {
HostedAppsCounter::HostedAppsResult* hosted_apps_result =
static_cast<HostedAppsCounter::HostedAppsResult*>(result.get());
num_apps_ = hosted_apps_result->Value();
examples_ = hosted_apps_result->examples();
}
}
Profile* GetProfile() {
return profile_.get();
}
private:
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<TestingProfile> profile_;
raw_ptr<extensions::ExtensionRegistry> extension_registry_;
bool finished_;
browsing_data::BrowsingDataCounter::ResultInt num_apps_;
std::vector<std::string> examples_;
};
TEST_F(HostedAppsCounterTest, Count) {
Profile* profile = GetProfile();
HostedAppsCounter counter(profile);
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
base::BindRepeating(&HostedAppsCounterTest::Callback,
base::Unretained(this)));
counter.Restart();
EXPECT_EQ(0u, GetNumHostedApps());
std::string first_app = AddHostedApp();
AddHostedApp();
std::string last_app = AddHostedApp();
counter.Restart();
EXPECT_EQ(3u, GetNumHostedApps());
RemoveItem(last_app);
RemoveItem(first_app);
counter.Restart();
EXPECT_EQ(1u, GetNumHostedApps());
AddHostedApp();
counter.Restart();
EXPECT_EQ(2u, GetNumHostedApps());
}
TEST_F(HostedAppsCounterTest, OnlyHostedApps) {
Profile* profile = GetProfile();
HostedAppsCounter counter(profile);
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
base::BindRepeating(&HostedAppsCounterTest::Callback,
base::Unretained(this)));
AddHostedApp();
AddExtension();
AddPackagedApp();
AddExtension();
counter.Restart();
EXPECT_EQ(1u, GetNumHostedApps());
AddHostedApp();
AddHostedApp();
AddExtension();
counter.Restart();
EXPECT_EQ(3u, GetNumHostedApps());
AddPackagedApp();
AddExtension();
counter.Restart();
EXPECT_EQ(3u, GetNumHostedApps());
AddHostedApp();
AddPackagedApp();
AddHostedApp();
AddExtension();
AddExtension();
AddExtension();
AddPackagedApp();
counter.Restart();
EXPECT_EQ(5u, GetNumHostedApps());
}
TEST_F(HostedAppsCounterTest, Examples) {
Profile* profile = GetProfile();
HostedAppsCounter counter(profile);
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
base::BindRepeating(&HostedAppsCounterTest::Callback,
base::Unretained(this)));
counter.Restart();
EXPECT_EQ(0u, GetExamples().size());
AddHostedAppWithName("App 1");
counter.Restart();
EXPECT_EQ(1u, GetExamples().size());
EXPECT_EQ("App 1", GetExamples().front());
AddHostedAppWithName("App 2");
counter.Restart();
EXPECT_EQ(2u, GetExamples().size());
EXPECT_EQ("App 1", GetExamples().front());
EXPECT_EQ("App 2", GetExamples().back());
AddHostedAppWithName("App 3");
counter.Restart();
EXPECT_EQ(2u, GetExamples().size());
EXPECT_EQ("App 1", GetExamples().front());
EXPECT_EQ("App 2", GetExamples().back());
}
}