@@ -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