chromium/ui/views/accessibility/atomic_view_ax_tree_manager_unittest.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/accessibility/atomic_view_ax_tree_manager.h"

#include <memory>
#include <utility>

#include "base/memory/raw_ptr.h"
#include "base/test/scoped_feature_list.h"
#include "ui/accessibility/accessibility_features.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"

namespace views {
class AtomicViewAXTreeManagerTest : public ViewsTestBase {
 public:
  AtomicViewAXTreeManagerTest() = default;
  ~AtomicViewAXTreeManagerTest() override = default;
  void SetUp() override {
    ViewsTestBase::SetUp();

    scoped_feature_list_.InitAndEnableFeature(features::kUiaProvider);

    widget_ = std::make_unique<Widget>();

    Widget::InitParams params =
        CreateParams(Widget::InitParams::CLIENT_OWNS_WIDGET,
                     Widget::InitParams::TYPE_WINDOW);
    params.bounds = gfx::Rect(50, 50, 200, 200);
    widget_->Init(std::move(params));

    textfield_ = new Textfield();
    textfield_->SetBounds(10, 20, 30, 40);
    widget_->GetContentsView()->AddChildView(textfield_.get());

    delegate_ = static_cast<ViewAXPlatformNodeDelegate*>(
        &textfield_->GetViewAccessibility());

    // TODO(accessibility): This is not obvious, but the AtomicViewAXTreeManager
    // gets initialized from this GetData() call. Might want to improve that.
    delegate_->GetData();
    CHECK(delegate_->GetAtomicViewAXTreeManagerForTesting());
  }

  void TearDown() override {
    delegate_ = nullptr;
    textfield_ = nullptr;
    if (!widget_->IsClosed()) {
      widget_->Close();
    }
    ViewsTestBase::TearDown();
  }

  void CompareNodeData(ui::AXNodeData expected, ui::AXNodeData actual) {
    EXPECT_EQ(expected.id, actual.id);
    EXPECT_EQ(expected.role, actual.role);
    EXPECT_EQ(expected.state, actual.state);
    EXPECT_EQ(expected.actions, actual.actions);
    EXPECT_EQ(expected.string_attributes, actual.string_attributes);
    EXPECT_EQ(expected.float_attributes, actual.float_attributes);
    EXPECT_EQ(expected.bool_attributes, actual.bool_attributes);
    EXPECT_EQ(expected.intlist_attributes, actual.intlist_attributes);
    EXPECT_EQ(expected.stringlist_attributes, actual.stringlist_attributes);
    EXPECT_EQ(expected.relative_bounds, actual.relative_bounds);
  }

  ui::AXNodeData delegate_data() { return delegate_->data(); }

 protected:
  raw_ptr<Textfield> textfield_ = nullptr;  // Owned by views hierarchy.
  std::unique_ptr<Widget> widget_;
  raw_ptr<ViewAXPlatformNodeDelegate> delegate_ = nullptr;
  base::test::ScopedFeatureList scoped_feature_list_;
};

TEST_F(AtomicViewAXTreeManagerTest, UpdateNode) {
  ui::AXNodeData previous =
      delegate_->GetAtomicViewAXTreeManagerForTesting()->GetRoot()->data();
  textfield_->SetText(u"text");
  ui::AXNodeData actual =
      delegate_->GetAtomicViewAXTreeManagerForTesting()->GetRoot()->data();
  CompareNodeData(delegate_data(), actual);
  EXPECT_EQ(actual.GetString16Attribute(ax::mojom::StringAttribute::kValue),
            u"text");
  EXPECT_EQ(previous.GetString16Attribute(ax::mojom::StringAttribute::kValue),
            u"");
}

TEST_F(AtomicViewAXTreeManagerTest, GetRootAsAXNode) {
  CompareNodeData(
      delegate_data(),
      delegate_->GetAtomicViewAXTreeManagerForTesting()->GetRoot()->data());
}

TEST_F(AtomicViewAXTreeManagerTest, GetNodeFromTree) {
  CompareNodeData(
      delegate_data(),
      delegate_->GetAtomicViewAXTreeManagerForTesting()
          ->GetNodeFromTree(
              delegate_->GetAtomicViewAXTreeManagerForTesting()->GetTreeID(),
              delegate_->GetAtomicViewAXTreeManagerForTesting()
                  ->GetRoot()
                  ->id())
          ->data());
}

}  // namespace views