151c0b2f7Stbbdev /*
2b15aabb3Stbbdev     Copyright (c) 2005-2021 Intel Corporation
351c0b2f7Stbbdev 
451c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev     you may not use this file except in compliance with the License.
651c0b2f7Stbbdev     You may obtain a copy of the License at
751c0b2f7Stbbdev 
851c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev 
1051c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev     See the License for the specific language governing permissions and
1451c0b2f7Stbbdev     limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev 
1751c0b2f7Stbbdev //! \file test_environment_whitebox.cpp
1851c0b2f7Stbbdev //! \brief Test for [internal] functionality
1951c0b2f7Stbbdev 
20*478de5b1Stbbdev #if _WIN32 || _WIN64
21*478de5b1Stbbdev #define _CRT_SECURE_NO_WARNINGS
22*478de5b1Stbbdev #endif
23*478de5b1Stbbdev 
2451c0b2f7Stbbdev #include "common/test.h"
2551c0b2f7Stbbdev #include "common/utils.h"
2651c0b2f7Stbbdev #include "common/utils_env.h"
27*478de5b1Stbbdev #include "src/tbb/environment.h"
2851c0b2f7Stbbdev 
2951c0b2f7Stbbdev #include <string>
3051c0b2f7Stbbdev #include <algorithm>
3151c0b2f7Stbbdev #include <sstream>
3251c0b2f7Stbbdev #include <climits>
3351c0b2f7Stbbdev #include <utility>
3451c0b2f7Stbbdev #include <vector>
3551c0b2f7Stbbdev 
3651c0b2f7Stbbdev const char* environment_variable_name = "TEST_VARIABLE_NAME";
3751c0b2f7Stbbdev 
3851c0b2f7Stbbdev // For WIN8UI applications reading and writing the environment variables
3951c0b2f7Stbbdev // is prohibited due to the platform limitations
4051c0b2f7Stbbdev #if !__TBB_WIN8UI_SUPPORT
4151c0b2f7Stbbdev 
4251c0b2f7Stbbdev #if _WIN32 || _WIN64
4351c0b2f7Stbbdev // Environment variable length is limited by 32K on Windows
4451c0b2f7Stbbdev const std::size_t large_length = 32000;
4551c0b2f7Stbbdev #else
4651c0b2f7Stbbdev const std::size_t large_length = 1000000;
4751c0b2f7Stbbdev #endif
4851c0b2f7Stbbdev 
4951c0b2f7Stbbdev template <typename T>
set_and_get_test_variable(T (* environment_variable_getter)(const char *),std::pair<std::string,T> test_case)5051c0b2f7Stbbdev void set_and_get_test_variable( T (*environment_variable_getter)( const char* ),
5151c0b2f7Stbbdev                                 std::pair<std::string, T> test_case )
5251c0b2f7Stbbdev {
5351c0b2f7Stbbdev     utils::SetEnv(environment_variable_name, test_case.first.c_str());
5451c0b2f7Stbbdev     T result = environment_variable_getter(environment_variable_name);
5551c0b2f7Stbbdev     REQUIRE_MESSAGE(result == test_case.second, "Wrong Get<Type>EnvironmentVariable return value");
5651c0b2f7Stbbdev     utils::SetEnv(environment_variable_name, "");
5751c0b2f7Stbbdev }
5851c0b2f7Stbbdev 
5951c0b2f7Stbbdev utils::FastRandom<> rnd(12345);
6051c0b2f7Stbbdev 
6151c0b2f7Stbbdev struct RandomCharacterGenerator {
operator ()RandomCharacterGenerator6251c0b2f7Stbbdev     char operator()() {
6351c0b2f7Stbbdev         return rnd.get() % 128; // 127 - the last ASCII symbol
6451c0b2f7Stbbdev     }
6551c0b2f7Stbbdev }; // struct RandomCharacterGenerator
6651c0b2f7Stbbdev 
alternative_env_variable_checker(const char * str,bool)6751c0b2f7Stbbdev bool alternative_env_variable_checker( const char* str, bool ) {
6851c0b2f7Stbbdev     bool result = false;
6951c0b2f7Stbbdev     for (unsigned i = 0; str[i]; ++i) {
7051c0b2f7Stbbdev         if (str[i] == '1') {
7151c0b2f7Stbbdev             // if we found more then one '1' character -> return false
7251c0b2f7Stbbdev             result = !result;
7351c0b2f7Stbbdev             if (!result) return false;
7451c0b2f7Stbbdev         } else if (str[i] != ' ') {
7551c0b2f7Stbbdev             // if we found some character other than ' ' and '1' -> return false
7651c0b2f7Stbbdev             return false;
7751c0b2f7Stbbdev         }
7851c0b2f7Stbbdev     }
7951c0b2f7Stbbdev     return result;
8051c0b2f7Stbbdev }
8151c0b2f7Stbbdev 
8251c0b2f7Stbbdev // Suitable alternative checker for GetLongEnvVariable() was not found
8351c0b2f7Stbbdev // So here we use the code from GetLongEnvVariable() realization
alternative_env_variable_checker(const char * str,long)8451c0b2f7Stbbdev long alternative_env_variable_checker( const char* str, long ) {
8551c0b2f7Stbbdev     char* end;
8651c0b2f7Stbbdev     errno = 0;
8751c0b2f7Stbbdev     long result = std::strtol(str, &end, 10);
8851c0b2f7Stbbdev 
8951c0b2f7Stbbdev     // We have exceeded the range, value is negative or it is the end of the string
9051c0b2f7Stbbdev     if (errno == ERANGE || result < 0 || end == str) {
9151c0b2f7Stbbdev         result = -1;
9251c0b2f7Stbbdev     }
9351c0b2f7Stbbdev 
9451c0b2f7Stbbdev     for (; *end != '\0'; ++end) {
9551c0b2f7Stbbdev         if (!std::isspace(*end))
9651c0b2f7Stbbdev             result = -1;
9751c0b2f7Stbbdev     }
9851c0b2f7Stbbdev     return result;
9951c0b2f7Stbbdev }
10051c0b2f7Stbbdev 
10151c0b2f7Stbbdev template <typename T>
create_random_case(std::size_t length)10251c0b2f7Stbbdev std::pair<std::string, T> create_random_case( std::size_t length ) {
10351c0b2f7Stbbdev     REQUIRE_MESSAGE(length != 0, "Requested random string cannot be empty");
10451c0b2f7Stbbdev     std::string rand_string(length, ' ');
10551c0b2f7Stbbdev     std::generate(rand_string.begin(), rand_string.end(), RandomCharacterGenerator{});
10651c0b2f7Stbbdev 
10751c0b2f7Stbbdev     T expected_result = alternative_env_variable_checker(rand_string.c_str(), T());
10851c0b2f7Stbbdev 
10951c0b2f7Stbbdev     return std::make_pair(rand_string, expected_result);
11051c0b2f7Stbbdev }
11151c0b2f7Stbbdev 
11251c0b2f7Stbbdev template <typename T>
prepare_random_cases(std::vector<std::pair<std::string,T>> & cases)11351c0b2f7Stbbdev void prepare_random_cases( std::vector<std::pair<std::string, T>>& cases ) {
11451c0b2f7Stbbdev     // Random cases
11551c0b2f7Stbbdev     std::size_t length = 10000;
11651c0b2f7Stbbdev 
11751c0b2f7Stbbdev     for (std::size_t i = 0; i < 10; ++i) {
11851c0b2f7Stbbdev         cases.push_back(create_random_case<T>((rnd.get() % length) + 1));
11951c0b2f7Stbbdev     }
12051c0b2f7Stbbdev 
12151c0b2f7Stbbdev     // Random case with large string
12251c0b2f7Stbbdev     cases.push_back(create_random_case<T>(large_length));
12351c0b2f7Stbbdev }
12451c0b2f7Stbbdev 
initialize_cases(bool wrong_result)12551c0b2f7Stbbdev std::vector<std::pair<std::string, bool>> initialize_cases( bool wrong_result ) {
12651c0b2f7Stbbdev     std::vector<std::pair<std::string, bool>> cases;
12751c0b2f7Stbbdev     // Valid cases
12851c0b2f7Stbbdev     cases.push_back(std::make_pair("1", true));
12951c0b2f7Stbbdev     cases.push_back(std::make_pair(" 1 ", true));
13051c0b2f7Stbbdev     cases.push_back(std::make_pair("1              ", true));
13151c0b2f7Stbbdev     cases.push_back(std::make_pair("             1           ", true));
13251c0b2f7Stbbdev     cases.push_back(std::make_pair("         1", true));
13351c0b2f7Stbbdev     cases.push_back(std::make_pair((std::string(large_length, ' ') + '1').c_str(), true));
13451c0b2f7Stbbdev 
13551c0b2f7Stbbdev     // Invalid cases
13651c0b2f7Stbbdev     cases.push_back(std::make_pair("", wrong_result));
13751c0b2f7Stbbdev     cases.push_back(std::make_pair(" ", wrong_result));
13851c0b2f7Stbbdev     cases.push_back(std::make_pair(" 11", wrong_result));
13951c0b2f7Stbbdev     cases.push_back(std::make_pair("111111", wrong_result));
14051c0b2f7Stbbdev     cases.push_back(std::make_pair("1 1", wrong_result));
14151c0b2f7Stbbdev     cases.push_back(std::make_pair(" 1 abc?", wrong_result));
14251c0b2f7Stbbdev     cases.push_back(std::make_pair("1;", wrong_result));
14351c0b2f7Stbbdev     cases.push_back(std::make_pair(" d ", wrong_result));
14451c0b2f7Stbbdev     cases.push_back(std::make_pair("0", wrong_result));
14551c0b2f7Stbbdev     cases.push_back(std::make_pair("0 ", wrong_result));
14651c0b2f7Stbbdev     cases.push_back(std::make_pair("000000", wrong_result));
14751c0b2f7Stbbdev     cases.push_back(std::make_pair("01", wrong_result));
14851c0b2f7Stbbdev     cases.push_back(std::make_pair("00000001", wrong_result));
14951c0b2f7Stbbdev     cases.push_back(std::make_pair("ABCDEFG", wrong_result));
15051c0b2f7Stbbdev     cases.push_back(std::make_pair("2018", wrong_result));
15151c0b2f7Stbbdev     cases.push_back(std::make_pair("ABC_123", wrong_result));
15251c0b2f7Stbbdev     cases.push_back(std::make_pair("true", wrong_result));
15351c0b2f7Stbbdev     cases.push_back(std::make_pair(std::string(large_length, 'A').c_str(), wrong_result));
15451c0b2f7Stbbdev 
15551c0b2f7Stbbdev     prepare_random_cases(cases);
15651c0b2f7Stbbdev     return cases;
15751c0b2f7Stbbdev }
15851c0b2f7Stbbdev 
initialize_cases(long wrong_result)15951c0b2f7Stbbdev std::vector<std::pair<std::string, long>> initialize_cases( long wrong_result ) {
16051c0b2f7Stbbdev     std::vector<std::pair<std::string, long>> cases;
16151c0b2f7Stbbdev     std::stringstream ss;
16251c0b2f7Stbbdev     // Valid cases
16351c0b2f7Stbbdev     for (long i = 0; i < 100; ++i) {
16451c0b2f7Stbbdev         ss << i;
16551c0b2f7Stbbdev         cases.push_back(std::make_pair(ss.str().c_str(), i));
16651c0b2f7Stbbdev         ss.str("");
16751c0b2f7Stbbdev 
16851c0b2f7Stbbdev         ss << "     " << i << "     ";
16951c0b2f7Stbbdev         cases.push_back(std::make_pair(ss.str().c_str(), i));
17051c0b2f7Stbbdev         ss.str("");
17151c0b2f7Stbbdev 
17251c0b2f7Stbbdev         ss << i << "     ";
17351c0b2f7Stbbdev         cases.push_back(std::make_pair(ss.str().c_str(), i));
17451c0b2f7Stbbdev         ss.str("");
17551c0b2f7Stbbdev 
17651c0b2f7Stbbdev         ss << "     " << i;
17751c0b2f7Stbbdev         cases.push_back(std::make_pair(ss.str().c_str(), i));
17851c0b2f7Stbbdev         ss.str("");
17951c0b2f7Stbbdev     }
18051c0b2f7Stbbdev 
18151c0b2f7Stbbdev     ss << LONG_MAX;
18251c0b2f7Stbbdev     cases.push_back(std::make_pair(ss.str().c_str(), LONG_MAX));
18351c0b2f7Stbbdev     ss.str("");
18451c0b2f7Stbbdev 
18551c0b2f7Stbbdev     cases.push_back(std::make_pair((std::string(large_length, ' ') + '1').c_str(), 1L));
18651c0b2f7Stbbdev 
18751c0b2f7Stbbdev     // Invalid cases
18851c0b2f7Stbbdev     cases.push_back(std::make_pair("", wrong_result));
18951c0b2f7Stbbdev     cases.push_back(std::make_pair("  ", wrong_result));
19051c0b2f7Stbbdev     cases.push_back(std::make_pair("a", wrong_result));
19151c0b2f7Stbbdev     cases.push_back(std::make_pair("^&*", wrong_result));
19251c0b2f7Stbbdev     cases.push_back(std::make_pair("  10   e", wrong_result));
19351c0b2f7Stbbdev     cases.push_back(std::make_pair("a   12", wrong_result));
19451c0b2f7Stbbdev     cases.push_back(std::make_pair("eeeeeeeeeeeeeeeeee", wrong_result));
19551c0b2f7Stbbdev     cases.push_back(std::make_pair("200000000000000000000000000", wrong_result));
19651c0b2f7Stbbdev     cases.push_back(std::make_pair("-1", wrong_result));
19751c0b2f7Stbbdev     cases.push_back(std::make_pair("-100", wrong_result));
19851c0b2f7Stbbdev     cases.push_back(std::make_pair("-200000000000000000000000000", wrong_result));
19951c0b2f7Stbbdev     cases.push_back(std::make_pair("ABBDDRR", wrong_result));
20051c0b2f7Stbbdev     cases.push_back(std::make_pair("10  10", wrong_result));
20151c0b2f7Stbbdev     cases.push_back(std::make_pair("true", wrong_result));
20251c0b2f7Stbbdev     cases.push_back(std::make_pair("false", wrong_result));
20351c0b2f7Stbbdev     cases.push_back(std::make_pair("1A", wrong_result));
20451c0b2f7Stbbdev     cases.push_back(std::make_pair("_123", wrong_result));
20551c0b2f7Stbbdev     cases.push_back(std::make_pair(std::string(large_length, 'A').c_str(), wrong_result));
20651c0b2f7Stbbdev 
20751c0b2f7Stbbdev     // Prepare string with LONG_MAX + 1 value
20851c0b2f7Stbbdev     ss << LONG_MAX / 10 << (LONG_MAX % 10 + 1);
20951c0b2f7Stbbdev     cases.push_back(std::make_pair(ss.str().c_str(), -1));
21051c0b2f7Stbbdev     ss.str("");
21151c0b2f7Stbbdev 
21251c0b2f7Stbbdev     prepare_random_cases(cases);
21351c0b2f7Stbbdev     return cases;
21451c0b2f7Stbbdev }
21551c0b2f7Stbbdev 
21651c0b2f7Stbbdev template <typename T>
test_environment_variable(T (* environment_variables_handler)(const char *),T wrong_result)21751c0b2f7Stbbdev void test_environment_variable( T (*environment_variables_handler)( const char* ), T wrong_result ) {
21851c0b2f7Stbbdev     REQUIRE_MESSAGE(environment_variables_handler(environment_variable_name) == wrong_result,
21951c0b2f7Stbbdev                     "Tested environment variable should not be defined in the beginning");
22051c0b2f7Stbbdev 
22151c0b2f7Stbbdev     // Each pair is a test case:
22251c0b2f7Stbbdev     // pair.first -> value of environment variable
22351c0b2f7Stbbdev     // pair.second -> expected result
22451c0b2f7Stbbdev     std::vector<std::pair<std::string, T>> cases = initialize_cases(wrong_result);
22551c0b2f7Stbbdev 
22651c0b2f7Stbbdev     for (std::size_t i = 0; i != cases.size(); ++i) {
22751c0b2f7Stbbdev         set_and_get_test_variable(environment_variables_handler, cases[i]);
22851c0b2f7Stbbdev     }
22951c0b2f7Stbbdev }
23051c0b2f7Stbbdev 
23151c0b2f7Stbbdev //! \brief \ref error_guessing
23251c0b2f7Stbbdev TEST_CASE("testing GetBoolEnvironmentVariable") {
23351c0b2f7Stbbdev     test_environment_variable(tbb::detail::r1::GetBoolEnvironmentVariable, false);
23451c0b2f7Stbbdev }
23551c0b2f7Stbbdev 
23651c0b2f7Stbbdev //! \brief \ref error_guessing
23751c0b2f7Stbbdev TEST_CASE("testing GetIntegralEnvironmentVariable") {
23851c0b2f7Stbbdev     test_environment_variable(tbb::detail::r1::GetIntegralEnvironmentVariable, -1L);
23951c0b2f7Stbbdev }
24051c0b2f7Stbbdev 
24151c0b2f7Stbbdev #endif // !__TBB_WIN8UI_SUPPORT
242