1 /*
2 Copyright (c) 2005-2021 Intel Corporation
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.0
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 //! \file test_environment_whitebox.cpp
18 //! \brief Test for [internal] functionality
19
20 #if _WIN32 || _WIN64
21 #define _CRT_SECURE_NO_WARNINGS
22 #endif
23
24 #include "common/test.h"
25 #include "common/utils.h"
26 #include "common/utils_env.h"
27 #include "src/tbb/environment.h"
28
29 #include <string>
30 #include <algorithm>
31 #include <sstream>
32 #include <climits>
33 #include <utility>
34 #include <vector>
35
36 const char* environment_variable_name = "TEST_VARIABLE_NAME";
37
38 // For WIN8UI applications reading and writing the environment variables
39 // is prohibited due to the platform limitations
40 #if !__TBB_WIN8UI_SUPPORT
41
42 #if _WIN32 || _WIN64
43 // Environment variable length is limited by 32K on Windows
44 const std::size_t large_length = 32000;
45 #else
46 const std::size_t large_length = 1000000;
47 #endif
48
49 template <typename T>
set_and_get_test_variable(T (* environment_variable_getter)(const char *),std::pair<std::string,T> test_case)50 void set_and_get_test_variable( T (*environment_variable_getter)( const char* ),
51 std::pair<std::string, T> test_case )
52 {
53 utils::SetEnv(environment_variable_name, test_case.first.c_str());
54 T result = environment_variable_getter(environment_variable_name);
55 REQUIRE_MESSAGE(result == test_case.second, "Wrong Get<Type>EnvironmentVariable return value");
56 utils::SetEnv(environment_variable_name, "");
57 }
58
59 utils::FastRandom<> rnd(12345);
60
61 struct RandomCharacterGenerator {
operator ()RandomCharacterGenerator62 char operator()() {
63 return rnd.get() % 128; // 127 - the last ASCII symbol
64 }
65 }; // struct RandomCharacterGenerator
66
alternative_env_variable_checker(const char * str,bool)67 bool alternative_env_variable_checker( const char* str, bool ) {
68 bool result = false;
69 for (unsigned i = 0; str[i]; ++i) {
70 if (str[i] == '1') {
71 // if we found more then one '1' character -> return false
72 result = !result;
73 if (!result) return false;
74 } else if (str[i] != ' ') {
75 // if we found some character other than ' ' and '1' -> return false
76 return false;
77 }
78 }
79 return result;
80 }
81
82 // Suitable alternative checker for GetLongEnvVariable() was not found
83 // So here we use the code from GetLongEnvVariable() realization
alternative_env_variable_checker(const char * str,long)84 long alternative_env_variable_checker( const char* str, long ) {
85 char* end;
86 errno = 0;
87 long result = std::strtol(str, &end, 10);
88
89 // We have exceeded the range, value is negative or it is the end of the string
90 if (errno == ERANGE || result < 0 || end == str) {
91 result = -1;
92 }
93
94 for (; *end != '\0'; ++end) {
95 if (!std::isspace(*end))
96 result = -1;
97 }
98 return result;
99 }
100
101 template <typename T>
create_random_case(std::size_t length)102 std::pair<std::string, T> create_random_case( std::size_t length ) {
103 REQUIRE_MESSAGE(length != 0, "Requested random string cannot be empty");
104 std::string rand_string(length, ' ');
105 std::generate(rand_string.begin(), rand_string.end(), RandomCharacterGenerator{});
106
107 T expected_result = alternative_env_variable_checker(rand_string.c_str(), T());
108
109 return std::make_pair(rand_string, expected_result);
110 }
111
112 template <typename T>
prepare_random_cases(std::vector<std::pair<std::string,T>> & cases)113 void prepare_random_cases( std::vector<std::pair<std::string, T>>& cases ) {
114 // Random cases
115 std::size_t length = 10000;
116
117 for (std::size_t i = 0; i < 10; ++i) {
118 cases.push_back(create_random_case<T>((rnd.get() % length) + 1));
119 }
120
121 // Random case with large string
122 cases.push_back(create_random_case<T>(large_length));
123 }
124
initialize_cases(bool wrong_result)125 std::vector<std::pair<std::string, bool>> initialize_cases( bool wrong_result ) {
126 std::vector<std::pair<std::string, bool>> cases;
127 // Valid cases
128 cases.push_back(std::make_pair("1", true));
129 cases.push_back(std::make_pair(" 1 ", true));
130 cases.push_back(std::make_pair("1 ", true));
131 cases.push_back(std::make_pair(" 1 ", true));
132 cases.push_back(std::make_pair(" 1", true));
133 cases.push_back(std::make_pair((std::string(large_length, ' ') + '1').c_str(), true));
134
135 // Invalid cases
136 cases.push_back(std::make_pair("", wrong_result));
137 cases.push_back(std::make_pair(" ", wrong_result));
138 cases.push_back(std::make_pair(" 11", wrong_result));
139 cases.push_back(std::make_pair("111111", wrong_result));
140 cases.push_back(std::make_pair("1 1", wrong_result));
141 cases.push_back(std::make_pair(" 1 abc?", wrong_result));
142 cases.push_back(std::make_pair("1;", wrong_result));
143 cases.push_back(std::make_pair(" d ", wrong_result));
144 cases.push_back(std::make_pair("0", wrong_result));
145 cases.push_back(std::make_pair("0 ", wrong_result));
146 cases.push_back(std::make_pair("000000", wrong_result));
147 cases.push_back(std::make_pair("01", wrong_result));
148 cases.push_back(std::make_pair("00000001", wrong_result));
149 cases.push_back(std::make_pair("ABCDEFG", wrong_result));
150 cases.push_back(std::make_pair("2018", wrong_result));
151 cases.push_back(std::make_pair("ABC_123", wrong_result));
152 cases.push_back(std::make_pair("true", wrong_result));
153 cases.push_back(std::make_pair(std::string(large_length, 'A').c_str(), wrong_result));
154
155 prepare_random_cases(cases);
156 return cases;
157 }
158
initialize_cases(long wrong_result)159 std::vector<std::pair<std::string, long>> initialize_cases( long wrong_result ) {
160 std::vector<std::pair<std::string, long>> cases;
161 std::stringstream ss;
162 // Valid cases
163 for (long i = 0; i < 100; ++i) {
164 ss << i;
165 cases.push_back(std::make_pair(ss.str().c_str(), i));
166 ss.str("");
167
168 ss << " " << i << " ";
169 cases.push_back(std::make_pair(ss.str().c_str(), i));
170 ss.str("");
171
172 ss << i << " ";
173 cases.push_back(std::make_pair(ss.str().c_str(), i));
174 ss.str("");
175
176 ss << " " << i;
177 cases.push_back(std::make_pair(ss.str().c_str(), i));
178 ss.str("");
179 }
180
181 ss << LONG_MAX;
182 cases.push_back(std::make_pair(ss.str().c_str(), LONG_MAX));
183 ss.str("");
184
185 cases.push_back(std::make_pair((std::string(large_length, ' ') + '1').c_str(), 1L));
186
187 // Invalid cases
188 cases.push_back(std::make_pair("", wrong_result));
189 cases.push_back(std::make_pair(" ", wrong_result));
190 cases.push_back(std::make_pair("a", wrong_result));
191 cases.push_back(std::make_pair("^&*", wrong_result));
192 cases.push_back(std::make_pair(" 10 e", wrong_result));
193 cases.push_back(std::make_pair("a 12", wrong_result));
194 cases.push_back(std::make_pair("eeeeeeeeeeeeeeeeee", wrong_result));
195 cases.push_back(std::make_pair("200000000000000000000000000", wrong_result));
196 cases.push_back(std::make_pair("-1", wrong_result));
197 cases.push_back(std::make_pair("-100", wrong_result));
198 cases.push_back(std::make_pair("-200000000000000000000000000", wrong_result));
199 cases.push_back(std::make_pair("ABBDDRR", wrong_result));
200 cases.push_back(std::make_pair("10 10", wrong_result));
201 cases.push_back(std::make_pair("true", wrong_result));
202 cases.push_back(std::make_pair("false", wrong_result));
203 cases.push_back(std::make_pair("1A", wrong_result));
204 cases.push_back(std::make_pair("_123", wrong_result));
205 cases.push_back(std::make_pair(std::string(large_length, 'A').c_str(), wrong_result));
206
207 // Prepare string with LONG_MAX + 1 value
208 ss << LONG_MAX / 10 << (LONG_MAX % 10 + 1);
209 cases.push_back(std::make_pair(ss.str().c_str(), -1));
210 ss.str("");
211
212 prepare_random_cases(cases);
213 return cases;
214 }
215
216 template <typename T>
test_environment_variable(T (* environment_variables_handler)(const char *),T wrong_result)217 void test_environment_variable( T (*environment_variables_handler)( const char* ), T wrong_result ) {
218 REQUIRE_MESSAGE(environment_variables_handler(environment_variable_name) == wrong_result,
219 "Tested environment variable should not be defined in the beginning");
220
221 // Each pair is a test case:
222 // pair.first -> value of environment variable
223 // pair.second -> expected result
224 std::vector<std::pair<std::string, T>> cases = initialize_cases(wrong_result);
225
226 for (std::size_t i = 0; i != cases.size(); ++i) {
227 set_and_get_test_variable(environment_variables_handler, cases[i]);
228 }
229 }
230
231 //! \brief \ref error_guessing
232 TEST_CASE("testing GetBoolEnvironmentVariable") {
233 test_environment_variable(tbb::detail::r1::GetBoolEnvironmentVariable, false);
234 }
235
236 //! \brief \ref error_guessing
237 TEST_CASE("testing GetIntegralEnvironmentVariable") {
238 test_environment_variable(tbb::detail::r1::GetIntegralEnvironmentVariable, -1L);
239 }
240
241 #endif // !__TBB_WIN8UI_SUPPORT
242