1// -*- C++ -*-
2// Filesystem utils for the C++ library testsuite.
3//
4// Copyright (C) 2014-2015 Free Software Foundation, Inc.
5//
6// This file is part of the GNU ISO C++ Library.  This library is free
7// software; you can redistribute it and/or modify it under the
8// terms of the GNU General Public License as published by the
9// Free Software Foundation; either version 3, or (at your option)
10// any later version.
11//
12// This library is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License along
18// with this library; see the file COPYING3.  If not see
19// <http://www.gnu.org/licenses/>.
20//
21
22#ifndef _TESTSUITE_FS_H
23#define _TESTSUITE_FS_H 1
24
25#include <experimental/filesystem>
26#include <iostream>
27#include <string>
28#include <cstdio>
29#include <stdlib.h>
30#include <unistd.h>
31
32namespace __gnu_test
33{
34#define PATH_CHK(p1, p2, fn) \
35    if ( p1.fn() != p2.fn() ) \
36      throw std::experimental::filesystem::filesystem_error( #fn, p1, p2, \
37	  std::make_error_code(std::errc::invalid_argument) )
38
39  void
40  compare_paths(const std::experimental::filesystem::path& p1,
41		const std::experimental::filesystem::path& p2)
42  {
43    // std::cout << "Comparing " << p1 << " and " << p2 << std::endl;
44    PATH_CHK( p1, p2, string );
45    PATH_CHK( p1, p2, empty );
46    PATH_CHK( p1, p2, has_root_path );
47    PATH_CHK( p1, p2, has_root_name );
48    PATH_CHK( p1, p2, has_root_directory );
49    PATH_CHK( p1, p2, has_relative_path );
50    PATH_CHK( p1, p2, has_parent_path );
51    PATH_CHK( p1, p2, has_filename );
52    PATH_CHK( p1, p2, has_stem );
53    PATH_CHK( p1, p2, has_extension );
54    PATH_CHK( p1, p2, is_absolute );
55    PATH_CHK( p1, p2, is_relative );
56    auto d1 = std::distance(p1.begin(), p1.end());
57    auto d2 = std::distance(p2.begin(), p2.end());
58    if( d1 != d2 )
59      throw std::experimental::filesystem::filesystem_error(
60	  "distance(begin, end)", p1, p2,
61	  std::make_error_code(std::errc::invalid_argument) );
62  }
63
64  const std::string test_paths[] = {
65    "", "/", "//", "/.", "/./", "/a", "/a/", "/a//", "/a/b/c/d", "/a//b",
66    "a", "a/b", "a/b/", "a/b/c", "a/b/c.d", "a/b/..", "a/b/c.", "a/b/.c"
67  };
68
69  // This is NOT supposed to be a secure way to get a unique name!
70  // We just need a path that doesn't exist for testing purposes.
71  std::experimental::filesystem::path
72  nonexistent_path()
73  {
74    std::experimental::filesystem::path p;
75#if defined(_GNU_SOURCE) || _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L
76    char tmp[] = "test.XXXXXX";
77    int fd = ::mkstemp(tmp);
78    if (fd == -1)
79      throw std::experimental::filesystem::filesystem_error("mkstemp failed",
80	  std::error_code(errno, std::generic_category()));
81    ::unlink(tmp);
82    ::close(fd);
83    p = tmp;
84#else
85    char buf[64];
86    static int counter;
87    std::sprintf(buf, "filesystem-ts-test.%d.%lu", counter++,
88		 (unsigned long) ::getpid());
89    p = buf;
90#endif
91    return p;
92  }
93
94} // namespace __gnu_test
95#endif
96