blob: 3dc1ad72d3e78f8a5c78708ad3519aa46d429cce [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;
15using fuchsia::accessibility::semantics::Node;
16using fuchsia::accessibility::semantics::Role;
17
18namespace {
19
20const char kLabel1[] = "label nodes, not people";
21const char kLabel2[] = "fancy stickers";
22const int32_t kChildId1 = 23901;
23const int32_t kChildId2 = 484345;
24const int32_t kChildId3 = 4156877;
25const int32_t kRectX = 1;
26const int32_t kRectY = 2;
27const int32_t kRectWidth = 7;
28const int32_t kRectHeight = 8;
Yilong Li4ada6192020-01-06 21:01:1929const std::array<float, 16> k4DIdentityMatrix = {1, 0, 0, 0, 0, 1, 0, 0,
30 0, 0, 1, 0, 0, 0, 0, 1};
Sharon Yang28eac792019-10-16 00:28:2331
32bool SemanticNodesAreEqual(const Node& first, const Node& second) {
33 if (first.node_id() != second.node_id())
34 return false;
35 if (first.has_role() && second.has_role() && first.role() != second.role()) {
36 return false;
37 }
38 if (first.has_attributes() && second.has_attributes() &&
39 first.attributes().label() != second.attributes().label()) {
40 return false;
41 }
42 if (first.has_actions() && second.has_actions() &&
43 first.actions() != second.actions()) {
44 return false;
45 }
46 if (first.has_child_ids() && second.has_child_ids() &&
47 first.child_ids() != second.child_ids()) {
48 return false;
49 }
50 if (first.has_location() && second.has_location()) {
51 if (first.location().min.x != second.location().min.x)
52 return false;
53 if (first.location().min.y != second.location().min.y)
54 return false;
55 if (first.location().min.z != second.location().min.z)
56 return false;
57 if (first.location().max.x != second.location().max.x)
58 return false;
59 if (first.location().max.y != second.location().max.y)
60 return false;
61 if (first.location().max.z != second.location().max.z)
62 return false;
63 }
64 if (first.has_transform() && second.has_transform() &&
65 first.transform().matrix != second.transform().matrix) {
66 return false;
67 }
68
69 return true;
70}
71
72ui::AXNodeData CreateAXNodeData(ax::mojom::Role role,
73 uint32_t actions,
74 std::vector<int32_t> child_ids,
75 ui::AXRelativeBounds relative_bounds,
76 base::StringPiece name) {
77 ui::AXNodeData node;
78 node.role = role;
79 node.actions = actions;
80 node.child_ids = child_ids;
81 node.relative_bounds = relative_bounds;
82 if (!name.empty())
83 node.AddStringAttribute(ax::mojom::StringAttribute::kName, name.data());
84 return node;
85}
86
87Node CreateSemanticNode(uint32_t id,
88 Role role,
89 Attributes attributes,
90 std::vector<Action> actions,
91 std::vector<uint32_t> child_ids,
92 fuchsia::ui::gfx::BoundingBox location,
93 fuchsia::ui::gfx::mat4 transform) {
94 Node node;
95 node.set_node_id(id);
96 node.set_role(role);
97 node.set_attributes(std::move(attributes));
98 node.set_actions(actions);
99 node.set_child_ids(child_ids);
100 node.set_location(location);
101 node.set_transform(transform);
102 return node;
103}
104
105class AXTreeConverterTest : public testing::Test {
106 public:
107 AXTreeConverterTest() = default;
108 ~AXTreeConverterTest() override = default;
109
110 DISALLOW_COPY_AND_ASSIGN(AXTreeConverterTest);
111};
112
113TEST_F(AXTreeConverterTest, AllFieldsSetAndEqual) {
114 ui::AXRelativeBounds relative_bounds = ui::AXRelativeBounds();
115 relative_bounds.bounds = gfx::RectF(kRectX, kRectY, kRectWidth, kRectHeight);
116 relative_bounds.transform =
117 std::make_unique<gfx::Transform>(gfx::Transform::kSkipInitialization);
118 relative_bounds.transform->MakeIdentity();
119 auto source_node_data =
120 CreateAXNodeData(ax::mojom::Role::kButton,
121 static_cast<uint32_t>(ax::mojom::Action::kDoDefault),
122 std::vector<int32_t>{kChildId1, kChildId2, kChildId3},
123 relative_bounds, kLabel1);
124 auto converted_node = AXNodeDataToSemanticNode(source_node_data);
125 EXPECT_EQ(static_cast<uint32_t>(source_node_data.id),
126 converted_node.node_id());
127
128 Attributes attributes;
129 attributes.set_label(kLabel1);
130 fuchsia::ui::gfx::BoundingBox box;
Yilong Li4ada6192020-01-06 21:01:19131 box.min = scenic::NewVector3({kRectX, kRectY + kRectHeight, 0.0f});
132 box.max = scenic::NewVector3({kRectHeight, kRectY, 0.0f});
Sharon Yang28eac792019-10-16 00:28:23133 fuchsia::ui::gfx::Matrix4Value mat =
134 scenic::NewMatrix4Value(k4DIdentityMatrix);
135 auto expected_node = CreateSemanticNode(
136 source_node_data.id, Role::UNKNOWN, std::move(attributes),
137 std::vector<Action>{Action::DEFAULT},
138 std::vector<uint32_t>{kChildId1, kChildId2, kChildId3}, box, mat.value);
139
140 EXPECT_TRUE(SemanticNodesAreEqual(std::move(converted_node),
141 std::move(expected_node)));
142}
143
144TEST_F(AXTreeConverterTest, SomeFieldsSetAndEqual) {
145 ui::AXNodeData source_node_data;
146 source_node_data.actions =
147 static_cast<uint32_t>(ax::mojom::Action::kDoDefault);
148 source_node_data.child_ids = std::vector<int32_t>{kChildId1};
149 auto converted_node = AXNodeDataToSemanticNode(source_node_data);
150 EXPECT_EQ(static_cast<uint32_t>(source_node_data.id),
151 converted_node.node_id());
152
153 Node expected_node;
154 expected_node.set_node_id(source_node_data.id);
155 expected_node.set_actions(std::vector<Action>{Action::DEFAULT});
156 expected_node.set_child_ids(std::vector<uint32_t>{kChildId1});
157
158 EXPECT_TRUE(SemanticNodesAreEqual(std::move(converted_node),
159 std::move(expected_node)));
160}
161
162TEST_F(AXTreeConverterTest, FieldMismatch) {
163 ui::AXRelativeBounds relative_bounds = ui::AXRelativeBounds();
164 relative_bounds.bounds = gfx::RectF(kRectX, kRectY, kRectWidth, kRectHeight);
165 relative_bounds.transform =
166 std::make_unique<gfx::Transform>(gfx::Transform::kSkipInitialization);
167 relative_bounds.transform->MakeIdentity();
168 auto source_node_data =
169 CreateAXNodeData(ax::mojom::Role::kButton,
170 static_cast<uint32_t>(ax::mojom::Action::kDoDefault),
171 std::vector<int32_t>{kChildId1, kChildId2, kChildId3},
172 relative_bounds, kLabel1);
173 auto converted_node = AXNodeDataToSemanticNode(source_node_data);
174 EXPECT_EQ(static_cast<uint32_t>(source_node_data.id),
175 converted_node.node_id());
176
177 Attributes attributes;
178 attributes.set_label(kLabel1);
179 fuchsia::ui::gfx::BoundingBox box;
Yilong Li4ada6192020-01-06 21:01:19180 std::array<float, 3> min = {kRectX, kRectY + kRectHeight, 0.0f};
181 std::array<float, 3> max = {kRectHeight, kRectY, 0.0f};
Sharon Yang28eac792019-10-16 00:28:23182 box.min = scenic::NewVector3(min);
183 box.max = scenic::NewVector3(max);
184 fuchsia::ui::gfx::Matrix4Value mat =
185 scenic::NewMatrix4Value(k4DIdentityMatrix);
186 auto expected_node = CreateSemanticNode(
187 source_node_data.id, Role::UNKNOWN, std::move(attributes),
188 std::vector<Action>{Action::DEFAULT},
189 std::vector<uint32_t>{kChildId1, kChildId2, kChildId3}, box, mat.value);
190
191 // Start with nodes being equal.
192 EXPECT_TRUE(SemanticNodesAreEqual(converted_node, expected_node));
193
194 // Make a copy of |source_node_data| and change the name attribute. Check that
195 // the resulting |converted_node| is different from |expected_node|.
196 auto modified_node_data = source_node_data;
197 modified_node_data.AddStringAttribute(ax::mojom::StringAttribute::kName,
198 kLabel2);
199 converted_node = AXNodeDataToSemanticNode(modified_node_data);
200 EXPECT_FALSE(SemanticNodesAreEqual(converted_node, expected_node));
201
202 // The same as above, this time changing |child_ids|.
203 modified_node_data = source_node_data;
204 modified_node_data.child_ids = std::vector<int32_t>{};
205 converted_node = AXNodeDataToSemanticNode(modified_node_data);
206 EXPECT_FALSE(SemanticNodesAreEqual(converted_node, expected_node));
207}
208
209} // namespace