Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/libs/filesystem/test/operations_test.cpp @ 12

Last change on this file since 12 was 12, checked in by landauf, 17 years ago

added boost

File size: 18.4 KB
Line 
1//  Boost operations_test.cpp  -----------------------------------------------//
2
3//  Copyright Beman Dawes 2002.
4//  Use, modification, and distribution is subject to the Boost Software
5//  License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6//  http://www.boost.org/LICENSE_1_0.txt)
7
8//  See library home page at http://www.boost.org/libs/filesystem
9
10#include <boost/filesystem/operations.hpp>
11#include <boost/filesystem/exception.hpp>
12namespace fs = boost::filesystem;
13
14#include <boost/config.hpp>
15#include <boost/test/minimal.hpp>
16#include <boost/concept_check.hpp>
17#include <boost/bind.hpp>
18using boost::bind;
19
20#include <fstream>
21#include <iostream>
22#include <string>
23#include <cerrno>
24#include <ctime>
25
26# ifdef BOOST_NO_STDC_NAMESPACE
27    namespace std { using ::asctime; using ::gmtime; using ::localtime;
28    using ::difftime; using ::time; using ::tm; using ::mktime; }
29# endif
30
31namespace
32{
33  bool report_throws;
34  fs::directory_iterator end_itr;
35
36  void create_file( const fs::path & ph, const std::string & contents )
37  {
38    std::ofstream f( ph.native_file_string().c_str() );
39    if ( !f )
40      throw fs::filesystem_error( "operations_test create_file",
41        ph, errno );
42    if ( !contents.empty() ) f << contents;
43  }
44
45  void verify_file( const fs::path & ph, const std::string & expected )
46  {
47    std::ifstream f( ph.native_file_string().c_str() );
48    if ( !f )
49      throw fs::filesystem_error( "operations_test verify_file",
50        ph, errno );
51    std::string contents;
52    f >> contents;
53    if ( contents != expected )
54      throw fs::filesystem_error( "operations_test verify_file",
55        ph, " contents \"" + contents
56        + "\" != \"" + expected + "\"" );
57  }
58
59  template< typename F >
60    bool throws_fs_error( F func, fs::error_code ec =
61      ::boost::filesystem::no_error ) // VC++ 7.1 build 2292 won't accept fs::
62  {
63    try { func(); }
64
65    catch ( const fs::filesystem_error & ex )
66    {
67      if ( report_throws ) std::cout << ex.what() << "\n";
68      if ( ec == fs::no_error || ec == ex.error() ) return true;
69      std::cout << "filesystem_error::error() reports " << ex.error()
70        << ", should be " << ec
71        << "\n native_error() is " << ex.native_error()
72        << std::endl;
73    }
74    return false;
75  }
76
77} // unnamed namespace
78
79//  test_main  ---------------------------------------------------------------//
80
81int test_main( int argc, char * argv[] )
82{
83  if ( argc > 1 && *argv[1]=='-' && *(argv[1]+1)=='t' ) report_throws = true;
84
85  std::string platform( BOOST_PLATFORM );
86
87  // The choice of platform is make at runtime rather than compile-time
88  // so that compile errors for all platforms will be detected even though
89  // only the current platform is runtime tested.
90# if defined( BOOST_POSIX )
91    platform = "POSIX";
92# elif defined( BOOST_WINDOWS )
93    platform = "Windows";
94# else
95    platform = ( platform == "Win32" || platform == "Win64" || platform == "Cygwin" )
96               ? "Windows"
97               : "POSIX";
98# endif
99  std::cout << "Platform is " << platform << '\n';
100
101  std::cout << "initial_path().string() is\n  \""
102            << fs::initial_path().string()
103            << "\"\n";
104  std::cout << "initial_path().native_file_string() is\n  \""
105            << fs::initial_path().native_file_string()
106            << "\"\n";
107
108  BOOST_CHECK( fs::initial_path().is_complete() );
109  BOOST_CHECK( fs::current_path().is_complete() );
110  BOOST_CHECK( fs::initial_path().string() == fs::current_path().string() );
111
112  BOOST_CHECK( fs::complete( "" ).empty() );
113  BOOST_CHECK( fs::complete( "/" ).string()
114    == fs::initial_path().root_path().string() );
115  BOOST_CHECK( fs::complete( "foo" ).string()
116    == fs::initial_path().string()+"/foo" );
117  BOOST_CHECK( fs::complete( "/foo" ).string()
118    == fs::initial_path().root_path().string()+"foo" );
119
120  fs::path dir(  fs::initial_path() / "temp_fs_test_directory" );
121 
122  // Windows only tests
123  if ( platform == "Windows" )
124  {
125    BOOST_CHECK( !fs::exists( fs::path( "//share-not/foo", fs::native ) ) );
126    BOOST_CHECK( dir.string().size() > 1
127      && dir.string()[1] == ':' ); // verify path includes drive
128
129    BOOST_CHECK( fs::system_complete( "" ).empty() );
130    BOOST_CHECK( fs::system_complete( "/" ).string()
131      == fs::initial_path().root_path().string() );
132    BOOST_CHECK( fs::system_complete( "foo" ).string()
133      == fs::initial_path().string()+"/foo" );
134    BOOST_CHECK( fs::system_complete( "/foo" ).string()
135      == fs::initial_path().root_path().string()+"foo" );
136
137//    BOOST_CHECK( fs::complete( fs::path( "c:", fs::native ) ).string()
138//      == fs::initial_path().string() );
139//    BOOST_CHECK( fs::complete( fs::path( "c:foo", fs::native ) ).string()
140//      == fs::initial_path().string()+"/foo" );
141    BOOST_CHECK( fs::complete( fs::path( "c:/", fs::native ) ).string()
142      == "c:/" );
143    BOOST_CHECK( fs::complete( fs::path( "c:/foo", fs::native ) ).string()
144      ==  "c:/foo" );
145    BOOST_CHECK( fs::complete( fs::path( "//share", fs::native ) ).string()
146      ==  "//share" );
147
148    BOOST_CHECK( fs::system_complete( fs::path( fs::initial_path().root_name(),
149      fs::native ) ).string() == fs::initial_path().string() );
150    BOOST_CHECK( fs::system_complete( fs::path( fs::initial_path().root_name()
151      + "foo", fs::native ) ).string() == fs::initial_path().string()+"/foo" );
152    BOOST_CHECK( fs::system_complete( fs::path( "c:/", fs::native ) ).string()
153      == "c:/" );
154    BOOST_CHECK( fs::system_complete( fs::path( "c:/foo", fs::native ) ).string()
155      ==  "c:/foo" );
156    BOOST_CHECK( fs::system_complete( fs::path( "//share", fs::native ) ).string()
157      ==  "//share" );
158  }
159
160  else if ( platform == "POSIX" )
161  {
162    BOOST_CHECK( fs::system_complete( "" ).empty() );
163    BOOST_CHECK( fs::initial_path().root_path().string() == "/" );
164    BOOST_CHECK( fs::system_complete( "/" ).string() == "/" );
165    BOOST_CHECK( fs::system_complete( "foo" ).string()
166      == fs::initial_path().string()+"/foo" );
167    BOOST_CHECK( fs::system_complete( "/foo" ).string()
168      == fs::initial_path().root_path().string()+"foo" );
169  }
170
171  fs::path ng( " no-way, Jose", fs::native );
172
173  fs::remove_all( dir );  // in case residue from prior failed tests
174  BOOST_CHECK( !fs::exists( dir ) );
175
176  // the bound functions should throw, so throws_fs_error() should return true
177  BOOST_CHECK( throws_fs_error( bind( fs::is_directory, ng ), fs::not_found_error ) );
178  BOOST_CHECK( throws_fs_error( bind( fs::file_size, ng ), fs::not_found_error ) );
179  BOOST_CHECK( throws_fs_error( bind( fs::is_directory, dir ) ) );
180  BOOST_CHECK( throws_fs_error( bind( fs::_is_empty, dir ) ) );
181
182  // test path::exception members
183  try { fs::is_directory( ng ); } // will throw
184
185  catch ( const fs::filesystem_error & ex )
186  {
187    BOOST_CHECK( ex.who() == "boost::filesystem::is_directory" );
188    BOOST_CHECK( ex.path1().string() == " no-way, Jose" );
189  }
190
191  BOOST_CHECK( fs::create_directory( dir ) );
192
193  BOOST_CHECK( fs::exists( dir ) );
194  BOOST_CHECK( fs::_is_empty( dir ) );
195  BOOST_CHECK( fs::is_directory( dir ) );
196  BOOST_CHECK( throws_fs_error( bind( fs::file_size, dir ),
197    fs::is_directory_error ) );
198  BOOST_CHECK( !fs::create_directory( dir ) );
199
200  BOOST_CHECK( !fs::symbolic_link_exists( dir ) );
201  BOOST_CHECK( !fs::symbolic_link_exists( "nosuchfileordirectory" ) );
202
203  fs::path d1( dir / "d1" );
204  BOOST_CHECK( fs::create_directory( d1 ) );
205  BOOST_CHECK( fs::exists( d1 ) );
206  BOOST_CHECK( fs::is_directory( d1 ) );
207  BOOST_CHECK( fs::_is_empty( d1 ) );
208
209  boost::function_requires< boost::InputIteratorConcept< fs::directory_iterator > >();
210
211  {
212    fs::directory_iterator dir_itr( dir );
213    BOOST_CHECK( dir_itr->leaf() == "d1" );
214  }
215
216  // create a second directory named d2
217  fs::path d2( dir / "d2" );
218  fs::create_directory(d2 );
219  BOOST_CHECK( fs::exists( d2 ) );
220  BOOST_CHECK( fs::is_directory( d2 ) );
221
222  // test the basic operation of directory_iterators, and test that
223  // stepping one iterator doesn't affect a different iterator.
224  {
225    fs::directory_iterator dir_itr( dir );
226    fs::directory_iterator dir_itr2( dir );
227    BOOST_CHECK( dir_itr->leaf() == "d1" || dir_itr->leaf() == "d2" );
228    BOOST_CHECK( dir_itr2->leaf() == "d1" || dir_itr2->leaf() == "d2" );
229    if ( dir_itr->leaf() == "d1" )
230    {
231      BOOST_CHECK( (++dir_itr)->leaf() == "d2" );
232      BOOST_CHECK( dir_itr2->leaf() == "d1" );
233      BOOST_CHECK( (++dir_itr2)->leaf() == "d2" );
234    }
235    else
236    {
237      BOOST_CHECK( (dir_itr)->leaf() == "d2" );
238      BOOST_CHECK( (++dir_itr)->leaf() == "d1" );
239      BOOST_CHECK( dir_itr2->leaf() == "d2" );
240      BOOST_CHECK( (++dir_itr2)->leaf() == "d1" );
241    }
242    BOOST_CHECK( ++dir_itr == fs::directory_iterator() );
243    BOOST_CHECK( dir_itr2 != fs::directory_iterator() );
244    BOOST_CHECK( ++dir_itr2 == fs::directory_iterator() );
245  }
246
247  { // *i++ must work to meet the standard's InputIterator requirements
248    fs::directory_iterator dir_itr( dir );
249    BOOST_CHECK( dir_itr->leaf() == "d1" || dir_itr->leaf() == "d2" );
250    if ( dir_itr->leaf() == "d1" )
251    {
252      BOOST_CHECK( (*dir_itr++).leaf() == "d1" );
253      BOOST_CHECK( dir_itr->leaf() == "d2" );
254    }
255    else
256    {
257      // Check C++98 input iterator requirements
258      BOOST_CHECK( (*dir_itr++).leaf() == "d2" );
259      // input iterator requirements in the current WP would require this check:
260      // BOOST_CHECK( implicit_cast<std::string const&>(*dir_itr++).leaf() == "d1" );
261
262      BOOST_CHECK( dir_itr->leaf() == "d1" );
263    }
264  }
265
266  // create an empty file named "f0"
267  fs::path file_ph( dir / "f0");
268  create_file( file_ph, "" );
269  BOOST_CHECK( fs::exists( file_ph ) );
270  BOOST_CHECK( !fs::is_directory( file_ph ) );
271  BOOST_CHECK( fs::_is_empty( file_ph ) );
272  BOOST_CHECK( fs::file_size( file_ph ) == 0 );
273  BOOST_CHECK( throws_fs_error( bind( fs::create_directory, file_ph ),
274    fs::not_directory_error ) );
275
276  // create a file named "f1"
277  file_ph = dir / "f1";
278  create_file( file_ph, "foobar1" );
279
280  // equivalence tests
281  fs::path ng2("does_not_exist2");
282  BOOST_CHECK( throws_fs_error( bind( fs::equivalent, ng, ng2 ) ) );
283  BOOST_CHECK( fs::equivalent( file_ph, dir / "f1" ) );
284  BOOST_CHECK( fs::equivalent( dir, d1 / ".." ) );
285  BOOST_CHECK( !fs::equivalent( file_ph, dir ) );
286  BOOST_CHECK( !fs::equivalent( dir, file_ph ) );
287  BOOST_CHECK( !fs::equivalent( d1, d2 ) );
288  BOOST_CHECK( !fs::equivalent( dir, ng ) );
289  BOOST_CHECK( !fs::equivalent( ng, dir ) );
290  BOOST_CHECK( !fs::equivalent( file_ph, ng ) );
291  BOOST_CHECK( !fs::equivalent( ng, file_ph ) );
292
293  std::time_t ft = fs::last_write_time( file_ph );
294  std::cout << "UTC should currently be about " << std::asctime(std::gmtime(&ft)) << "\n";
295  std::cout << "Local time should currently be about " << std::asctime(std::localtime(&ft)) << std::endl;
296
297  // hard to test time exactly, but except under the most unusual circumstances,
298  // time since file creation should be no more than one minute, I'm hoping.
299  double time_diff = std::difftime( std::time(0), fs::last_write_time( file_ph ) );
300  BOOST_CHECK( time_diff > -60.0 && time_diff < 60.0 );
301
302  BOOST_CHECK( fs::exists( file_ph ) );
303  BOOST_CHECK( !fs::is_directory( file_ph ) );
304  BOOST_CHECK( fs::file_size( file_ph ) == 7 );
305  verify_file( file_ph, "foobar1" );
306
307  std::tm * tmp = std::localtime( &ft );
308  std::cout << "Year is " << tmp->tm_year << std::endl;
309  --tmp->tm_year;
310  std::cout << "Change year to " << tmp->tm_year << std::endl;
311  fs::last_write_time( file_ph, std::mktime( tmp ) );
312  std::cout << "Get new value" << std::endl;
313  ft = fs::last_write_time( file_ph );
314  std::cout << "Local time one year ago should currently be about " << std::asctime(std::localtime(&ft)) << "\n";
315  std::cout << "Now get time difference" << std::endl;
316  time_diff = std::difftime( std::time(0), fs::last_write_time( file_ph ) );
317  time_diff -= 365*24*3600.0;
318  std::cout << "Time difference is : " << time_diff << std::endl;
319  BOOST_CHECK( time_diff >= -60.0 && time_diff <= 60.0 );
320  std::cout << "Reset to current time" << std::endl;
321  fs::last_write_time( file_ph, std::time(0) );
322  std::cout << "And check that" << std::endl;
323  time_diff = std::difftime( std::time(0), fs::last_write_time( file_ph ) );
324  BOOST_CHECK( time_diff >= -60.0 && time_diff <= 60.0 );
325  ft = fs::last_write_time( file_ph );
326  std::cout << "Local time should currently be about " << std::asctime(std::localtime(&ft)) << "\n";
327
328  // there was an inital bug in directory_iterator that caused premature
329  // close of an OS handle. This block will detect regression.
330  {
331    fs::directory_iterator di;
332    { di = fs::directory_iterator( dir ); }
333    BOOST_CHECK( ++di != fs::directory_iterator() );
334  }
335
336  // copy_file() tests
337  std::cout << "begin copy_file test..." << std::endl;
338  fs::copy_file( file_ph, d1 / "f2" );
339  std::cout << "copying complete" << std::endl;
340  BOOST_CHECK( fs::exists( file_ph ) );
341  BOOST_CHECK( fs::exists( d1 / "f2" ) );
342  BOOST_CHECK( !fs::is_directory( d1 / "f2" ) );
343  verify_file( d1 / "f2", "foobar1" );
344  std::cout << "copy_file test complete" << std::endl;
345
346  // rename() test case numbers refer to operations.htm#rename table
347
348  // [case 1] make sure can't rename() a non-existent file
349  BOOST_CHECK( !fs::exists( d1 / "f99" ) );
350  BOOST_CHECK( !fs::exists( d1 / "f98" ) );
351  BOOST_CHECK( throws_fs_error( bind( fs::rename, d1 / "f99", d1 / "f98" ),
352    fs::not_found_error ) );
353  BOOST_CHECK( throws_fs_error( bind( fs::rename, fs::path(""), d1 / "f98" ),
354    fs::not_found_error ) );
355
356  // [case 2] rename() target.empty()
357  BOOST_CHECK( throws_fs_error( bind( fs::rename, file_ph, "" ),
358    fs::not_found_error ) );
359
360  // [case 3] make sure can't rename() to an existent file or directory
361  BOOST_CHECK( fs::exists( dir / "f1" ) );
362  BOOST_CHECK( fs::exists( d1 / "f2" ) );
363  BOOST_CHECK( throws_fs_error( bind( fs::rename, dir / "f1", d1 / "f2" ) ) );
364  // several POSIX implementations (cygwin, openBSD) report ENOENT instead of EEXIST,
365  // so we don't verify error type on the above test.
366  BOOST_CHECK( throws_fs_error( bind( fs::rename, dir, d1 ) ) );
367
368  // [case 4A] can't rename() file to a nonexistent parent directory
369  BOOST_CHECK( !fs::is_directory( dir / "f1" ) );
370  BOOST_CHECK( !fs::exists( dir / "d3/f3" ) );
371  BOOST_CHECK( throws_fs_error( bind( fs::rename, dir / "f1", dir / "d3/f3" ),
372    fs::not_found_error ) );
373
374  // [case 4B] rename() file in same directory
375  BOOST_CHECK( fs::exists( d1 / "f2" ) );
376  BOOST_CHECK( !fs::exists( d1 / "f50" ) );
377  fs::rename( d1 / "f2", d1 / "f50" );
378  BOOST_CHECK( !fs::exists( d1 / "f2" ) );
379  BOOST_CHECK( fs::exists( d1 / "f50" ) );
380  fs::rename( d1 / "f50", d1 / "f2" );
381  BOOST_CHECK( fs::exists( d1 / "f2" ) );
382  BOOST_CHECK( !fs::exists( d1 / "f50" ) );
383
384  // [case 4C] rename() file d1/f2 to d2/f3
385  fs::rename( d1 / "f2", d2 / "f3" );
386  BOOST_CHECK( !fs::exists( d1 / "f2" ) );
387  BOOST_CHECK( !fs::exists( d2 / "f2" ) );
388  BOOST_CHECK( fs::exists( d2 / "f3" ) );
389  BOOST_CHECK( !fs::is_directory( d2 / "f3" ) );
390  verify_file( d2 / "f3", "foobar1" );
391  fs::rename( d2 / "f3", d1 / "f2" );
392  BOOST_CHECK( fs::exists( d1 / "f2" ) );
393
394  // [case 5A] rename() directory to nonexistent parent directory
395  BOOST_CHECK( fs::exists( d1 ) );
396  BOOST_CHECK( !fs::exists( dir / "d3/d5" ) );
397  BOOST_CHECK( !fs::exists( dir / "d3" ) );
398  BOOST_CHECK( throws_fs_error( bind( fs::rename, d1, dir / "d3/d5" ),
399    fs::not_found_error ) );
400
401  // [case 5B] rename() on directory
402  fs::path d3( dir / "d3" );
403  BOOST_CHECK( fs::exists( d1 ) );
404  BOOST_CHECK( fs::exists( d1 / "f2" ) );
405  BOOST_CHECK( !fs::exists( d3 ) );
406  fs::rename( d1, d3 );
407  BOOST_CHECK( !fs::exists( d1 ) );
408  BOOST_CHECK( fs::exists( d3 ) );
409  BOOST_CHECK( fs::is_directory( d3 ) );
410  BOOST_CHECK( !fs::exists( d1 / "f2" ) );
411  BOOST_CHECK( fs::exists( d3 / "f2" ) );
412  fs::rename( d3, d1 );
413  BOOST_CHECK( fs::exists( d1 ) );
414  BOOST_CHECK( fs::exists( d1 / "f2" ) );
415  BOOST_CHECK( !fs::exists( d3 ) );
416
417  // [case 5C] rename() rename and move d1 to d2 / "d20"
418  BOOST_CHECK( fs::exists( d1 ) );
419  BOOST_CHECK( !fs::exists( d2 / "d20" ) );
420  BOOST_CHECK( fs::exists( d1 / "f2" ) );
421  fs::rename( d1, d2 / "d20" );
422  BOOST_CHECK( !fs::exists( d1 ) );
423  BOOST_CHECK( fs::exists( d2 / "d20" ) );
424  BOOST_CHECK( fs::exists( d2 / "d20" / "f2" ) );
425  fs::rename( d2 / "d20", d1 );
426  BOOST_CHECK( fs::exists( d1 ) );
427  BOOST_CHECK( !fs::exists( d2 / "d20" ) );
428  BOOST_CHECK( fs::exists( d1 / "f2" ) );
429
430  // remove() tests on file
431  file_ph = dir / "shortlife";
432  BOOST_CHECK( !fs::exists( file_ph ) );
433  create_file( file_ph, "" );
434  BOOST_CHECK( fs::exists( file_ph ) );
435  BOOST_CHECK( !fs::is_directory( file_ph ) );
436  BOOST_CHECK( fs::remove( file_ph ) );
437  BOOST_CHECK( !fs::exists( file_ph ) );
438  BOOST_CHECK( !fs::remove( "no-such-file" ) );
439  BOOST_CHECK( !fs::remove( "no-such-directory/no-such-file" ) );
440
441  // remove() test on directory
442  d1 = dir / "shortlife_dir";
443  BOOST_CHECK( !fs::exists( d1 ) );
444  fs::create_directory( d1 );
445  BOOST_CHECK( fs::exists( d1 ) );
446  BOOST_CHECK( fs::is_directory( d1 ) );
447  BOOST_CHECK( fs::_is_empty( d1 ) );
448  BOOST_CHECK( throws_fs_error( bind( fs::remove, dir ), fs::not_empty_error ) );
449  BOOST_CHECK( fs::remove( d1 ) );
450  BOOST_CHECK( !fs::exists( d1 ) );
451
452// STLPort is allergic to std::system, so don't use runtime platform test
453# ifdef BOOST_POSIX
454  // remove() test on dangling symbolic link
455  fs::path link( "dangling_link" );
456  fs::remove( link );
457  BOOST_CHECK( !fs::symbolic_link_exists( link ) );
458  BOOST_CHECK( !fs::exists( link ) );
459  std::system("ln -s nowhere dangling_link");
460  BOOST_CHECK( !fs::exists( link ) );
461  BOOST_CHECK( fs::symbolic_link_exists( link ) );
462  BOOST_CHECK( fs::remove( link ) );
463  BOOST_CHECK( !fs::symbolic_link_exists( link ) );
464
465  // remove() test on symbolic link to a file
466  file_ph = "link_target";
467  fs::remove( file_ph );
468  BOOST_CHECK( !fs::exists( file_ph ) );
469  create_file( file_ph, "" );
470  BOOST_CHECK( fs::exists( file_ph ) );
471  BOOST_CHECK( !fs::is_directory( file_ph ) );
472  std::system("ln -s link_target non_dangling_link");
473  link = "non_dangling_link";
474  BOOST_CHECK( fs::exists( link ) );
475  BOOST_CHECK( !fs::is_directory( link ) );
476  BOOST_CHECK( fs::symbolic_link_exists( link ) );
477  BOOST_CHECK( fs::remove( link ) );
478  BOOST_CHECK( fs::exists( file_ph ) );
479  BOOST_CHECK( !fs::exists( link ) );
480  BOOST_CHECK( !fs::symbolic_link_exists( link ) );
481  BOOST_CHECK( fs::remove( file_ph ) );
482  BOOST_CHECK( !fs::exists( file_ph ) );
483  }
484# endif
485
486  // post-test cleanup
487  BOOST_CHECK( fs::remove_all( dir ) != 0 );
488  // above was added just to simplify testing, but it ended up detecting
489  // a bug (failure to close an internal search handle).
490  BOOST_CHECK( !fs::exists( dir ) );
491  BOOST_CHECK( fs::remove_all( dir ) == 0 );
492
493  return 0;
494} // main
495
Note: See TracBrowser for help on using the repository browser.