blob: 7f057915f1947ca8a1921506f74ee90f368fb966 [file]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0dd
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <utility>
#include <sstream>
#include <string>
#include <vector>
#include <flag_checker.h>
#include <gtest/gtest.h>
#define _FLAG_GTEST_CLASS_NAME(test_fixture, test_name) \
test_fixture##_##test_name##_FLAG_GTest
#define _FLAG_STRINGFY(...) #__VA_ARGS__
#define _FLAG_NAME(namespace, flag) namespace::flag
// Defines a class inherit from the original test fixture.
//
// The class is defined for each test case. The class constructor calls
// SkipIfFlagRequirementsNotMet to decide whether the test should be
// skipped.
#define _FLAG_GTEST_CLASS(test_fixture, test_name, parent_class, flags...) \
class _FLAG_GTEST_CLASS_NAME(test_fixture, test_name) \
: public parent_class { \
public: \
void SkipTest( \
std::vector<std::pair<bool, std::string>> unsatisfied_flags) { \
std::ostringstream skip_message; \
for (const std::pair<bool, std::string> flag : unsatisfied_flags) { \
skip_message << " flag(" \
<< flag.second << ")=" \
<< (flag.first ? "true":"false"); \
} \
GTEST_SKIP() << "Skipping test: not meet feature flag conditions:" \
<< skip_message.str(); \
} \
\
_FLAG_GTEST_CLASS_NAME(test_fixture, test_name)() { \
std::vector<std::pair<bool, std::string>> unsatisfied_flags = \
android::test::flag::GetFlagsNotMetRequirements({flags}); \
if (unsatisfied_flags.size() != 0) { \
SkipTest(unsatisfied_flags); \
} \
} \
};
// Defines an aconfig feature flag.
//
// The first parameter is the package (with cpp namespace format) of the
// feature flag. The second parameter is the name of the feature flag.
//
// For example: ACONFIG_FLAG(android::cts::test, flag_rw)
#if !TEST_WITH_FLAGS_DONT_DEFINE
#define ACONFIG_FLAG(package, flag) \
std::make_pair<std::function<bool()>, std::string>( \
static_cast<bool (*)()>(_FLAG_NAME(package, flag)), \
_FLAG_STRINGFY(package, flag))
#endif
// Defines a legacy feature flag.
//
// The first parameter is the namespace of the feature flag. The second
// parameter (with cpp namespace format) is the package of the feature
// flag. The third parameter is the name of the feature flag.
//
// For example: LEGACY_FLAG(cts, android::cts::test, flag_rw)
#if !TEST_WITH_FLAGS_DONT_DEFINE
#define LEGACY_FLAG(namespace, package, flag) \
std::make_pair<std::function<bool()>, std::string>( \
nullptr, _FLAG_STRINGFY(namespace, package, flag))
#endif
// Defines a set of feature flags that must meet "enabled" condition.
//
// The input parameters of REQUIRES_FLAGS_ENABLED is a set of flags
// warpped by ACONFIG_FLAG or LEGACY_FLAG macros, indicating that the
// expected values of these flags are true.
//
// For example:
// REQUIRES_FLAGS_ENABLED(LEGACY_FLAG(...), ACONFIG_FLAG(...))
#if !TEST_WITH_FLAGS_DONT_DEFINE
#define REQUIRES_FLAGS_ENABLED(flags...) \
std::make_pair<bool, std::vector< \
std::pair<std::function<bool()>, std::string>>>(true, {flags})
#endif
// Defines a set of feature flags that must meet "disabled" condition.
//
// The input parameters of REQUIRES_FLAGS_DISABLED is a set of flags
// warpped by ACONFIG_FLAG or LEGACY_FLAG macros, indicating that the
// expected values of these flags are false.
//
// For example:
// REQUIRES_FLAGS_DISABLED(LEGACY_FLAG(...), ACONFIG_FLAG(...))
#if !TEST_WITH_FLAGS_DONT_DEFINE
#define REQUIRES_FLAGS_DISABLED(flags...) \
std::make_pair<bool, std::vector< \
std::pair<std::function<bool()>, std::string>>>(false, {flags})
#endif
// TEST_F_WITH_FLAGS is an extension to the TEST_F macro in the GoogleTest
// framework. It supports adding feature flag conditions wrapped by
// REQUIRES_FLAGS_ENABLED or REQUIRES_FLAGS_DISABLED macros at the end of
// input parameters.
//
// For example:
//
// TEST_F_WITH_FLAGS(
// MyTestFixture,
// myTest,
// REQUIRES_FLAGS_ENABLED(...),
// REQUIRES_FLAGS_DISABLED(...)) {...}
//
// If any feature flag condition cannot be satisfied, the test will be
// skipped.
#if !TEST_WITH_FLAGS_DONT_DEFINE
#define TEST_F_WITH_FLAGS(test_fixture, test_name, flags...) \
_FLAG_GTEST_CLASS(test_fixture, test_name, test_fixture, flags) \
GTEST_TEST_(test_fixture, test_name, \
_FLAG_GTEST_CLASS_NAME(test_fixture, test_name), \
::testing::internal::GetTypeId<test_fixture>())
#endif
// TEST_WITH_FLAGS is an extension to the TEST macro in the GoogleTest
// framework. It supports adding feature flag conditions wrapped by
// REQUIRES_FLAGS_ENABLED or REQUIRES_FLAGS_DISABLED macros at the end of
// input parameters.
//
// For example:
//
// TEST_WITH_FLAGS(
// MyTestFixture,
// myTest,
// REQUIRES_FLAGS_ENABLED(...),
// REQUIRES_FLAGS_DISABLED(...)) {...}
//
// If any feature flag condition cannot be satisfied, the test will be
// skipped.
#if !TEST_WITH_FLAGS_DONT_DEFINE
#define TEST_WITH_FLAGS(test_fixture, test_name, flags...) \
_FLAG_GTEST_CLASS(test_fixture, test_name, ::testing::Test, flags) \
GTEST_TEST_(test_fixture, test_name, \
_FLAG_GTEST_CLASS_NAME(test_fixture, test_name), \
::testing::internal::GetTestTypeId())
#endif