Skip to content

Commit d1489f2

Browse files
Improve P0218R1_filesystem test reliability and temp filename generation (#4665)
1 parent 6bad24d commit d1489f2

File tree

10 files changed

+57
-60
lines changed

10 files changed

+57
-60
lines changed

tests/std/include/temp_file_name.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
#include <string>
88

99
[[nodiscard]] inline std::string temp_file_name() {
10-
std::string ret{"temp_file_"};
10+
std::string ret{"msvc_stl_"};
1111
std::uniform_int_distribution<int> dist{0, 15};
1212
std::random_device rd;
1313

14-
for (int i = 0; i < 64; ++i) { // 64 hexits = 256 bits of entropy
14+
for (int i = 0; i < 32; ++i) { // 32 hexits = 128 bits of entropy
1515
ret.push_back("0123456789ABCDEF"[dist(rd)]);
1616
}
1717

tests/std/include/test_filesystem_support.hpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,31 @@
66
#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
77

88
#include <algorithm>
9-
#include <cstring>
109
#include <experimental/filesystem>
1110
#include <filesystem>
1211
#include <iterator>
1312
#include <random>
1413
#include <string>
1514

16-
inline std::string get_test_directory_subname(const char* const testName, const size_t testNameLength) {
15+
template <class T>
16+
std::string get_test_directory_subname(const T& testName) {
1717
using namespace std;
1818
random_device rd;
1919
uniform_int_distribution<> dist(0, 15);
20-
string subName(testName, testNameLength);
20+
string subName(testName);
2121
subName.push_back('_');
22-
generate_n(back_inserter(subName), 16, [&] { return "0123456789ABCDEF"[dist(rd)]; });
22+
generate_n(back_inserter(subName), 32, [&] { return "0123456789ABCDEF"[dist(rd)]; });
2323
return subName;
2424
}
2525

26-
inline std::experimental::filesystem::path get_test_directory(const char* const testName) {
27-
return std::experimental::filesystem::temp_directory_path()
28-
/ get_test_directory_subname(testName, strlen(testName));
26+
inline std::experimental::filesystem::path get_experimental_test_directory(const char* const testName) {
27+
return std::experimental::filesystem::temp_directory_path() / get_test_directory_subname(testName);
2928
}
3029

3130
#if _HAS_CXX17
3231
#include <string_view>
3332

34-
inline std::filesystem::path get_new_test_directory(std::string_view testName) {
35-
return std::filesystem::temp_directory_path() / get_test_directory_subname(testName.data(), testName.size());
33+
inline std::filesystem::path get_test_directory(std::string_view testName) {
34+
return std::filesystem::temp_directory_path() / get_test_directory_subname(testName);
3635
}
3736
#endif // _HAS_CXX17

tests/std/tests/Dev11_1066931_filesystem_rename_noop/test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ int main() {
345345
error_code ec;
346346
const auto previousCd = fs::current_path(ec);
347347
assert_success(ec);
348-
const auto testDir = get_test_directory("filesystem_rename_noop");
348+
const auto testDir = get_experimental_test_directory("filesystem_rename_noop");
349349
printf("changing directory to \"%ls\"\n", testDir.native().c_str());
350350
fs::create_directory(testDir, ec);
351351
assert_success(ec);

tests/std/tests/P0218R1_filesystem/test.cpp

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ template <typename Elem, typename Traits>
5353
return str.size() >= prefix.size() && Traits::compare(str.data(), prefix.data(), prefix.size()) == 0;
5454
}
5555

56-
struct test_temp_directory {
57-
error_code ec;
56+
struct [[nodiscard]] test_temp_directory {
5857
path directoryPath;
59-
explicit test_temp_directory(const string_view testName) : directoryPath(get_new_test_directory(testName)) {
58+
explicit test_temp_directory(const string_view testName) : directoryPath(get_test_directory(testName)) {
59+
error_code ec;
6060
remove_all(directoryPath, ec);
6161
if (ec) {
6262
wcerr << L"Warning, couldn't clean up " << directoryPath << L" before test.\n";
@@ -68,7 +68,11 @@ struct test_temp_directory {
6868
}
6969
}
7070

71+
test_temp_directory(const test_temp_directory&) = delete;
72+
test_temp_directory& operator=(const test_temp_directory&) = delete;
73+
7174
~test_temp_directory() noexcept {
75+
error_code ec;
7276
remove_all(directoryPath, ec);
7377
if (ec) {
7478
wcerr << L"Warning, couldn't clean up " << directoryPath << L" after test.\n";
@@ -1420,8 +1424,8 @@ void test_recursive_directory_iterator() {
14201424
test_directory_iterator_common_parts<recursive_directory_iterator>("recursive_directory_iterator"sv);
14211425

14221426
{
1423-
const test_temp_directory recursiveTests("recursive_directory_iterator specific"sv);
1424-
create_file_containing(recursiveTests.directoryPath / L"a.txt"sv, L"hello");
1427+
const test_temp_directory tempDir("recursive_directory_iterator-specific"sv);
1428+
create_file_containing(tempDir.directoryPath / L"a.txt"sv, L"hello");
14251429

14261430
// _NODISCARD directory_options options() const;
14271431
// _NODISCARD int depth() const;
@@ -1430,19 +1434,19 @@ void test_recursive_directory_iterator() {
14301434
// void disable_recursion_pending();
14311435
{
14321436
error_code ec;
1433-
recursive_directory_iterator good_dir(recursiveTests.directoryPath, directory_options::none, ec);
1437+
recursive_directory_iterator good_dir(tempDir.directoryPath, directory_options::none, ec);
14341438
if (!EXPECT(good(ec))) {
14351439
return;
14361440
}
14371441

14381442
EXPECT(good_dir.options() == directory_options::none);
14391443

14401444
recursive_directory_iterator good_dir2(
1441-
recursiveTests.directoryPath, directory_options::skip_permission_denied, ec);
1445+
tempDir.directoryPath, directory_options::skip_permission_denied, ec);
14421446
EXPECT(good_dir2.options() == directory_options::skip_permission_denied);
14431447

14441448
recursive_directory_iterator good_dir3(
1445-
recursiveTests.directoryPath, directory_options::follow_directory_symlink, ec);
1449+
tempDir.directoryPath, directory_options::follow_directory_symlink, ec);
14461450
EXPECT(good_dir3.options() == directory_options::follow_directory_symlink);
14471451

14481452
EXPECT(good_dir.depth() == 0);
@@ -1461,7 +1465,7 @@ void test_recursive_directory_iterator() {
14611465

14621466
// void pop();
14631467
{
1464-
recursive_directory_iterator good_dir(recursiveTests.directoryPath, directory_options::none);
1468+
recursive_directory_iterator good_dir(tempDir.directoryPath, directory_options::none);
14651469
good_dir.pop();
14661470
EXPECT(good_dir == recursive_directory_iterator{});
14671471
}
@@ -1481,10 +1485,10 @@ void test_recursive_directory_iterator() {
14811485

14821486
// Also test VSO-649431 <filesystem> follow_directory_symlinks with a broken symlink causes iteration to break
14831487
{
1484-
const test_temp_directory followSymlinkTests("recursive_directory_iterator_VSO-649431"sv);
1485-
const path aaa = followSymlinkTests.directoryPath / L"aaa"sv;
1486-
const path bbb = followSymlinkTests.directoryPath / L"bbb"sv;
1487-
const path ccc = followSymlinkTests.directoryPath / L"ccc"sv;
1488+
const test_temp_directory tempDir("recursive_directory_iterator-VSO-649431"sv);
1489+
const path aaa = tempDir.directoryPath / L"aaa"sv;
1490+
const path bbb = tempDir.directoryPath / L"bbb"sv;
1491+
const path ccc = tempDir.directoryPath / L"ccc"sv;
14881492
error_code ec;
14891493
create_directory_symlink(nonexistentPaths[0], bbb, ec);
14901494
if (ec) {
@@ -1496,7 +1500,7 @@ void test_recursive_directory_iterator() {
14961500
directory_options::follow_directory_symlink, directory_options::skip_permission_denied,
14971501
directory_options::follow_directory_symlink | directory_options::skip_permission_denied};
14981502
for (const auto& option : options) {
1499-
recursive_directory_iterator first(followSymlinkTests.directoryPath, option);
1503+
recursive_directory_iterator first(tempDir.directoryPath, option);
15001504
assert(first != recursive_directory_iterator{});
15011505
EXPECT(first->is_directory());
15021506
EXPECT(!first->is_symlink());
@@ -2883,7 +2887,7 @@ void test_invalid_conversions() {
28832887
}
28842888

28852889
void test_status() {
2886-
const test_temp_directory tempDir("test_status"sv);
2890+
const test_temp_directory tempDir("status"sv);
28872891
const path& testDir = tempDir.directoryPath;
28882892
const path testFile(testDir / L"test_file"sv);
28892893
const path testLink(testDir / L"test_link"sv);
@@ -3328,9 +3332,9 @@ void test_rename() {
33283332
const path fileA(tempDir.directoryPath / L"filea.txt"sv);
33293333
const path fileB(tempDir.directoryPath / L"fileb.txt"sv);
33303334

3331-
create_directories(dir.native(), ec);
3335+
create_directories(dir, ec);
33323336
EXPECT(good(ec));
3333-
create_directory(otherDir.native(), ec);
3337+
create_directory(otherDir, ec);
33343338
EXPECT(good(ec));
33353339
create_file_containing(fileA, L"hello");
33363340
create_file_containing(fileB, L"world");
@@ -3342,15 +3346,26 @@ void test_rename() {
33423346
EXPECT(good(ec));
33433347
EXPECT(read_file_contents(fileA) == L"hello");
33443348

3349+
#ifndef _MSVC_INTERNAL_TESTING // TRANSITION, skip this for all MSVC-internal test runs.
3350+
// As of 2024-05-09, these rename() tests sporadically fail in MSVC-internal private test runs with
3351+
// "Access is denied" error codes. We've never observed such failures in MSVC-internal PR/CI checks,
3352+
// MSVC-internal local test runs, GitHub PR/CI checks, or GitHub local test runs. There's no significant
3353+
// compiler interaction here, so we can live with GitHub-only test coverage. Although we don't know the
3354+
// root cause, we suspect that this is related to the physical machines that are used for MSVC-internal
3355+
// private test runs, so we should check whether they've been replaced in a year or two.
3356+
33453357
// If new_p resolves to an existing non-directory file, new_p is removed
33463358
rename(fileA, fileB, ec);
33473359
EXPECT(good(ec));
3348-
EXPECT(!exists(fileA.native()));
3360+
EXPECT(!exists(fileA));
33493361
EXPECT(read_file_contents(fileB) == L"hello");
33503362

33513363
// Standard rename where target doesn't exist
3352-
rename(fileB, fileA);
3364+
rename(fileB, fileA, ec);
3365+
EXPECT(good(ec));
3366+
EXPECT(!exists(fileB));
33533367
EXPECT(read_file_contents(fileA) == L"hello");
3368+
#endif // ^^^ no workaround ^^^
33543369

33553370
// Bad cases
33563371
EXPECT(throws_filesystem_error([&] { rename(dir, otherDir); }, "rename", dir, otherDir));
@@ -3364,7 +3379,7 @@ void test_space() {
33643379
const path file(dir / L"test_space_file.txt"sv);
33653380

33663381
error_code ec;
3367-
create_directory(dir.native(), ec);
3382+
create_directory(dir, ec);
33683383
EXPECT(good(ec));
33693384
create_file_containing(file, L"hello");
33703385

@@ -3643,7 +3658,7 @@ void test_create_directory() {
36433658
}
36443659

36453660
void test_create_dirs_and_remove_all() {
3646-
const test_temp_directory tempDir("create_dirs_and_remove_all"sv);
3661+
const test_temp_directory tempDir("create_directories-and-remove_all"sv);
36473662
const path& r = tempDir.directoryPath;
36483663

36493664
// test long path support

tests/std/tests/VSO_0000000_path_stream_parameter/test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ int main() {
1818
error_code ec;
1919

2020
{
21-
const auto testDir = get_test_directory("path_stream_parameter");
21+
const auto testDir = get_experimental_test_directory("path_stream_parameter");
2222
fs::create_directories(testDir, ec);
2323
assert(!ec);
2424

@@ -81,7 +81,7 @@ int main() {
8181

8282
#if _HAS_CXX17
8383
{
84-
const auto testDir = get_new_test_directory("path_stream_parameter");
84+
const auto testDir = get_test_directory("path_stream_parameter");
8585
fs::create_directories(testDir.native(), ec);
8686
assert(!ec);
8787

tests/tr1/include/temp_file_name.h

Lines changed: 0 additions & 21 deletions
This file was deleted.

tests/tr1/tests/cstdio/test.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
#define TEST_NAMEX "<cstdio>"
66

77
#include "tdefs.h"
8-
#include "temp_file_name.h"
98
#include <assert.h>
109
#include <cstdio>
1110
#include <errno.h>
1211
#include <stdarg.h>
1312
#include <string.h>
1413

14+
#include <temp_file_name.hpp>
15+
1516
#undef clearerr // tested in stdio2.c
1617
#undef feof
1718
#undef ferror

tests/tr1/tests/cwchar1/test.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
#define TEST_NAMEX "<cwchar>, part 1"
66

77
#include "tdefs.h"
8-
#include "temp_file_name.h"
98
#include <assert.h>
109
#include <cwchar>
1110
#include <stdarg.h>
1211
#include <stdlib.h>
1312
#include <string.h>
1413

14+
#include <temp_file_name.hpp>
15+
1516
#pragma warning(disable : 4793) // function compiled as native
1617

1718

tests/tr1/tests/fstream1/test.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
#define TEST_NAME "<fstream>, part 1"
66

77
#include "tdefs.h"
8-
#include "temp_file_name.h"
98
#include <assert.h>
109
#include <fstream>
1110
#include <string>
1211

12+
#include <temp_file_name.hpp>
13+
1314
void test_main() { // test basic workings of char fstream definitions
1415
STD string tn_str = temp_file_name();
1516
const char* tn = tn_str.c_str();

tests/tr1/tests/fstream2/test.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
#define TEST_NAME "<fstream>, part 2"
66

77
#include "tdefs.h"
8-
#include "temp_file_name.h"
98
#include <assert.h>
109
#include <fstream>
1110
#include <wchar.h>
1211

12+
#include <temp_file_name.hpp>
13+
1314
void test_main() { // test basic workings of wide fstream definitions
1415
const auto temp_name = temp_file_name();
1516
const char* tn = temp_name.c_str();

0 commit comments

Comments
 (0)