| // Copyright 2016 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 <stdint.h> |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/accessibility/ax_enums.mojom.h" |
| #include "ui/accessibility/ax_node.h" |
| #include "ui/accessibility/ax_node_data.h" |
| #include "ui/accessibility/ax_node_position.h" |
| #include "ui/accessibility/ax_range.h" |
| #include "ui/accessibility/ax_serializable_tree.h" |
| #include "ui/accessibility/ax_tree_serializer.h" |
| #include "ui/accessibility/ax_tree_update.h" |
| |
| namespace ui { |
| |
| using TestPositionType = std::unique_ptr<AXPosition<AXNodePosition, AXNode>>; |
| |
| namespace { |
| |
| int32_t ROOT_ID = 1; |
| int32_t BUTTON_ID = 2; |
| int32_t CHECK_BOX_ID = 3; |
| int32_t TEXT_FIELD_ID = 4; |
| int32_t STATIC_TEXT1_ID = 5; |
| int32_t INLINE_BOX1_ID = 6; |
| int32_t LINE_BREAK_ID = 7; |
| int32_t STATIC_TEXT2_ID = 8; |
| int32_t INLINE_BOX2_ID = 9; |
| |
| class AXPositionTest : public testing::Test { |
| public: |
| static const char* TEXT_VALUE; |
| |
| AXPositionTest() = default; |
| ~AXPositionTest() override = default; |
| |
| protected: |
| void SetUp() override; |
| void TearDown() override; |
| |
| AXNodeData root_; |
| AXNodeData button_; |
| AXNodeData check_box_; |
| AXNodeData text_field_; |
| AXNodeData static_text1_; |
| AXNodeData line_break_; |
| AXNodeData static_text2_; |
| AXNodeData inline_box1_; |
| AXNodeData inline_box2_; |
| |
| AXTree tree_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AXPositionTest); |
| }; |
| |
| // Used by parameterized tests. |
| // The test starts from a pre-determined position and repeats until there are no |
| // more expectations. |
| // TODO(nektar): Only text positions are tested for now. |
| struct TestParam { |
| TestParam() = default; |
| |
| // Required by GTest framework. |
| TestParam(const TestParam& other) = default; |
| TestParam& operator=(const TestParam& other) = default; |
| |
| ~TestParam() = default; |
| |
| // Stores the method that should be called repeatedly by the test to create |
| // the next position. |
| base::RepeatingCallback<TestPositionType(const TestPositionType&)> TestMethod; |
| |
| // The node at which the test should start. |
| int32_t start_node_id_; |
| |
| // The text offset at which the test should start. |
| int start_offset_; |
| |
| // A list of positions that should be returned from the method being tested, |
| // in stringified form. |
| std::vector<std::string> expectations; |
| }; |
| |
| class AXPositionTestWithParam : public AXPositionTest, |
| public testing::WithParamInterface<TestParam> { |
| public: |
| AXPositionTestWithParam() = default; |
| ~AXPositionTestWithParam() override = default; |
| |
| DISALLOW_COPY_AND_ASSIGN(AXPositionTestWithParam); |
| }; |
| |
| const char* AXPositionTest::TEXT_VALUE = "Line 1\nLine 2"; |
| |
| void AXPositionTest::SetUp() { |
| root_.id = ROOT_ID; |
| button_.id = BUTTON_ID; |
| check_box_.id = CHECK_BOX_ID; |
| text_field_.id = TEXT_FIELD_ID; |
| static_text1_.id = STATIC_TEXT1_ID; |
| inline_box1_.id = INLINE_BOX1_ID; |
| line_break_.id = LINE_BREAK_ID; |
| static_text2_.id = STATIC_TEXT2_ID; |
| inline_box2_.id = INLINE_BOX2_ID; |
| |
| root_.role = ax::mojom::Role::kDialog; |
| root_.AddState(ax::mojom::State::kFocusable); |
| root_.SetName(std::string("ButtonCheck box") + TEXT_VALUE); |
| root_.relative_bounds.bounds = gfx::RectF(0, 0, 800, 600); |
| |
| button_.role = ax::mojom::Role::kButton; |
| button_.SetHasPopup(ax::mojom::HasPopup::kMenu); |
| button_.SetName("Button"); |
| button_.relative_bounds.bounds = gfx::RectF(20, 20, 200, 30); |
| button_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts, |
| std::vector<int32_t>{0}); |
| button_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds, |
| std::vector<int32_t>{6}); |
| button_.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId, |
| check_box_.id); |
| root_.child_ids.push_back(button_.id); |
| |
| check_box_.role = ax::mojom::Role::kCheckBox; |
| check_box_.SetCheckedState(ax::mojom::CheckedState::kTrue); |
| check_box_.SetName("Check box"); |
| check_box_.relative_bounds.bounds = gfx::RectF(20, 50, 200, 30); |
| check_box_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts, |
| std::vector<int32_t>{0, 6}); |
| check_box_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds, |
| std::vector<int32_t>{5, 9}); |
| check_box_.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId, |
| button_.id); |
| root_.child_ids.push_back(check_box_.id); |
| |
| text_field_.role = ax::mojom::Role::kTextField; |
| text_field_.AddState(ax::mojom::State::kEditable); |
| text_field_.SetValue(TEXT_VALUE); |
| text_field_.AddIntListAttribute( |
| ax::mojom::IntListAttribute::kCachedLineStarts, |
| std::vector<int32_t>{0, 7}); |
| text_field_.child_ids.push_back(static_text1_.id); |
| text_field_.child_ids.push_back(line_break_.id); |
| text_field_.child_ids.push_back(static_text2_.id); |
| root_.child_ids.push_back(text_field_.id); |
| |
| static_text1_.role = ax::mojom::Role::kStaticText; |
| static_text1_.AddState(ax::mojom::State::kEditable); |
| static_text1_.SetName("Line 1"); |
| static_text1_.child_ids.push_back(inline_box1_.id); |
| |
| inline_box1_.role = ax::mojom::Role::kInlineTextBox; |
| inline_box1_.AddState(ax::mojom::State::kEditable); |
| inline_box1_.SetName("Line 1"); |
| inline_box1_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts, |
| std::vector<int32_t>{0, 5}); |
| inline_box1_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds, |
| std::vector<int32_t>{4, 6}); |
| inline_box1_.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId, |
| line_break_.id); |
| |
| line_break_.role = ax::mojom::Role::kLineBreak; |
| line_break_.AddState(ax::mojom::State::kEditable); |
| line_break_.SetName("\n"); |
| line_break_.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId, |
| inline_box1_.id); |
| |
| static_text2_.role = ax::mojom::Role::kStaticText; |
| static_text2_.AddState(ax::mojom::State::kEditable); |
| static_text2_.SetName("Line 2"); |
| static_text2_.child_ids.push_back(inline_box2_.id); |
| |
| inline_box2_.role = ax::mojom::Role::kInlineTextBox; |
| inline_box2_.AddState(ax::mojom::State::kEditable); |
| inline_box2_.SetName("Line 2"); |
| inline_box2_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts, |
| std::vector<int32_t>{0, 5}); |
| inline_box2_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds, |
| std::vector<int32_t>{4, 6}); |
| |
| AXTreeUpdate initial_state; |
| initial_state.root_id = 1; |
| initial_state.nodes.push_back(root_); |
| initial_state.nodes.push_back(button_); |
| initial_state.nodes.push_back(check_box_); |
| initial_state.nodes.push_back(text_field_); |
| initial_state.nodes.push_back(static_text1_); |
| initial_state.nodes.push_back(inline_box1_); |
| initial_state.nodes.push_back(line_break_); |
| initial_state.nodes.push_back(static_text2_); |
| initial_state.nodes.push_back(inline_box2_); |
| initial_state.has_tree_data = true; |
| initial_state.tree_data.tree_id = AXTreeID::CreateNewAXTreeID(); |
| initial_state.tree_data.title = "Dialog title"; |
| AXSerializableTree src_tree(initial_state); |
| |
| std::unique_ptr<AXTreeSource<const AXNode*, AXNodeData, AXTreeData>> |
| tree_source(src_tree.CreateTreeSource()); |
| AXTreeSerializer<const AXNode*, AXNodeData, AXTreeData> serializer( |
| tree_source.get()); |
| AXTreeUpdate update; |
| serializer.SerializeChanges(src_tree.root(), &update); |
| ASSERT_TRUE(tree_.Unserialize(update)); |
| AXNodePosition::SetTreeForTesting(&tree_); |
| } |
| |
| void AXPositionTest::TearDown() { |
| AXNodePosition::SetTreeForTesting(nullptr); |
| } |
| |
| } // namespace |
| |
| TEST_F(AXPositionTest, Clone) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| TestPositionType copy_position = null_position->Clone(); |
| ASSERT_NE(nullptr, copy_position); |
| EXPECT_TRUE(copy_position->IsNullPosition()); |
| |
| TestPositionType tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 1 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| copy_position = tree_position->Clone(); |
| ASSERT_NE(nullptr, copy_position); |
| EXPECT_TRUE(copy_position->IsTreePosition()); |
| EXPECT_EQ(root_.id, copy_position->anchor_id()); |
| EXPECT_EQ(1, copy_position->child_index()); |
| EXPECT_EQ(AXNodePosition::INVALID_OFFSET, copy_position->text_offset()); |
| |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, AXNodePosition::BEFORE_TEXT); |
| ASSERT_NE(nullptr, tree_position); |
| copy_position = tree_position->Clone(); |
| ASSERT_NE(nullptr, copy_position); |
| EXPECT_TRUE(copy_position->IsTreePosition()); |
| EXPECT_EQ(root_.id, copy_position->anchor_id()); |
| EXPECT_EQ(AXNodePosition::BEFORE_TEXT, copy_position->child_index()); |
| EXPECT_EQ(AXNodePosition::INVALID_OFFSET, copy_position->text_offset()); |
| |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, text_field_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position); |
| copy_position = text_position->Clone(); |
| ASSERT_NE(nullptr, copy_position); |
| EXPECT_TRUE(copy_position->IsTextPosition()); |
| EXPECT_EQ(text_field_.id, copy_position->anchor_id()); |
| EXPECT_EQ(1, copy_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, copy_position->affinity()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, text_field_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| copy_position = text_position->Clone(); |
| ASSERT_NE(nullptr, copy_position); |
| EXPECT_TRUE(copy_position->IsTextPosition()); |
| EXPECT_EQ(text_field_.id, copy_position->anchor_id()); |
| EXPECT_EQ(1, copy_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, copy_position->affinity()); |
| EXPECT_EQ(AXNodePosition::INVALID_INDEX, copy_position->child_index()); |
| } |
| |
| TEST_F(AXPositionTest, AtStartOfAnchorWithNullPosition) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| EXPECT_FALSE(null_position->AtStartOfAnchor()); |
| } |
| |
| TEST_F(AXPositionTest, AtStartOfAnchorWithTreePosition) { |
| TestPositionType tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| EXPECT_TRUE(tree_position->AtStartOfAnchor()); |
| |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 1 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| EXPECT_FALSE(tree_position->AtStartOfAnchor()); |
| |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 3 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| EXPECT_FALSE(tree_position->AtStartOfAnchor()); |
| |
| // A "before text" position. |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, inline_box1_.id, AXNodePosition::BEFORE_TEXT); |
| ASSERT_NE(nullptr, tree_position); |
| EXPECT_TRUE(tree_position->AtStartOfAnchor()); |
| |
| // An "after text" position. |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| EXPECT_FALSE(tree_position->AtStartOfAnchor()); |
| } |
| |
| TEST_F(AXPositionTest, AtStartOfAnchorWithTextPosition) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_TRUE(text_position->AtStartOfAnchor()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_FALSE(text_position->AtStartOfAnchor()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 6 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_FALSE(text_position->AtStartOfAnchor()); |
| } |
| |
| TEST_F(AXPositionTest, AtEndOfAnchorWithNullPosition) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| EXPECT_FALSE(null_position->AtEndOfAnchor()); |
| } |
| |
| TEST_F(AXPositionTest, AtEndOfAnchorWithTreePosition) { |
| TestPositionType tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 3 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| EXPECT_TRUE(tree_position->AtEndOfAnchor()); |
| |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 2 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| EXPECT_FALSE(tree_position->AtEndOfAnchor()); |
| |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| EXPECT_FALSE(tree_position->AtEndOfAnchor()); |
| } |
| |
| TEST_F(AXPositionTest, AtEndOfAnchorWithTextPosition) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 6 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_TRUE(text_position->AtEndOfAnchor()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_FALSE(text_position->AtEndOfAnchor()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_FALSE(text_position->AtEndOfAnchor()); |
| } |
| |
| TEST_F(AXPositionTest, AtStartOfLineWithTextPosition) { |
| // An upstream affinity should not affect the outcome since there is no soft |
| // line break. |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_TRUE(text_position->AtStartOfLine()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_FALSE(text_position->AtStartOfLine()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, line_break_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_FALSE(text_position->AtStartOfLine()); |
| |
| // An "after text" position anchored at the line break should not be the same |
| // as a text position at the start of the next line. |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, line_break_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_FALSE(text_position->AtStartOfLine()); |
| |
| // An upstream affinity should not affect the outcome since there is no soft |
| // line break. |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box2_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_TRUE(text_position->AtStartOfLine()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box2_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_FALSE(text_position->AtStartOfLine()); |
| } |
| |
| TEST_F(AXPositionTest, AtEndOfLineWithTextPosition) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_FALSE(text_position->AtEndOfLine()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 6 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_TRUE(text_position->AtEndOfLine()); |
| |
| // A "before text" position anchored at the line break should visually be the |
| // same as a text position at the end of the previous line. |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, line_break_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_TRUE(text_position->AtEndOfLine()); |
| |
| // The following position comes after the soft line break, so it should not be |
| // marked as the end of the line. |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, line_break_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_FALSE(text_position->AtEndOfLine()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box2_.id, 5 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_FALSE(text_position->AtEndOfLine()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box2_.id, 6 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| EXPECT_TRUE(text_position->AtEndOfLine()); |
| } |
| |
| TEST_F(AXPositionTest, LowestCommonAncestor) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| // An "after children" position. |
| TestPositionType root_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 3 /* child_index */); |
| ASSERT_NE(nullptr, root_position); |
| // A "before text" position. |
| TestPositionType button_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, button_.id, AXNodePosition::BEFORE_TEXT); |
| ASSERT_NE(nullptr, button_position); |
| TestPositionType text_field_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, text_field_.id, 2 /* child_index */); |
| ASSERT_NE(nullptr, text_field_position); |
| TestPositionType static_text1_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, static_text1_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, static_text1_position); |
| TestPositionType static_text2_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, static_text2_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, static_text2_position); |
| TestPositionType inline_box1_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, inline_box1_position); |
| TestPositionType inline_box2_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box2_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, inline_box2_position); |
| |
| TestPositionType test_position = |
| root_position->LowestCommonAncestor(*null_position.get()); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| |
| test_position = root_position->LowestCommonAncestor(*root_position.get()); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(root_.id, test_position->anchor_id()); |
| // The child index should be for an "after children" position, i.e. it should |
| // be unchanged. |
| EXPECT_EQ(3, test_position->child_index()); |
| |
| test_position = |
| button_position->LowestCommonAncestor(*text_field_position.get()); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(root_.id, test_position->anchor_id()); |
| // The child index should point to the button. |
| EXPECT_EQ(0, test_position->child_index()); |
| |
| test_position = |
| static_text2_position->LowestCommonAncestor(*static_text1_position.get()); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(text_field_.id, test_position->anchor_id()); |
| // The child index should point to the second static text node. |
| EXPECT_EQ(2, test_position->child_index()); |
| |
| test_position = |
| static_text1_position->LowestCommonAncestor(*text_field_position.get()); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(text_field_.id, test_position->anchor_id()); |
| // The child index should point to the first static text node. |
| EXPECT_EQ(0, test_position->child_index()); |
| |
| test_position = |
| inline_box1_position->LowestCommonAncestor(*inline_box2_position.get()); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(text_field_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| test_position = |
| inline_box2_position->LowestCommonAncestor(*inline_box1_position.get()); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(text_field_.id, test_position->anchor_id()); |
| // The text offset should point to the second line. |
| EXPECT_EQ(7, test_position->text_offset()); |
| } |
| |
| TEST_F(AXPositionTest, AsTreePositionWithNullPosition) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| TestPositionType test_position = null_position->AsTreePosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, AsTreePositionWithTreePosition) { |
| TestPositionType tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 1 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| TestPositionType test_position = tree_position->AsTreePosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(root_.id, test_position->anchor_id()); |
| EXPECT_EQ(1, test_position->child_index()); |
| EXPECT_EQ(AXNodePosition::INVALID_OFFSET, test_position->text_offset()); |
| } |
| |
| TEST_F(AXPositionTest, AsTreePositionWithTextPosition) { |
| // Create a text position pointing to the last character in the text field. |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, text_field_.id, 12 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| TestPositionType test_position = text_position->AsTreePosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(text_field_.id, test_position->anchor_id()); |
| // The created tree position should point to the second static text node |
| // inside the text field. |
| EXPECT_EQ(2, test_position->child_index()); |
| // But its text offset should be unchanged. |
| EXPECT_EQ(12, test_position->text_offset()); |
| |
| // Test for a "before text" position. |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box2_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->AsTreePosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); |
| EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| // Test for an "after text" position. |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box2_.id, 6 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->AsTreePosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->child_index()); |
| EXPECT_EQ(6, test_position->text_offset()); |
| } |
| |
| TEST_F(AXPositionTest, AsTextPositionWithNullPosition) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| TestPositionType test_position = null_position->AsTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, AsTextPositionWithTreePosition) { |
| // Create a tree position pointing to the line break node inside the text |
| // field. |
| TestPositionType tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, text_field_.id, 1 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| TestPositionType test_position = tree_position->AsTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(text_field_.id, test_position->anchor_id()); |
| // The created text position should point to the 6th character inside the text |
| // field, i.e. the line break. |
| EXPECT_EQ(6, test_position->text_offset()); |
| // But its child index should be unchanged. |
| EXPECT_EQ(1, test_position->child_index()); |
| // And the affinity cannot be anything other than downstream because we |
| // haven't moved up the tree and so there was no opportunity to introduce any |
| // ambiguity regarding the new position. |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| |
| // Test for a "before text" position. |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, inline_box1_.id, AXNodePosition::BEFORE_TEXT); |
| ASSERT_NE(nullptr, tree_position); |
| test_position = tree_position->AsTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| |
| // Test for an "after text" position. |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| test_position = tree_position->AsTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(6, test_position->text_offset()); |
| EXPECT_EQ(0, test_position->child_index()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| } |
| |
| TEST_F(AXPositionTest, AsTextPositionWithTextPosition) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, text_field_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| TestPositionType test_position = text_position->AsTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(text_field_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| EXPECT_EQ(AXNodePosition::INVALID_INDEX, test_position->child_index()); |
| } |
| |
| TEST_F(AXPositionTest, AsLeafTextPositionWithNullPosition) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| TestPositionType test_position = null_position->AsLeafTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, AsLeafTextPositionWithTreePosition) { |
| // Create a tree position pointing to the first static text node inside the |
| // text field. |
| TestPositionType tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, text_field_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| TestPositionType test_position = tree_position->AsLeafTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| |
| // Create a tree position pointing to the line break node inside the text |
| // field. |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, text_field_.id, 1 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| test_position = tree_position->AsLeafTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(line_break_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| |
| // Create a text position pointing to the second static text node inside the |
| // text field. |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, text_field_.id, 2 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| test_position = tree_position->AsLeafTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| } |
| |
| TEST_F(AXPositionTest, AsLeafTextPositionWithTextPosition) { |
| // Create a text position pointing to the end of the root (an "after text" |
| // position). |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, root_.id, 28 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| TestPositionType test_position = text_position->AsLeafTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); |
| EXPECT_EQ(6, test_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, text_field_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->AsLeafTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, text_field_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->AsLeafTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(1, test_position->text_offset()); |
| // Even though upstream affinity doesn't make sense on a leaf node, there is |
| // no need to reset it to downstream. |
| EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, test_position->affinity()); |
| |
| // Create a text position on the root, pointing to the line break character |
| // inside the text field but with an upstream affinity which will cause the |
| // leaf text position to be placed after the text of the first inline text |
| // box. |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, root_.id, 21 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->AsLeafTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(6, test_position->text_offset()); |
| // Even though upstream affinity doesn't make sense on a leaf node, there is |
| // no need to reset it to downstream. |
| EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, test_position->affinity()); |
| |
| // Create a text position pointing to the line break character inside the text |
| // field but with an upstream affinity which will cause the leaf text position |
| // to be placed after the text of the first inline text box. |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, text_field_.id, 6 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->AsLeafTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(6, test_position->text_offset()); |
| // Even though upstream affinity doesn't make sense on a leaf node, there is |
| // no need to reset it to downstream. |
| EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, test_position->affinity()); |
| |
| // Create a text position on the root, pointing to the line break character |
| // inside the text field. |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, root_.id, 21 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->AsLeafTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(line_break_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| |
| // Create a text position pointing to the line break character inside the text |
| // field. |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, text_field_.id, 6 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->AsLeafTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(line_break_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| |
| // Create a text position pointing to the offset after the last character in |
| // the text field, (an "after text" position). |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, text_field_.id, 13 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->AsLeafTextPosition(); |
| ASSERT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); |
| EXPECT_EQ(6, test_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| } |
| |
| TEST_F(AXPositionTest, CreatePositionAtStartOfAnchorWithNullPosition) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| TestPositionType test_position = |
| null_position->CreatePositionAtStartOfAnchor(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, CreatePositionAtStartOfAnchorWithTreePosition) { |
| TestPositionType tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| TestPositionType test_position = |
| tree_position->CreatePositionAtStartOfAnchor(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(root_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->child_index()); |
| |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 1 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| test_position = tree_position->CreatePositionAtStartOfAnchor(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(root_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->child_index()); |
| |
| // An "after text" position. |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| test_position = tree_position->CreatePositionAtStartOfAnchor(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index()); |
| } |
| |
| TEST_F(AXPositionTest, CreatePositionAtStartOfAnchorWithTextPosition) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| TestPositionType test_position = |
| text_position->CreatePositionAtStartOfAnchor(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->CreatePositionAtStartOfAnchor(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| // Affinity should have been reset to the default value. |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| } |
| |
| TEST_F(AXPositionTest, CreatePositionAtEndOfAnchorWithNullPosition) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| TestPositionType test_position = null_position->CreatePositionAtEndOfAnchor(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, CreatePositionAtEndOfAnchorWithTreePosition) { |
| TestPositionType tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 3 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| TestPositionType test_position = tree_position->CreatePositionAtEndOfAnchor(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(root_.id, test_position->anchor_id()); |
| EXPECT_EQ(3, test_position->child_index()); |
| |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 1 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| test_position = tree_position->CreatePositionAtEndOfAnchor(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(root_.id, test_position->anchor_id()); |
| EXPECT_EQ(3, test_position->child_index()); |
| } |
| |
| TEST_F(AXPositionTest, CreatePositionAtEndOfAnchorWithTextPosition) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 6 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| TestPositionType test_position = text_position->CreatePositionAtEndOfAnchor(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(6, test_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->CreatePositionAtEndOfAnchor(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(6, test_position->text_offset()); |
| // Affinity should have been reset to the default value. |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| } |
| |
| TEST_F(AXPositionTest, CreateChildPositionAtWithNullPosition) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| TestPositionType test_position = null_position->CreateChildPositionAt(0); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, CreateChildPositionAtWithTreePosition) { |
| TestPositionType tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 2 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| TestPositionType test_position = tree_position->CreateChildPositionAt(1); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(check_box_.id, test_position->anchor_id()); |
| // Since the anchor is a leaf node, |child_index| should signify that this is |
| // a "before text" position. |
| EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index()); |
| |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, button_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| test_position = tree_position->CreateChildPositionAt(0); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, CreateChildPositionAtWithTextPosition) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, static_text1_.id, 5 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| TestPositionType test_position = text_position->CreateChildPositionAt(0); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, static_text2_.id, 4 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->CreateChildPositionAt(1); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, CreateParentPositionWithNullPosition) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| TestPositionType test_position = null_position->CreateParentPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, CreateParentPositionWithTreePosition) { |
| TestPositionType tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, check_box_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| TestPositionType test_position = tree_position->CreateParentPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTreePosition()); |
| EXPECT_EQ(root_.id, test_position->anchor_id()); |
| // |child_index| should point to the check box node. |
| EXPECT_EQ(1, test_position->child_index()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| |
| tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 1 /* child_index */); |
| ASSERT_NE(nullptr, tree_position); |
| test_position = tree_position->CreateParentPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, CreateParentPositionWithTextPosition) { |
| // Create a position that points at the end of the first line, right after the |
| // check box. |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, check_box_.id, 9 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| TestPositionType test_position = text_position->CreateParentPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(root_.id, test_position->anchor_id()); |
| EXPECT_EQ(15, test_position->text_offset()); |
| // Since the same text offset in the root could be used to point to the |
| // beginning of the second line, affinity should have been adjusted to |
| // upstream. |
| EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, test_position->affinity()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box2_.id, 5 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->CreateParentPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(static_text2_.id, test_position->anchor_id()); |
| EXPECT_EQ(5, test_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| |
| test_position = test_position->CreateParentPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(text_field_.id, test_position->anchor_id()); |
| // |text_offset| should point to the same offset on the second line where the |
| // static text node position was pointing at. |
| EXPECT_EQ(12, test_position->text_offset()); |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| } |
| |
| TEST_F(AXPositionTest, |
| CreateNextAndPreviousTextAnchorPositionWithNullPosition) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| TestPositionType test_position = |
| null_position->CreateNextTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| test_position = null_position->CreatePreviousTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, CreateNextTextAnchorPosition) { |
| TestPositionType check_box_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 1 /* child_index */); |
| ASSERT_NE(nullptr, check_box_position); |
| TestPositionType test_position = |
| check_box_position->CreateNextTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(check_box_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| // The text offset on the root points to the text coming from inside the check |
| // box. |
| check_box_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, root_.id, 6 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, check_box_position); |
| test_position = check_box_position->CreateNextTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(check_box_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| TestPositionType button_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, button_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, button_position); |
| test_position = button_position->CreateNextTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(check_box_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| test_position = test_position->CreateNextTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| test_position = test_position->CreateNextTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(line_break_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| test_position = test_position->CreateNextTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| test_position = test_position->CreateNextTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| |
| TestPositionType text_field_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 2 /* child_index */); |
| ASSERT_NE(nullptr, text_field_position); |
| test_position = text_field_position->CreateNextTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| } |
| |
| TEST_F(AXPositionTest, CreatePreviousTextAnchorPosition) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box2_.id, 5 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| TestPositionType test_position = |
| text_position->CreatePreviousTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(line_break_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| // Create a "before text" tree position on the second line of the text box. |
| TestPositionType before_text_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, inline_box2_.id, AXNodePosition::BEFORE_TEXT); |
| ASSERT_NE(nullptr, before_text_position); |
| test_position = before_text_position->CreatePreviousTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(line_break_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| test_position = test_position->CreatePreviousTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| test_position = test_position->CreatePreviousTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(check_box_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| test_position = test_position->CreatePreviousTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(button_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| test_position = test_position->CreatePreviousTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| |
| TestPositionType text_field_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, text_field_.id, 2 /* child_index */); |
| ASSERT_NE(nullptr, text_field_position); |
| test_position = text_field_position->CreatePreviousTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(check_box_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| // The text offset on the root points to the text coming from inside the check |
| // box. |
| TestPositionType check_box_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, check_box_.id, 6 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, check_box_position); |
| test_position = check_box_position->CreatePreviousTextAnchorPosition(); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); |
| EXPECT_EQ(button_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| } |
| |
| TEST_F(AXPositionTest, CreateNextAndPreviousCharacterPositionWithNullPosition) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| TestPositionType test_position = null_position->CreateNextCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| test_position = null_position->CreatePreviousCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, CreateNextCharacterPosition) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 4 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| TestPositionType test_position = text_position->CreateNextCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(5, test_position->text_offset()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->CreateNextCharacterPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(5, test_position->text_offset()); |
| test_position = text_position->CreateNextCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(line_break_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| test_position = test_position->CreateNextCharacterPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(line_break_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| test_position = test_position->CreateNextCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| test_position = test_position->CreateNextCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); |
| EXPECT_EQ(1, test_position->text_offset()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, check_box_.id, 9 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->CreateNextCharacterPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(check_box_.id, test_position->anchor_id()); |
| EXPECT_EQ(9, test_position->text_offset()); |
| test_position = text_position->CreateNextCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, text_field_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->CreateNextCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(text_field_.id, test_position->anchor_id()); |
| EXPECT_EQ(1, test_position->text_offset()); |
| // Affinity should have been reset to downstream. |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| } |
| |
| TEST_F(AXPositionTest, CreatePreviousCharacterPosition) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box2_.id, 5 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| TestPositionType test_position = |
| text_position->CreatePreviousCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); |
| EXPECT_EQ(4, test_position->text_offset()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box2_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->CreatePreviousCharacterPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| test_position = text_position->CreatePreviousCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(line_break_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| |
| test_position = test_position->CreatePreviousCharacterPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(line_break_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| test_position = test_position->CreatePreviousCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(5, test_position->text_offset()); |
| |
| test_position = test_position->CreatePreviousCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(4, test_position->text_offset()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->CreatePreviousCharacterPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| test_position = text_position->CreatePreviousCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(check_box_.id, test_position->anchor_id()); |
| EXPECT_EQ(8, test_position->text_offset()); |
| |
| text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, text_field_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position); |
| test_position = text_position->CreatePreviousCharacterPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsTextPosition()); |
| EXPECT_EQ(text_field_.id, test_position->anchor_id()); |
| EXPECT_EQ(0, test_position->text_offset()); |
| // Affinity should have been reset to downstream. |
| EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); |
| } |
| |
| TEST_F(AXPositionTest, CreateNextAndPreviousWordStartPositionWithNullPosition) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| TestPositionType test_position = null_position->CreateNextWordStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| test_position = null_position->CreatePreviousWordStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, CreateNextAndPreviousWordEndPositionWithNullPosition) { |
| TestPositionType null_position = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position); |
| TestPositionType test_position = null_position->CreateNextWordEndPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| test_position = null_position->CreatePreviousWordEndPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| EXPECT_NE(nullptr, test_position); |
| EXPECT_TRUE(test_position->IsNullPosition()); |
| } |
| |
| TEST_F(AXPositionTest, OperatorEquals) { |
| TestPositionType null_position1 = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position1); |
| TestPositionType null_position2 = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position2); |
| EXPECT_EQ(*null_position1, *null_position2); |
| |
| // Child indices must match. |
| TestPositionType button_position1 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, button_position1); |
| TestPositionType button_position2 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, button_position2); |
| EXPECT_EQ(*button_position1, *button_position2); |
| |
| // Both child indices are invalid. It should result in equivalent null |
| // positions. |
| TestPositionType tree_position1 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 4 /* child_index */); |
| ASSERT_NE(nullptr, tree_position1); |
| TestPositionType tree_position2 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, AXNodePosition::INVALID_INDEX); |
| ASSERT_NE(nullptr, tree_position2); |
| EXPECT_EQ(*tree_position1, *tree_position2); |
| |
| // An invalid position should not be equivalent to an "after children" |
| // position. |
| tree_position1 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 3 /* child_index */); |
| ASSERT_NE(nullptr, tree_position1); |
| tree_position2 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, -1 /* child_index */); |
| ASSERT_NE(nullptr, tree_position2); |
| EXPECT_NE(*tree_position1, *tree_position2); |
| |
| // Two "after children" positions on the same node should be equivalent. |
| tree_position1 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, text_field_.id, 3 /* child_index */); |
| ASSERT_NE(nullptr, tree_position1); |
| tree_position2 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, text_field_.id, 3 /* child_index */); |
| ASSERT_NE(nullptr, tree_position2); |
| EXPECT_EQ(*tree_position1, *tree_position2); |
| |
| // Two "before text" positions on the same node should be equivalent. |
| tree_position1 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, inline_box1_.id, AXNodePosition::BEFORE_TEXT); |
| ASSERT_NE(nullptr, tree_position1); |
| tree_position2 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, inline_box1_.id, AXNodePosition::BEFORE_TEXT); |
| ASSERT_NE(nullptr, tree_position2); |
| EXPECT_EQ(*tree_position1, *tree_position2); |
| |
| // Both text offsets are invalid. It should result in equivalent null |
| // positions. |
| TestPositionType text_position1 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 15 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position1); |
| TestPositionType text_position2 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, text_field_.id, -1 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position2); |
| EXPECT_EQ(*text_position1, *text_position2); |
| |
| text_position1 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position1); |
| text_position2 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position2); |
| EXPECT_EQ(*text_position1, *text_position2); |
| |
| // Affinities should match. |
| text_position2 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position2); |
| EXPECT_NE(*text_position1, *text_position2); |
| |
| // Text offsets should match. |
| text_position1 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position1); |
| EXPECT_NE(*text_position1, *text_position2); |
| |
| // Two "after text" positions on the same node should be equivalent. |
| text_position1 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, line_break_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position1); |
| text_position2 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, line_break_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position2); |
| EXPECT_EQ(*text_position1, *text_position2); |
| |
| // Two text positions that are consequtive, one "before text" and one "after |
| // text". |
| text_position1 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box2_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position1); |
| text_position2 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, line_break_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position2); |
| EXPECT_NE(*text_position1, *text_position2); |
| } |
| |
| TEST_F(AXPositionTest, OperatorsLessThanAndGreaterThan) { |
| TestPositionType null_position1 = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position1); |
| TestPositionType null_position2 = AXNodePosition::CreateNullPosition(); |
| ASSERT_NE(nullptr, null_position2); |
| EXPECT_FALSE(*null_position1 < *null_position2); |
| EXPECT_FALSE(*null_position1 > *null_position2); |
| |
| TestPositionType button_position1 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, button_position1); |
| TestPositionType button_position2 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, root_.id, 1 /* child_index */); |
| ASSERT_NE(nullptr, button_position2); |
| EXPECT_LT(*button_position1, *button_position2); |
| EXPECT_GT(*button_position2, *button_position1); |
| |
| TestPositionType tree_position1 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, text_field_.id, 2 /* child_index */); |
| ASSERT_NE(nullptr, tree_position1); |
| // An "after children" position. |
| TestPositionType tree_position2 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, text_field_.id, 3 /* child_index */); |
| ASSERT_NE(nullptr, tree_position2); |
| EXPECT_LT(*tree_position1, *tree_position2); |
| EXPECT_GT(*tree_position2, *tree_position1); |
| |
| // A "before text" position. |
| tree_position1 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, inline_box1_.id, AXNodePosition::BEFORE_TEXT); |
| ASSERT_NE(nullptr, tree_position1); |
| // An "after text" position. |
| tree_position2 = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* child_index */); |
| ASSERT_NE(nullptr, tree_position2); |
| EXPECT_LT(*tree_position1, *tree_position2); |
| EXPECT_GT(*tree_position2, *tree_position1); |
| |
| // Two text positions that share a common anchor. |
| TestPositionType text_position1 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 2 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position1); |
| TestPositionType text_position2 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position2); |
| EXPECT_GT(*text_position1, *text_position2); |
| EXPECT_LT(*text_position2, *text_position1); |
| |
| // Affinities should not matter. |
| text_position2 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position2); |
| EXPECT_GT(*text_position1, *text_position2); |
| EXPECT_LT(*text_position2, *text_position1); |
| |
| // An "after text" position. |
| text_position1 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, line_break_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position1); |
| // A "before text" position. |
| text_position2 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, line_break_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kUpstream); |
| ASSERT_NE(nullptr, text_position2); |
| EXPECT_GT(*text_position1, *text_position2); |
| EXPECT_LT(*text_position2, *text_position1); |
| |
| // A text position that is an ancestor of another. |
| text_position1 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, text_field_.id, 6 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position1); |
| text_position2 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position2); |
| EXPECT_GT(*text_position1, *text_position2); |
| EXPECT_LT(*text_position2, *text_position1); |
| |
| // Two text positions that share a common ancestor. |
| text_position1 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, inline_box2_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position1); |
| text_position2 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, line_break_.id, 0 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position2); |
| EXPECT_GT(*text_position1, *text_position2); |
| EXPECT_LT(*text_position2, *text_position1); |
| |
| // Two consequtive positions. One "before text" and one "after text". |
| text_position2 = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, line_break_.id, 1 /* text_offset */, |
| ax::mojom::TextAffinity::kDownstream); |
| ASSERT_NE(nullptr, text_position2); |
| EXPECT_GT(*text_position1, *text_position2); |
| EXPECT_LT(*text_position2, *text_position1); |
| } |
| |
| // |
| // Parameterized tests. |
| // |
| |
| TEST_P(AXPositionTestWithParam, TraverseTreeStartingWithAffinityDownstream) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, GetParam().start_node_id_, GetParam().start_offset_, |
| ax::mojom::TextAffinity::kDownstream); |
| for (const std::string& expectation : GetParam().expectations) { |
| text_position = GetParam().TestMethod.Run(text_position); |
| EXPECT_NE(nullptr, text_position); |
| EXPECT_EQ(expectation, text_position->ToString()); |
| } |
| } |
| |
| TEST_P(AXPositionTestWithParam, TraverseTreeStartingWithAffinityUpstream) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, GetParam().start_node_id_, GetParam().start_offset_, |
| ax::mojom::TextAffinity::kUpstream); |
| for (const std::string& expectation : GetParam().expectations) { |
| text_position = GetParam().TestMethod.Run(text_position); |
| EXPECT_NE(nullptr, text_position); |
| EXPECT_EQ(expectation, text_position->ToString()); |
| } |
| } |
| |
| // |
| // Instantiations of parameterized tests. |
| // |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreateNextWordStartPositionWithBoundaryBehaviorCrossBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| ROOT_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=1 text_offset=6 " |
| "affinity=downstream annotated_text=Button<C>heck boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=12 " |
| "affinity=downstream annotated_text=ButtonCheck <b>oxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=15 " |
| "affinity=downstream annotated_text=ButtonCheck box<L>ine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=20 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "<1>\nLine 2", |
| "TextPosition anchor_id=1 text_offset=22 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\n<L>ine 2", |
| "TextPosition anchor_id=1 text_offset=27 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine <2>", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=4 text_offset=5 " |
| "affinity=downstream annotated_text=Line <1>\nLine 2", |
| "TextPosition anchor_id=4 text_offset=7 " |
| "affinity=downstream annotated_text=Line 1\n<L>ine 2", |
| "TextPosition anchor_id=4 text_offset=12 " |
| "affinity=downstream annotated_text=Line 1\nLine <2>", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 1 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=5 " |
| "affinity=downstream annotated_text=Line <1>", |
| "TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2", |
| "TextPosition anchor_id=9 text_offset=5 " |
| "affinity=downstream annotated_text=Line <2>", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=5 " |
| "affinity=downstream annotated_text=Line <2>", |
| "NullPosition"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreateNextWordStartPositionWithBoundaryBehaviorStopAtAnchorBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| ROOT_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=1 text_offset=6 " |
| "affinity=downstream annotated_text=Button<C>heck boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=12 " |
| "affinity=downstream annotated_text=ButtonCheck <b>oxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=15 " |
| "affinity=downstream annotated_text=ButtonCheck box<L>ine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=20 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "<1>\nLine 2", |
| "TextPosition anchor_id=1 text_offset=22 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\n<L>ine 2", |
| "TextPosition anchor_id=1 text_offset=27 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine <2>", |
| "TextPosition anchor_id=1 text_offset=28 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine 2<>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=4 text_offset=5 " |
| "affinity=downstream annotated_text=Line <1>\nLine 2", |
| "TextPosition anchor_id=4 text_offset=7 " |
| "affinity=downstream annotated_text=Line 1\n<L>ine 2", |
| "TextPosition anchor_id=4 text_offset=12 " |
| "affinity=downstream annotated_text=Line 1\nLine <2>", |
| "TextPosition anchor_id=4 text_offset=13 " |
| "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 1 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=5 " |
| "affinity=downstream annotated_text=Line <1>", |
| "TextPosition anchor_id=5 text_offset=6 " |
| "affinity=downstream annotated_text=Line 1<>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=5 " |
| "affinity=downstream annotated_text=Line <2>", |
| "TextPosition anchor_id=9 text_offset=6 " |
| "affinity=downstream annotated_text=Line 2<>"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreateNextWordStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| ROOT_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=1 text_offset=0 " |
| "affinity=downstream annotated_text=<B>uttonCheck boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=0 " |
| "affinity=downstream annotated_text=<B>uttonCheck boxLine " |
| "1\nLine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=4 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1\nLine 2", |
| "TextPosition anchor_id=4 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 1 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=5 " |
| "affinity=downstream annotated_text=Line <1>", |
| "TextPosition anchor_id=5 text_offset=5 " |
| "affinity=downstream annotated_text=Line <1>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=5 " |
| "affinity=downstream annotated_text=Line <2>", |
| "TextPosition anchor_id=9 text_offset=5 " |
| "affinity=downstream annotated_text=Line <2>"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreatePreviousWordStartPositionWithBoundaryBehaviorCrossBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| ROOT_ID, |
| 28 /* text_offset at end of root. */, |
| {"TextPosition anchor_id=1 text_offset=27 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine <2>", |
| "TextPosition anchor_id=1 text_offset=22 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\n<L>ine 2", |
| "TextPosition anchor_id=1 text_offset=20 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "<1>\nLine 2", |
| "TextPosition anchor_id=1 text_offset=15 " |
| "affinity=downstream annotated_text=ButtonCheck box<L>ine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=12 " |
| "affinity=downstream annotated_text=ButtonCheck <b>oxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=6 " |
| "affinity=downstream annotated_text=Button<C>heck boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=0 " |
| "affinity=downstream annotated_text=<B>uttonCheck boxLine " |
| "1\nLine 2", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 13 /* text_offset at end of text field */, |
| {"TextPosition anchor_id=4 text_offset=12 " |
| "affinity=downstream annotated_text=Line 1\nLine <2>", |
| "TextPosition anchor_id=4 text_offset=7 " |
| "affinity=downstream annotated_text=Line 1\n<L>ine 2", |
| "TextPosition anchor_id=4 text_offset=5 " |
| "affinity=downstream annotated_text=Line <1>\nLine 2", |
| "TextPosition anchor_id=4 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1\nLine 2", |
| "TextPosition anchor_id=3 text_offset=6 " |
| "affinity=downstream annotated_text=Check <b>ox", |
| "TextPosition anchor_id=3 text_offset=0 " |
| "affinity=downstream annotated_text=<C>heck box", |
| "TextPosition anchor_id=2 text_offset=0 " |
| "affinity=downstream annotated_text=<B>utton", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 5 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1", |
| "TextPosition anchor_id=3 text_offset=6 " |
| "affinity=downstream annotated_text=Check <b>ox", |
| "TextPosition anchor_id=3 text_offset=0 " |
| "affinity=downstream annotated_text=<C>heck box", |
| "TextPosition anchor_id=2 text_offset=0 " |
| "affinity=downstream annotated_text=<B>utton", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2", |
| "TextPosition anchor_id=6 text_offset=5 " |
| "affinity=downstream annotated_text=Line <1>", |
| "TextPosition anchor_id=6 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1", |
| "TextPosition anchor_id=3 text_offset=6 " |
| "affinity=downstream annotated_text=Check <b>ox", |
| "TextPosition anchor_id=3 text_offset=0 " |
| "affinity=downstream annotated_text=<C>heck box", |
| "TextPosition anchor_id=2 text_offset=0 " |
| "affinity=downstream annotated_text=<B>utton", |
| "NullPosition"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreatePreviousWordStartPositionWithBoundaryBehaviorStopAtAnchorBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| ROOT_ID, |
| 28 /* text_offset at end of root. */, |
| {"TextPosition anchor_id=1 text_offset=27 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine <2>", |
| "TextPosition anchor_id=1 text_offset=22 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\n<L>ine 2", |
| "TextPosition anchor_id=1 text_offset=20 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "<1>\nLine 2", |
| "TextPosition anchor_id=1 text_offset=15 " |
| "affinity=downstream annotated_text=ButtonCheck box<L>ine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=12 " |
| "affinity=downstream annotated_text=ButtonCheck <b>oxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=6 " |
| "affinity=downstream annotated_text=Button<C>heck boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=0 " |
| "affinity=downstream annotated_text=<B>uttonCheck boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=0 " |
| "affinity=downstream annotated_text=<B>uttonCheck boxLine " |
| "1\nLine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 13 /* text_offset at end of text field */, |
| {"TextPosition anchor_id=4 text_offset=12 " |
| "affinity=downstream annotated_text=Line 1\nLine <2>", |
| "TextPosition anchor_id=4 text_offset=7 " |
| "affinity=downstream annotated_text=Line 1\n<L>ine 2", |
| "TextPosition anchor_id=4 text_offset=5 " |
| "affinity=downstream annotated_text=Line <1>\nLine 2", |
| "TextPosition anchor_id=4 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1\nLine 2", |
| "TextPosition anchor_id=4 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 5 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1", |
| "TextPosition anchor_id=5 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2", |
| "TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreatePreviousWordStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| ROOT_ID, |
| 28 /* text_offset at end of root. */, |
| {"TextPosition anchor_id=1 text_offset=27 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine <2>", |
| "TextPosition anchor_id=1 text_offset=27 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine <2>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 13 /* text_offset at end of text field */, |
| {"TextPosition anchor_id=4 text_offset=12 " |
| "affinity=downstream annotated_text=Line 1\nLine <2>", |
| "TextPosition anchor_id=4 text_offset=12 " |
| "affinity=downstream annotated_text=Line 1\nLine <2>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 5 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=5 " |
| "affinity=downstream annotated_text=Line <1>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2", |
| "TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreateNextWordEndPositionWithBoundaryBehaviorCrossBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordEndPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| ROOT_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=1 text_offset=6 " |
| "affinity=downstream annotated_text=Button<C>heck boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=11 " |
| "affinity=downstream annotated_text=ButtonCheck< >boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=15 " |
| "affinity=upstream annotated_text=ButtonCheck box<L>ine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=19 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine< " |
| ">1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=21 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1<\n>Line 2", |
| "TextPosition anchor_id=1 text_offset=26 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine< >2", |
| "TextPosition anchor_id=1 text_offset=28 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine 2<>", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordEndPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=4 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1\nLine 2", |
| "TextPosition anchor_id=4 text_offset=6 " |
| "affinity=downstream annotated_text=Line 1<\n>Line 2", |
| "TextPosition anchor_id=4 text_offset=11 " |
| "affinity=downstream annotated_text=Line 1\nLine< >2", |
| "TextPosition anchor_id=4 text_offset=13 " |
| "affinity=downstream annotated_text=Line 1\nLine 2<>", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordEndPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 1 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1", |
| "TextPosition anchor_id=5 text_offset=6 " |
| "affinity=downstream annotated_text=Line 1<>", |
| "TextPosition anchor_id=9 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >2", |
| "TextPosition anchor_id=9 text_offset=6 " |
| "affinity=downstream annotated_text=Line 2<>", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordEndPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=6 " |
| "affinity=downstream annotated_text=Line 2<>", |
| "NullPosition"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreateNextWordEndPositionWithBoundaryBehaviorStopAtAnchorBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordEndPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| ROOT_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=1 text_offset=6 " |
| "affinity=downstream annotated_text=Button<C>heck boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=11 " |
| "affinity=downstream annotated_text=ButtonCheck< >boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=15 " |
| "affinity=upstream annotated_text=ButtonCheck box<L>ine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=19 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine< " |
| ">1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=21 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1<\n>Line 2", |
| "TextPosition anchor_id=1 text_offset=26 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine< >2", |
| "TextPosition anchor_id=1 text_offset=28 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine 2<>", |
| "TextPosition anchor_id=1 text_offset=28 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine 2<>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordEndPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=4 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1\nLine 2", |
| "TextPosition anchor_id=4 text_offset=6 " |
| "affinity=downstream annotated_text=Line 1<\n>Line 2", |
| "TextPosition anchor_id=4 text_offset=11 " |
| "affinity=downstream annotated_text=Line 1\nLine< >2", |
| "TextPosition anchor_id=4 text_offset=13 " |
| "affinity=downstream annotated_text=Line 1\nLine 2<>", |
| "TextPosition anchor_id=4 text_offset=13 " |
| "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordEndPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 1 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1", |
| "TextPosition anchor_id=5 text_offset=6 " |
| "affinity=downstream annotated_text=Line 1<>", |
| "TextPosition anchor_id=5 text_offset=6 " |
| "affinity=downstream annotated_text=Line 1<>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordEndPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=6 " |
| "affinity=downstream annotated_text=Line 2<>", |
| "TextPosition anchor_id=9 text_offset=6 " |
| "affinity=downstream annotated_text=Line 2<>"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreateNextWordEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordEndPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| ROOT_ID, |
| 7 /* text_offset after the first character of "Check". */, |
| {"TextPosition anchor_id=1 text_offset=11 " |
| "affinity=downstream annotated_text=ButtonCheck< >boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=11 " |
| "affinity=downstream annotated_text=ButtonCheck< >boxLine " |
| "1\nLine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordEndPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=4 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1\nLine 2", |
| "TextPosition anchor_id=4 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1\nLine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordEndPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 1 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1", |
| "TextPosition anchor_id=5 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextWordEndPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >2"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreatePreviousWordEndPositionWithBoundaryBehaviorCrossBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordEndPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| ROOT_ID, |
| 28 /* text_offset at end of root. */, |
| {"TextPosition anchor_id=1 text_offset=26 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine< >2", |
| "TextPosition anchor_id=1 text_offset=21 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1<\n>Line 2", |
| "TextPosition anchor_id=1 text_offset=19 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine< " |
| ">1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=15 " |
| "affinity=upstream annotated_text=ButtonCheck box<L>ine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=11 " |
| "affinity=downstream annotated_text=ButtonCheck< >boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=6 " |
| "affinity=downstream annotated_text=Button<C>heck boxLine " |
| "1\nLine 2", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordEndPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 13 /* text_offset at end of text field */, |
| {"TextPosition anchor_id=4 text_offset=11 " |
| "affinity=downstream annotated_text=Line 1\nLine< >2", |
| "TextPosition anchor_id=4 text_offset=6 " |
| "affinity=downstream annotated_text=Line 1<\n>Line 2", |
| "TextPosition anchor_id=4 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1\nLine 2", |
| "TextPosition anchor_id=3 text_offset=9 " |
| "affinity=downstream annotated_text=Check box<>", |
| "TextPosition anchor_id=3 text_offset=5 " |
| "affinity=downstream annotated_text=Check< >box", |
| "TextPosition anchor_id=2 text_offset=6 " |
| "affinity=downstream annotated_text=Button<>", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordEndPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 5 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1", |
| "TextPosition anchor_id=3 text_offset=9 " |
| "affinity=downstream annotated_text=Check box<>", |
| "TextPosition anchor_id=3 text_offset=5 " |
| "affinity=downstream annotated_text=Check< >box", |
| "TextPosition anchor_id=2 text_offset=6 " |
| "affinity=downstream annotated_text=Button<>", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordEndPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=6 text_offset=6 " |
| "affinity=downstream annotated_text=Line 1<>", |
| "TextPosition anchor_id=6 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1", |
| "TextPosition anchor_id=3 text_offset=9 " |
| "affinity=downstream annotated_text=Check box<>", |
| "TextPosition anchor_id=3 text_offset=5 " |
| "affinity=downstream annotated_text=Check< >box", |
| "TextPosition anchor_id=2 text_offset=6 " |
| "affinity=downstream annotated_text=Button<>", |
| "NullPosition"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreatePreviousWordEndPositionWithBoundaryBehaviorStopAtAnchorBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordEndPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| ROOT_ID, |
| 28 /* text_offset at end of root. */, |
| {"TextPosition anchor_id=1 text_offset=26 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine< >2", |
| "TextPosition anchor_id=1 text_offset=21 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1<\n>Line 2", |
| "TextPosition anchor_id=1 text_offset=19 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine< " |
| ">1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=15 " |
| "affinity=upstream annotated_text=ButtonCheck box<L>ine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=11 " |
| "affinity=downstream annotated_text=ButtonCheck< >boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=6 " |
| "affinity=downstream annotated_text=Button<C>heck boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=0 " |
| "affinity=downstream annotated_text=<B>uttonCheck boxLine " |
| "1\nLine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordEndPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 13 /* text_offset at end of text field */, |
| {"TextPosition anchor_id=4 text_offset=11 " |
| "affinity=downstream annotated_text=Line 1\nLine< >2", |
| "TextPosition anchor_id=4 text_offset=6 " |
| "affinity=downstream annotated_text=Line 1<\n>Line 2", |
| "TextPosition anchor_id=4 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1\nLine 2", |
| "TextPosition anchor_id=4 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordEndPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 5 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1", |
| "TextPosition anchor_id=5 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordEndPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreatePreviousWordEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordEndPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| ROOT_ID, |
| 28 /* text_offset at end of root. */, |
| {"TextPosition anchor_id=1 text_offset=28 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine 2<>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordEndPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 13 /* text_offset at end of text field */, |
| {"TextPosition anchor_id=4 text_offset=13 " |
| "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordEndPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 5 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1", |
| "TextPosition anchor_id=5 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >1"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousWordEndPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=4 " |
| "affinity=downstream annotated_text=Line< >2"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreateNextLineStartPositionWithBoundaryBehaviorCrossBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| ROOT_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=1 text_offset=15 " |
| "affinity=downstream annotated_text=ButtonCheck box<L>ine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=22 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\n<L>ine 2", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=4 text_offset=7 " |
| "affinity=downstream annotated_text=Line 1\n<L>ine 2", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 1 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"NullPosition"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreateNextLineStartPositionWithBoundaryBehaviorStopAtAnchorBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| ROOT_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=1 text_offset=15 " |
| "affinity=downstream annotated_text=ButtonCheck box<L>ine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=22 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\n<L>ine 2", |
| "TextPosition anchor_id=1 text_offset=28 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine 2<>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=4 text_offset=7 " |
| "affinity=downstream annotated_text=Line 1\n<L>ine 2", |
| "TextPosition anchor_id=4 text_offset=13 " |
| "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 1 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=6 " |
| "affinity=downstream annotated_text=Line 1<>"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=6 " |
| "affinity=downstream annotated_text=Line 2<>"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreateNextLineStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| ROOT_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=1 text_offset=0 " |
| "affinity=downstream annotated_text=<B>uttonCheck boxLine " |
| "1\nLine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=4 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 1 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2", |
| "TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"NullPosition"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreatePreviousLineStartPositionWithBoundaryBehaviorCrossBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousLineStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| ROOT_ID, |
| 28 /* text_offset at the end of root. */, |
| {"TextPosition anchor_id=1 text_offset=22 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\n<L>ine 2", |
| "TextPosition anchor_id=1 text_offset=15 " |
| "affinity=downstream annotated_text=ButtonCheck box<L>ine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=0 " |
| "affinity=downstream annotated_text=<B>uttonCheck boxLine " |
| "1\nLine 2", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousLineStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 13 /* text_offset at end of text field */, |
| {"TextPosition anchor_id=4 text_offset=7 " |
| "affinity=downstream annotated_text=Line 1\n<L>ine 2", |
| "TextPosition anchor_id=4 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1\nLine 2", |
| "TextPosition anchor_id=2 text_offset=0 " |
| "affinity=downstream annotated_text=<B>utton", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousLineStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 5 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1", |
| "TextPosition anchor_id=2 text_offset=0 " |
| "affinity=downstream annotated_text=<B>utton", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousLineStartPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2", |
| "TextPosition anchor_id=6 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1", |
| "TextPosition anchor_id=2 text_offset=0 " |
| "affinity=downstream annotated_text=<B>utton", |
| "NullPosition"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreatePreviousLineStartPositionWithBoundaryBehaviorStopAtAnchorBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousLineStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| ROOT_ID, |
| 28 /* text_offset at the end of root. */, |
| {"TextPosition anchor_id=1 text_offset=22 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\n<L>ine 2", |
| "TextPosition anchor_id=1 text_offset=15 " |
| "affinity=downstream annotated_text=ButtonCheck box<L>ine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=0 " |
| "affinity=downstream annotated_text=<B>uttonCheck boxLine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=0 " |
| "affinity=downstream annotated_text=<B>uttonCheck boxLine " |
| "1\nLine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousLineStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 13 /* text_offset at end of text field */, |
| {"TextPosition anchor_id=4 text_offset=7 " |
| "affinity=downstream annotated_text=Line 1\n<L>ine 2", |
| "TextPosition anchor_id=4 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1\nLine 2", |
| "TextPosition anchor_id=4 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousLineStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 5 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1", |
| "TextPosition anchor_id=5 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousLineStartPosition( |
| AXBoundaryBehavior::StopAtAnchorBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2", |
| "TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreatePreviousLineStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousLineStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| ROOT_ID, |
| 28 /* text_offset at the end of root. */, |
| {"TextPosition anchor_id=1 text_offset=22 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\n<L>ine 2", |
| "TextPosition anchor_id=1 text_offset=22 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\n<L>ine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousLineStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 13 /* text_offset at end of text field */, |
| {"TextPosition anchor_id=4 text_offset=7 " |
| "affinity=downstream annotated_text=Line 1\n<L>ine 2", |
| "TextPosition anchor_id=4 text_offset=7 " |
| "affinity=downstream annotated_text=Line 1\n<L>ine 2"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousLineStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| STATIC_TEXT1_ID, |
| 5 /* text_offset */, |
| {"TextPosition anchor_id=5 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1", |
| "TextPosition anchor_id=5 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 1"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreatePreviousLineStartPosition( |
| AXBoundaryBehavior::StopIfAlreadyAtBoundary); |
| }), |
| INLINE_BOX2_ID, |
| 4 /* text_offset */, |
| {"TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2", |
| "TextPosition anchor_id=9 text_offset=0 " |
| "affinity=downstream annotated_text=<L>ine 2"}})); |
| |
| INSTANTIATE_TEST_CASE_P( |
| CreateNextLineEndPositionWithBoundaryBehaviorCrossBoundary, |
| AXPositionTestWithParam, |
| testing::Values( |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineEndPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| ROOT_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=1 text_offset=15 " |
| "affinity=upstream annotated_text=ButtonCheck box<L>ine " |
| "1\nLine 2", |
| "TextPosition anchor_id=1 text_offset=21 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine 1" |
| "<\n>Line 2", |
| "TextPosition anchor_id=1 text_offset=28 " |
| "affinity=downstream annotated_text=ButtonCheck boxLine " |
| "1\nLine 2<>", |
| "NullPosition"}}, |
| TestParam{base::BindRepeating([](const TestPositionType& position) { |
| return position->CreateNextLineEndPosition( |
| AXBoundaryBehavior::CrossBoundary); |
| }), |
| TEXT_FIELD_ID, |
| 0 /* text_offset */, |
| {"TextPosition anchor_id=4 text_offset=6 " |
| "affinity=downstream annotated_text=Line 1<\n>Line 2", |
| "TextPosition anchor_id=4 text_offset=13 " |
| "affinity=downstream annotated_text=Line 1\nLine 2<>", |
|