1 // -*- C++ -*- 2 // Filesystem utils for the C++ library testsuite. 3 // 4 // Copyright (C) 2014-2016 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 <fstream> 27 #include <string> 28 #include <cstdio> 29 #include <stdlib.h> 30 #include <unistd.h> 31 32 namespace __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 compare_paths(const std::experimental::filesystem::path & p1,const std::experimental::filesystem::path & p2)40 compare_paths(const std::experimental::filesystem::path& p1, 41 const std::experimental::filesystem::path& p2) 42 { 43 PATH_CHK( p1, p2, string ); 44 PATH_CHK( p1, p2, empty ); 45 PATH_CHK( p1, p2, has_root_path ); 46 PATH_CHK( p1, p2, has_root_name ); 47 PATH_CHK( p1, p2, has_root_directory ); 48 PATH_CHK( p1, p2, has_relative_path ); 49 PATH_CHK( p1, p2, has_parent_path ); 50 PATH_CHK( p1, p2, has_filename ); 51 PATH_CHK( p1, p2, has_stem ); 52 PATH_CHK( p1, p2, has_extension ); 53 PATH_CHK( p1, p2, is_absolute ); 54 PATH_CHK( p1, p2, is_relative ); 55 auto d1 = std::distance(p1.begin(), p1.end()); 56 auto d2 = std::distance(p2.begin(), p2.end()); 57 if( d1 != d2 ) 58 throw std::experimental::filesystem::filesystem_error( 59 "distance(begin, end)", p1, p2, 60 std::make_error_code(std::errc::invalid_argument) ); 61 } 62 63 const std::string test_paths[] = { 64 "", "/", "//", "/.", "/./", "/a", "/a/", "/a//", "/a/b/c/d", "/a//b", 65 "a", "a/b", "a/b/", "a/b/c", "a/b/c.d", "a/b/..", "a/b/c.", "a/b/.c" 66 }; 67 68 // This is NOT supposed to be a secure way to get a unique name! 69 // We just need a path that doesn't exist for testing purposes. 70 std::experimental::filesystem::path nonexistent_path()71 nonexistent_path() 72 { 73 std::experimental::filesystem::path p; 74 #if defined(_GNU_SOURCE) || _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L 75 char tmp[] = "filesystem-ts-test.XXXXXX"; 76 int fd = ::mkstemp(tmp); 77 if (fd == -1) 78 throw std::experimental::filesystem::filesystem_error("mkstemp failed", 79 std::error_code(errno, std::generic_category())); 80 ::unlink(tmp); 81 ::close(fd); 82 p = tmp; 83 #else 84 char buf[64]; 85 static int counter; 86 #if _GLIBCXX_USE_C99_STDIO 87 std::snprintf(buf, 64, 88 #else 89 std::sprintf(buf, 90 #endif 91 "filesystem-ts-test.%d.%lu", counter++, (unsigned long) ::getpid()); 92 p = buf; 93 #endif 94 return p; 95 } 96 97 // RAII helper to remove a file on scope exit. 98 struct scoped_file 99 { 100 using path_type = std::experimental::filesystem::path; 101 102 enum adopt_file_t { adopt_file }; 103 104 explicit pathscoped_file105 scoped_file(const path_type& p = nonexistent_path()) : path(p) 106 { std::ofstream{p.native()}; } 107 scoped_filescoped_file108 scoped_file(path_type p, adopt_file_t) : path(p) { } 109 ~scoped_filescoped_file110 ~scoped_file() { if (!path.empty()) remove(path); } 111 112 path_type path; 113 }; 114 115 } // namespace __gnu_test 116 #endif 117