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> 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 { 62 char operator()() { 63 return rnd.get() % 128; // 127 - the last ASCII symbol 64 } 65 }; // struct RandomCharacterGenerator 66 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 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> 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> 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 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 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> 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