On Thu, 29 Jan 2026 at 02:09, Adam Wood <[email protected]> wrote:
>
> Adds tests for std::filesystem::copy_symlink.
>
> Tested on x86_64-pc-linux-gnu.
>
> libstdc++-v3/Changelog:
>
>         PR libstdc++/122217
>         * testsuite/27_io/filesystem/operations/copy_symlink/1.cc: New test.
>         * testsuite/27_io/filesystem/operations/copy_symlink/2.cc: New test.
>         * testsuite/27_io/filesystem/operations/copy_symlink/3.cc: New test.
>         * testsuite/27_io/filesystem/operations/copy_symlink/4.cc: New test.
> ---
>  .../filesystem/operations/copy_symlink/1.cc   | 63 +++++++++++++++++++
>  .../filesystem/operations/copy_symlink/2.cc   | 43 +++++++++++++
>  .../filesystem/operations/copy_symlink/3.cc   | 47 ++++++++++++++
>  .../filesystem/operations/copy_symlink/4.cc   | 44 +++++++++++++
>  4 files changed, 197 insertions(+)
>  create mode 100644 
> libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/1.cc
>  create mode 100644 
> libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/2.cc
>  create mode 100644 
> libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/3.cc
>  create mode 100644 
> libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/4.cc
>
> diff --git 
> a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/1.cc 
> b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/1.cc
> new file mode 100644
> index 00000000000..e04b2672e6d
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/1.cc
> @@ -0,0 +1,63 @@
> +// { dg-do run { target c++17 } }
> +// { dg-require-filesystem-ts "" }
> +
> +#include <filesystem>
> +#include <testsuite_hooks.h>
> +#include <testsuite_fs.h>
> +
> +// Test successful copies
> +
> +namespace fs = std::filesystem;
> +
> +void
> +test_successful_copy(const fs::path& p,
> +                    bool (*is_some_file_type)(const fs::path&))

Using a function pointer to the is_directory function isn't guaranteed
to work, due to:
https://eel.is/c++draft/namespace.std#6.sentence-2

But it's OK for the testsuite.

I've pushed this to trunk - thanks!


> +{
> +  const std::error_code bad_ec = 
> make_error_code(std::errc::invalid_argument);
> +  std::error_code ec;
> +
> +  auto to1 = read_symlink(p);
> +
> +  auto p2 = __gnu_test::nonexistent_path();
> +  ec = bad_ec;
> +  copy_symlink(p, p2, ec);
> +  VERIFY( !ec );
> +  VERIFY( exists(symlink_status(p2)) );
> +  VERIFY( is_symlink(p2) );
> +  VERIFY( is_some_file_type(p2) );
> +  auto to2 = read_symlink(p2);
> +  VERIFY( to1 == to2 );
> +
> +  // Copy again without ec
> +  remove(p2);
> +  copy_symlink(p, p2);
> +  VERIFY( exists(symlink_status(p2)) );
> +  VERIFY( is_symlink(p2) );
> +  VERIFY( is_some_file_type(p2) );
> +  to2 = read_symlink(p2);
> +  VERIFY( to1 == to2 );
> +
> +  remove(p);
> +  remove(p2);
> +}
> +
> +void
> +test01()
> +{
> +  __gnu_test::scoped_file f;
> +  auto p = __gnu_test::nonexistent_path();
> +  create_symlink(f.path, p);
> +  test_successful_copy(p, fs::is_regular_file);
> +
> +  auto dir = __gnu_test::nonexistent_path();
> +  create_directory(dir);
> +  create_directory_symlink(dir, p);
> +  test_successful_copy(p, fs::is_directory);
> +  remove_all(dir);
> +}
> +
> +int
> +main()
> +{
> +  test01();
> +}
> diff --git 
> a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/2.cc 
> b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/2.cc
> new file mode 100644
> index 00000000000..27caf4a1d4a
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/2.cc
> @@ -0,0 +1,43 @@
> +// { dg-do run { target c++17 } }
> +// { dg-require-filesystem-ts "" }
> +
> +#include <filesystem>
> +#include <testsuite_hooks.h>
> +#include <testsuite_fs.h>
> +
> +// Test copying into an existing file
> +
> +void
> +test01()
> +{
> +  std::error_code ec, ec2;
> +  __gnu_test::scoped_file f, f2;
> +
> +  auto p = __gnu_test::nonexistent_path();
> +  create_symlink(f.path, p);
> +
> +  copy_symlink(p, f2.path, ec);
> +  VERIFY( ec );
> +  VERIFY( !is_symlink(f2.path) );
> +
> +  try
> +    {
> +      copy_symlink(p, f2.path);
> +    }
> +  catch (const std::filesystem::filesystem_error& ex)
> +    {
> +      ec2 = ex.code();
> +      VERIFY( ex.path1() == p );
> +      VERIFY( ex.path2() == f2.path );
> +    }
> +  VERIFY( ec2 == ec );
> +  VERIFY( !is_symlink(f2.path) );
> +
> +  remove(p);
> +}
> +
> +int
> +main()
> +{
> +  test01();
> +}
> diff --git 
> a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/3.cc 
> b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/3.cc
> new file mode 100644
> index 00000000000..13e9dad20fc
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/3.cc
> @@ -0,0 +1,47 @@
> +// { dg-do run { target c++17 } }
> +// { dg-require-filesystem-ts "" }
> +
> +#include <filesystem>
> +#include <testsuite_hooks.h>
> +#include <testsuite_fs.h>
> +
> +// Test copying from a non-symlink
> +
> +namespace fs = std::filesystem;
> +
> +void
> +test_copy_from_non_symlink(const fs::path& from)
> +{
> +  std::error_code ec, ec2;
> +  auto p = __gnu_test::nonexistent_path();
> +  copy_symlink(from, p, ec);
> +  VERIFY( ec );
> +  VERIFY( !is_symlink(p) );
> +
> +  try
> +    {
> +      copy_symlink(from, p);
> +    }
> +  catch (const fs::filesystem_error& ex)
> +    {
> +      ec2 = ex.code();
> +      VERIFY( ex.path1() == from );
> +      VERIFY( ex.path2() == p );
> +    }
> +  VERIFY( ec2 == ec );
> +  VERIFY( !is_symlink(p) );
> +}
> +
> +void
> +test01()
> +{
> +  __gnu_test::scoped_file f;
> +  test_copy_from_non_symlink(f.path);
> +  test_copy_from_non_symlink(__gnu_test::nonexistent_path());
> +}
> +
> +int
> +main()
> +{
> +  test01();
> +}
> diff --git 
> a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/4.cc 
> b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/4.cc
> new file mode 100644
> index 00000000000..2e4f300194b
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/4.cc
> @@ -0,0 +1,44 @@
> +// { dg-do run { target c++17 } }
> +// { dg-require-filesystem-ts "" }
> +
> +#include <filesystem>
> +#include <testsuite_hooks.h>
> +#include <testsuite_fs.h>
> +
> +// Test copying into an empty path
> +
> +namespace fs = std::filesystem;
> +
> +void
> +test01()
> +{
> +  std::error_code ec, ec2;
> +  __gnu_test::scoped_file f, f2;
> +
> +  auto p = __gnu_test::nonexistent_path();
> +  create_symlink(f.path, p);
> +
> +  fs::path empty;
> +  copy_symlink(p, empty, ec);
> +  VERIFY( ec );
> +
> +  try
> +    {
> +      copy_symlink(p, empty);
> +    }
> +  catch (const std::filesystem::filesystem_error& ex)
> +    {
> +      ec2 = ex.code();
> +      VERIFY( ex.path1() == p );
> +      VERIFY( ex.path2() == empty );
> +    }
> +  VERIFY( ec2 == ec );
> +
> +  remove(p);
> +}
> +
> +int
> +main()
> +{
> +  test01();
> +}
> --
> 2.52.0
>

Reply via email to