Ensure filefunc unit test works with all working dirs
[libi2ncommon] / test / test_filefunc.cpp
... / ...
CommitLineData
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
20/** @file
21 *
22 * tests for the modules "filefunc", "daemonfunc"
23 *
24 * (c) Copyright 2007-2008 by Intra2net AG
25 */
26
27//#define NOISEDEBUG
28
29#include <string>
30#include <vector>
31#include <list>
32#include <set>
33#include <iostream>
34#include <iomanip>
35#include <fstream>
36#include <sstream>
37#include <algorithm>
38
39#define BOOST_TEST_DYN_LINK
40#include <boost/test/unit_test.hpp>
41
42#include <filefunc.hxx>
43#include <daemonfunc.hpp>
44#include <pipestream.hxx>
45#include <stringfunc.hxx>
46
47#ifdef NOISEDEBUG
48#define DOUT(msg) std::cout << msg << std::endl
49#else
50#define DOUT(msg) do {} while (0)
51#endif
52
53using namespace std;
54using namespace I2n;
55
56class TestFileFuncFixture
57{
58protected:
59 typedef std::list< std::string > StringList;
60 std::set<std::string> used_check_files;
61
62 std::string get_check_file_path(std::string tag)
63 {
64 std::string result;
65 result= "__unittest__" + tag + ".dat";
66 used_check_files.insert(result);
67 return result;
68 } // eo get_check_file_path
69
70 void remove_check_files()
71 {
72 for (std::set<std::string>::iterator it= used_check_files.begin();
73 it != used_check_files.end();
74 ++it)
75 {
76 std::string filepath(*it);
77 if (path_exists(filepath))
78 {
79 unlink(filepath);
80 }
81 //TODO
82 }
83 used_check_files.clear();
84 } // eo remove_check_files
85
86public:
87 TestFileFuncFixture()
88 {
89 }
90
91 ~TestFileFuncFixture()
92 {
93 remove_check_files();
94 }
95};
96
97BOOST_FIXTURE_TEST_SUITE(TestFileFunc, TestFileFuncFixture)
98
99BOOST_AUTO_TEST_CASE(StatTest1)
100{
101 I2n::Stat stat(__FILE__);
102
103 BOOST_CHECK_EQUAL( true, (bool)stat );
104 BOOST_CHECK_EQUAL( true, stat.is_regular_file() );
105 BOOST_CHECK_EQUAL( false, stat.is_directory() );
106
107 stat= Stat("/dev/null");
108
109 BOOST_CHECK_EQUAL( true, (bool)stat );
110 BOOST_CHECK_EQUAL( false, stat.is_regular_file() );
111 BOOST_CHECK_EQUAL( false, stat.is_directory() );
112 BOOST_CHECK_EQUAL( true, stat.is_device() );
113 BOOST_CHECK_EQUAL( true, stat.is_character_device() );
114 BOOST_CHECK_EQUAL( false, stat.is_block_device() );
115} // eo StatTest1
116
117BOOST_AUTO_TEST_CASE(StatSize)
118{
119 write_file("/tmp/test","some nice content to make sure the file system optimizations don't inline this into the inode block");
120
121 I2n::Stat stat("/tmp/test");
122
123 BOOST_CHECK_EQUAL( true, (bool)stat );
124 BOOST_CHECK_EQUAL( true, stat.is_regular_file() );
125
126 BOOST_CHECK_EQUAL( true, ( stat.bytes_on_disk() >= 512 ) );
127
128 unlink("/tmp/test");
129} // eo StatSize
130
131BOOST_AUTO_TEST_CASE(StatRecheck)
132{
133 // just to be sure
134 unlink(".foobar");
135
136 I2n::Stat stat(".foobar");
137 BOOST_CHECK_EQUAL( false, (bool)stat );
138
139 write_file(".foobar","hello world");
140
141 stat.recheck();
142
143 BOOST_CHECK_EQUAL( true, (bool)stat );
144 BOOST_CHECK_EQUAL( true, stat.size() > 0 );
145
146 unlink(".foobar");
147}
148
149BOOST_AUTO_TEST_CASE(DirTest1)
150{
151 typedef std::vector< std::string > StringVector;
152 StringVector names;
153
154 string test_dir = dirname(__FILE__);
155 bool res= I2n::get_dir(test_dir,names);
156
157 BOOST_CHECK_EQUAL( true, res );
158 BOOST_CHECK( ! names.empty() );
159
160 BOOST_MESSAGE("Looking for " << basename(__FILE__) << " in " << test_dir);
161 StringVector::iterator it = std::find( names.begin(), names.end(), basename(__FILE__));
162 BOOST_CHECK( it != names.end() );
163
164 it = std::find( names.begin(), names.end(), "." );
165 BOOST_CHECK( it == names.end() );
166
167 names= get_dir(test_dir,true);
168 BOOST_CHECK( ! names.empty() );
169
170 for (it= names.begin(); it!=names.end(); ++it)
171 {
172 DOUT(" \"" << *it << "\"");
173 BOOST_CHECK_EQUAL( false, it->empty() );
174 }
175
176 it = std::find( names.begin(), names.end(), "." );
177 BOOST_CHECK( it != names.end() );
178} // eo DirTest1
179
180
181
182BOOST_AUTO_TEST_CASE(PathCuts1)
183{
184 std::string path1("/an/absolute/path");
185
186 BOOST_CHECK_EQUAL( std::string("/an/absolute"), dirname(path1) );
187 BOOST_CHECK_EQUAL( std::string("path"), basename(path1) );
188
189 std::string path2("just.a.name");
190 BOOST_CHECK_EQUAL( std::string("just.a.name"), basename(path2) );
191 BOOST_CHECK_EQUAL( std::string("."), dirname(path2) );
192} // eo PathCuts1()
193
194
195
196BOOST_AUTO_TEST_CASE(NormalizePath1)
197{
198 std::string path;
199
200 path= normalize_path("/a/simple/path/");
201 BOOST_CHECK_EQUAL( std::string("/a/simple/path"), path );
202
203 path= normalize_path("//another///simple/.//path//");
204 BOOST_CHECK_EQUAL( std::string("/another/simple/path"), path );
205
206 path= normalize_path("//..//..//a/dummy///../././simple/././/path//");
207 BOOST_CHECK_EQUAL( std::string("/a/simple/path"), path );
208
209 path= normalize_path("../a/dummy//././..//simple//nice//absolute//.././..//relative/path//");
210 BOOST_CHECK_EQUAL( std::string("../a/simple/relative/path"), path );
211
212 path= normalize_path("../../a/dummy//././..//simple/../nice//absolute//../.x/..//relative/path//");
213 BOOST_CHECK_EQUAL( std::string("../../a/nice/relative/path"), path );
214
215} // eo NormalizePath1
216
217BOOST_AUTO_TEST_CASE(NormalizePath2)
218{
219 std::string path;
220
221 path= normalize_path("/");
222 BOOST_CHECK_EQUAL( std::string("/"), path );
223
224 path= normalize_path("//");
225 BOOST_CHECK_EQUAL( std::string("/"), path );
226
227 path= normalize_path("/.//");
228 BOOST_CHECK_EQUAL( std::string("/"), path );
229
230 path= normalize_path(".");
231 BOOST_CHECK_EQUAL( std::string(""), path );
232
233 path= normalize_path("./");
234 BOOST_CHECK_EQUAL( std::string(""), path );
235
236 path= normalize_path(".///");
237 BOOST_CHECK_EQUAL( std::string(""), path );
238
239 path= normalize_path("/./data/files");
240 BOOST_CHECK_EQUAL( std::string("/data/files"), path );
241
242 path= normalize_path("./data/files/");
243 BOOST_CHECK_EQUAL( std::string("data/files"), path );
244} // eo NormalizePath2
245
246BOOST_AUTO_TEST_CASE(TestUserAndGroupStuff1)
247{
248 User user_root((uid_t)0);
249 BOOST_CHECK_EQUAL( true, user_root.is_valid() );
250 BOOST_CHECK_EQUAL( true, (bool)user_root );
251
252 BOOST_CHECK_EQUAL( std::string("root"), user_root.Name );
253 BOOST_CHECK_EQUAL( (uid_t)0, user_root.Uid );
254 BOOST_CHECK_EQUAL( (gid_t)0, user_root.Gid );
255
256 User user_root2("root");
257 BOOST_CHECK_EQUAL( true, user_root2.is_valid() );
258 BOOST_CHECK_EQUAL( true, (bool)user_root2 );
259
260 BOOST_CHECK_EQUAL( std::string("root"), user_root2.Name );
261 BOOST_CHECK_EQUAL( (uid_t)0, user_root2.Uid );
262 BOOST_CHECK_EQUAL( (gid_t)0, user_root2.Gid );
263
264 Group group_root("root");
265 BOOST_CHECK_EQUAL( true, group_root.is_valid() );
266 BOOST_CHECK_EQUAL( true, (bool)group_root );
267
268 BOOST_CHECK_EQUAL( std::string("root"), group_root.Name );
269 BOOST_CHECK_EQUAL( (gid_t)0, group_root.Gid );
270
271} // TestUserAndGroupStuff1()
272
273BOOST_AUTO_TEST_CASE(TestUserAndGroupStuff2)
274{
275 // Test if is_valid() works correctly
276 User user_root;
277 BOOST_CHECK_EQUAL( false, user_root.is_valid() );
278
279 Group group_root;
280 BOOST_CHECK_EQUAL( false, group_root.is_valid() );
281}
282
283BOOST_AUTO_TEST_CASE(TestFileModes1)
284{
285 std::string path= get_check_file_path("FileModes1");
286
287 write_file(path,"42");
288
289 Stat stat(path, false);
290 BOOST_CHECK_EQUAL( true, stat.is_valid() );
291
292 User user( stat.uid() );
293 Group group( stat.gid() );
294
295 BOOST_CHECK_EQUAL( true, user.is_valid() );
296 BOOST_CHECK_EQUAL( true, group.is_valid() );
297
298 bool res=chown( path, user.Name.c_str(), group.Gid );
299
300 BOOST_CHECK_EQUAL( true, res );
301} // eo TestFileModes1()
302
303
304
305BOOST_AUTO_TEST_CASE(TestPidOf1)
306{
307 using I2n::Daemon::pid_of;
308
309 std::vector< pid_t > pid_list;
310
311 bool res= pid_of("init", pid_list);
312 BOOST_CHECK_EQUAL( true, res);
313
314 if (pid_list.empty())
315 {
316 res= pid_of("systemd", pid_list);
317 BOOST_CHECK_EQUAL( true, res);
318 }
319
320 BOOST_CHECK_EQUAL( false, pid_list.empty() );
321
322 std::vector< pid_t >::const_iterator pos1 =
323 std::find( pid_list.begin(), pid_list.end(), 1);
324
325 BOOST_CHECK( pos1 != pid_list.end() );
326} // eo TestPidOf1()
327
328BOOST_AUTO_TEST_CASE(TestCopyFileSourceFail)
329{
330 bool res = copy_file("does not exist", "destination");
331 BOOST_CHECK_EQUAL( false, res );
332}
333
334BOOST_AUTO_TEST_CASE(TestCopyFileDestFail)
335{
336 bool res = copy_file("/etc/HOSTNAME", "/proc/not/writable");
337 BOOST_CHECK_EQUAL( false, res );
338}
339
340BOOST_AUTO_TEST_CASE(TestCopyFileOk)
341{
342 string input = "copy_source";
343 string data = "test";
344
345 long input_size = 0;
346 ofstream finput(input.c_str());
347 if (finput)
348 {
349 finput << data;
350 finput.close();
351 input_size = file_size(input);
352 }
353
354 string output = "copy_dest";
355 long output_size = 0;
356 bool res = copy_file(input, output);
357 if (res)
358 {
359 output_size = file_size(output);
360 }
361 unlink(input);
362 unlink(output);
363
364 bool size_is_zero = output_size == 0 ? true : false;
365
366 BOOST_CHECK_EQUAL( true, res );
367 BOOST_CHECK_EQUAL( input_size, output_size );
368 BOOST_CHECK_EQUAL( false, size_is_zero );
369}
370
371BOOST_AUTO_TEST_CASE(TestMkdtemp)
372{
373 // Create unique directory
374 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
375 BOOST_REQUIRE(unique_dir.size() > 0);
376
377 // Test if it's really a directory
378 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
379
380 // Unlink it
381 BOOST_CHECK_EQUAL(true, rmdir(unique_dir));
382}
383
384BOOST_AUTO_TEST_CASE(TestRecursiveDelete)
385{
386 // Create unique directory
387 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
388 BOOST_REQUIRE(unique_dir.size() > 0);
389
390 // Test if it's really a directory
391 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
392
393 // Create dirs and files below it
394 const std::string sub_dir = unique_dir + "/" + "some_subdir";
395 const std::string some_file = sub_dir + "/" + "some_file";
396 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
397 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
398
399 // Unlink it
400 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
401 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
402}
403
404BOOST_AUTO_TEST_CASE(TestRecursiveDeleteKeepParentDir)
405{
406 // Create unique directory
407 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
408 BOOST_REQUIRE(unique_dir.size() > 0);
409
410 // Test if it's really a directory
411 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
412
413 // Create dirs and files below it
414 const std::string sub_dir = unique_dir + "/" + "some_subdir";
415 const std::string some_file = sub_dir + "/" + "some_file";
416 const std::string other_file = unique_dir + "/" + "other_file";
417
418 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
419 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
420 BOOST_CHECK_EQUAL(true, write_file(other_file, "foobar"));
421
422 // Unlink it
423 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir, true));
424
425 // check result
426 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
427 BOOST_CHECK_EQUAL(false, Stat(sub_dir).is_directory());
428 BOOST_CHECK_EQUAL(false, Stat(other_file).is_regular_file());
429
430 BOOST_CHECK_EQUAL(true, I2n::rmdir(unique_dir));
431}
432
433BOOST_AUTO_TEST_CASE(TestRecursiveDeleteSymlinkedDirs1)
434{
435 // Create unique directory
436 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
437 BOOST_REQUIRE(unique_dir.size() > 0);
438
439 // Test if it's really a directory
440 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
441
442 // Create dirs and files below it
443 const std::string sub_dir = unique_dir + "/" + "some_subdir";
444 const std::string some_file = sub_dir + "/" + "some_file";
445 const std::string dir_symlink_within_unique_dir = unique_dir + "/" + "dir_symlink_within_unique_dir";
446 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
447 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
448 BOOST_CHECK_EQUAL(true, symlink(sub_dir, dir_symlink_within_unique_dir));
449
450 // Unlink it
451 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
452 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
453}
454
455BOOST_AUTO_TEST_CASE(TestRecursiveDeleteSymlinkedDirs2)
456{
457 // Create unique directory
458 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
459 BOOST_REQUIRE(unique_dir.size() > 0);
460
461 // Test if it's really a directory
462 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
463
464 // Create another unique directory
465 string other_unique_dir = I2n::mkdtemp("foobar_other.XXXXXX");
466 BOOST_REQUIRE(other_unique_dir.size() > 0);
467
468 // Test if it's really a directory
469 BOOST_CHECK_EQUAL(true, Stat(other_unique_dir).is_directory());
470
471 const std::string other_file = other_unique_dir + "/" + "other_file";
472 BOOST_CHECK_EQUAL(true, write_file(other_file, "foobar"));
473
474 // Create dirs and files below it
475 const std::string sub_dir = unique_dir + "/" + "some_subdir";
476 const std::string some_file = sub_dir + "/" + "some_file";
477 const std::string dir_symlink_to_outside_unique_dir = unique_dir + "/" + "dir_symlink_to_outside_unique_dir";
478 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
479 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
480 BOOST_CHECK_EQUAL(true, symlink(other_unique_dir, dir_symlink_to_outside_unique_dir));
481
482 // Unlink it
483 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
484 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
485
486 // other unique dir must still be there
487 BOOST_CHECK_EQUAL(true, Stat(other_unique_dir).is_directory());
488 BOOST_CHECK_EQUAL(true, Stat(other_file).is_regular_file());
489
490 // finally delete the other unique dir
491 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(other_unique_dir));
492 BOOST_CHECK_EQUAL(false, Stat(other_unique_dir).is_directory());
493}
494
495BOOST_AUTO_TEST_CASE(TestMkdtempBrokenTemplate)
496{
497 // Broken directory template -> fail
498 string unique_dir = I2n::mkdtemp("foobar.XXX");
499 BOOST_CHECK_EQUAL("", unique_dir);
500}
501
502BOOST_AUTO_TEST_CASE(DirectoryCreation)
503{
504 string dirname = "test_directory";
505
506 I2n::rmdir (dirname);
507
508 BOOST_CHECK_EQUAL(true, I2n::mkdir(dirname));
509 BOOST_CHECK_EQUAL(true, Stat(dirname).is_directory());
510 // Verify default permissions
511 BOOST_CHECK_EQUAL(0700, Stat(dirname).mode());
512
513 BOOST_CHECK_EQUAL(true, I2n::rmdir(dirname));
514
515 // Second call must fail: Directory already deleted
516 BOOST_CHECK_EQUAL(false, I2n::rmdir(dirname));
517}
518
519BOOST_AUTO_TEST_CASE(DirectoryCreatePermission)
520{
521 string dirname = "test_directory";
522
523 // Save and fix umask
524 mode_t previous_mask = I2n::umask(0);
525
526 I2n::rmdir (dirname);
527 BOOST_CHECK_EQUAL(true, I2n::mkdir(dirname, 0770));
528 BOOST_CHECK_EQUAL(0770, Stat(dirname).mode());
529 I2n::rmdir (dirname);
530
531 // Restore umask
532 I2n::umask(previous_mask);
533}
534
535BOOST_AUTO_TEST_CASE(ChangeDirectory)
536{
537 string current_directory = I2n::getcwd();
538 BOOST_REQUIRE(!current_directory.empty());
539
540 BOOST_CHECK_EQUAL(true, I2n::chdir("/"));
541 BOOST_CHECK_EQUAL("/", I2n::getcwd());
542
543 BOOST_CHECK_EQUAL(true, I2n::chdir(current_directory));
544 BOOST_REQUIRE_EQUAL(current_directory, I2n::getcwd());
545}
546
547BOOST_AUTO_TEST_CASE(WriteFileEmptyData)
548{
549 // just to be sure
550 unlink(".foobar");
551
552 I2n::Stat stat(".foobar");
553 BOOST_CHECK_EQUAL( false, (bool)stat );
554
555 // Call write_file() with empty data. Should still create the file.
556 write_file(".foobar","");
557
558 stat.recheck();
559
560 BOOST_CHECK_EQUAL( true, (bool)stat );
561 BOOST_CHECK_EQUAL( true, stat.size() == 0 );
562
563 unlink(".foobar");
564}
565
566BOOST_AUTO_TEST_CASE(FileContentDiffersIsIdentical)
567{
568 BOOST_CHECK_EQUAL( false, file_content_differs("/etc/passwd", "/etc/passwd") );
569}
570
571BOOST_AUTO_TEST_CASE(FileContentDiffersNonExistent)
572{
573 BOOST_CHECK_EQUAL( true, file_content_differs("/etc/passwd", "abc") );
574 BOOST_CHECK_EQUAL( true, file_content_differs("abc", "/etc/passwd") );
575}
576
577BOOST_AUTO_TEST_CASE(FileContentDiffersEqualSize)
578{
579 const string name1 = "file1", name2 = "file2";
580 {
581 ofstream out1(name1.c_str());
582 out1 << "abc";
583
584 ofstream out2(name2.c_str());
585 out2 << "xyz";
586 }
587
588 bool res = file_content_differs(name1, name2);
589 unlink(name1);
590 unlink(name2);
591
592 BOOST_CHECK_EQUAL( true, res );
593}
594
595BOOST_AUTO_TEST_CASE(FreeDiskSpace1)
596{
597 long long dfout;
598 long long get_free_diskspace_tmp;
599
600 // we need a partition to do this test. we can't create our own because that would require root
601 // so we use /tmp and retry it a few times in case of an error
602 int retries = 5;
603 while (retries > 0)
604 {
605 string dfstr=capture_exec("df -P -B 1 /tmp | tail -n 1 | sed \"s/ \\+/\\\\n/g\" | sed -n 4,4p");
606
607 dfout=-1;
608 string_to<long long>(dfstr,dfout);
609
610 get_free_diskspace_tmp=get_free_diskspace("/tmp");
611
612 if ( dfout == get_free_diskspace_tmp )
613 break;
614
615 retries--;
616 }
617
618 // do the check again with BOOST_CHECK_EQUAL to show it in the unit test output
619 BOOST_CHECK_EQUAL( dfout, get_free_diskspace_tmp );
620}
621
622BOOST_AUTO_TEST_CASE(FreeDiskSpace2)
623{
624 BOOST_CHECK_EQUAL( -1, get_free_diskspace("/this/path/is/really/bogus") );
625}
626
627BOOST_AUTO_TEST_CASE(TestDu)
628{
629 // Create unique directory
630 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
631 BOOST_REQUIRE(unique_dir.size() > 0);
632
633 // Test if it's really a directory
634 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
635
636 // Create dirs and files below it
637 const std::string sub_dir = unique_dir + "/" + "some_subdir";
638 const std::string some_file = sub_dir + "/" + "some_file";
639 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
640 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar and some more data, even more that Tom would like to see in one line without linebreak but I still want to have it all here"));
641
642 string dustr=capture_exec(string("du --block-size=1 --sum ")+unique_dir+" | cut -f 1");
643 long long duout=-1;
644 string_to<long long>(dustr,duout);
645
646 long long first_du=du(unique_dir);
647
648 BOOST_CHECK_EQUAL( duout, first_du );
649
650 // create hardlinks
651 string cmd;
652 cmd=string("ln ")+some_file+" hardlink1";
653 system(cmd.c_str());
654
655 cmd=string("ln ")+some_file+" hardlink2";
656 system(cmd.c_str());
657
658 cmd=string("ln ")+some_file+" hardlink3";
659 system(cmd.c_str());
660
661 long long du_with_hardlinks=du(unique_dir);
662
663 BOOST_CHECK_EQUAL( first_du , du_with_hardlinks );
664
665 // Unlink it
666 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
667 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
668
669 // remove links
670 unlink("hardlink1");
671 unlink("hardlink2");
672 unlink("hardlink3");
673}
674
675
676
677BOOST_AUTO_TEST_SUITE_END()