blob: 4fa37a9423f8a2aeced0c2d55a6ea8e95deeb6d7 [file] [log] [blame]
// Copyright 2019 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 "ui/views/accessibility/view_ax_platform_node_delegate.h"
#include <atk/atk.h>
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/views_test_base.h"
namespace views {
namespace test {
class ViewAXPlatformNodeDelegateAuraLinuxTest : public ViewsTestBase {
public:
ViewAXPlatformNodeDelegateAuraLinuxTest() = default;
~ViewAXPlatformNodeDelegateAuraLinuxTest() override = default;
};
TEST_F(ViewAXPlatformNodeDelegateAuraLinuxTest, TextfieldAccessibility) {
Widget widget;
Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget.Init(std::move(init_params));
View* content = new View;
widget.SetContentsView(content);
Textfield* textfield = new Textfield;
textfield->SetAccessibleName(base::UTF8ToUTF16("Name"));
textfield->SetText(base::UTF8ToUTF16("Value"));
content->AddChildView(textfield);
AtkText* atk_text = ATK_TEXT(textfield->GetNativeViewAccessible());
ASSERT_NE(nullptr, atk_text);
struct TextChangeData {
int position;
int length;
std::string text;
};
std::vector<TextChangeData> text_remove_events;
std::vector<TextChangeData> text_insert_events;
GCallback callback = G_CALLBACK(
+[](AtkText*, int position, int length, char* text, gpointer data) {
auto* events = static_cast<std::vector<TextChangeData>*>(data);
events->push_back(TextChangeData{position, length, text});
});
g_signal_connect(atk_text, "text-insert", callback, &text_insert_events);
g_signal_connect(atk_text, "text-remove", callback, &text_remove_events);
textfield->NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true);
ASSERT_EQ(text_remove_events.size(), 0ul);
ASSERT_EQ(text_insert_events.size(), 1ul);
ASSERT_EQ(text_insert_events[0].position, 0);
ASSERT_EQ(text_insert_events[0].length, 5);
ASSERT_EQ(text_insert_events[0].text, "Value");
text_insert_events.clear();
textfield->SetText(base::UTF8ToUTF16("Value A"));
textfield->NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true);
ASSERT_EQ(text_remove_events.size(), 0ul);
ASSERT_EQ(text_insert_events.size(), 1ul);
ASSERT_EQ(text_insert_events[0].position, 5);
ASSERT_EQ(text_insert_events[0].length, 2);
ASSERT_EQ(text_insert_events[0].text, " A");
text_insert_events.clear();
textfield->SetText(base::UTF8ToUTF16("Value"));
textfield->NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true);
ASSERT_EQ(text_remove_events.size(), 1ul);
ASSERT_EQ(text_insert_events.size(), 0ul);
ASSERT_EQ(text_remove_events[0].position, 5);
ASSERT_EQ(text_remove_events[0].length, 2);
ASSERT_EQ(text_remove_events[0].text, " A");
text_remove_events.clear();
textfield->SetText(base::UTF8ToUTF16("Prefix Value"));
textfield->NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true);
ASSERT_EQ(text_remove_events.size(), 0ul);
ASSERT_EQ(text_insert_events.size(), 1ul);
ASSERT_EQ(text_insert_events[0].position, 0);
ASSERT_EQ(text_insert_events[0].length, 7);
ASSERT_EQ(text_insert_events[0].text, "Prefix ");
text_insert_events.clear();
textfield->SetText(base::UTF8ToUTF16("Value"));
textfield->NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true);
ASSERT_EQ(text_remove_events.size(), 1ul);
ASSERT_EQ(text_insert_events.size(), 0ul);
ASSERT_EQ(text_remove_events[0].position, 0);
ASSERT_EQ(text_remove_events[0].length, 7);
ASSERT_EQ(text_remove_events[0].text, "Prefix ");
text_insert_events.clear();
}
TEST_F(ViewAXPlatformNodeDelegateAuraLinuxTest, AuraChildWidgets) {
// Create the parent widget.
Widget widget;
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
init_params.bounds = gfx::Rect(0, 0, 400, 200);
widget.Init(std::move(init_params));
widget.Show();
// Initially it has 1 child.
AtkObject* root_view_accessible =
widget.GetRootView()->GetNativeViewAccessible();
ASSERT_EQ(1, atk_object_get_n_accessible_children(root_view_accessible));
// Create the child widget, one of two ways (see below).
Widget child_widget;
Widget::InitParams child_init_params =
CreateParams(Widget::InitParams::TYPE_BUBBLE);
child_init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
child_init_params.parent = widget.GetNativeView();
child_init_params.bounds = gfx::Rect(30, 40, 100, 50);
child_init_params.child = false;
child_widget.Init(std::move(child_init_params));
child_widget.Show();
// Now the AtkObject for the parent widget should have 2 children.
ASSERT_EQ(2, atk_object_get_n_accessible_children(root_view_accessible));
// Make sure that querying the parent of the child gets us back to
// the original parent.
AtkObject* child_widget_accessible =
child_widget.GetRootView()->GetNativeViewAccessible();
ASSERT_EQ(atk_object_get_parent(child_widget_accessible),
root_view_accessible);
// Make sure that querying the second child of the parent is the child widget
// accessible as well.
AtkObject* second_child =
atk_object_ref_accessible_child(root_view_accessible, 1);
ASSERT_EQ(second_child, child_widget_accessible);
g_object_unref(second_child);
}
} // namespace test
} // namespace views