chromium/base/feature_list_unittest.cc

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

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif

#include "base/feature_list.h"

#include <stddef.h>

#include <ostream>
#include <set>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "base/feature_list_buildflags.h"
#include "base/format_macros.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_param_associator.h"
#include "base/metrics/persistent_memory_allocator.h"
#include "base/ranges/algorithm.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/test/scoped_feature_list.h"
#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "base/feature_visitor.h"
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

namespace base {

namespace {

constexpr char kFeatureOnByDefaultName[] =;
BASE_FEATURE();

constexpr char kFeatureOffByDefaultName[] =;
BASE_FEATURE();

std::string SortFeatureListString(const std::string& feature_list) {}

}  // namespace

class FeatureListTest : public testing::Test {};

TEST_F(FeatureListTest, DefaultStates) {}

TEST_F(FeatureListTest, InitFromCommandLine) {}

TEST_F(FeatureListTest, InitFromCommandLineWithFeatureParams) {}

TEST_F(FeatureListTest, CheckFeatureIdentity) {}

TEST_F(FeatureListTest, FieldTrialOverrides) {}

TEST_F(FeatureListTest, FieldTrialAssociateUseDefault) {}

TEST_F(FeatureListTest, CommandLineEnableTakesPrecedenceOverFieldTrial) {}

TEST_F(FeatureListTest, CommandLineDisableTakesPrecedenceOverFieldTrial) {}

TEST_F(FeatureListTest, IsFeatureOverriddenFromFieldTrial) {}

TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) {}

TEST_F(FeatureListTest, AssociateReportingFieldTrial) {}

TEST_F(FeatureListTest, RegisterExtraFeatureOverrides) {}

TEST_F(FeatureListTest, InitFromCommandLineThenRegisterExtraOverrides) {}

TEST_F(FeatureListTest, GetFeatureOverrides) {}

TEST_F(FeatureListTest, GetFeatureOverrides_UseDefault) {}

TEST_F(FeatureListTest, GetFieldTrial) {}

TEST_F(FeatureListTest, InitFromCommandLine_WithFieldTrials) {}

TEST_F(FeatureListTest, InitFromCommandLine_UseDefault) {}

TEST_F(FeatureListTest, InitInstance) {}

TEST_F(FeatureListTest, UninitializedInstance_IsEnabledReturnsFalse) {}

TEST_F(FeatureListTest, StoreAndRetrieveFeaturesFromSharedMemory) {}

TEST_F(FeatureListTest, StoreAndRetrieveAssociatedFeaturesFromSharedMemory) {}

TEST_F(FeatureListTest, SetEarlyAccessInstance_AllowList) {}

TEST_F(FeatureListTest, SetEarlyAccessInstance_ReplaceByRealList) {}

#if BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) && \
    defined(GTEST_HAS_DEATH_TEST)
using FeatureListDeathTest = FeatureListTest;
TEST_F(FeatureListDeathTest, DiesWithBadFeatureName) {
  // TODO(dcheng): Add a nocompile version of this test. In general, people
  // should not be constructing features at runtime anyway but just in case...
  EXPECT_DEATH(
      Feature(
          StrCat({BUILDFLAG(BANNED_BASE_FEATURE_PREFIX), "MyFeature"}).c_str(),
          FEATURE_DISABLED_BY_DEFAULT,
          internal::FeatureMacroHandshake::kSecret),
      StrCat({"Invalid feature name ", BUILDFLAG(BANNED_BASE_FEATURE_PREFIX),
              "MyFeature"}));
}
#endif  // BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) &&
        // defined(GTEST_HAS_DEATH_TEST)

TEST(FeatureListAccessorTest, DefaultStates) {}

TEST(FeatureListAccessorTest, InitFromCommandLine) {}

TEST(FeatureListAccessorTest, InitFromCommandLineWithFeatureParams) {}

#if BUILDFLAG(IS_CHROMEOS_ASH)
// Test only class to verify correctness of
// FeatureList::VisitFeaturesAndParams().
class TestFeatureVisitor : public FeatureVisitor {
 public:
  TestFeatureVisitor() = default;

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

  ~TestFeatureVisitor() override = default;

  struct VisitedFeatureState {
    auto operator<=>(const VisitedFeatureState&) const = default;

    std::string feature_name;
    const base::FeatureList::OverrideState override_state;
    base::FieldTrialParams params;
    std::string trial_name;
    std::string group_name;
  };

  void Visit(const std::string& feature_name,
             FeatureList::OverrideState override_state,
             const FieldTrialParams& params,
             const std::string& trial_name,
             const std::string& group_name) override {
    feature_state_.insert(TestFeatureVisitor::VisitedFeatureState{
        feature_name, override_state, params, trial_name, group_name});
  }

  const std::multiset<TestFeatureVisitor::VisitedFeatureState>&
  feature_state() {
    return feature_state_;
  }

 private:
  std::multiset<VisitedFeatureState> feature_state_;
};

// Makes test output human readable.
std::ostream& operator<<(std::ostream& out,
                         const TestFeatureVisitor::VisitedFeatureState& state) {
  out << ".feature_name='" << state.feature_name
      << "', .override_state=" << state.override_state << ", .params={";

  for (const auto& param : state.params) {
    out << param.first << "=" << param.second << ", ";
  }

  out << "}, .trial_name='" << state.trial_name << "', .group_name='"
      << state.group_name << "'";
  return out;
}

TEST(TestFeatureVisitor, FeatureWithNoFieldTrial) {
  base::test::ScopedFeatureList outer_scope;
  outer_scope.InitWithEmptyFeatureAndFieldTrialLists();

  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures(/*enabled_features=*/{kFeatureOffByDefault},
                                /*disabled_features=*/{kFeatureOnByDefault});

  TestFeatureVisitor visitor;
  base::FeatureList::VisitFeaturesAndParams(visitor);
  std::multiset<TestFeatureVisitor::VisitedFeatureState> actual_feature_state =
      visitor.feature_state();

  std::multiset<TestFeatureVisitor::VisitedFeatureState>
      expected_feature_state = {
          {"OnByDefault", FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE,
           FieldTrialParams{}, "", ""},
          {"OffByDefault", FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
           FieldTrialParams{}, "", ""},
      };

  EXPECT_EQ(actual_feature_state, expected_feature_state);
}

TEST(TestFeatureVisitor, FeatureOverrideUseDefault) {
  base::test::ScopedFeatureList outer_scope;
  outer_scope.InitWithEmptyFeatureAndFieldTrialLists();

  auto feature_list = std::make_unique<base::FeatureList>();
  base::FieldTrial* trial =
      base::FieldTrialList::CreateFieldTrial("TrialExample", "A");
  feature_list->RegisterFieldTrialOverride(
      "TestFeature", base::FeatureList::OVERRIDE_USE_DEFAULT, trial);

  base::test::ScopedFeatureList initialized_feature_list;
  initialized_feature_list.InitWithFeatureList(std::move(feature_list));

  TestFeatureVisitor visitor;
  base::FeatureList::VisitFeaturesAndParams(visitor);
  std::multiset<TestFeatureVisitor::VisitedFeatureState> actual_feature_state =
      visitor.feature_state();

  std::multiset<TestFeatureVisitor::VisitedFeatureState>
      expected_feature_state = {
          {"TestFeature", FeatureList::OverrideState::OVERRIDE_USE_DEFAULT,
           FieldTrialParams{}, "TrialExample", "A"}};

  EXPECT_EQ(actual_feature_state, expected_feature_state);
}

TEST(TestFeatureVisitor, FeatureHasParams) {
  base::test::ScopedFeatureList outer_scope;
  outer_scope.InitWithEmptyFeatureAndFieldTrialLists();

  base::test::ScopedFeatureList initialized_feature_list;

  initialized_feature_list.InitFromCommandLine(
      /*enabled_features=*/"TestFeature<foo.bar:k1/v1/k2/v2",
      /*disabled_features=*/"");

  TestFeatureVisitor visitor;
  base::FeatureList::VisitFeaturesAndParams(visitor);
  std::multiset<TestFeatureVisitor::VisitedFeatureState> actual_feature_state =
      visitor.feature_state();

  std::multiset<TestFeatureVisitor::VisitedFeatureState>
      expected_feature_state = {
          {"TestFeature", FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
           FieldTrialParams{{"k1", "v1"}, {"k2", "v2"}}, "foo", "bar"},
      };

  EXPECT_EQ(actual_feature_state, expected_feature_state);
}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

}  // namespace base