1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0dd
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <utility>
20 #include <sstream>
21 #include <string>
22 #include <vector>
23 
24 #include <flag_checker.h>
25 #include <gtest/gtest.h>
26 
27 #define _FLAG_GTEST_CLASS_NAME(test_fixture, test_name)                      \
28   test_fixture##_##test_name##_FLAG_GTest
29 
30 #define _FLAG_STRINGFY(...) #__VA_ARGS__
31 
32 #define _FLAG_NAME(namespace, flag) namespace::flag
33 
34 // Defines a class inherit from the original test fixture.
35 //
36 // The class is defined for each test case. The class constructor calls
37 // SkipIfFlagRequirementsNotMet to decide whether the test should be
38 // skipped.
39 
40 #define _FLAG_GTEST_CLASS(test_fixture, test_name, parent_class, flags...)   \
41   class _FLAG_GTEST_CLASS_NAME(test_fixture, test_name)                      \
42                             : public parent_class {                          \
43     public:                                                                  \
44       void SkipTest(                                                         \
45         std::vector<std::pair<bool, std::string>> unsatisfied_flags) {       \
46         std::ostringstream skip_message;                                     \
47         for (const std::pair<bool, std::string> flag : unsatisfied_flags) {  \
48           skip_message << " flag("                                           \
49               << flag.second << ")="                                         \
50               << (flag.first ? "true":"false");                              \
51         }                                                                    \
52         GTEST_SKIP() << "Skipping test: not meet feature flag conditions:"   \
53           << skip_message.str();                                             \
54       }                                                                      \
55                                                                              \
56       _FLAG_GTEST_CLASS_NAME(test_fixture, test_name)() {                    \
57         std::vector<std::pair<bool, std::string>> unsatisfied_flags =        \
58           android::test::flag::GetFlagsNotMetRequirements({flags});          \
59         if (unsatisfied_flags.size() != 0) {                                 \
60           SkipTest(unsatisfied_flags);                                       \
61         }                                                                    \
62       }                                                                      \
63   };
64 
65 // Defines an aconfig feature flag.
66 //
67 // The first parameter is the package (with cpp namespace format) of the
68 // feature flag. The second parameter is the name of the feature flag.
69 //
70 // For example: ACONFIG_FLAG(android::cts::test, flag_rw)
71 
72 #if !TEST_WITH_FLAGS_DONT_DEFINE
73 #define ACONFIG_FLAG(package, flag)                                            \
74   std::make_pair<std::function<bool()>, std::string>(                          \
75       static_cast<bool (*)()>(_FLAG_NAME(package, flag)),                      \
76       _FLAG_STRINGFY(package, flag))
77 #endif
78 
79 // Defines a legacy feature flag.
80 //
81 // The first parameter is the namespace of the feature flag. The second
82 // parameter (with cpp namespace format) is the package of the feature
83 // flag. The third parameter is the name of the feature flag.
84 //
85 // For example: LEGACY_FLAG(cts, android::cts::test, flag_rw)
86 
87 #if !TEST_WITH_FLAGS_DONT_DEFINE
88 #define LEGACY_FLAG(namespace, package, flag)                               \
89   std::make_pair<std::function<bool()>, std::string>(                       \
90     nullptr, _FLAG_STRINGFY(namespace, package, flag))
91 #endif
92 
93 // Defines a set of feature flags that must meet "enabled" condition.
94 //
95 // The input parameters of REQUIRES_FLAGS_ENABLED is a set of flags
96 // warpped by ACONFIG_FLAG or LEGACY_FLAG macros, indicating that the
97 // expected values of these flags are true.
98 //
99 // For example:
100 //   REQUIRES_FLAGS_ENABLED(LEGACY_FLAG(...), ACONFIG_FLAG(...))
101 
102 #if !TEST_WITH_FLAGS_DONT_DEFINE
103 #define REQUIRES_FLAGS_ENABLED(flags...)                                    \
104   std::make_pair<bool, std::vector<                                         \
105     std::pair<std::function<bool()>, std::string>>>(true, {flags})
106 #endif
107 
108 // Defines a set of feature flags that must meet "disabled" condition.
109 //
110 // The input parameters of REQUIRES_FLAGS_DISABLED is a set of flags
111 // warpped by ACONFIG_FLAG or LEGACY_FLAG macros, indicating that the
112 // expected values of these flags are false.
113 //
114 // For example:
115 //   REQUIRES_FLAGS_DISABLED(LEGACY_FLAG(...), ACONFIG_FLAG(...))
116 
117 #if !TEST_WITH_FLAGS_DONT_DEFINE
118 #define REQUIRES_FLAGS_DISABLED(flags...)                                   \
119   std::make_pair<bool, std::vector<                                         \
120     std::pair<std::function<bool()>, std::string>>>(false, {flags})
121 #endif
122 
123 // TEST_F_WITH_FLAGS is an extension to the TEST_F macro in the GoogleTest
124 // framework. It supports adding feature flag conditions wrapped by
125 // REQUIRES_FLAGS_ENABLED or REQUIRES_FLAGS_DISABLED macros at the end of
126 // input parameters.
127 //
128 // For example:
129 //
130 // TEST_F_WITH_FLAGS(
131 //   MyTestFixture,
132 //   myTest,
133 //   REQUIRES_FLAGS_ENABLED(...),
134 //   REQUIRES_FLAGS_DISABLED(...)) {...}
135 //
136 // If any feature flag condition cannot be satisfied, the test will be
137 // skipped.
138 
139 #if !TEST_WITH_FLAGS_DONT_DEFINE
140 #define TEST_F_WITH_FLAGS(test_fixture, test_name, flags...)                 \
141   _FLAG_GTEST_CLASS(test_fixture, test_name, test_fixture, flags)            \
142   GTEST_TEST_(test_fixture, test_name,                                       \
143               _FLAG_GTEST_CLASS_NAME(test_fixture, test_name),               \
144               ::testing::internal::GetTypeId<test_fixture>())
145 #endif
146 
147 // TEST_WITH_FLAGS is an extension to the TEST macro in the GoogleTest
148 // framework. It supports adding feature flag conditions wrapped by
149 // REQUIRES_FLAGS_ENABLED or REQUIRES_FLAGS_DISABLED macros at the end of
150 // input parameters.
151 //
152 // For example:
153 //
154 // TEST_WITH_FLAGS(
155 //   MyTestFixture,
156 //   myTest,
157 //   REQUIRES_FLAGS_ENABLED(...),
158 //   REQUIRES_FLAGS_DISABLED(...)) {...}
159 //
160 // If any feature flag condition cannot be satisfied, the test will be
161 // skipped.
162 
163 #if !TEST_WITH_FLAGS_DONT_DEFINE
164 #define TEST_WITH_FLAGS(test_fixture, test_name, flags...)                   \
165   _FLAG_GTEST_CLASS(test_fixture, test_name, ::testing::Test, flags)         \
166   GTEST_TEST_(test_fixture, test_name,                                       \
167               _FLAG_GTEST_CLASS_NAME(test_fixture, test_name),               \
168               ::testing::internal::GetTestTypeId())
169 #endif