| // Copyright 2017 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/accessibility/ax_event_generator.h" |
| |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/accessibility/ax_node.h" |
| #include "ui/accessibility/ax_serializable_tree.h" |
| #include "ui/accessibility/ax_tree_serializer.h" |
| |
| namespace ui { |
| |
| namespace { |
| |
| std::string DumpEvents(AXEventGenerator* generator) { |
| std::vector<std::string> event_strs; |
| for (auto targeted_event : *generator) { |
| const char* event_name; |
| switch (targeted_event.event) { |
| case AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED: |
| event_name = "ACTIVE_DESCENDANT_CHANGED"; |
| break; |
| case AXEventGenerator::Event::ALERT: |
| event_name = "ALERT"; |
| break; |
| case AXEventGenerator::Event::CHECKED_STATE_CHANGED: |
| event_name = "CHECKED_STATE_CHANGED"; |
| break; |
| case AXEventGenerator::Event::CHILDREN_CHANGED: |
| event_name = "CHILDREN_CHANGED"; |
| break; |
| case AXEventGenerator::Event::COLLAPSED: |
| event_name = "COLLAPSED"; |
| break; |
| case AXEventGenerator::Event::DESCRIPTION_CHANGED: |
| event_name = "DESCRIPTION_CHANGED"; |
| break; |
| case AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED: |
| event_name = "DOCUMENT_SELECTION_CHANGED"; |
| break; |
| case AXEventGenerator::Event::DOCUMENT_TITLE_CHANGED: |
| event_name = "DOCUMENT_TITLE_CHANGED"; |
| break; |
| case AXEventGenerator::Event::EXPANDED: |
| event_name = "EXPANDED"; |
| break; |
| case AXEventGenerator::Event::INVALID_STATUS_CHANGED: |
| event_name = "INVALID_STATUS_CHANGED"; |
| break; |
| case AXEventGenerator::Event::LIVE_REGION_CHANGED: |
| event_name = "LIVE_REGION_CHANGED"; |
| break; |
| case AXEventGenerator::Event::LIVE_REGION_CREATED: |
| event_name = "LIVE_REGION_CREATED"; |
| break; |
| case AXEventGenerator::Event::LIVE_REGION_NODE_CHANGED: |
| event_name = "LIVE_REGION_NODE_CHANGED"; |
| break; |
| case AXEventGenerator::Event::LOAD_COMPLETE: |
| event_name = "LOAD_COMPLETE"; |
| break; |
| case AXEventGenerator::Event::MENU_ITEM_SELECTED: |
| event_name = "MENU_ITEM_SELECTED"; |
| break; |
| case AXEventGenerator::Event::NAME_CHANGED: |
| event_name = "NAME_CHANGED"; |
| break; |
| case AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED: |
| event_name = "OTHER_ATTRIBUTE_CHANGED"; |
| break; |
| case AXEventGenerator::Event::ROLE_CHANGED: |
| event_name = "ROLE_CHANGED"; |
| break; |
| case AXEventGenerator::Event::ROW_COUNT_CHANGED: |
| event_name = "ROW_COUNT_CHANGED"; |
| break; |
| case AXEventGenerator::Event::SCROLL_POSITION_CHANGED: |
| event_name = "SCROLL_POSITION_CHANGED"; |
| break; |
| case AXEventGenerator::Event::SELECTED_CHANGED: |
| event_name = "SELECTED_CHANGED"; |
| break; |
| case AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED: |
| event_name = "SELECTED_CHILDREN_CHANGED"; |
| break; |
| case AXEventGenerator::Event::STATE_CHANGED: |
| event_name = "STATE_CHANGED"; |
| break; |
| case AXEventGenerator::Event::VALUE_CHANGED: |
| event_name = "VALUE_CHANGED"; |
| break; |
| default: |
| NOTREACHED(); |
| event_name = "UNKNOWN"; |
| break; |
| } |
| event_strs.push_back( |
| base::StringPrintf("%s on %d", event_name, targeted_event.node->id())); |
| } |
| |
| // The order of events is arbitrary, so just sort the strings |
| // alphabetically to make the test output predictable. |
| std::sort(event_strs.begin(), event_strs.end()); |
| |
| return base::JoinString(event_strs, ", "); |
| } |
| |
| } // namespace |
| |
| TEST(AXEventGeneratorTest, LoadCompleteSameTree) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| initial_state.has_tree_data = true; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate load_complete_update = initial_state; |
| load_complete_update.tree_data.loaded = true; |
| EXPECT_TRUE(tree.Unserialize(load_complete_update)); |
| EXPECT_EQ("LOAD_COMPLETE on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, LoadCompleteNewTree) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| initial_state.has_tree_data = true; |
| initial_state.tree_data.loaded = true; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate load_complete_update; |
| load_complete_update.root_id = 2; |
| load_complete_update.nodes.resize(1); |
| load_complete_update.nodes[0].id = 2; |
| load_complete_update.has_tree_data = true; |
| load_complete_update.tree_data.loaded = true; |
| EXPECT_TRUE(tree.Unserialize(load_complete_update)); |
| EXPECT_EQ("LOAD_COMPLETE on 2", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, DocumentSelectionChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| initial_state.has_tree_data = true; |
| initial_state.tree_data.sel_focus_object_id = 1; |
| initial_state.tree_data.sel_focus_offset = 1; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.tree_data.sel_focus_offset = 2; |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("DOCUMENT_SELECTION_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, DocumentTitleChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| initial_state.has_tree_data = true; |
| initial_state.tree_data.title = "Before"; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.tree_data.title = "After"; |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("DOCUMENT_TITLE_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, ExpandedAndRowCount) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(4); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].role = ui::AX_ROLE_ROOT_WEB_AREA; |
| initial_state.nodes[0].child_ids.push_back(2); |
| initial_state.nodes[0].child_ids.push_back(4); |
| initial_state.nodes[1].id = 2; |
| initial_state.nodes[1].role = ui::AX_ROLE_TABLE; |
| initial_state.nodes[1].child_ids.push_back(3); |
| initial_state.nodes[2].id = 3; |
| initial_state.nodes[2].role = ui::AX_ROLE_ROW; |
| initial_state.nodes[3].id = 4; |
| initial_state.nodes[3].role = ui::AX_ROLE_POP_UP_BUTTON; |
| initial_state.nodes[3].AddState(ui::AX_STATE_EXPANDED); |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[2].AddState(ui::AX_STATE_EXPANDED); |
| update.nodes[3].state = 0; |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ( |
| "COLLAPSED on 4, " |
| "EXPANDED on 3, " |
| "ROW_COUNT_CHANGED on 2, " |
| "STATE_CHANGED on 3, " |
| "STATE_CHANGED on 4", |
| DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, SelectedAndSelectedChildren) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(4); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].role = ui::AX_ROLE_ROOT_WEB_AREA; |
| initial_state.nodes[0].child_ids.push_back(2); |
| initial_state.nodes[0].child_ids.push_back(4); |
| initial_state.nodes[1].id = 2; |
| initial_state.nodes[1].role = ui::AX_ROLE_MENU; |
| initial_state.nodes[1].child_ids.push_back(3); |
| initial_state.nodes[2].id = 3; |
| initial_state.nodes[2].role = ui::AX_ROLE_MENU_ITEM; |
| initial_state.nodes[3].id = 4; |
| initial_state.nodes[3].role = ui::AX_ROLE_LIST_BOX_OPTION; |
| initial_state.nodes[3].AddState(ui::AX_STATE_SELECTED); |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[2].AddState(ui::AX_STATE_SELECTED); |
| update.nodes[3].state = 0; |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ( |
| "SELECTED_CHANGED on 3, " |
| "SELECTED_CHANGED on 4, " |
| "SELECTED_CHILDREN_CHANGED on 2, " |
| "STATE_CHANGED on 3, " |
| "STATE_CHANGED on 4", |
| DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, StringValueChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].role = ui::AX_ROLE_TEXT_FIELD; |
| initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_VALUE, "Before"); |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[0].string_attributes.clear(); |
| update.nodes[0].AddStringAttribute(ui::AX_ATTR_VALUE, "After"); |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("VALUE_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, FloatValueChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].role = ui::AX_ROLE_SLIDER; |
| initial_state.nodes[0].AddFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, 1.0); |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[0].float_attributes.clear(); |
| update.nodes[0].AddFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, 2.0); |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("VALUE_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, InvalidStatusChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].role = ui::AX_ROLE_TEXT_FIELD; |
| initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_VALUE, "Text"); |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[0].AddIntAttribute(ui::AX_ATTR_INVALID_STATE, |
| ui::AX_INVALID_STATE_SPELLING); |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("INVALID_STATUS_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, AddLiveRegionAttribute) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[0].AddStringAttribute(ui::AX_ATTR_LIVE_STATUS, "polite"); |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("LIVE_REGION_CREATED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, CheckedStateChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].role = ui::AX_ROLE_CHECK_BOX; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[0].AddIntAttribute(ui::AX_ATTR_CHECKED_STATE, |
| ui::AX_CHECKED_STATE_TRUE); |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("CHECKED_STATE_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, ActiveDescendantChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(3); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].role = ui::AX_ROLE_LIST_BOX; |
| initial_state.nodes[0].child_ids.push_back(2); |
| initial_state.nodes[0].child_ids.push_back(3); |
| initial_state.nodes[0].AddIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, 2); |
| initial_state.nodes[1].id = 2; |
| initial_state.nodes[1].role = ui::AX_ROLE_LIST_BOX_OPTION; |
| initial_state.nodes[2].id = 3; |
| initial_state.nodes[2].role = ui::AX_ROLE_LIST_BOX_OPTION; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[0].int_attributes.clear(); |
| update.nodes[0].AddIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, 3); |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("ACTIVE_DESCENDANT_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, CreateAlertAndLiveRegion) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes.resize(3); |
| update.nodes[0].child_ids.push_back(2); |
| update.nodes[0].child_ids.push_back(3); |
| update.nodes[1].id = 2; |
| update.nodes[1].AddStringAttribute(ui::AX_ATTR_LIVE_STATUS, "polite"); |
| update.nodes[2].id = 3; |
| update.nodes[2].role = ui::AX_ROLE_ALERT; |
| update.nodes[2].AddStringAttribute(ui::AX_ATTR_LIVE_STATUS, "polite"); |
| |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ( |
| "ALERT on 3, " |
| "CHILDREN_CHANGED on 1, " |
| "LIVE_REGION_CREATED on 2", |
| DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, LiveRegionChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(3); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_LIVE_STATUS, "polite"); |
| initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| "polite"); |
| initial_state.nodes[0].child_ids.push_back(2); |
| initial_state.nodes[0].child_ids.push_back(3); |
| initial_state.nodes[1].id = 2; |
| initial_state.nodes[1].role = ui::AX_ROLE_STATIC_TEXT; |
| initial_state.nodes[1].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| "polite"); |
| initial_state.nodes[1].AddStringAttribute(ui::AX_ATTR_NAME, "Before 1"); |
| initial_state.nodes[2].id = 3; |
| initial_state.nodes[2].role = ui::AX_ROLE_STATIC_TEXT; |
| initial_state.nodes[2].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| "polite"); |
| initial_state.nodes[2].AddStringAttribute(ui::AX_ATTR_NAME, "Before 2"); |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[1].string_attributes.clear(); |
| update.nodes[1].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| "polite"); |
| update.nodes[1].AddStringAttribute(ui::AX_ATTR_NAME, "After 1"); |
| update.nodes[2].string_attributes.clear(); |
| update.nodes[2].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| "polite"); |
| update.nodes[2].AddStringAttribute(ui::AX_ATTR_NAME, "After 2"); |
| |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ( |
| "LIVE_REGION_CHANGED on 1, " |
| "LIVE_REGION_NODE_CHANGED on 2, " |
| "LIVE_REGION_NODE_CHANGED on 3, " |
| "NAME_CHANGED on 2, " |
| "NAME_CHANGED on 3", |
| DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, LiveRegionOnlyTextChanges) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(3); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_LIVE_STATUS, "polite"); |
| initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| "polite"); |
| initial_state.nodes[0].child_ids.push_back(2); |
| initial_state.nodes[0].child_ids.push_back(3); |
| initial_state.nodes[1].id = 2; |
| initial_state.nodes[1].role = ui::AX_ROLE_STATIC_TEXT; |
| initial_state.nodes[1].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| "polite"); |
| initial_state.nodes[1].AddStringAttribute(ui::AX_ATTR_NAME, "Before 1"); |
| initial_state.nodes[2].id = 3; |
| initial_state.nodes[2].role = ui::AX_ROLE_STATIC_TEXT; |
| initial_state.nodes[2].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| "polite"); |
| initial_state.nodes[2].AddStringAttribute(ui::AX_ATTR_NAME, "Before 2"); |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[1].AddStringAttribute(ui::AX_ATTR_DESCRIPTION, "Description 1"); |
| update.nodes[2].AddIntAttribute(ui::AX_ATTR_CHECKED_STATE, |
| ui::AX_CHECKED_STATE_TRUE); |
| |
| // Note that we do NOT expect a LIVE_REGION_CHANGED event here, because |
| // the name did not change. |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ( |
| "CHECKED_STATE_CHANGED on 3, " |
| "DESCRIPTION_CHANGED on 2", |
| DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, BusyLiveRegionChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(3); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_LIVE_STATUS, "polite"); |
| initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| "polite"); |
| initial_state.nodes[0].AddBoolAttribute(ui::AX_ATTR_BUSY, true); |
| initial_state.nodes[0].child_ids.push_back(2); |
| initial_state.nodes[0].child_ids.push_back(3); |
| initial_state.nodes[1].id = 2; |
| initial_state.nodes[1].role = ui::AX_ROLE_STATIC_TEXT; |
| initial_state.nodes[1].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| "polite"); |
| initial_state.nodes[1].AddStringAttribute(ui::AX_ATTR_NAME, "Before 1"); |
| initial_state.nodes[2].id = 3; |
| initial_state.nodes[2].role = ui::AX_ROLE_STATIC_TEXT; |
| initial_state.nodes[2].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| "polite"); |
| initial_state.nodes[2].AddStringAttribute(ui::AX_ATTR_NAME, "Before 2"); |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[1].string_attributes.clear(); |
| update.nodes[1].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| "polite"); |
| update.nodes[1].AddStringAttribute(ui::AX_ATTR_NAME, "After 1"); |
| update.nodes[2].string_attributes.clear(); |
| update.nodes[2].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| "polite"); |
| update.nodes[2].AddStringAttribute(ui::AX_ATTR_NAME, "After 2"); |
| |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ( |
| "NAME_CHANGED on 2, " |
| "NAME_CHANGED on 3", |
| DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, AddChild) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(2); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].child_ids.push_back(2); |
| initial_state.nodes[1].id = 2; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes.resize(3); |
| update.nodes[0].child_ids.push_back(3); |
| update.nodes[2].id = 3; |
| |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("CHILDREN_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, RemoveChild) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(3); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].child_ids.push_back(2); |
| initial_state.nodes[0].child_ids.push_back(3); |
| initial_state.nodes[1].id = 2; |
| initial_state.nodes[2].id = 3; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes.resize(2); |
| update.nodes[0].child_ids.clear(); |
| update.nodes[0].child_ids.push_back(2); |
| |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("CHILDREN_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, ReorderChildren) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(3); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].child_ids.push_back(2); |
| initial_state.nodes[0].child_ids.push_back(3); |
| initial_state.nodes[1].id = 2; |
| initial_state.nodes[2].id = 3; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[0].child_ids.clear(); |
| update.nodes[0].child_ids.push_back(3); |
| update.nodes[0].child_ids.push_back(2); |
| |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("CHILDREN_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, ScrollPositionChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[0].AddIntAttribute(ui::AX_ATTR_SCROLL_Y, 10); |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("SCROLL_POSITION_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, OtherAttributeChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(6); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].child_ids.push_back(2); |
| initial_state.nodes[0].child_ids.push_back(3); |
| initial_state.nodes[0].child_ids.push_back(4); |
| initial_state.nodes[0].child_ids.push_back(5); |
| initial_state.nodes[0].child_ids.push_back(6); |
| initial_state.nodes[1].id = 2; |
| initial_state.nodes[2].id = 3; |
| initial_state.nodes[3].id = 4; |
| initial_state.nodes[4].id = 5; |
| initial_state.nodes[5].id = 6; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[1].AddStringAttribute(ui::AX_ATTR_LANGUAGE, "de"); |
| update.nodes[2].AddIntAttribute(ui::AX_ATTR_ARIA_CELL_COLUMN_INDEX, 7); |
| update.nodes[3].AddFloatAttribute(ui::AX_ATTR_FONT_SIZE, 12.0f); |
| update.nodes[4].AddBoolAttribute(ui::AX_ATTR_MODAL, true); |
| std::vector<int> ids = {2}; |
| update.nodes[5].AddIntListAttribute(ui::AX_ATTR_CONTROLS_IDS, ids); |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ( |
| "OTHER_ATTRIBUTE_CHANGED on 2, " |
| "OTHER_ATTRIBUTE_CHANGED on 3, " |
| "OTHER_ATTRIBUTE_CHANGED on 4, " |
| "OTHER_ATTRIBUTE_CHANGED on 5, " |
| "OTHER_ATTRIBUTE_CHANGED on 6", |
| DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, NameChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[0].AddStringAttribute(ui::AX_ATTR_NAME, "Hello"); |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("NAME_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, DescriptionChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[0].AddStringAttribute(ui::AX_ATTR_DESCRIPTION, "Hello"); |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("DESCRIPTION_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, RoleChanged) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(1); |
| initial_state.nodes[0].id = 1; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[0].role = ui::AX_ROLE_CHECK_BOX; |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ("ROLE_CHANGED on 1", DumpEvents(&event_generator)); |
| } |
| |
| TEST(AXEventGeneratorTest, MenuItemSelected) { |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.resize(3); |
| initial_state.nodes[0].id = 1; |
| initial_state.nodes[0].role = ui::AX_ROLE_MENU; |
| initial_state.nodes[0].child_ids.push_back(2); |
| initial_state.nodes[0].child_ids.push_back(3); |
| initial_state.nodes[0].AddIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, 2); |
| initial_state.nodes[1].id = 2; |
| initial_state.nodes[1].role = ui::AX_ROLE_MENU_LIST_OPTION; |
| initial_state.nodes[2].id = 3; |
| initial_state.nodes[2].role = ui::AX_ROLE_MENU_LIST_OPTION; |
| AXTree tree(initial_state); |
| |
| AXEventGenerator event_generator(&tree); |
| AXTreeUpdate update = initial_state; |
| update.nodes[0].int_attributes.clear(); |
| update.nodes[0].AddIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, 3); |
| EXPECT_TRUE(tree.Unserialize(update)); |
| EXPECT_EQ( |
| "ACTIVE_DESCENDANT_CHANGED on 1, " |
| "MENU_ITEM_SELECTED on 3", |
| DumpEvents(&event_generator)); |
| } |
| |
| } // namespace ui |