1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
//
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
//
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifdef _MSC_VER
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#endif
#include <boost/nowide/args.hpp>
#include <boost/nowide/cstdlib.hpp>
#include <boost/nowide/utf/convert.hpp>
#include <boost/nowide/utf/utf.hpp>
#include "test.hpp"
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>
bool is_ascii(const std::string& s)
{
return std::find_if(s.begin(), s.end(), [](const char c) { return static_cast<unsigned char>(c) > 0x7F; })
== s.end();
}
std::string replace_non_ascii(const std::string& s) // LCOV_EXCL_LINE
{
std::string::const_iterator it = s.begin();
namespace utf = boost::nowide::utf;
using utf8 = utf::utf_traits<char>;
std::string result;
result.reserve(s.size());
while(it != s.end())
{
utf::code_point c = utf8::decode(it, s.end());
TEST(c != utf::illegal && c != utf::incomplete);
if(c > 0x7F)
c = '?'; // WinAPI seems to do this
result.push_back(static_cast<char>(c));
}
return result;
}
void compare_string_arrays(char** main_val, char** utf8_val, bool sort)
{
std::vector<std::string> vec_main, vec_utf8;
for(; *main_val; ++main_val)
vec_main.push_back(std::string(*main_val));
for(; *utf8_val; ++utf8_val)
vec_utf8.push_back(std::string(*utf8_val));
// Same number of strings
TEST_EQ(vec_main.size(), vec_utf8.size());
if(sort)
{
// Order doesn't matter
std::sort(vec_main.begin(), vec_main.end());
std::sort(vec_utf8.begin(), vec_utf8.end());
}
for(size_t i = 0; i < vec_main.size(); ++i)
{
// Skip strings with non-ascii chars
if(is_ascii(vec_main[i]) && vec_main[i] != vec_utf8[i])
TEST_EQ(vec_main[i], replace_non_ascii(vec_utf8[i]));
}
}
void compare_getenv(char** env)
{
// For all all variables in env check against getenv
for(char** e = env; *e != 0; e++)
{
const char* key_begin = *e;
const char* key_end = strchr(key_begin, '=');
TEST(key_end);
std::string key = std::string(key_begin, key_end);
const char* std_value = std::getenv(key.c_str());
const char* bnw_value = boost::nowide::getenv(key.c_str());
assert(std_value);
TEST(bnw_value);
// Compare only if ascii
if(is_ascii(std_value) && std::string(std_value) != std::string(bnw_value))
TEST_EQ(std_value, replace_non_ascii(bnw_value));
}
}
const std::string example = "\xd7\xa9-\xd0\xbc-\xce\xbd";
void run_child(int argc, char** argv, char** env)
{
// Test arguments
TEST_EQ(argc, 2);
TEST_EQ(argv[1], example);
TEST(argv[2] == nullptr);
// Test getenv
TEST(boost::nowide::getenv("BOOST_NOWIDE_TEST"));
TEST_EQ(boost::nowide::getenv("BOOST_NOWIDE_TEST"), example);
TEST(!boost::nowide::getenv("BOOST_NOWIDE_TEST_NONE"));
// Empty variables are unreliable on windows, hence skip. E.g. using "set FOO=" unsets FOO
#ifndef BOOST_WINDOWS
TEST(boost::nowide::getenv("BOOST_NOWIDE_EMPTY"));
TEST_EQ(boost::nowide::getenv("BOOST_NOWIDE_EMPTY"), std::string());
#endif // !_WIN32
// This must be contained in env
std::string sample = "BOOST_NOWIDE_TEST=" + example;
bool found = false;
for(char** e = env; *e != 0; e++)
{
if(*e == sample)
found = true;
}
TEST(found);
std::cout << "Subprocess ok" << std::endl;
}
void run_parent(const std::string& exe_path)
{
TEST(boost::nowide::system(nullptr) != 0);
const std::string command = "\"" + exe_path + "\" " + example;
#if BOOST_NOWIDE_TEST_USE_NARROW
TEST_EQ(boost::nowide::setenv("BOOST_NOWIDE_TEST", example.c_str(), 1), 0);
TEST_EQ(boost::nowide::setenv("BOOST_NOWIDE_TEST_NONE", example.c_str(), 1), 0);
TEST_EQ(boost::nowide::unsetenv("BOOST_NOWIDE_TEST_NONE"), 0);
TEST_EQ(boost::nowide::setenv("BOOST_NOWIDE_EMPTY", "", 1), 0);
TEST(boost::nowide::getenv("BOOST_NOWIDE_EMPTY"));
TEST_EQ(boost::nowide::system(command.c_str()), 0);
std::cout << "Parent ok" << std::endl;
#else
const std::wstring envVar = L"BOOST_NOWIDE_TEST=" + boost::nowide::widen(example);
TEST_EQ(_wputenv(envVar.c_str()), 0);
const std::wstring wcommand = boost::nowide::widen(command);
TEST_EQ(_wsystem(wcommand.c_str()), 0);
std::cout << "Wide Parent ok" << std::endl;
#endif
}
// coverity[root_function]
void test_main(int argc, char** argv, char** env)
{
const int old_argc = argc;
char** old_argv = argv;
char** old_env = env;
{
boost::nowide::args _(argc, argv, env);
TEST_EQ(argc, old_argc);
std::cout << "Checking arguments" << std::endl;
compare_string_arrays(old_argv, argv, false);
std::cout << "Checking env" << std::endl;
compare_string_arrays(old_env, env, true);
compare_getenv(env);
}
// When `args` is destructed the old values must be restored
TEST_EQ(argc, old_argc);
TEST(argv == old_argv);
TEST(env == old_env);
boost::nowide::args a(argc, argv, env);
if(argc == 1)
run_parent(argv[0]);
else
run_child(argc, argv, env);
}
|