blob: 14e0679fff079202840bcc55bbe03933199a4a74 [file] [log] [blame]
// Copyright 2021 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 <initializer_list>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "ash/components/arc/mojom/intent_common.mojom.h"
#include "ash/components/arc/mojom/intent_helper.mojom.h"
#include "base/check.h"
#include "base/containers/flat_map.h"
#include "base/values.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/apps/app_service/intent_util.h"
#include "chrome/browser/ash/file_manager/fileapi_util.h"
#include "chrome/browser/web_applications/test/web_app_test_utils.h"
#include "chrome/browser/web_applications/web_app.h"
#include "components/arc/intent_helper/intent_constants.h"
#include "components/arc/intent_helper/intent_filter.h"
#include "components/services/app_service/public/cpp/file_handler.h"
#include "components/services/app_service/public/cpp/intent_filter_util.h"
#include "components/services/app_service/public/cpp/intent_util.h"
#include "components/services/app_service/public/mojom/types.mojom.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/value_builder.h"
#include "mojo/public/cpp/bindings/struct_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "base/strings/strcat.h"
#include "chrome/browser/ash/file_manager/app_id.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "chromeos/crosapi/mojom/app_service_types.mojom.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/common/extension.h"
#include "storage/browser/file_system/external_mount_points.h"
#include "storage/common/file_system/file_system_mount_option.h"
#include "storage/common/file_system/file_system_types.h"
#include "storage/common/file_system/file_system_util.h"
#include "url/origin.h"
#include "url/url_constants.h"
class TestingProfile;
#endif
using apps::mojom::Condition;
using apps::mojom::ConditionType;
using apps::mojom::IntentFilterPtr;
using apps::mojom::PatternMatchType;
class IntentUtilsTest : public testing::Test {
protected:
arc::mojom::IntentInfoPtr CreateArcIntent() {
arc::mojom::IntentInfoPtr arc_intent = arc::mojom::IntentInfo::New();
arc_intent->action = "android.intent.action.PROCESS_TEXT";
std::vector<std::string> categories = {"text"};
arc_intent->categories = categories;
arc_intent->data = "/tmp";
arc_intent->type = "text/plain";
arc_intent->ui_bypassed = false;
base::flat_map<std::string, std::string> extras = {
{"android.intent.action.PROCESS_TEXT", "arc_apps"}};
arc_intent->extras = extras;
return arc_intent;
}
arc::mojom::ActivityNamePtr CreateActivity() {
arc::mojom::ActivityNamePtr arc_activity = arc::mojom::ActivityName::New();
arc_activity->package_name = "com.google.android.apps.translate";
arc_activity->activity_name =
"com.google.android.apps.translate.TranslateActivity";
return arc_activity;
}
bool IsEqual(arc::mojom::IntentInfoPtr src_intent,
arc::mojom::IntentInfoPtr dst_intent) {
if (!src_intent && !dst_intent) {
return true;
}
if (!src_intent || !dst_intent) {
return false;
}
if (src_intent->action != dst_intent->action) {
return false;
}
if (src_intent->categories != dst_intent->categories) {
return false;
}
if (src_intent->data != dst_intent->data) {
return false;
}
if (src_intent->ui_bypassed != dst_intent->ui_bypassed) {
return false;
}
if (src_intent->extras != dst_intent->extras) {
return false;
}
return true;
}
bool IsEqual(arc::mojom::ActivityNamePtr src_activity,
arc::mojom::ActivityNamePtr dst_activity) {
if (!src_activity && !dst_activity) {
return true;
}
if (!src_activity || !dst_activity) {
return false;
}
if (src_activity->activity_name != dst_activity->activity_name) {
return false;
}
return true;
}
};
TEST_F(IntentUtilsTest, CreateIntentForArcIntentAndActivity) {
arc::mojom::IntentInfoPtr arc_intent = CreateArcIntent();
arc::mojom::ActivityNamePtr src_activity = CreateActivity();
apps::mojom::IntentPtr intent =
apps_util::CreateIntentForArcIntentAndActivity(arc_intent.Clone(),
src_activity.Clone());
std::string intent_str =
apps_util::CreateLaunchIntent("com.android.vending", intent);
EXPECT_TRUE(intent_str.empty());
arc::mojom::ActivityNamePtr dst_activity = arc::mojom::ActivityName::New();
if (intent->activity_name.has_value() &&
!intent->activity_name.value().empty()) {
dst_activity->activity_name = intent->activity_name.value();
}
EXPECT_TRUE(IsEqual(std::move(arc_intent),
apps_util::ConvertAppServiceToArcIntent(intent)));
EXPECT_TRUE(IsEqual(std::move(src_activity), std::move(dst_activity)));
}
TEST_F(IntentUtilsTest, CreateIntentForActivity) {
const std::string& activity_name = "com.android.vending.AssetBrowserActivity";
const std::string& start_type = "initialStart";
const std::string& category = "android.intent.category.LAUNCHER";
apps::mojom::IntentPtr intent =
apps_util::CreateIntentForActivity(activity_name, start_type, category);
arc::mojom::IntentInfoPtr arc_intent =
apps_util::ConvertAppServiceToArcIntent(intent);
ASSERT_TRUE(intent);
ASSERT_TRUE(arc_intent);
std::string intent_str =
"#Intent;action=android.intent.action.MAIN;category=android.intent."
"category.LAUNCHER;launchFlags=0x10200000;component=com.android.vending/"
".AssetBrowserActivity;S.org.chromium.arc.start_type=initialStart;end";
EXPECT_EQ(intent_str,
apps_util::CreateLaunchIntent("com.android.vending", intent));
EXPECT_EQ(arc::kIntentActionMain, arc_intent->action);
base::flat_map<std::string, std::string> extras;
extras.insert(std::make_pair("org.chromium.arc.start_type", start_type));
EXPECT_TRUE(arc_intent->extras.has_value());
EXPECT_EQ(extras, arc_intent->extras);
EXPECT_TRUE(arc_intent->categories.has_value());
EXPECT_EQ(category, arc_intent->categories.value()[0]);
arc_intent->extras = apps_util::CreateArcIntentExtras(intent);
EXPECT_TRUE(intent->activity_name.has_value());
EXPECT_EQ(activity_name, intent->activity_name.value());
}
TEST_F(IntentUtilsTest, CreateShareIntentFromText) {
apps::mojom::IntentPtr intent =
apps_util::CreateShareIntentFromText("text", "title");
std::string intent_str =
"#Intent;action=android.intent.action.SEND;launchFlags=0x10200000;"
"component=com.android.vending/;type=text/"
"plain;S.android.intent.extra.TEXT=text;S.android.intent.extra.SUBJECT="
"title;end";
EXPECT_EQ(intent_str,
apps_util::CreateLaunchIntent("com.android.vending", intent));
}
TEST_F(IntentUtilsTest, CreateWebAppIntentFilters_WebApp_HasUrlFilter) {
auto web_app = web_app::test::CreateWebApp();
DCHECK(web_app->start_url().is_valid());
GURL scope = web_app->start_url().GetWithoutFilename();
web_app->SetScope(scope);
std::vector<IntentFilterPtr> filters =
apps_util::CreateWebAppIntentFilters(*web_app.get(), scope);
ASSERT_EQ(filters.size(), 1);
IntentFilterPtr& filter = filters[0];
EXPECT_FALSE(filter->activity_name.has_value());
EXPECT_FALSE(filter->activity_label.has_value());
ASSERT_EQ(filter->conditions.size(), 4U);
{
const Condition& condition = *filter->conditions[0];
EXPECT_EQ(condition.condition_type, ConditionType::kAction);
ASSERT_EQ(condition.condition_values.size(), 1U);
EXPECT_EQ(condition.condition_values[0]->match_type,
PatternMatchType::kNone);
EXPECT_EQ(condition.condition_values[0]->value,
apps_util::kIntentActionView);
}
{
const Condition& condition = *filter->conditions[1];
EXPECT_EQ(condition.condition_type, ConditionType::kScheme);
ASSERT_EQ(condition.condition_values.size(), 1U);
EXPECT_EQ(condition.condition_values[0]->match_type,
PatternMatchType::kNone);
EXPECT_EQ(condition.condition_values[0]->value, scope.scheme());
}
{
const Condition& condition = *filter->conditions[2];
EXPECT_EQ(condition.condition_type, ConditionType::kHost);
ASSERT_EQ(condition.condition_values.size(), 1U);
EXPECT_EQ(condition.condition_values[0]->match_type,
PatternMatchType::kNone);
EXPECT_EQ(condition.condition_values[0]->value, scope.host());
}
{
const Condition& condition = *filter->conditions[3];
EXPECT_EQ(condition.condition_type, ConditionType::kPattern);
ASSERT_EQ(condition.condition_values.size(), 1U);
EXPECT_EQ(condition.condition_values[0]->match_type,
PatternMatchType::kPrefix);
EXPECT_EQ(condition.condition_values[0]->value, scope.path());
}
EXPECT_TRUE(apps_util::IntentMatchesFilter(
apps_util::CreateIntentFromUrl(web_app->start_url()), filter));
EXPECT_FALSE(apps_util::IntentMatchesFilter(
apps_util::CreateIntentFromUrl(GURL("https://bar.com")), filter));
}
TEST_F(IntentUtilsTest, CreateWebAppIntentFilters_FileHandlers) {
auto web_app = web_app::test::CreateWebApp();
DCHECK(web_app->start_url().is_valid());
GURL scope = web_app->start_url().GetWithoutFilename();
web_app->SetScope(scope);
apps::FileHandler::AcceptEntry accept_entry;
accept_entry.mime_type = "text/plain";
accept_entry.file_extensions.insert(".txt");
apps::FileHandler file_handler;
file_handler.action = GURL("https://example.com/path/handler.html");
file_handler.accept.push_back(std::move(accept_entry));
apps::FileHandlers file_handlers;
file_handlers.push_back(std::move(file_handler));
web_app->SetFileHandlers(file_handlers);
std::vector<IntentFilterPtr> filters =
apps_util::CreateWebAppIntentFilters(*web_app.get(), scope);
ASSERT_EQ(filters.size(), 2);
// 1st filter is URL filter.
// File filter - View action
const IntentFilterPtr& file_filter = filters[1];
ASSERT_EQ(file_filter->conditions.size(), 2);
const Condition& view_cond = *file_filter->conditions[0];
EXPECT_EQ(view_cond.condition_type, ConditionType::kAction);
ASSERT_EQ(view_cond.condition_values.size(), 1);
EXPECT_EQ(view_cond.condition_values[0]->value, apps_util::kIntentActionView);
// File filter - mime & file extension match
const Condition& file_cond = *file_filter->conditions[1];
EXPECT_EQ(file_cond.condition_type, ConditionType::kFile);
ASSERT_EQ(file_cond.condition_values.size(), 2);
EXPECT_EQ(file_cond.condition_values[0]->match_type,
PatternMatchType::kMimeType);
EXPECT_EQ(file_cond.condition_values[0]->value, "text/plain");
EXPECT_EQ(file_cond.condition_values[1]->match_type,
PatternMatchType::kFileExtension);
EXPECT_EQ(file_cond.condition_values[1]->value, ".txt");
}
TEST_F(IntentUtilsTest, CreateWebAppIntentFilters_NoteTakingApp) {
auto web_app = web_app::test::CreateWebApp();
DCHECK(web_app->start_url().is_valid());
GURL scope = web_app->start_url().GetWithoutFilename();
web_app->SetScope(scope);
GURL new_note_url = scope.Resolve("/new_note.html");
web_app->SetNoteTakingNewNoteUrl(new_note_url);
std::vector<IntentFilterPtr> filters =
apps_util::CreateWebAppIntentFilters(*web_app.get(), scope);
ASSERT_EQ(filters.size(), 2);
// 1st filter is URL filter.
EXPECT_TRUE(apps_util::IntentMatchesFilter(
apps_util::CreateIntentFromUrl(scope), filters[0]));
// 2nd filter is note-taking filter.
ASSERT_EQ(filters[1]->conditions.size(), 1);
const Condition& condition = *filters[1]->conditions[0];
EXPECT_EQ(condition.condition_type, ConditionType::kAction);
ASSERT_EQ(condition.condition_values.size(), 1);
EXPECT_EQ(condition.condition_values[0]->value,
apps_util::kIntentActionCreateNote);
EXPECT_TRUE(apps_util::IntentMatchesFilter(
apps_util::CreateCreateNoteIntent(), filters[1]));
}
TEST_F(IntentUtilsTest, CreateChromeAppIntentFilters_FileHandlers) {
// Foo app provides file handler for text/plain and all file types.
extensions::ExtensionBuilder foo_app;
foo_app.SetManifest(
extensions::DictionaryBuilder()
.Set("name", "Foo")
.Set("version", "1.0.0")
.Set("manifest_version", 2)
.Set("app", extensions::DictionaryBuilder()
.Set("background",
extensions::DictionaryBuilder()
.Set("scripts", extensions::ListBuilder()
.Append("background.js")
.Build())
.Build())
.Build())
.Set(
"file_handlers",
extensions::DictionaryBuilder()
.Set("any",
extensions::DictionaryBuilder()
.Set("types",
extensions::ListBuilder().Append("*/*").Build())
.Build())
.Set("text",
extensions::DictionaryBuilder()
.Set("types", extensions::ListBuilder()
.Append("text/plain")
.Build())
.Set("extensions",
extensions::ListBuilder().Append("txt").Build())
.Set("verb", "open_with")
.Build())
.Build())
.Build());
foo_app.SetID("abcdzxcv");
scoped_refptr<const extensions::Extension> foo = foo_app.Build();
std::vector<IntentFilterPtr> filters =
apps_util::CreateChromeAppIntentFilters(foo.get());
ASSERT_EQ(filters.size(), 2);
// "any" filter - View action
const IntentFilterPtr& mime_filter = filters[0];
ASSERT_EQ(mime_filter->conditions.size(), 2);
const Condition& view_cond = *mime_filter->conditions[0];
EXPECT_EQ(view_cond.condition_type, ConditionType::kAction);
ASSERT_EQ(view_cond.condition_values.size(), 1);
EXPECT_EQ(view_cond.condition_values[0]->value, apps_util::kIntentActionView);
// "any" filter - mime type match
const Condition& file_cond = *mime_filter->conditions[1];
EXPECT_EQ(file_cond.condition_type, ConditionType::kFile);
ASSERT_EQ(file_cond.condition_values.size(), 1);
EXPECT_EQ(file_cond.condition_values[0]->match_type,
PatternMatchType::kMimeType);
EXPECT_EQ(file_cond.condition_values[0]->value, "*/*");
// Text filter - View action
const IntentFilterPtr& mime_filter2 = filters[1];
ASSERT_EQ(mime_filter2->conditions.size(), 2);
const Condition& view_cond2 = *mime_filter2->conditions[0];
EXPECT_EQ(view_cond2.condition_type, ConditionType::kAction);
ASSERT_EQ(view_cond2.condition_values.size(), 1);
EXPECT_EQ(view_cond2.condition_values[0]->value,
apps_util::kIntentActionView);
// Text filter - mime type match
const Condition& file_cond2 = *mime_filter2->conditions[1];
EXPECT_EQ(file_cond2.condition_type, ConditionType::kFile);
ASSERT_EQ(file_cond2.condition_values.size(), 2);
EXPECT_EQ(file_cond2.condition_values[0]->match_type,
PatternMatchType::kMimeType);
EXPECT_EQ(file_cond2.condition_values[0]->value, "text/plain");
// Text filter - file extension match
EXPECT_EQ(file_cond2.condition_values[1]->match_type,
PatternMatchType::kFileExtension);
EXPECT_EQ(file_cond2.condition_values[1]->value, "txt");
}
TEST_F(IntentUtilsTest, CreateExtensionIntentFilters_FileHandlers) {
// Foo extension provides file_browser_handlers for html and anything.
extensions::ExtensionBuilder foo_ext;
foo_ext.SetManifest(
extensions::DictionaryBuilder()
.Set("name", "Foo")
.Set("version", "1.0.0")
.Set("manifest_version", 2)
.Set(
"background",
extensions::DictionaryBuilder()
.Set(
"scripts",
extensions::ListBuilder().Append("background.js").Build())
.Set("persistent", false)
.Build())
.Set(
"file_browser_handlers",
extensions::ListBuilder()
.Append(
extensions::DictionaryBuilder()
.Set("id", "open")
.Set("default_title", "Open me!")
.Set("file_filters", extensions::ListBuilder()
.Append("filesystem:*.html")
.Build())
.Build())
.Append(extensions::DictionaryBuilder()
.Set("id", "open_all")
.Set("default_title", "Open anything!")
.Set("file_filters", extensions::ListBuilder()
.Append("filesystem:*.*")
.Build())
.Build())
.Build())
.Set("permissions",
extensions::ListBuilder().Append("fileBrowserHandler").Build())
.Build());
foo_ext.SetID("abcdzxcv");
scoped_refptr<const extensions::Extension> foo = foo_ext.Build();
std::vector<IntentFilterPtr> filters =
apps_util::CreateExtensionIntentFilters(foo.get());
ASSERT_EQ(filters.size(), 2);
// "html" filter - View action
const IntentFilterPtr& mime_filter = filters[0];
ASSERT_EQ(mime_filter->conditions.size(), 2);
const Condition& view_cond = *mime_filter->conditions[0];
EXPECT_EQ(view_cond.condition_type, ConditionType::kAction);
ASSERT_EQ(view_cond.condition_values.size(), 1);
EXPECT_EQ(view_cond.condition_values[0]->value, apps_util::kIntentActionView);
// "html" filter - glob match
const Condition& file_cond = *mime_filter->conditions[1];
EXPECT_EQ(file_cond.condition_type, ConditionType::kFile);
ASSERT_EQ(file_cond.condition_values.size(), 1);
EXPECT_EQ(file_cond.condition_values[0]->match_type, PatternMatchType::kGlob);
EXPECT_EQ(file_cond.condition_values[0]->value,
R"(filesystem:chrome-extension://.*/.*\.html)");
// "any" filter - View action
const IntentFilterPtr& mime_filter2 = filters[1];
ASSERT_EQ(mime_filter2->conditions.size(), 2);
const Condition& view_cond2 = *mime_filter2->conditions[0];
EXPECT_EQ(view_cond2.condition_type, ConditionType::kAction);
ASSERT_EQ(view_cond2.condition_values.size(), 1);
EXPECT_EQ(view_cond2.condition_values[0]->value,
apps_util::kIntentActionView);
// "any" filter - glob match
const Condition& file_cond2 = *mime_filter2->conditions[1];
EXPECT_EQ(file_cond2.condition_type, ConditionType::kFile);
ASSERT_EQ(file_cond2.condition_values.size(), 1);
EXPECT_EQ(file_cond2.condition_values[0]->match_type,
PatternMatchType::kGlob);
EXPECT_EQ(file_cond2.condition_values[0]->value,
R"(filesystem:chrome-extension://.*/.*\..*)");
}
// Converting an Arc Intent filter for a URL view intent filter should add a
// condition covering every possible path.
TEST_F(IntentUtilsTest, ConvertArcIntentFilter_AddsMissingPath) {
const char* kPackageName = "com.foo.bar";
const char* kHost = "www.google.com";
const char* kPath = "/";
const char* kScheme = "https";
std::vector<arc::IntentFilter::AuthorityEntry> authorities1;
authorities1.emplace_back(kHost, 0);
std::vector<arc::IntentFilter::PatternMatcher> patterns;
patterns.emplace_back(kPath, arc::mojom::PatternType::PATTERN_PREFIX);
arc::IntentFilter filter_with_path(kPackageName, {arc::kIntentActionView},
std::move(authorities1),
std::move(patterns), {kScheme}, {});
IntentFilterPtr app_service_filter1 =
apps_util::ConvertArcToAppServiceIntentFilter(filter_with_path);
std::vector<arc::IntentFilter::AuthorityEntry> authorities2;
authorities2.emplace_back(kHost, 0);
arc::IntentFilter filter_without_path(kPackageName, {arc::kIntentActionView},
std::move(authorities2), {}, {kScheme},
{});
IntentFilterPtr app_service_filter2 =
apps_util::ConvertArcToAppServiceIntentFilter(filter_without_path);
ASSERT_EQ(app_service_filter1, app_service_filter2);
}
TEST_F(IntentUtilsTest, ConvertArcIntentFilter_ConvertsSimpleGlobToPrefix) {
const char* kPackageName = "com.foo.bar";
const char* kHost = "www.google.com";
const char* kScheme = "https";
std::vector<arc::IntentFilter::AuthorityEntry> authorities;
authorities.emplace_back(kHost, 0);
std::vector<arc::IntentFilter::PatternMatcher> patterns;
patterns.emplace_back("/foo.*", arc::mojom::PatternType::PATTERN_SIMPLE_GLOB);
patterns.emplace_back(".*", arc::mojom::PatternType::PATTERN_SIMPLE_GLOB);
patterns.emplace_back("/foo/.*/bar",
arc::mojom::PatternType::PATTERN_SIMPLE_GLOB);
patterns.emplace_back("/..*", arc::mojom::PatternType::PATTERN_SIMPLE_GLOB);
arc::IntentFilter filter_with_path(kPackageName, {arc::kIntentActionView},
std::move(authorities),
std::move(patterns), {kScheme}, {});
IntentFilterPtr app_service_filter =
apps_util::ConvertArcToAppServiceIntentFilter(filter_with_path);
for (auto& condition : app_service_filter->conditions) {
if (condition->condition_type == apps::mojom::ConditionType::kPattern) {
EXPECT_EQ(4u, condition->condition_values.size());
EXPECT_EQ(apps_util::MakeConditionValue(
"/foo", apps::mojom::PatternMatchType::kPrefix),
condition->condition_values[0]);
EXPECT_EQ(apps_util::MakeConditionValue(
std::string(), apps::mojom::PatternMatchType::kPrefix),
condition->condition_values[1]);
EXPECT_EQ(apps_util::MakeConditionValue(
"/foo/.*/bar", apps::mojom::PatternMatchType::kGlob),
condition->condition_values[2]);
EXPECT_EQ(apps_util::MakeConditionValue(
"/..*", apps::mojom::PatternMatchType::kGlob),
condition->condition_values[3]);
}
}
}
TEST_F(IntentUtilsTest, ConvertArcIntentFilter_DeduplicatesHosts) {
const char* kPackageName = "com.foo.bar";
const char* kPath = "/";
const char* kScheme = "https";
const char* kHost1 = "www.a.com";
const char* kHost2 = "www.b.com";
std::vector<arc::IntentFilter::AuthorityEntry> authorities;
authorities.emplace_back(kHost1, 0);
authorities.emplace_back(kHost2, 0);
authorities.emplace_back(kHost2, 0);
authorities.emplace_back(kHost1, 0);
std::vector<arc::IntentFilter::PatternMatcher> patterns;
patterns.emplace_back(kPath, arc::mojom::PatternType::PATTERN_PREFIX);
arc::IntentFilter arc_filter(kPackageName, {arc::kIntentActionView},
std::move(authorities), std::move(patterns),
{kScheme}, {});
IntentFilterPtr app_service_filter =
apps_util::ConvertArcToAppServiceIntentFilter(arc_filter);
for (auto& condition : app_service_filter->conditions) {
if (condition->condition_type == apps::mojom::ConditionType::kHost) {
ASSERT_EQ(2u, condition->condition_values.size());
ASSERT_EQ(kHost1, condition->condition_values[0]->value);
ASSERT_EQ(kHost2, condition->condition_values[1]->value);
}
}
}
#if defined(OS_CHROMEOS)
TEST_F(IntentUtilsTest, CrosapiIntentConversion) {
apps::mojom::IntentPtr original_intent =
apps_util::CreateIntentFromUrl(GURL("www.google.com"));
auto crosapi_intent =
apps_util::ConvertAppServiceToCrosapiIntent(original_intent, nullptr);
auto converted_intent =
apps_util::ConvertCrosapiToAppServiceIntent(crosapi_intent, nullptr);
EXPECT_EQ(original_intent, converted_intent);
original_intent = apps_util::CreateShareIntentFromText("text", "title");
crosapi_intent =
apps_util::ConvertAppServiceToCrosapiIntent(original_intent, nullptr);
converted_intent =
apps_util::ConvertCrosapiToAppServiceIntent(crosapi_intent, nullptr);
EXPECT_EQ(original_intent, converted_intent);
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
class IntentUtilsFileTest : public ::testing::Test {
public:
void SetUp() override {
testing::Test::SetUp();
profile_manager_ = std::make_unique<TestingProfileManager>(
TestingBrowserProcess::GetGlobal());
ASSERT_TRUE(profile_manager_->SetUp());
profile_ = profile_manager_->CreateTestingProfile("testing_profile");
ASSERT_TRUE(
storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
mount_name_, storage::FileSystemType::kFileSystemTypeExternal,
storage::FileSystemMountOption(), base::FilePath(fs_root_)));
}
void TearDown() override {
ASSERT_TRUE(
storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
mount_name_));
profile_manager_->DeleteAllTestingProfiles();
profile_ = nullptr;
profile_manager_.reset();
}
TestingProfile* GetProfile() { return profile_; }
// FileUtils explicitly relies on ChromeOS Files.app for files manipulation.
const url::Origin GetFileManagerOrigin() {
return url::Origin::Create(file_manager::util::GetFileManagerURL());
}
// For a given |root| converts the given virtual |path| to a GURL.
GURL ToGURL(const base::FilePath& root, const std::string& path) {
const std::string abs_path = root.Append(path).value();
return GURL(base::StrCat({url::kFileSystemScheme, ":",
GetFileManagerOrigin().Serialize(), abs_path}));
}
protected:
const std::string mount_name_ = "TestMountName";
const std::string fs_root_ = "/path/to/test/filesystemroot";
private:
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<TestingProfileManager> profile_manager_;
TestingProfile* profile_;
};
TEST_F(IntentUtilsFileTest, AppServiceIntentToCrosapi) {
auto app_service_intent = apps::mojom::Intent::New();
app_service_intent->action = "action";
app_service_intent->mime_type = "*/*";
const std::string path = "Documents/foo.txt";
const std::string mime_type = "text/plain";
auto url = ToGURL(base::FilePath(storage::kTestDir), path);
app_service_intent->files = std::vector<apps::mojom::IntentFilePtr>{};
auto file = apps::mojom::IntentFile::New();
file->url = url;
file->mime_type = mime_type;
app_service_intent->files->push_back(std::move(file));
auto crosapi_intent = apps_util::ConvertAppServiceToCrosapiIntent(
app_service_intent, GetProfile());
EXPECT_EQ(app_service_intent->action, crosapi_intent->action);
EXPECT_EQ(app_service_intent->mime_type, crosapi_intent->mime_type);
ASSERT_TRUE(crosapi_intent->files.has_value());
ASSERT_EQ(crosapi_intent->files.value().size(), 1U);
EXPECT_EQ(crosapi_intent->files.value()[0]->file_path, base::FilePath(path));
EXPECT_EQ(crosapi_intent->files.value()[0]->mime_type, mime_type);
}
TEST_F(IntentUtilsFileTest, CrosapiIntentToAppService) {
const std::string path = "Documents/foo.txt";
auto file_path = base::FilePath(fs_root_).Append(path);
auto file_paths = apps::mojom::FilePaths::New();
file_paths->file_paths.push_back(file_path);
auto crosapi_intent = apps_util::CreateCrosapiIntentForViewFiles(file_paths);
auto app_service_intent =
apps_util::ConvertCrosapiToAppServiceIntent(crosapi_intent, GetProfile());
EXPECT_EQ(app_service_intent->action, crosapi_intent->action);
EXPECT_EQ(app_service_intent->mime_type, crosapi_intent->mime_type);
ASSERT_TRUE(crosapi_intent->files.has_value());
ASSERT_EQ(crosapi_intent->files.value().size(), 1U);
EXPECT_EQ(
app_service_intent->files.value()[0]->url,
ToGURL(base::FilePath(storage::kExternalDir).Append(mount_name_), path));
}
#endif