blob: fa7207e76bead3fbbda767589699152757b008d7 [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/chromeos/accessibility/ax_host_service.h"
#include "base/bind.h"
#include "base/macros.h"
#include "base/test/scoped_task_environment.h"
#include "chrome/browser/chromeos/accessibility/ax_remote_host_delegate.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_tree_id_registry.h"
#include "ui/accessibility/mojom/ax_host.mojom.h"
namespace {
class TestAXRemoteHost : ax::mojom::AXRemoteHost {
public:
TestAXRemoteHost() : binding_(this) {}
~TestAXRemoteHost() override = default;
ax::mojom::AXRemoteHostPtr CreateInterfacePtr() {
ax::mojom::AXRemoteHostPtr ptr;
binding_.Bind(mojo::MakeRequest(&ptr));
return ptr;
}
// Simulates the real AXRemoteHost.
void RegisterRemoteHostCallback(const ui::AXTreeID& tree_id, bool enabled) {
tree_id_ = tree_id;
OnAutomationEnabled(enabled);
}
// ax::mojom::AXRemoteHost:
void OnAutomationEnabled(bool enabled) override {
++automation_enabled_count_;
last_automation_enabled_ = enabled;
}
void PerformAction(const ui::AXActionData& action) override {
++perform_action_count_;
last_action_ = action;
}
mojo::Binding<ax::mojom::AXRemoteHost> binding_;
ui::AXTreeID tree_id_;
int automation_enabled_count_ = 0;
bool last_automation_enabled_ = false;
int perform_action_count_ = 0;
ui::AXActionData last_action_;
private:
DISALLOW_COPY_AND_ASSIGN(TestAXRemoteHost);
};
class AXHostServiceTest : public testing::Test {
public:
AXHostServiceTest() = default;
~AXHostServiceTest() override = default;
void RegisterRemoteHost(AXHostService* service, TestAXRemoteHost* remote) {
service->RegisterRemoteHost(
remote->CreateInterfacePtr(),
base::BindOnce(&TestAXRemoteHost::RegisterRemoteHostCallback,
base::Unretained(remote)));
service->FlushForTesting();
}
private:
base::test::ScopedTaskEnvironment scoped_task_enviroment_;
DISALLOW_COPY_AND_ASSIGN(AXHostServiceTest);
};
TEST_F(AXHostServiceTest, AddClientThenEnable) {
AXHostService service;
TestAXRemoteHost remote;
RegisterRemoteHost(&service, &remote);
// Remote received initial state.
EXPECT_EQ(1, remote.automation_enabled_count_);
EXPECT_FALSE(remote.last_automation_enabled_);
// AXHostService assigned a tree id.
ui::AXTreeID tree_id = remote.tree_id_;
EXPECT_NE(ui::AXTreeIDUnknown(), tree_id);
AXHostService::SetAutomationEnabled(true);
service.FlushForTesting();
// Remote received updated state.
EXPECT_EQ(2, remote.automation_enabled_count_);
EXPECT_TRUE(remote.last_automation_enabled_);
}
TEST_F(AXHostServiceTest, EnableThenAddClient) {
AXHostService service;
AXHostService::SetAutomationEnabled(true);
TestAXRemoteHost remote;
RegisterRemoteHost(&service, &remote);
// Remote received initial state.
EXPECT_EQ(1, remote.automation_enabled_count_);
EXPECT_TRUE(remote.last_automation_enabled_);
// AXHostService assigned a tree id.
EXPECT_NE(ui::AXTreeIDUnknown(), remote.tree_id_);
}
TEST_F(AXHostServiceTest, PerformAction) {
AXHostService service;
AXHostService::SetAutomationEnabled(true);
TestAXRemoteHost remote;
RegisterRemoteHost(&service, &remote);
// AXHostDelegate was created.
ui::AXTreeID tree_id = remote.tree_id_;
ui::AXHostDelegate* delegate =
ui::AXTreeIDRegistry::GetInstance()->GetHostDelegate(tree_id);
ASSERT_TRUE(delegate);
// Trigger an action.
ui::AXActionData action;
action.action = ax::mojom::Action::kScrollUp;
delegate->PerformAction(action);
service.FlushForTesting();
// Remote interface received the action.
EXPECT_EQ(1, remote.perform_action_count_);
EXPECT_EQ(ax::mojom::Action::kScrollUp, remote.last_action_.action);
}
TEST_F(AXHostServiceTest, MultipleRemoteHosts) {
AXHostService service;
AXHostService::SetAutomationEnabled(true);
// Connect 2 remote hosts.
TestAXRemoteHost remote1;
RegisterRemoteHost(&service, &remote1);
TestAXRemoteHost remote2;
RegisterRemoteHost(&service, &remote2);
// Different tree ids were assigned.
EXPECT_NE(ui::AXTreeIDUnknown(), remote1.tree_id_);
EXPECT_NE(ui::AXTreeIDUnknown(), remote2.tree_id_);
EXPECT_NE(remote1.tree_id_, remote2.tree_id_);
// Trigger an action on the first remote.
ui::AXActionData action;
action.action = ax::mojom::Action::kScrollUp;
ui::AXHostDelegate* delegate =
ui::AXTreeIDRegistry::GetInstance()->GetHostDelegate(remote1.tree_id_);
delegate->PerformAction(action);
service.FlushForTesting();
// Remote 1 received the action.
EXPECT_EQ(1, remote1.perform_action_count_);
EXPECT_EQ(ax::mojom::Action::kScrollUp, remote1.last_action_.action);
// Remote 2 did not receive the action.
EXPECT_EQ(0, remote2.perform_action_count_);
}
TEST_F(AXHostServiceTest, RemoteHostDisconnect) {
AXHostService service;
AXHostService::SetAutomationEnabled(true);
// Connect 2 remote hosts.
TestAXRemoteHost remote1;
RegisterRemoteHost(&service, &remote1);
TestAXRemoteHost remote2;
RegisterRemoteHost(&service, &remote2);
// Tree IDs exist for both.
auto* tree_id_registry = ui::AXTreeIDRegistry::GetInstance();
EXPECT_TRUE(tree_id_registry->GetHostDelegate(remote1.tree_id_));
EXPECT_TRUE(tree_id_registry->GetHostDelegate(remote2.tree_id_));
// Simulate remote 1 disconnecting.
service.OnRemoteHostDisconnected(remote1.tree_id_);
// Tree ID for remote 1 is gone.
EXPECT_FALSE(tree_id_registry->GetHostDelegate(remote1.tree_id_));
EXPECT_TRUE(tree_id_registry->GetHostDelegate(remote2.tree_id_));
}
} // namespace