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