blob: b3a55a909d21145b589a9778dd66957de45ead2a [file] [log] [blame]
Sharon Yang28eac792019-10-16 00:28:231// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "fuchsia/engine/browser/ax_tree_converter.h"
6
7#include <lib/ui/scenic/cpp/commands.h>
8#include <vector>
9
10#include "testing/gtest/include/gtest/gtest.h"
11#include "ui/gfx/transform.h"
12
13using fuchsia::accessibility::semantics::Action;
14using fuchsia::accessibility::semantics::Attributes;
Sharon Yang6f3a47b2020-01-08 21:32:2915using fuchsia::accessibility::semantics::CheckedState;
Sharon Yang28eac792019-10-16 00:28:2316using fuchsia::accessibility::semantics::Node;
17using fuchsia::accessibility::semantics::Role;
Sharon Yang6f3a47b2020-01-08 21:32:2918using fuchsia::accessibility::semantics::States;
Sharon Yang28eac792019-10-16 00:28:2319
20namespace {
21
22const char kLabel1[] = "label nodes, not people";
23const char kLabel2[] = "fancy stickers";
Sharon Yang6f3a47b2020-01-08 21:32:2924const char kDescription1[] = "this node does some stuff";
25const char kValue1[] = "user entered value";
Sharon Yang28eac792019-10-16 00:28:2326const int32_t kChildId1 = 23901;
27const int32_t kChildId2 = 484345;
28const int32_t kChildId3 = 4156877;
29const int32_t kRectX = 1;
30const int32_t kRectY = 2;
31const int32_t kRectWidth = 7;
32const int32_t kRectHeight = 8;
Yilong Li4ada6192020-01-06 21:01:1933const std::array<float, 16> k4DIdentityMatrix = {1, 0, 0, 0, 0, 1, 0, 0,
34 0, 0, 1, 0, 0, 0, 0, 1};
Sharon Yang28eac792019-10-16 00:28:2335
Sharon Yang28eac792019-10-16 00:28:2336ui::AXNodeData CreateAXNodeData(ax::mojom::Role role,
Sharon Yang6f3a47b2020-01-08 21:32:2937 ax::mojom::Action action,
Sharon Yang28eac792019-10-16 00:28:2338 std::vector<int32_t> child_ids,
39 ui::AXRelativeBounds relative_bounds,
Sharon Yang6f3a47b2020-01-08 21:32:2940 base::StringPiece name,
41 base::StringPiece description,
42 ax::mojom::CheckedState checked_state) {
Sharon Yang28eac792019-10-16 00:28:2343 ui::AXNodeData node;
Lucas Radaelli9019dc22020-10-12 18:51:4544 // Important! ID must be set to zero here because its default value (-1), will
45 // fail when getting converted to an unsigned int (Fuchsia's ID format).
46 node.id = 0;
Sharon Yang28eac792019-10-16 00:28:2347 node.role = role;
Sharon Yang6f3a47b2020-01-08 21:32:2948 node.AddAction(action);
49 node.AddIntAttribute(ax::mojom::IntAttribute::kCheckedState,
50 static_cast<int32_t>(checked_state));
Sharon Yang28eac792019-10-16 00:28:2351 node.child_ids = child_ids;
52 node.relative_bounds = relative_bounds;
53 if (!name.empty())
54 node.AddStringAttribute(ax::mojom::StringAttribute::kName, name.data());
Sharon Yang6f3a47b2020-01-08 21:32:2955 if (!description.empty()) {
56 node.AddStringAttribute(ax::mojom::StringAttribute::kDescription,
57 description.data());
58 }
Sharon Yang28eac792019-10-16 00:28:2359 return node;
60}
61
62Node CreateSemanticNode(uint32_t id,
63 Role role,
64 Attributes attributes,
Sharon Yang6f3a47b2020-01-08 21:32:2965 States states,
Sharon Yang28eac792019-10-16 00:28:2366 std::vector<Action> actions,
67 std::vector<uint32_t> child_ids,
68 fuchsia::ui::gfx::BoundingBox location,
69 fuchsia::ui::gfx::mat4 transform) {
70 Node node;
71 node.set_node_id(id);
72 node.set_role(role);
73 node.set_attributes(std::move(attributes));
Sharon Yang6f3a47b2020-01-08 21:32:2974 node.set_states(std::move(states));
Sharon Yang28eac792019-10-16 00:28:2375 node.set_actions(actions);
76 node.set_child_ids(child_ids);
77 node.set_location(location);
78 node.set_transform(transform);
79 return node;
80}
81
82class AXTreeConverterTest : public testing::Test {
83 public:
84 AXTreeConverterTest() = default;
85 ~AXTreeConverterTest() override = default;
86
87 DISALLOW_COPY_AND_ASSIGN(AXTreeConverterTest);
88};
89
90TEST_F(AXTreeConverterTest, AllFieldsSetAndEqual) {
91 ui::AXRelativeBounds relative_bounds = ui::AXRelativeBounds();
92 relative_bounds.bounds = gfx::RectF(kRectX, kRectY, kRectWidth, kRectHeight);
93 relative_bounds.transform =
94 std::make_unique<gfx::Transform>(gfx::Transform::kSkipInitialization);
95 relative_bounds.transform->MakeIdentity();
Sharon Yang6f3a47b2020-01-08 21:32:2996 auto source_node_data = CreateAXNodeData(
97 ax::mojom::Role::kButton, ax::mojom::Action::kFocus,
98 std::vector<int32_t>{kChildId1, kChildId2, kChildId3}, relative_bounds,
99 kLabel1, kDescription1, ax::mojom::CheckedState::kMixed);
100 source_node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, false);
Lucas Radaelli6afb9022020-10-09 19:32:00101 source_node_data.RemoveState(ax::mojom::State::kIgnored);
Sharon Yang28eac792019-10-16 00:28:23102 auto converted_node = AXNodeDataToSemanticNode(source_node_data);
103 EXPECT_EQ(static_cast<uint32_t>(source_node_data.id),
104 converted_node.node_id());
105
106 Attributes attributes;
107 attributes.set_label(kLabel1);
Sharon Yang6f3a47b2020-01-08 21:32:29108 attributes.set_secondary_label(kDescription1);
Sharon Yang28eac792019-10-16 00:28:23109 fuchsia::ui::gfx::BoundingBox box;
Yilong Li4ada6192020-01-06 21:01:19110 box.min = scenic::NewVector3({kRectX, kRectY + kRectHeight, 0.0f});
111 box.max = scenic::NewVector3({kRectHeight, kRectY, 0.0f});
Sharon Yang28eac792019-10-16 00:28:23112 fuchsia::ui::gfx::Matrix4Value mat =
113 scenic::NewMatrix4Value(k4DIdentityMatrix);
Sharon Yang6f3a47b2020-01-08 21:32:29114 States states;
115 states.set_checked_state(CheckedState::MIXED);
116 states.set_hidden(false);
117 states.set_selected(false);
Sharon Yang28eac792019-10-16 00:28:23118 auto expected_node = CreateSemanticNode(
Lucas Radaelli9019dc22020-10-12 18:51:45119 static_cast<uint32_t>(source_node_data.id), Role::BUTTON,
120 std::move(attributes), std::move(states),
121 std::vector<Action>{Action::SET_FOCUS},
Sharon Yang28eac792019-10-16 00:28:23122 std::vector<uint32_t>{kChildId1, kChildId2, kChildId3}, box, mat.value);
123
Sharon Yang6f3a47b2020-01-08 21:32:29124 EXPECT_TRUE(fidl::Equals(converted_node, expected_node));
Sharon Yang28eac792019-10-16 00:28:23125}
126
127TEST_F(AXTreeConverterTest, SomeFieldsSetAndEqual) {
128 ui::AXNodeData source_node_data;
Lucas Radaelli9019dc22020-10-12 18:51:45129 source_node_data.id = 0;
Sharon Yang6f3a47b2020-01-08 21:32:29130 source_node_data.AddAction(ax::mojom::Action::kFocus);
131 source_node_data.AddAction(ax::mojom::Action::kSetValue);
Sharon Yang28eac792019-10-16 00:28:23132 source_node_data.child_ids = std::vector<int32_t>{kChildId1};
Sharon Yang6f3a47b2020-01-08 21:32:29133 source_node_data.role = ax::mojom::Role::kImage;
134 source_node_data.AddStringAttribute(ax::mojom::StringAttribute::kValue,
135 kValue1);
Sharon Yang28eac792019-10-16 00:28:23136 auto converted_node = AXNodeDataToSemanticNode(source_node_data);
137 EXPECT_EQ(static_cast<uint32_t>(source_node_data.id),
138 converted_node.node_id());
139
140 Node expected_node;
Lucas Radaelli9019dc22020-10-12 18:51:45141 expected_node.set_node_id(static_cast<uint32_t>(source_node_data.id));
Sharon Yang6f3a47b2020-01-08 21:32:29142 expected_node.set_actions(
143 std::vector<Action>{Action::SET_FOCUS, Action::SET_VALUE});
Lucas Radaelli9019dc22020-10-12 18:51:45144 expected_node.set_child_ids(
145 std::vector<uint32_t>{static_cast<uint32_t>(kChildId1)});
Sharon Yang6f3a47b2020-01-08 21:32:29146 expected_node.set_role(Role::IMAGE);
147 States states;
148 states.set_hidden(false);
149 states.set_value(kValue1);
150 expected_node.set_states(std::move(states));
151 Attributes attributes;
152 expected_node.set_attributes(std::move(attributes));
153 fuchsia::ui::gfx::BoundingBox box;
154 expected_node.set_location(std::move(box));
Sharon Yang28eac792019-10-16 00:28:23155
Sharon Yang6f3a47b2020-01-08 21:32:29156 EXPECT_TRUE(fidl::Equals(converted_node, expected_node));
Sharon Yang28eac792019-10-16 00:28:23157}
158
159TEST_F(AXTreeConverterTest, FieldMismatch) {
160 ui::AXRelativeBounds relative_bounds = ui::AXRelativeBounds();
161 relative_bounds.bounds = gfx::RectF(kRectX, kRectY, kRectWidth, kRectHeight);
162 relative_bounds.transform =
163 std::make_unique<gfx::Transform>(gfx::Transform::kSkipInitialization);
164 relative_bounds.transform->MakeIdentity();
Sharon Yang6f3a47b2020-01-08 21:32:29165 auto source_node_data = CreateAXNodeData(
166 ax::mojom::Role::kHeader, ax::mojom::Action::kSetValue,
167 std::vector<int32_t>{kChildId1, kChildId2, kChildId3}, relative_bounds,
168 kLabel1, kDescription1, ax::mojom::CheckedState::kFalse);
Sharon Yang28eac792019-10-16 00:28:23169 auto converted_node = AXNodeDataToSemanticNode(source_node_data);
170 EXPECT_EQ(static_cast<uint32_t>(source_node_data.id),
171 converted_node.node_id());
172
173 Attributes attributes;
174 attributes.set_label(kLabel1);
Sharon Yang6f3a47b2020-01-08 21:32:29175 attributes.set_secondary_label(kDescription1);
176 States states;
177 states.set_hidden(false);
178 states.set_checked_state(CheckedState::UNCHECKED);
Sharon Yang28eac792019-10-16 00:28:23179 fuchsia::ui::gfx::BoundingBox box;
Sharon Yang6f3a47b2020-01-08 21:32:29180 box.min = scenic::NewVector3({kRectX, kRectY + kRectHeight, 0.0f});
181 box.max = scenic::NewVector3({kRectHeight, kRectY, 0.0f});
Sharon Yang28eac792019-10-16 00:28:23182 fuchsia::ui::gfx::Matrix4Value mat =
183 scenic::NewMatrix4Value(k4DIdentityMatrix);
184 auto expected_node = CreateSemanticNode(
Sharon Yang6f3a47b2020-01-08 21:32:29185 source_node_data.id, Role::HEADER, std::move(attributes),
186 std::move(states), std::vector<Action>{Action::SET_VALUE},
Sharon Yang28eac792019-10-16 00:28:23187 std::vector<uint32_t>{kChildId1, kChildId2, kChildId3}, box, mat.value);
188
189 // Start with nodes being equal.
Sharon Yang6f3a47b2020-01-08 21:32:29190 EXPECT_TRUE(fidl::Equals(converted_node, expected_node));
Sharon Yang28eac792019-10-16 00:28:23191
192 // Make a copy of |source_node_data| and change the name attribute. Check that
193 // the resulting |converted_node| is different from |expected_node|.
194 auto modified_node_data = source_node_data;
195 modified_node_data.AddStringAttribute(ax::mojom::StringAttribute::kName,
196 kLabel2);
197 converted_node = AXNodeDataToSemanticNode(modified_node_data);
Sharon Yang6f3a47b2020-01-08 21:32:29198 EXPECT_FALSE(fidl::Equals(converted_node, expected_node));
Sharon Yang28eac792019-10-16 00:28:23199
200 // The same as above, this time changing |child_ids|.
201 modified_node_data = source_node_data;
202 modified_node_data.child_ids = std::vector<int32_t>{};
203 converted_node = AXNodeDataToSemanticNode(modified_node_data);
Sharon Yang6f3a47b2020-01-08 21:32:29204 EXPECT_FALSE(fidl::Equals(converted_node, expected_node));
Sharon Yang28eac792019-10-16 00:28:23205}
206
Lucas Radaelli9019dc22020-10-12 18:51:45207TEST_F(AXTreeConverterTest, ConvertToFuchsiaNodeId) {
208 // Root AxNode is 0, Fuchsia is also 0.
209 EXPECT_EQ(0u, ConvertToFuchsiaNodeId(0, 0));
210
211 // Root AxNode is not 0, Fuchsia is still 0.
212 EXPECT_EQ(0u, ConvertToFuchsiaNodeId(2, 2));
213
214 // Regular AxNode is 0, Fuchsia can't be 0.
215 EXPECT_EQ(static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) + 1,
216 ConvertToFuchsiaNodeId(0, 2));
217
218 // Regular AxNode is not 0, Fuchsia is same value.
219 EXPECT_EQ(10u, ConvertToFuchsiaNodeId(10, 0));
220}
221
Sharon Yang28eac792019-10-16 00:28:23222} // namespace