blob: 481a8c695a729bc64aa2cc29fe3f224596334802 [file] [log] [blame]
// Copyright (c) 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 "content/browser/accessibility/browser_accessibility_auralinux.h"
#include <atk/atk.h>
#include <memory>
#include <string>
#include <vector>
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/test_browser_accessibility_delegate.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/platform/ax_platform_node_auralinux.h"
namespace content {
class BrowserAccessibilityAuraLinuxTest : public testing::Test {
public:
BrowserAccessibilityAuraLinuxTest();
~BrowserAccessibilityAuraLinuxTest() override;
protected:
std::unique_ptr<TestBrowserAccessibilityDelegate>
test_browser_accessibility_delegate_;
private:
void SetUp() override;
content::TestBrowserThreadBundle thread_bundle_;
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityAuraLinuxTest);
};
BrowserAccessibilityAuraLinuxTest::BrowserAccessibilityAuraLinuxTest() {}
BrowserAccessibilityAuraLinuxTest::~BrowserAccessibilityAuraLinuxTest() {}
void BrowserAccessibilityAuraLinuxTest::SetUp() {
test_browser_accessibility_delegate_ =
std::make_unique<TestBrowserAccessibilityDelegate>();
}
TEST_F(BrowserAccessibilityAuraLinuxTest, TestSimpleAtkText) {
ui::AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kStaticText;
root_data.SetName("\xE2\x98\xBA Multiple Words");
std::unique_ptr<BrowserAccessibilityManager> manager(
BrowserAccessibilityManager::Create(
MakeAXTreeUpdate(root_data),
test_browser_accessibility_delegate_.get(),
new BrowserAccessibilityFactory()));
ui::AXPlatformNodeAuraLinux* root_obj =
ToBrowserAccessibilityAuraLinux(manager->GetRoot())->GetNode();
AtkObject* root_atk_object(root_obj->GetNativeViewAccessible());
ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
ASSERT_TRUE(ATK_IS_TEXT(root_atk_object));
g_object_ref(root_atk_object);
AtkText* atk_text = ATK_TEXT(root_atk_object);
auto verify_atk_text_contents = [&](const char* expected_text,
int start_offset, int end_offset) {
gchar* text = atk_text_get_text(atk_text, start_offset, end_offset);
EXPECT_STREQ(expected_text, text);
g_free(text);
};
verify_atk_text_contents("\xE2\x98\xBA Multiple Words", 0, -1);
verify_atk_text_contents("Multiple Words", 2, -1);
verify_atk_text_contents("\xE2\x98\xBA", 0, 1);
EXPECT_EQ(16, atk_text_get_character_count(atk_text));
g_object_unref(root_atk_object);
manager.reset();
}
TEST_F(BrowserAccessibilityAuraLinuxTest, TestCompositeAtkText) {
const std::string text1_name = "One two three.";
const std::string text2_name = " Four five six.";
const int text_name_len = text1_name.length() + text2_name.length();
ui::AXNodeData text1;
text1.id = 11;
text1.role = ax::mojom::Role::kStaticText;
text1.SetName(text1_name);
ui::AXNodeData text2;
text2.id = 12;
text2.role = ax::mojom::Role::kStaticText;
text2.SetName(text2_name);
ui::AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
root.child_ids.push_back(text1.id);
root.child_ids.push_back(text2.id);
std::unique_ptr<BrowserAccessibilityManager> manager(
BrowserAccessibilityManager::Create(
MakeAXTreeUpdate(root, text1, text2),
test_browser_accessibility_delegate_.get(),
new BrowserAccessibilityFactory()));
ui::AXPlatformNodeAuraLinux* root_obj =
ToBrowserAccessibilityAuraLinux(manager->GetRoot())->GetNode();
AtkObject* root_atk_object(root_obj->GetNativeViewAccessible());
ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
ASSERT_TRUE(ATK_IS_TEXT(root_atk_object));
g_object_ref(root_atk_object);
AtkText* atk_text = ATK_TEXT(root_atk_object);
EXPECT_EQ(text_name_len, atk_text_get_character_count(atk_text));
gchar* text = atk_text_get_text(atk_text, 0, -1);
EXPECT_STREQ((text1_name + text2_name).c_str(), text);
g_free(text);
ASSERT_TRUE(ATK_IS_HYPERTEXT(root_atk_object));
AtkHypertext* atk_hypertext = ATK_HYPERTEXT(root_atk_object);
// There should be no hyperlinks in the node and trying to get one should
// always return -1.
EXPECT_EQ(0, atk_hypertext_get_n_links(atk_hypertext));
EXPECT_EQ(-1, atk_hypertext_get_link_index(atk_hypertext, 0));
EXPECT_EQ(-1, atk_hypertext_get_link_index(atk_hypertext, -1));
EXPECT_EQ(-1, atk_hypertext_get_link_index(atk_hypertext, 1));
g_object_unref(root_atk_object);
manager.reset();
}
TEST_F(BrowserAccessibilityAuraLinuxTest, TestComplexHypertext) {
const std::string text1_name = "One two three.";
const std::string combo_box_name = "City:";
const std::string combo_box_value = "Happyland";
const std::string text2_name = " Four five six.";
const std::string check_box_name = "I agree";
const std::string check_box_value = "Checked";
const std::string button_text_name = "Red";
const std::string link_text_name = "Blue";
// Each control (combo / check box, button and link) will be represented by an
// embedded object character.
const base::string16 string16_embed(
1, ui::AXPlatformNodeAuraLinux::kEmbeddedCharacter);
const std::string embed = base::UTF16ToUTF8(string16_embed);
const std::string root_hypertext =
text1_name + embed + text2_name + embed + embed + embed;
ui::AXNodeData text1;
text1.id = 11;
text1.role = ax::mojom::Role::kStaticText;
text1.SetName(text1_name);
ui::AXNodeData combo_box;
combo_box.id = 12;
combo_box.role = ax::mojom::Role::kTextFieldWithComboBox;
combo_box.AddState(ax::mojom::State::kEditable);
combo_box.SetName(combo_box_name);
combo_box.SetValue(combo_box_value);
ui::AXNodeData text2;
text2.id = 13;
text2.role = ax::mojom::Role::kStaticText;
text2.SetName(text2_name);
ui::AXNodeData check_box;
check_box.id = 14;
check_box.role = ax::mojom::Role::kCheckBox;
check_box.SetCheckedState(ax::mojom::CheckedState::kTrue);
check_box.SetName(check_box_name);
check_box.SetValue(check_box_value);
ui::AXNodeData button, button_text;
button.id = 15;
button_text.id = 17;
button_text.SetName(button_text_name);
button.role = ax::mojom::Role::kButton;
button_text.role = ax::mojom::Role::kStaticText;
button.child_ids.push_back(button_text.id);
ui::AXNodeData link, link_text;
link.id = 16;
link_text.id = 18;
link_text.SetName(link_text_name);
link.role = ax::mojom::Role::kLink;
link_text.role = ax::mojom::Role::kStaticText;
link.child_ids.push_back(link_text.id);
ui::AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
root.child_ids.push_back(text1.id);
root.child_ids.push_back(combo_box.id);
root.child_ids.push_back(text2.id);
root.child_ids.push_back(check_box.id);
root.child_ids.push_back(button.id);
root.child_ids.push_back(link.id);
std::unique_ptr<BrowserAccessibilityManager> manager(
BrowserAccessibilityManager::Create(
MakeAXTreeUpdate(root, text1, combo_box, text2, check_box, button,
button_text, link, link_text),
test_browser_accessibility_delegate_.get(),
new BrowserAccessibilityFactory()));
ui::AXPlatformNodeAuraLinux* root_obj =
ToBrowserAccessibilityAuraLinux(manager->GetRoot())->GetNode();
AtkObject* root_atk_object(root_obj->GetNativeViewAccessible());
ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
ASSERT_TRUE(ATK_IS_TEXT(root_atk_object));
g_object_ref(root_atk_object);
AtkText* atk_text = ATK_TEXT(root_atk_object);
EXPECT_EQ(g_utf8_strlen(root_hypertext.c_str(), -1),
atk_text_get_character_count(atk_text));
gchar* text = atk_text_get_text(atk_text, 0, -1);
EXPECT_STREQ(root_hypertext.c_str(), text);
g_free(text);
ASSERT_TRUE(ATK_IS_HYPERTEXT(root_atk_object));
AtkHypertext* atk_hypertext = ATK_HYPERTEXT(root_atk_object);
EXPECT_EQ(4, atk_hypertext_get_n_links(atk_hypertext));
auto verify_atk_link_text = [&](const char* expected_text, int link_index,
int expected_start_index) {
AtkHyperlink* link = atk_hypertext_get_link(atk_hypertext, link_index);
ASSERT_NE(nullptr, link);
ASSERT_TRUE(ATK_IS_HYPERLINK(link));
ASSERT_EQ(atk_hyperlink_get_start_index(link), expected_start_index);
ASSERT_EQ(atk_hyperlink_get_end_index(link), expected_start_index + 1);
AtkObject* object = atk_hyperlink_get_object(link, 0);
ASSERT_TRUE(ATK_IS_TEXT(object));
char* text = atk_text_get_text(ATK_TEXT(object), 0, -1);
EXPECT_STREQ(expected_text, text);
g_free(text);
};
AtkHyperlink* combo_box_link = atk_hypertext_get_link(atk_hypertext, 0);
ASSERT_NE(nullptr, combo_box_link);
ASSERT_TRUE(ATK_IS_HYPERLINK(combo_box_link));
// Get the text of the combo box. It should be its value.
verify_atk_link_text(combo_box_value.c_str(), 0, 14);
// Get the text of the check box. It should be its name.
verify_atk_link_text(check_box_name.c_str(), 1, 30);
// Get the text of the button.
verify_atk_link_text(button_text_name.c_str(), 2, 31);
// Get the text of the link.
verify_atk_link_text(link_text_name.c_str(), 3, 32);
// Now test that all the object indices map back to the correct link indices.
EXPECT_EQ(-1, atk_hypertext_get_link_index(atk_hypertext, -1));
EXPECT_EQ(-1, atk_hypertext_get_link_index(atk_hypertext, 0));
EXPECT_EQ(-1, atk_hypertext_get_link_index(atk_hypertext, 1));
EXPECT_EQ(-1, atk_hypertext_get_link_index(atk_hypertext, 5));
EXPECT_EQ(-1, atk_hypertext_get_link_index(atk_hypertext, 13));
EXPECT_EQ(0, atk_hypertext_get_link_index(atk_hypertext, 14));
EXPECT_EQ(1, atk_hypertext_get_link_index(atk_hypertext, 30));
EXPECT_EQ(2, atk_hypertext_get_link_index(atk_hypertext, 31));
EXPECT_EQ(3, atk_hypertext_get_link_index(atk_hypertext, 32));
EXPECT_EQ(-1, atk_hypertext_get_link_index(atk_hypertext, 33));
EXPECT_EQ(-1, atk_hypertext_get_link_index(atk_hypertext, 34));
g_object_unref(root_atk_object);
manager.reset();
}
} // namespace content