Skip to content

Commit 116ba71

Browse files
committed
Add filesystem semantic edge coverage
1 parent 66af2af commit 116ba71

4 files changed

Lines changed: 126 additions & 8 deletions

File tree

docs/feature-coverage.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,10 @@ are tracked in the [cppreference attribution note](./cppreference-attribution.md
372372
[(cppreference example)](../test/cmake/driver/src/cpp/stl/filesystem.cpp)
373373
- [x] [std::filesystem::canonical / weakly_canonical](https://en.cppreference.com/w/cpp/filesystem/canonical)
374374
[(cppreference example)](../test/cmake/driver/src/cpp/stl/filesystem.cpp)
375+
- [x] `std::filesystem` semantic edge checks
376+
- Error-code overloads, metadata refresh after file changes, and recursive
377+
traversal pruning are covered by driver semantic tests.
378+
[(driver semantic test)](../test/cmake/driver/src/cpp/stl/filesystem.cpp)
375379
- [x] [std::string](https://en.cppreference.com/w/cpp/string/basic_string)
376380
[(cppreference example)](../test/cmake/driver/src/cpp/stl/string.cpp)
377381
- [x] String member operations:
@@ -560,10 +564,6 @@ semantics beyond the simple standalone examples.
560564
- Timed shared-lock behavior.
561565
- Additional `std::future` / `std::shared_future` error-path and timeout
562566
behavior.
563-
- [ ] Filesystem edge coverage
564-
- More error-code overloads, metadata transitions, recursive traversal
565-
options, and negative-path behavior for already-covered filesystem
566-
operations.
567567

568568
### Needs Investigation
569569

docs/ko-kr-feature-coverage.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,10 @@ cppreference Example 코드를 이식한 항목은
371371
[(cppreference example)](../test/cmake/driver/src/cpp/stl/filesystem.cpp)
372372
- [x] [std::filesystem::canonical / weakly_canonical](https://en.cppreference.com/w/cpp/filesystem/canonical)
373373
[(cppreference example)](../test/cmake/driver/src/cpp/stl/filesystem.cpp)
374+
- [x] `std::filesystem` semantic edge check
375+
- Error-code overload, file 변경 후 metadata refresh, recursive traversal
376+
pruning은 driver semantic test로 검증합니다.
377+
[(driver semantic test)](../test/cmake/driver/src/cpp/stl/filesystem.cpp)
374378
- [x] [std::string](https://en.cppreference.com/w/cpp/string/basic_string)
375379
[(cppreference example)](../test/cmake/driver/src/cpp/stl/string.cpp)
376380
- [x] String member operation:
@@ -558,10 +562,6 @@ standalone 예제보다 더 넓은 driver-runtime error path나 timing-sensitive
558562
- [ ] Threading 및 synchronization
559563
- timed shared-lock 동작
560564
- `std::future` / `std::shared_future` error-path 및 timeout 동작
561-
- [ ] Filesystem edge coverage
562-
- 이미 coverage된 filesystem operation의 error-code overload,
563-
metadata transition, recursive traversal option, negative-path 동작
564-
보강
565565

566566
### 추가 조사가 필요한 후보
567567

test/cmake/driver/src/all.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,9 @@ void run();
352352
namespace filesystem_canonical_test {
353353
void run();
354354
}
355+
namespace filesystem_semantic_edge_test {
356+
void run();
357+
}
355358
namespace forward_list_insert_after_test {
356359
void run();
357360
}
@@ -688,6 +691,12 @@ template <typename Fn> void run_cppreference_test(const char *name, Fn fn) {
688691
fn();
689692
std::cout << "[crtsys] PASS " << name << '\n';
690693
}
694+
695+
template <typename Fn> void run_driver_semantic_test(const char *name, Fn fn) {
696+
std::cout << "\n[crtsys] RUN " << name << " (driver semantic)\n";
697+
fn();
698+
std::cout << "[crtsys] PASS " << name << '\n';
699+
}
691700
} // namespace
692701

693702
#define CRTSYS_RUN_CPPREFERENCE_TEST(test_namespace) \
@@ -697,6 +706,9 @@ template <typename Fn> void run_cppreference_test(const char *name, Fn fn) {
697706
run_cppreference_test(#test_namespace, \
698707
[] { ntl::expand_stack(test_namespace::run); })
699708

709+
#define CRTSYS_RUN_DRIVER_SEMANTIC_TEST(test_namespace) \
710+
run_driver_semantic_test(#test_namespace, [] { test_namespace::run(); })
711+
700712
//
701713
// C++ Standard tests.
702714
//
@@ -834,6 +846,7 @@ void cpp_std_tests() {
834846
CRTSYS_RUN_CPPREFERENCE_TEST(filesystem_relative_test);
835847
CRTSYS_RUN_CPPREFERENCE_TEST(filesystem_last_write_time_test);
836848
CRTSYS_RUN_CPPREFERENCE_TEST(filesystem_canonical_test);
849+
CRTSYS_RUN_DRIVER_SEMANTIC_TEST(filesystem_semantic_edge_test);
837850
CRTSYS_RUN_CPPREFERENCE_TEST(sort_test);
838851
CRTSYS_RUN_CPPREFERENCE_TEST(find_test);
839852
CRTSYS_RUN_CPPREFERENCE_TEST(transform_test);

test/cmake/driver/src/cpp/stl/filesystem.cpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,3 +638,108 @@ void run() {
638638
std::cout << "Deleted " << count << " files or directories.\n";
639639
}
640640
} // namespace filesystem_canonical_test
641+
642+
namespace filesystem_semantic_edge_test {
643+
void run() {
644+
const fs::path sandbox{"sandbox"};
645+
remove_sandbox(sandbox);
646+
647+
const bool created_sandbox = fs::create_directory(sandbox);
648+
(void)created_sandbox;
649+
assert(created_sandbox);
650+
651+
std::error_code ec;
652+
const fs::path missing = sandbox / "missing.txt";
653+
const fs::path target = sandbox / "target.txt";
654+
655+
const bool copied_missing = fs::copy_file(missing, target, ec);
656+
(void)copied_missing;
657+
assert(!copied_missing);
658+
assert(ec);
659+
660+
bool caught_copy_error{};
661+
try {
662+
fs::copy_file(missing, target);
663+
} catch (const fs::filesystem_error &ex) {
664+
caught_copy_error = true;
665+
assert(ex.code());
666+
std::cout << "copy_file missing source reported: " << ex.what() << '\n';
667+
}
668+
assert(caught_copy_error);
669+
// Release builds compile out assert(), so mark assert-only locals as used.
670+
(void)caught_copy_error;
671+
672+
ec.clear();
673+
fs::rename(missing, target, ec);
674+
assert(ec);
675+
676+
ec.clear();
677+
const bool removed_missing = fs::remove(missing, ec);
678+
(void)removed_missing;
679+
assert(!ec);
680+
assert(!removed_missing);
681+
682+
const fs::path metadata_file = sandbox / "metadata.txt";
683+
std::ofstream(metadata_file) << "ab";
684+
fs::directory_entry entry{metadata_file};
685+
assert(entry.exists());
686+
assert(entry.is_regular_file());
687+
assert(entry.file_size() == 2);
688+
689+
fs::resize_file(metadata_file, 5, ec);
690+
assert(!ec);
691+
entry.refresh(ec);
692+
assert(!ec);
693+
assert(entry.file_size() == 5);
694+
695+
fs::remove(metadata_file, ec);
696+
assert(!ec);
697+
entry.refresh(ec);
698+
assert(!entry.exists());
699+
700+
fs::create_directories(sandbox / "a" / "b");
701+
fs::create_directory(sandbox / "c");
702+
std::ofstream(sandbox / "root.txt").put('r');
703+
std::ofstream(sandbox / "a" / "one.txt").put('1');
704+
std::ofstream(sandbox / "a" / "b" / "two.txt").put('2');
705+
std::ofstream(sandbox / "c" / "three.txt").put('3');
706+
707+
std::uintmax_t full_recursive_entries{};
708+
for (auto it = fs::recursive_directory_iterator{sandbox};
709+
it != fs::recursive_directory_iterator{}; ++it) {
710+
++full_recursive_entries;
711+
}
712+
assert(full_recursive_entries == 7);
713+
// Release builds compile out assert(), so mark assert-only locals as used.
714+
(void)full_recursive_entries;
715+
716+
bool saw_pruned_dir{};
717+
bool saw_pruned_child{};
718+
bool saw_sibling_child{};
719+
std::uintmax_t pruned_recursive_entries{};
720+
for (auto it = fs::recursive_directory_iterator{sandbox};
721+
it != fs::recursive_directory_iterator{}; ++it) {
722+
if (it->path().filename() == "a") {
723+
saw_pruned_dir = true;
724+
it.disable_recursion_pending();
725+
}
726+
saw_pruned_child = saw_pruned_child || it->path().filename() == "two.txt";
727+
saw_sibling_child =
728+
saw_sibling_child || it->path().filename() == "three.txt";
729+
++pruned_recursive_entries;
730+
}
731+
732+
assert(saw_pruned_dir);
733+
assert(!saw_pruned_child);
734+
assert(saw_sibling_child);
735+
assert(pruned_recursive_entries == 4);
736+
// Release builds compile out assert(), so mark assert-only locals as used.
737+
(void)saw_pruned_dir;
738+
(void)saw_pruned_child;
739+
(void)saw_sibling_child;
740+
(void)pruned_recursive_entries;
741+
742+
remove_sandbox(sandbox);
743+
std::cout << "filesystem semantic edge assertions passed\n";
744+
}
745+
} // namespace filesystem_semantic_edge_test

0 commit comments

Comments
 (0)