| // 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 "fuchsia/engine/browser/fake_semantic_tree.h" |
| |
| #include <lib/fidl/cpp/binding.h> |
| #include <zircon/types.h> |
| |
| #include "base/auto_reset.h" |
| #include "base/notreached.h" |
| #include "base/run_loop.h" |
| #include "base/test/bind_test_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| FakeSemanticTree::FakeSemanticTree() : semantic_tree_binding_(this) {} |
| FakeSemanticTree::~FakeSemanticTree() = default; |
| |
| void FakeSemanticTree::Bind( |
| fidl::InterfaceRequest<fuchsia::accessibility::semantics::SemanticTree> |
| semantic_tree_request) { |
| semantic_tree_binding_.Bind(std::move(semantic_tree_request)); |
| } |
| |
| bool FakeSemanticTree::IsTreeValid( |
| fuchsia::accessibility::semantics::Node* node, |
| size_t* tree_size) { |
| (*tree_size)++; |
| |
| if (!node->has_child_ids()) |
| return true; |
| |
| bool is_valid = true; |
| for (auto c : node->child_ids()) { |
| fuchsia::accessibility::semantics::Node* child = GetNodeWithId(c); |
| if (!child) |
| return false; |
| |
| is_valid &= IsTreeValid(child, tree_size); |
| } |
| return is_valid; |
| } |
| |
| void FakeSemanticTree::Disconnect() { |
| semantic_tree_binding_.Close(ZX_ERR_INTERNAL); |
| } |
| |
| void FakeSemanticTree::RunUntilNodeCountAtLeast(size_t count) { |
| DCHECK(!on_commit_updates_); |
| if (nodes_.size() >= count) |
| return; |
| |
| base::RunLoop run_loop; |
| base::AutoReset<base::RepeatingClosure> auto_reset( |
| &on_commit_updates_, |
| base::BindLambdaForTesting([this, count, &run_loop]() { |
| if (nodes_.size() >= count) { |
| run_loop.Quit(); |
| } |
| })); |
| run_loop.Run(); |
| } |
| |
| void FakeSemanticTree::RunUntilCommitCountIs(size_t count) { |
| DCHECK(!on_commit_updates_); |
| if (count == num_commit_calls_) |
| return; |
| |
| base::RunLoop run_loop; |
| base::AutoReset<base::RepeatingClosure> auto_reset( |
| &on_commit_updates_, |
| base::BindLambdaForTesting([this, count, &run_loop]() { |
| if (static_cast<size_t>(num_commit_calls_) == count) { |
| run_loop.Quit(); |
| } |
| })); |
| run_loop.Run(); |
| } |
| |
| void FakeSemanticTree::SetNodeUpdatedCallback( |
| uint32_t node_id, |
| base::OnceClosure node_updated_callback) { |
| node_wait_id_ = node_id; |
| on_node_updated_callback_ = std::move(node_updated_callback); |
| } |
| |
| fuchsia::accessibility::semantics::Node* FakeSemanticTree::GetNodeWithId( |
| uint32_t id) { |
| auto it = nodes_.find(id); |
| return it == nodes_.end() ? nullptr : &it->second; |
| } |
| |
| fuchsia::accessibility::semantics::Node* FakeSemanticTree::GetNodeFromLabel( |
| base::StringPiece label) { |
| fuchsia::accessibility::semantics::Node* to_return = nullptr; |
| for (auto& n : nodes_) { |
| auto* node = &n.second; |
| if (node->has_attributes() && node->attributes().has_label() && |
| node->attributes().label() == label) { |
| // There are sometimes multiple semantic nodes with the same label. Hit |
| // testing should return the node with the smallest node ID so behaviour |
| // is consistent with the hit testing API being called. |
| if (!to_return) { |
| to_return = node; |
| } else if (node->node_id() < to_return->node_id()) { |
| to_return = node; |
| } |
| } |
| } |
| |
| return to_return; |
| } |
| |
| fuchsia::accessibility::semantics::Node* FakeSemanticTree::GetNodeFromRole( |
| fuchsia::accessibility::semantics::Role role) { |
| for (auto& n : nodes_) { |
| auto* node = &n.second; |
| if (node->has_role() && node->role() == role) |
| return node; |
| } |
| |
| return nullptr; |
| } |
| |
| void FakeSemanticTree::UpdateSemanticNodes( |
| std::vector<fuchsia::accessibility::semantics::Node> nodes) { |
| num_update_calls_++; |
| bool wait_node_updated = false; |
| for (auto& node : nodes) { |
| if (node.node_id() == node_wait_id_ && on_node_updated_callback_) |
| wait_node_updated = true; |
| |
| nodes_[node.node_id()] = std::move(node); |
| } |
| |
| if (wait_node_updated) |
| std::move(on_node_updated_callback_).Run(); |
| } |
| |
| void FakeSemanticTree::DeleteSemanticNodes(std::vector<uint32_t> node_ids) { |
| num_delete_calls_++; |
| for (auto id : node_ids) |
| nodes_.erase(id); |
| } |
| |
| void FakeSemanticTree::CommitUpdates(CommitUpdatesCallback callback) { |
| num_commit_calls_++; |
| callback(); |
| if (on_commit_updates_) |
| on_commit_updates_.Run(); |
| if (nodes_.size() > 0) { |
| size_t tree_size = 0; |
| EXPECT_TRUE(IsTreeValid(GetNodeWithId(0), &tree_size)); |
| EXPECT_EQ(tree_size, nodes_.size()); |
| } |
| } |
| |
| void FakeSemanticTree::NotImplemented_(const std::string& name) { |
| NOTIMPLEMENTED() << name; |
| } |
| |
| void FakeSemanticTree::Clear() { |
| nodes_.clear(); |
| } |