42 #define WIN32_LEAN_AND_MEAN
43 #include <google/protobuf/io/io_win32.h>
50 #include <sys/types.h>
59 #include <gtest/gtest.h>
67 const char kUtf8Text[] = {
70 static_cast<char>(0xd0),
static_cast<char>(0x9f),
72 static_cast<char>(0xd1),
static_cast<char>(0x80),
74 static_cast<char>(0xd0),
static_cast<char>(0xb8),
76 static_cast<char>(0xd0),
static_cast<char>(0xb2),
78 static_cast<char>(0xd0),
static_cast<char>(0xb5),
80 static_cast<char>(0xd1),
static_cast<char>(0x82), 0
83 const wchar_t kUtf16Text[] = {
85 L'\x41f',
L'\x440',
L'\x438',
L'\x432',
L'\x435',
L'\x442', 0
101 WCHAR working_directory[MAX_PATH];
106 #define ASSERT_INITIALIZED \
108 EXPECT_FALSE(test_tmpdir.empty()); \
109 EXPECT_FALSE(wtest_tmpdir.empty()); \
113 void StripTrailingSlashes(
string*
str) {
114 int i =
str->size() - 1;
115 for (;
i >= 0 && ((*str)[
i] ==
'/' || (*str)[
i] ==
'\\'); --
i) {}
119 bool GetEnvVarAsUtf8(
const WCHAR*
name,
string*
result) {
120 DWORD
size = ::GetEnvironmentVariableW(
name,
nullptr, 0);
121 if (
size > 0 && GetLastError() != ERROR_ENVVAR_NOT_FOUND) {
122 std::unique_ptr<WCHAR[]> wcs(
new WCHAR[
size]);
123 ::GetEnvironmentVariableW(
name, wcs.get(),
size);
129 return strings::wcs_to_utf8(wcs.get(),
result);
135 bool GetCwdAsUtf8(
string*
result) {
136 DWORD
size = ::GetCurrentDirectoryW(0,
nullptr);
138 std::unique_ptr<WCHAR[]> wcs(
new WCHAR[
size]);
139 ::GetCurrentDirectoryW(
size, wcs.get());
145 return strings::wcs_to_utf8(wcs.get(),
result);
152 HANDLE
h = CreateFileW(
path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
153 FILE_ATTRIBUTE_NORMAL, NULL);
163 void IoWin32Test::SetUp() {
165 wtest_tmpdir.clear();
166 DWORD
size = ::GetCurrentDirectoryW(MAX_PATH, working_directory);
174 ok = GetEnvVarAsUtf8(L
"TEST_TMPDIR", &
tmp);
178 ok = GetEnvVarAsUtf8(L
"TEMP", &
tmp);
182 ok = GetEnvVarAsUtf8(L
"TMP", &
tmp);
186 ok = GetCwdAsUtf8(&
tmp);
188 if (!
ok ||
tmp.empty()) {
189 FAIL() <<
"Cannot find a temp directory.";
192 StripTrailingSlashes(&
tmp);
198 static unsigned int counter = 0;
200 test_tmpdir =
result.str();
201 wtest_tmpdir = testonly_utf8_to_winpath(test_tmpdir.c_str());
207 void IoWin32Test::TearDown() {
208 if (!wtest_tmpdir.empty()) {
209 DeleteAllUnder(wtest_tmpdir);
211 ::SetCurrentDirectoryW(working_directory);
218 if (
path.find(L
"\\\\?\\") != 0) {
221 if (::CreateDirectoryW(
path.c_str(),
nullptr) ||
222 GetLastError() == ERROR_ALREADY_EXISTS ||
223 GetLastError() == ERROR_ACCESS_DENIED) {
226 if (GetLastError() == ERROR_PATH_NOT_FOUND) {
227 size_t pos =
path.find_last_of(L
'\\');
228 if (
pos != wstring::npos) {
230 if (CreateAllUnder(parent) && CreateDirectoryW(
path.c_str(),
nullptr)) {
239 static const wstring kDot(L
".");
240 static const wstring kDotDot(L
"..");
245 if (
path.find(L
"\\\\?\\") != 0) {
249 if (
path[
path.size() - 1] != L
'\\') {
250 path.push_back(L
'\\');
262 if (kDot != childname && kDotDot != childname) {
264 if ((
metadata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
267 if (((
metadata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0 &&
268 !DeleteAllUnder(childpath)) ||
269 !::RemoveDirectoryW(childpath.c_str())) {
274 if (!::DeleteFileW(childpath.c_str())) {
285 TEST_F(IoWin32Test, AccessTest) {
288 string path = test_tmpdir;
289 while (
path.size() < MAX_PATH - 30) {
290 path +=
"\\accesstest";
294 int fd =
open(
file.c_str(), O_CREAT | O_WRONLY, 0644);
325 TEST_F(IoWin32Test, OpenTest) {
328 string path = test_tmpdir;
329 while (
path.size() < MAX_PATH) {
330 path +=
"\\opentest";
334 int fd =
open(
file.c_str(), O_CREAT | O_WRONLY, 0644);
344 ASSERT_EQ(
open(
"/tmp/bad.txt", O_CREAT | O_WRONLY, 0644), -1);
350 TEST_F(IoWin32Test, MkdirTest) {
353 string path = test_tmpdir;
355 path +=
"\\mkdirtest";
357 }
while (
path.size() <= MAX_PATH);
367 TEST_F(IoWin32Test, MkdirTestNonAscii) {
373 EXPECT_TRUE(CreateDirectoryW((wtest_tmpdir + L
"\\1\\" + kUtf16Text).
c_str(),
nullptr));
378 EXPECT_EQ(mkdir((test_tmpdir +
"\\2\\" + kUtf8Text).
c_str(), 0644), 0);
381 TEST_F(IoWin32Test, ChdirTest) {
393 path = test_tmpdir +
"/foo.";
399 TEST_F(IoWin32Test, ChdirTestNonAscii) {
403 wstring wNonAscii(wtest_tmpdir + L
"\\" + kUtf16Text);
405 EXPECT_TRUE(strings::wcs_to_utf8(wNonAscii.c_str(), &nonAscii));
406 EXPECT_TRUE(CreateDirectoryW(wNonAscii.c_str(),
nullptr));
410 EXPECT_TRUE(SetCurrentDirectoryW(wNonAscii.c_str()));
419 TEST_F(IoWin32Test, ExpandWildcardsInRelativePathTest) {
420 wstring wNonAscii(wtest_tmpdir + L
"\\" + kUtf16Text);
421 EXPECT_TRUE(CreateDirectoryW(wNonAscii.c_str(),
nullptr));
423 EXPECT_TRUE(CreateEmptyFile(wNonAscii + L
"\\foo_a.proto"));
424 EXPECT_TRUE(CreateEmptyFile(wNonAscii + L
"\\foo_b.proto"));
425 EXPECT_TRUE(CreateEmptyFile(wNonAscii + L
"\\bar.proto"));
427 EXPECT_TRUE(SetCurrentDirectoryW(wtest_tmpdir.c_str()));
431 vector<string> found_bad;
433 ExpandWildcardsResult
result =
434 ExpandWildcards(
string(kUtf8Text) +
"\\foo*.proto",
435 [&found_a, &found_b, &found_bad](
const string& p) {
436 if (p ==
string(kUtf8Text) +
"\\foo_a.proto") {
438 }
else if (p ==
string(kUtf8Text) +
"\\foo_b.proto") {
441 found_bad.push_back(p);
447 if (!found_bad.empty()) {
448 FAIL() << found_bad[0];
454 result = ExpandWildcards(
string(kUtf8Text) +
"\\foo_a.proto",
455 [&found_a, &found_bad](
const string& p) {
456 if (p ==
string(kUtf8Text) +
"\\foo_a.proto") {
459 found_bad.push_back(p);
464 if (!found_bad.empty()) {
465 FAIL() << found_bad[0];
469 TEST_F(IoWin32Test, ExpandWildcardsInAbsolutePathTest) {
470 wstring wNonAscii(wtest_tmpdir + L
"\\" + kUtf16Text);
471 EXPECT_TRUE(CreateDirectoryW(wNonAscii.c_str(),
nullptr));
473 EXPECT_TRUE(CreateEmptyFile(wNonAscii + L
"\\foo_a.proto"));
474 EXPECT_TRUE(CreateEmptyFile(wNonAscii + L
"\\foo_b.proto"));
475 EXPECT_TRUE(CreateEmptyFile(wNonAscii + L
"\\bar.proto"));
479 vector<string> found_bad;
482 ExpandWildcardsResult
result =
483 ExpandWildcards(
string(test_tmpdir) +
"\\" + kUtf8Text +
"\\foo*.proto",
484 [
this, &found_a, &found_b, &found_bad](
const string& p) {
485 if (p ==
string(this->test_tmpdir) +
"\\" + kUtf8Text +
488 }
else if (p ==
string(this->test_tmpdir) +
"\\" +
489 kUtf8Text +
"\\foo_b.proto") {
492 found_bad.push_back(p);
498 if (!found_bad.empty()) {
499 FAIL() << found_bad[0];
506 ExpandWildcards(
string(test_tmpdir) +
"\\" + kUtf8Text +
"\\foo_a.proto",
507 [
this, &found_a, &found_bad](
const string& p) {
508 if (p ==
string(this->test_tmpdir) +
"\\" + kUtf8Text +
512 found_bad.push_back(p);
517 if (!found_bad.empty()) {
518 FAIL() << found_bad[0];
522 TEST_F(IoWin32Test, ExpandWildcardsIgnoresDirectoriesTest) {
523 wstring wNonAscii(wtest_tmpdir + L
"\\" + kUtf16Text);
524 EXPECT_TRUE(CreateDirectoryW(wNonAscii.c_str(),
nullptr));
526 EXPECT_TRUE(CreateEmptyFile(wNonAscii + L
"\\foo_a.proto"));
528 CreateDirectoryW((wNonAscii + L
"\\foo_b.proto").
c_str(),
nullptr));
529 EXPECT_TRUE(CreateEmptyFile(wNonAscii + L
"\\foo_c.proto"));
531 EXPECT_TRUE(SetCurrentDirectoryW(wtest_tmpdir.c_str()));
535 vector<string> found_bad;
538 ExpandWildcardsResult
result =
539 ExpandWildcards(
string(kUtf8Text) +
"\\foo*.proto",
540 [&found_a, &found_c, &found_bad](
const string& p) {
541 if (p ==
string(kUtf8Text) +
"\\foo_a.proto") {
543 }
else if (p ==
string(kUtf8Text) +
"\\foo_c.proto") {
546 found_bad.push_back(p);
552 if (!found_bad.empty()) {
553 FAIL() << found_bad[0];
557 TEST_F(IoWin32Test, ExpandWildcardsFailsIfNoFileMatchesTest) {
558 wstring wNonAscii(wtest_tmpdir + L
"\\" + kUtf16Text);
559 EXPECT_TRUE(CreateDirectoryW(wNonAscii.c_str(),
nullptr));
561 EXPECT_TRUE(CreateEmptyFile(wNonAscii + L
"\\foo_a.proto"));
563 EXPECT_TRUE(SetCurrentDirectoryW(wtest_tmpdir.c_str()));
566 ExpandWildcardsResult
result =
567 ExpandWildcards(
string(kUtf8Text) +
"\\foo*.proto", [](
const string&) {});
571 result = ExpandWildcards(
string(kUtf8Text) +
"\\foo_a.proto",
572 [](
const string&) {});
577 ExpandWildcards(
string(kUtf8Text) +
"\\bar*.proto", [](
const string&) {});
581 TEST_F(IoWin32Test, AsWindowsPathTest) {
582 DWORD
size = GetCurrentDirectoryW(0,
nullptr);
583 std::unique_ptr<wchar_t[]> cwd_str(
new wchar_t[
size]);
587 ASSERT_EQ(testonly_utf8_to_winpath(
"relative_mkdirtest"),
588 cwd + L
"\\relative_mkdirtest");
589 ASSERT_EQ(testonly_utf8_to_winpath(
"preserve//\\trailing///"),
590 cwd + L
"\\preserve\\trailing\\");
591 ASSERT_EQ(testonly_utf8_to_winpath(
"./normalize_me\\/../blah"),
593 std::ostringstream relpath;
594 for (
wchar_t* p = cwd_str.get(); *p; ++p) {
595 if (*p ==
'/' || *p ==
'\\') {
599 relpath <<
".\\/../\\./beyond-toplevel";
600 ASSERT_EQ(testonly_utf8_to_winpath(relpath.str().c_str()),
601 wstring(L
"\\\\?\\") + cwd_str.get()[0] + L
":\\beyond-toplevel");
606 ASSERT_EQ(testonly_utf8_to_winpath(
"/absolute/unix/path"), L
"");
608 ASSERT_EQ(testonly_utf8_to_winpath(
"\\driveless\\absolute"), L
"");
610 ASSERT_EQ(testonly_utf8_to_winpath(
"c:foo"), L
"");
611 ASSERT_EQ(testonly_utf8_to_winpath(
"c:/foo"), L
"\\\\?\\c:\\foo");
612 ASSERT_EQ(testonly_utf8_to_winpath(
"\\\\?\\C:\\foo"), L
"\\\\?\\C:\\foo");
615 TEST_F(IoWin32Test, Utf8Utf16ConversionTest) {
618 ASSERT_TRUE(strings::utf8_to_wcs(kUtf8Text, &wcs));
619 ASSERT_TRUE(strings::wcs_to_utf8(kUtf16Text, &mbs));
630 #endif // defined(_WIN32)