910e62b5创建于 1月15日历史提交
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/strings/stringprintf.h"
#include "base/timer/lap_timer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
#include "ui/accessibility/ax_node_position.h"
#include "ui/accessibility/ax_tree_id.h"
#include "ui/accessibility/ax_tree_update.h"
#include "ui/accessibility/test_single_ax_tree_manager.h"

namespace ui {

using TestPositionType = std::unique_ptr<AXPosition<AXNodePosition, AXNode>>;

namespace {

constexpr int kLaps = 5000;
constexpr int kWarmupLaps = 5;
constexpr char kMetricCallsPerSecondRunsPerS[] = "calls_per_second";

class AXPositionPerfTest : public ::testing::Test,
                           public TestSingleAXTreeManager {
 public:
  AXPositionPerfTest() = default;

  AXPositionPerfTest(const AXPositionPerfTest&) = delete;
  AXPositionPerfTest& operator=(const AXPositionPerfTest&) = delete;

  ~AXPositionPerfTest() override = default;

 protected:
  void SetUp() override;

  perf_test::PerfResultReporter SetUpReporter(const std::string& story) {
    perf_test::PerfResultReporter reporter("AXPositionPerfTest.", story);
    reporter.RegisterImportantMetric(kMetricCallsPerSecondRunsPerS, "runs/s");
    return reporter;
  }
};

void AXPositionPerfTest::SetUp() {
  // Setup a root with 5 child kGenericContainer with 5 kStaticText each.
  // Each kStaticText contains 5 characters of text.
  //
  // +------------------------+--------------+
  // | Tree Hierarchy + Role  | anchor_id(s) |
  // +------------------------+--------------+
  // | ++kRootWebArea         | 1            |
  // | ++++kGenericContainer  | 2            |
  // | ++++++kStaticText      | 7 - 11       |
  // | ++++kGenericContainer  | 3            |
  // | ++++++kStaticText      | 12 - 16      |
  // | ++++kGenericContainer  | 4            |
  // | ++++++kStaticText      | 17 - 21      |
  // | ++++kGenericContainer  | 5            |
  // | ++++++kStaticText      | 22 - 26      |
  // | ++++kGenericContainer  | 6            |
  // | ++++++kStaticText      | 27 - 31      |
  // +------------------------+--------------+

  constexpr int kNumberOfGroups = 5;
  constexpr int kStaticTextNodesPerGroup = 5;
  constexpr int kNumberOfStaticTextNodes =
      kNumberOfGroups * kStaticTextNodesPerGroup;

  constexpr int kGroupNodesStartIndex = 1;
  constexpr int kStaticTextNodesStartIndex =
      kGroupNodesStartIndex + kNumberOfGroups;

  AXNodeID current_id = 0;
  std::vector<AXNodeData> nodes;
  nodes.resize(1 + kNumberOfGroups + kNumberOfStaticTextNodes);

  AXNodeData& root_data = nodes[0];
  root_data.id = ++current_id;
  root_data.role = ax::mojom::Role::kRootWebArea;

  for (int group_index = 0; group_index < kNumberOfGroups; ++group_index) {
    AXNodeData& group = nodes[kGroupNodesStartIndex + group_index];
    group.id = ++current_id;
    group.role = ax::mojom::Role::kGenericContainer;
    root_data.child_ids.push_back(group.id);
  }

  for (int text_index = 0; text_index < kNumberOfStaticTextNodes;
       ++text_index) {
    const int group_index = text_index / kStaticTextNodesPerGroup;
    AXNodeData& group = nodes[kGroupNodesStartIndex + group_index];
    AXNodeData& static_text = nodes[kStaticTextNodesStartIndex + text_index];
    static_text.id = ++current_id;
    static_text.role = ax::mojom::Role::kStaticText;
    static_text.SetName(base::StringPrintf("id_%02X", static_text.id));
    group.child_ids.push_back(static_text.id);
  }

  AXTreeUpdate initial_state;
  initial_state.root_id = nodes[0].id;
  initial_state.nodes = nodes;
  initial_state.has_tree_data = true;
  initial_state.tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
  initial_state.tree_data.title = "Perftest title";

  SetTree(std::make_unique<AXTree>(initial_state));
}

}  // namespace

TEST_F(AXPositionPerfTest, AsTreePositionFromTextPosition) {
  TestPositionType text_position = CreateTextPosition(
      /*anchor_id=*/1, /*text_offset=*/103,
      ax::mojom::TextAffinity::kDownstream);

  // The time limit is unused. Use kLaps for the check interval so the time is
  // only measured once.
  base::LapTimer timer(kWarmupLaps, base::TimeDelta(), kLaps);
  for (int i = 0; i < kLaps + kWarmupLaps; ++i) {
    TestPositionType as_tree_position = text_position->AsTreePosition();
    timer.NextLap();
  }

  auto reporter = SetUpReporter("AsTreePositionFromTextPosition");
  reporter.AddResult(kMetricCallsPerSecondRunsPerS, timer.LapsPerSecond());
}

TEST_F(AXPositionPerfTest, AsLeafTextPositionFromTextPosition) {
  TestPositionType text_position = CreateTextPosition(
      /*anchor_id=*/1, /*text_offset=*/103,
      ax::mojom::TextAffinity::kDownstream);

  // The time limit is unused. Use kLaps for the check interval so the time is
  // only measured once.
  base::LapTimer timer(kWarmupLaps, base::TimeDelta(), kLaps);
  for (int i = 0; i < kLaps + kWarmupLaps; ++i) {
    TestPositionType as_tree_position = text_position->AsLeafTextPosition();
    timer.NextLap();
  }

  auto reporter = SetUpReporter("AsLeafTextPositionFromTextPosition");
  reporter.AddResult(kMetricCallsPerSecondRunsPerS, timer.LapsPerSecond());
}

TEST_F(AXPositionPerfTest, AsLeafTextPositionFromTreePosition) {
  TestPositionType tree_position =
      CreateTreePosition(*ax_tree()->root(), /*child_index=*/4);

  base::LapTimer timer(kWarmupLaps, base::TimeDelta(), kLaps);
  for (int i = 0; i < kLaps + kWarmupLaps; ++i) {
    TestPositionType as_tree_position = tree_position->AsLeafTextPosition();
    timer.NextLap();
  }

  auto reporter = SetUpReporter("AsLeafTextPositionFromTreePosition");
  reporter.AddResult(kMetricCallsPerSecondRunsPerS, timer.LapsPerSecond());
}

TEST_F(AXPositionPerfTest, CompareTextPositions) {
  TestPositionType text_position_1 = CreateTextPosition(
      /*anchor_id=*/7, /*text_offset=*/1, ax::mojom::TextAffinity::kDownstream);

  TestPositionType text_position_2 = CreateTextPosition(
      /*anchor_id=*/27, /*text_offset=*/1,
      ax::mojom::TextAffinity::kDownstream);

  base::LapTimer timer(kWarmupLaps, base::TimeDelta(), kLaps);
  for (int i = 0; i < kLaps + kWarmupLaps; ++i) {
    text_position_1->CompareTo(*text_position_2);
    timer.NextLap();
  }

  auto reporter = SetUpReporter("CompareTextPositions");
  reporter.AddResult(kMetricCallsPerSecondRunsPerS, timer.LapsPerSecond());
}

}  // namespace ui