Commit b587a5ed authored by Dominic Mazzoni's avatar Dominic Mazzoni Committed by Commit Bot

Add generated tree test to ensure ignored nodes are handled properly.

First, extends TreeGenerator so that it can not only generate every
"shape" of tree, but it can then populate that tree with every
permutation of ignored nodes.

Then, write a new test that tries every possible tree up to a certain
size and tries every possible source and destination permutation of
ignored nodes. We call this the "fat" tree. Update the source tree into
the destination tree and capture the events fired.

Next, build the equivalent "skinny" trees - the same trees but with
the ignored nodes removed. Now convert the source skinny tree into the
destination skinny tree.

Assert that the generated events fired are the same in the fat tree as
the skinny tree. In other words, ignored nodes really are ignored and
don't affect things. (The only exception is the ignored_changed
attribute.)

Finally, check every unignored node in the fat tree and make sure that its
unignored parent, children, siblings, and index in parent are all
consistent with the equivalent values in the skinny tree.

This test uncovered bugs, which were fixed in http://crrev.com/c/2125235
before this patch was uploaded for review.

Bug: 1065144
Change-Id: I82f9b3487485f1024ee066b82c23ab0cd7b60e38
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2139082Reviewed-by: default avatarAdam Ettenberger <Adam.Ettenberger@microsoft.com>
Commit-Queue: Dominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#757989}
parent 96d5c648
...@@ -47,17 +47,6 @@ void RemoveEvent(std::set<AXEventGenerator::EventParams>* node_events, ...@@ -47,17 +47,6 @@ void RemoveEvent(std::set<AXEventGenerator::EventParams>* node_events,
} }
} }
bool HasOtherLiveRegionEvent(
const std::set<AXEventGenerator::EventParams>& events) {
auto is_live_region_event = [](const AXEventGenerator::EventParams& params) {
return params.event == AXEventGenerator::Event::ALERT ||
params.event == AXEventGenerator::Event::LIVE_REGION_CREATED;
};
return std::find_if(events.begin(), events.end(), is_live_region_event) !=
events.end();
}
} // namespace } // namespace
AXEventGenerator::EventParams::EventParams(Event event, AXEventGenerator::EventParams::EventParams(Event event,
...@@ -149,31 +138,6 @@ void AXEventGenerator::AddEvent(AXNode* node, AXEventGenerator::Event event) { ...@@ -149,31 +138,6 @@ void AXEventGenerator::AddEvent(AXNode* node, AXEventGenerator::Event event) {
return; return;
std::set<EventParams>& node_events = tree_events_[node]; std::set<EventParams>& node_events = tree_events_[node];
// A newly created live region or alert should not *also* fire a
// live region changed event.
if (event == Event::LIVE_REGION_CHANGED &&
HasOtherLiveRegionEvent(node_events)) {
return;
}
// We shouldn't fire children changed events on nodes that become
// ignored or unignored.
if (event == Event::IGNORED_CHANGED) {
for (auto& iter : node_events) {
if (iter.event == Event::CHILDREN_CHANGED) {
node_events.erase(iter);
break;
}
}
}
if (event == Event::CHILDREN_CHANGED) {
for (auto& iter : node_events) {
if (iter.event == Event::IGNORED_CHANGED)
return;
}
}
node_events.emplace(event, ax::mojom::EventFrom::kNone); node_events.emplace(event, ax::mojom::EventFrom::kNone);
} }
......
...@@ -44,23 +44,64 @@ int TreeGenerator::UniqueTreeCount() const { ...@@ -44,23 +44,64 @@ int TreeGenerator::UniqueTreeCount() const {
} }
void TreeGenerator::BuildUniqueTree(int tree_index, AXTree* out_tree) const { void TreeGenerator::BuildUniqueTree(int tree_index, AXTree* out_tree) const {
AXTreeUpdate update;
BuildUniqueTreeUpdate(tree_index, &update);
CHECK(out_tree->Unserialize(update)) << out_tree->error();
}
int TreeGenerator::IgnoredPermutationCountPerUniqueTree(int tree_index) const {
int unique_tree_count_so_far = 0;
for (int node_count = 1; node_count <= max_node_count_; ++node_count) {
int unique_tree_count = unique_tree_count_by_size_[node_count];
if (tree_index - unique_tree_count_so_far < unique_tree_count) {
// Each node other than the root can be either ignored or not,
// so return 2 ^ (node_count - 1)
return 1 << (node_count - 1);
}
unique_tree_count_so_far += unique_tree_count;
}
NOTREACHED();
return 0;
}
void TreeGenerator::BuildUniqueTreeWithIgnoredNodes(int tree_index,
int ignored_index,
AXTree* out_tree) const {
AXTreeUpdate update;
BuildUniqueTreeUpdate(tree_index, &update);
int node_count = int{update.nodes.size()};
CHECK_GE(ignored_index, 0);
CHECK_LT(ignored_index, 1 << (node_count - 1));
for (int i = 0; i < node_count - 1; i++) {
if (ignored_index & (1 << i))
update.nodes[i + 1].AddState(ax::mojom::State::kIgnored);
}
CHECK(out_tree->Unserialize(update)) << out_tree->error();
}
void TreeGenerator::BuildUniqueTreeUpdate(int tree_index,
AXTreeUpdate* out_update) const {
CHECK_LT(tree_index, total_unique_tree_count_); CHECK_LT(tree_index, total_unique_tree_count_);
int unique_tree_count_so_far = 0; int unique_tree_count_so_far = 0;
for (int node_count = 1; node_count <= max_node_count_; ++node_count) { for (int node_count = 1; node_count <= max_node_count_; ++node_count) {
int unique_tree_count = unique_tree_count_by_size_[node_count]; int unique_tree_count = unique_tree_count_by_size_[node_count];
if (tree_index - unique_tree_count_so_far < unique_tree_count) { if (tree_index - unique_tree_count_so_far < unique_tree_count) {
BuildUniqueTreeWithSize(node_count, BuildUniqueTreeUpdateWithSize(
tree_index - unique_tree_count_so_far, node_count, tree_index - unique_tree_count_so_far, out_update);
out_tree);
return; return;
} }
unique_tree_count_so_far += unique_tree_count; unique_tree_count_so_far += unique_tree_count;
} }
} }
void TreeGenerator::BuildUniqueTreeWithSize( void TreeGenerator::BuildUniqueTreeUpdateWithSize(
int node_count, int tree_index, AXTree* out_tree) const { int node_count,
int tree_index,
AXTreeUpdate* out_update) const {
std::vector<int> indices; std::vector<int> indices;
std::vector<int> permuted; std::vector<int> permuted;
int unique_tree_count = unique_tree_count_by_size_[node_count]; int unique_tree_count = unique_tree_count_by_size_[node_count];
...@@ -84,26 +125,22 @@ void TreeGenerator::BuildUniqueTreeWithSize( ...@@ -84,26 +125,22 @@ void TreeGenerator::BuildUniqueTreeWithSize(
// Build an AXTreeUpdate. The first two nodes of the tree always // Build an AXTreeUpdate. The first two nodes of the tree always
// go in the same place. // go in the same place.
AXTreeUpdate update; out_update->root_id = permuted[0];
update.root_id = permuted[0]; out_update->nodes.resize(node_count);
update.nodes.resize(node_count); out_update->nodes[0].id = permuted[0];
update.nodes[0].id = permuted[0];
if (node_count > 1) { if (node_count > 1) {
update.nodes[0].child_ids.push_back(permuted[1]); out_update->nodes[0].child_ids.push_back(permuted[1]);
update.nodes[1].id = permuted[1]; out_update->nodes[1].id = permuted[1];
} }
// The remaining nodes are assigned based on their parent // The remaining nodes are assigned based on their parent
// selected from the next bits from |tree_index|. // selected from the next bits from |tree_index|.
for (int i = 2; i < node_count; ++i) { for (int i = 2; i < node_count; ++i) {
update.nodes[i].id = permuted[i]; out_update->nodes[i].id = permuted[i];
int parent_index = (tree_index % i); int parent_index = (tree_index % i);
tree_index /= i; tree_index /= i;
update.nodes[parent_index].child_ids.push_back(permuted[i]); out_update->nodes[parent_index].child_ids.push_back(permuted[i]);
} }
// Unserialize the tree update into the destination tree.
CHECK(out_tree->Unserialize(update)) << out_tree->error();
} }
} // namespace ui } // namespace ui
...@@ -2,8 +2,13 @@ ...@@ -2,8 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef UI_ACCESSIBILITY_TREE_GENERATOR_H_
#define UI_ACCESSIBILITY_TREE_GENERATOR_H_
#include <vector> #include <vector>
#include "ui/accessibility/ax_tree_update_forward.h"
namespace ui { namespace ui {
class AXTree; class AXTree;
...@@ -45,13 +50,23 @@ class TreeGenerator { ...@@ -45,13 +50,23 @@ class TreeGenerator {
TreeGenerator(int max_node_count, bool permutations); TreeGenerator(int max_node_count, bool permutations);
~TreeGenerator(); ~TreeGenerator();
// Build all unique trees (no nodes ignored).
int UniqueTreeCount() const; int UniqueTreeCount() const;
void BuildUniqueTree(int tree_index, AXTree* out_tree) const; void BuildUniqueTree(int tree_index, AXTree* out_tree) const;
// Support for returning every permutation of ignored nodes
// (other than the root, which is never ignored) per unique tree.
int IgnoredPermutationCountPerUniqueTree(int tree_index) const;
void BuildUniqueTreeWithIgnoredNodes(int tree_index,
int ignored_index,
AXTree* out_tree) const;
private: private:
void BuildUniqueTreeWithSize( void BuildUniqueTreeUpdate(int tree_index,
int node_count, int tree_index, AXTree* out_tree) const; AXTreeUpdate* out_tree_update) const;
void BuildUniqueTreeUpdateWithSize(int node_count,
int tree_index,
AXTreeUpdate* out_tree_update) const;
int max_node_count_; int max_node_count_;
bool permutations_; bool permutations_;
...@@ -60,3 +75,5 @@ class TreeGenerator { ...@@ -60,3 +75,5 @@ class TreeGenerator {
}; };
} // namespace ui } // namespace ui
#endif // UI_ACCESSIBILITY_TREE_GENERATOR_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment