/* * 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