Test if write_file() creates empty files, too
[libi2ncommon] / test / test_filefunc.cpp
1 /*
2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
4
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
7
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
13
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
16
17 This exception does not invalidate any other reasons why a work based
18 on 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
45 #ifdef NOISEDEBUG
46 #define DOUT(msg) std::cout << msg << std::endl
47 #else
48 #define DOUT(msg) do {} while (0)
49 #endif
50
51 using namespace std;
52 using namespace I2n;
53
54 class TestFileFuncFixture
55 {
56 protected:
57    typedef std::list< std::string > StringList;
58    std::set<std::string>  used_check_files;
59
60    std::string get_check_file_path(std::string tag)
61    {
62       std::string result;
63       result= "__unittest__" + tag + ".dat";
64       used_check_files.insert(result);
65       return result;
66    } // eo get_check_file_path
67
68    void remove_check_files()
69    {
70       for (std::set<std::string>::iterator it= used_check_files.begin();
71             it != used_check_files.end();
72             ++it)
73       {
74          std::string filepath(*it);
75          if (path_exists(filepath))
76          {
77             unlink(filepath);
78          }
79          //TODO
80       }
81       used_check_files.clear();
82    } // eo remove_check_files
83
84 public:
85     TestFileFuncFixture()
86     {
87     }
88
89     ~TestFileFuncFixture()
90     {
91         remove_check_files();
92     }
93 };
94
95 BOOST_FIXTURE_TEST_SUITE(TestFileFunc, TestFileFuncFixture)
96
97 BOOST_AUTO_TEST_CASE(StatTest1)
98 {
99     I2n::Stat stat("Makefile");
100
101     BOOST_CHECK_EQUAL( true, (bool)stat );
102     BOOST_CHECK_EQUAL( true, stat.is_regular_file() );
103     BOOST_CHECK_EQUAL( false, stat.is_directory() );
104
105     stat= Stat("/dev/null");
106
107     BOOST_CHECK_EQUAL( true, (bool)stat );
108     BOOST_CHECK_EQUAL( false, stat.is_regular_file() );
109     BOOST_CHECK_EQUAL( false, stat.is_directory() );
110     BOOST_CHECK_EQUAL( true, stat.is_device() );
111     BOOST_CHECK_EQUAL( true, stat.is_character_device() );
112     BOOST_CHECK_EQUAL( false, stat.is_block_device() );
113 } // eo StatTest1
114
115 BOOST_AUTO_TEST_CASE(StatRecheck)
116 {
117     // just to be sure
118     unlink(".foobar");
119
120     I2n::Stat stat(".foobar");
121     BOOST_CHECK_EQUAL( false, (bool)stat );
122
123     write_file(".foobar","hello world");
124
125     stat.recheck();
126
127     BOOST_CHECK_EQUAL( true, (bool)stat );
128     BOOST_CHECK_EQUAL( true, stat.size() > 0 );
129
130     unlink(".foobar");
131 }
132
133 BOOST_AUTO_TEST_CASE(DirTest1)
134 {
135     typedef std::vector< std::string > StringVector;
136     StringVector names;
137
138     bool res= I2n::get_dir(".",names);
139
140     BOOST_CHECK_EQUAL( true, res );
141     BOOST_CHECK( ! names.empty() );
142
143     StringVector::iterator it = std::find( names.begin(), names.end(), "Makefile");
144     BOOST_CHECK( it != names.end() );
145
146     it = std::find( names.begin(), names.end(), "." );
147     BOOST_CHECK( it == names.end() );
148
149     names= get_dir(".",true);
150     BOOST_CHECK( ! names.empty() );
151
152     for (it= names.begin(); it!=names.end(); ++it)
153     {
154         DOUT("  \"" << *it << "\"");
155         BOOST_CHECK_EQUAL( false, it->empty() );
156     }
157
158     it = std::find( names.begin(), names.end(), "." );
159     BOOST_CHECK( it != names.end() );
160 } // eo DirTest1
161
162
163
164 BOOST_AUTO_TEST_CASE(PathCuts1)
165 {
166     std::string path1("/an/absolute/path");
167
168     BOOST_CHECK_EQUAL( std::string("/an/absolute"), dirname(path1) );
169     BOOST_CHECK_EQUAL( std::string("path"), basename(path1) );
170
171     std::string path2("just.a.name");
172     BOOST_CHECK_EQUAL( std::string("just.a.name"), basename(path2) );
173     BOOST_CHECK_EQUAL( std::string("."), dirname(path2) );
174 } // eo PathCuts1()
175
176
177
178 BOOST_AUTO_TEST_CASE(NormalizePath1)
179 {
180     std::string path;
181
182     path= normalize_path("/a/simple/path/");
183     BOOST_CHECK_EQUAL( std::string("/a/simple/path"), path );
184
185     path= normalize_path("//another///simple/.//path//");
186     BOOST_CHECK_EQUAL( std::string("/another/simple/path"), path );
187
188     path= normalize_path("//..//..//a/dummy///../././simple/././/path//");
189     BOOST_CHECK_EQUAL( std::string("/a/simple/path"), path );
190
191     path= normalize_path("../a/dummy//././..//simple//nice//absolute//.././..//relative/path//");
192     BOOST_CHECK_EQUAL( std::string("../a/simple/relative/path"), path );
193
194     path= normalize_path("../../a/dummy//././..//simple/../nice//absolute//../.x/..//relative/path//");
195     BOOST_CHECK_EQUAL( std::string("../../a/nice/relative/path"), path );
196
197 } // eo NormalizePath1
198
199 BOOST_AUTO_TEST_CASE(NormalizePath2)
200 {
201     std::string path;
202
203     path= normalize_path("/");
204     BOOST_CHECK_EQUAL( std::string("/"), path );
205
206     path= normalize_path("//");
207     BOOST_CHECK_EQUAL( std::string("/"), path );
208
209     path= normalize_path("/.//");
210     BOOST_CHECK_EQUAL( std::string("/"), path );
211
212     path= normalize_path(".");
213     BOOST_CHECK_EQUAL( std::string(""), path );
214
215     path= normalize_path("./");
216     BOOST_CHECK_EQUAL( std::string(""), path );
217
218     path= normalize_path(".///");
219     BOOST_CHECK_EQUAL( std::string(""), path );
220
221     path= normalize_path("/./data/files");
222     BOOST_CHECK_EQUAL( std::string("/data/files"), path );
223
224     path= normalize_path("./data/files/");
225     BOOST_CHECK_EQUAL( std::string("data/files"), path );
226 } // eo NormalizePath2
227
228 BOOST_AUTO_TEST_CASE(TestUserAndGroupStuff1)
229 {
230     User user_root((uid_t)0);
231     BOOST_CHECK_EQUAL( true, user_root.is_valid() );
232     BOOST_CHECK_EQUAL( true, (bool)user_root );
233
234     BOOST_CHECK_EQUAL( std::string("root"), user_root.Name );
235     BOOST_CHECK_EQUAL( (uid_t)0, user_root.Uid );
236     BOOST_CHECK_EQUAL( (gid_t)0, user_root.Gid );
237
238     User user_root2("root");
239     BOOST_CHECK_EQUAL( true, user_root2.is_valid() );
240     BOOST_CHECK_EQUAL( true, (bool)user_root2 );
241
242     BOOST_CHECK_EQUAL( std::string("root"), user_root2.Name );
243     BOOST_CHECK_EQUAL( (uid_t)0, user_root2.Uid );
244     BOOST_CHECK_EQUAL( (gid_t)0, user_root2.Gid );
245
246     Group group_root("root");
247     BOOST_CHECK_EQUAL( true, group_root.is_valid() );
248     BOOST_CHECK_EQUAL( true, (bool)group_root );
249
250     BOOST_CHECK_EQUAL( std::string("root"), group_root.Name );
251     BOOST_CHECK_EQUAL( (gid_t)0, group_root.Gid );
252
253 } // TestUserAndGroupStuff1()
254
255 BOOST_AUTO_TEST_CASE(TestUserAndGroupStuff2)
256 {
257     // Test if is_valid() works correctly
258     User user_root;
259     BOOST_CHECK_EQUAL( false, user_root.is_valid() );
260
261     Group group_root;
262     BOOST_CHECK_EQUAL( false, group_root.is_valid() );
263 }
264
265 BOOST_AUTO_TEST_CASE(TestFileModes1)
266 {
267     std::string path= get_check_file_path("FileModes1");
268
269     write_file(path,"42");
270
271     Stat stat(path, false);
272     BOOST_CHECK_EQUAL( true, stat.is_valid() );
273
274     User user( stat.uid() );
275     Group group( stat.gid() );
276
277     BOOST_CHECK_EQUAL( true, user.is_valid() );
278     BOOST_CHECK_EQUAL( true, group.is_valid() );
279
280     bool res=chown( path, user.Name.c_str(), group.Gid );
281
282     BOOST_CHECK_EQUAL( true, res );
283 } // eo TestFileModes1()
284
285
286
287 BOOST_AUTO_TEST_CASE(TestPidOf1)
288 {
289     using I2n::Daemon::pid_of;
290
291     std::vector< pid_t > pid_list;
292
293     bool res= pid_of("init", pid_list);
294     BOOST_CHECK_EQUAL( true, res);
295     
296     if (pid_list.empty())
297     {
298         res= pid_of("systemd", pid_list);
299         BOOST_CHECK_EQUAL( true, res);
300     }
301     
302     BOOST_CHECK_EQUAL( false, pid_list.empty() );
303
304     std::vector< pid_t >::const_iterator pos1 =
305         std::find( pid_list.begin(), pid_list.end(), 1);
306
307     BOOST_CHECK( pos1 != pid_list.end() );
308 } // eo TestPidOf1()
309
310 BOOST_AUTO_TEST_CASE(TestCopyFileSourceFail)
311 {
312     bool res = copy_file("does not exist", "destination");
313     BOOST_CHECK_EQUAL( false, res );
314 }
315
316 BOOST_AUTO_TEST_CASE(TestCopyFileDestFail)
317 {
318     bool res = copy_file("/etc/HOSTNAME", "/proc/not/writable");
319     BOOST_CHECK_EQUAL( false, res );
320 }
321
322 BOOST_AUTO_TEST_CASE(TestCopyFileOk)
323 {
324     string input = "copy_source";
325     string data = "test";
326
327     long input_size = 0;
328     ofstream finput(input.c_str());
329     if (finput)
330     {
331         finput << data;
332         finput.close();
333         input_size = file_size(input);
334     }
335
336     string output = "copy_dest";
337     long output_size = 0;
338     bool res = copy_file(input, output);
339     if (res)
340     {
341         output_size = file_size(output);
342     }
343     unlink(input);
344     unlink(output);
345
346     bool size_is_zero = output_size == 0 ? true : false;
347
348     BOOST_CHECK_EQUAL( true, res );
349     BOOST_CHECK_EQUAL( input_size, output_size );
350     BOOST_CHECK_EQUAL( false, size_is_zero );
351 }
352
353 BOOST_AUTO_TEST_CASE(TestMkdtemp)
354 {
355     // Create unique directory
356     string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
357     BOOST_REQUIRE(unique_dir.size() > 0);
358
359     // Test if it's really a directory
360     BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
361
362     // Unlink it
363     BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
364 }
365
366 BOOST_AUTO_TEST_CASE(TestMkdtempBrokenTemplate)
367 {
368     // Broken directory template -> fail
369     string unique_dir = I2n::mkdtemp("foobar.XXX");
370     BOOST_CHECK_EQUAL("", unique_dir);
371 }
372
373 BOOST_AUTO_TEST_CASE(DirectoryCreation)
374 {
375     string dirname = "test_directory";
376
377     I2n::rmdir (dirname);
378
379     BOOST_CHECK_EQUAL(true, I2n::mkdir(dirname));
380     BOOST_CHECK_EQUAL(true, Stat(dirname).is_directory());
381     // Verify default permissions
382     BOOST_CHECK_EQUAL(0700, Stat(dirname).mode());
383
384     BOOST_CHECK_EQUAL(true, I2n::rmdir(dirname));
385
386     // Second call  must fail: Directory already deleted
387     BOOST_CHECK_EQUAL(false, I2n::rmdir(dirname));
388 }
389
390 BOOST_AUTO_TEST_CASE(DirectoryCreatePermission)
391 {
392     string dirname = "test_directory";
393
394     // Save and fix umask
395     mode_t previous_mask = I2n::umask(0);
396
397     I2n::rmdir (dirname);
398     BOOST_CHECK_EQUAL(true, I2n::mkdir(dirname, 0770));
399     BOOST_CHECK_EQUAL(0770, Stat(dirname).mode());
400     I2n::rmdir (dirname);
401
402     // Restore umask
403     I2n::umask(previous_mask);
404 }
405
406 BOOST_AUTO_TEST_CASE(ChangeDirectory)
407 {
408     string current_directory = I2n::getcwd();
409     BOOST_REQUIRE(!current_directory.empty());
410
411     BOOST_CHECK_EQUAL(true, I2n::chdir("/"));
412     BOOST_CHECK_EQUAL("/", I2n::getcwd());
413
414     BOOST_CHECK_EQUAL(true, I2n::chdir(current_directory));
415     BOOST_REQUIRE_EQUAL(current_directory, I2n::getcwd());
416 }
417
418 BOOST_AUTO_TEST_CASE(WriteFileEmptyData)
419 {
420     // just to be sure
421     unlink(".foobar");
422
423     I2n::Stat stat(".foobar");
424     BOOST_CHECK_EQUAL( false, (bool)stat );
425
426     // Call write_file() with empty data. Should still create the file.
427     write_file(".foobar","");
428
429     stat.recheck();
430
431     BOOST_CHECK_EQUAL( true, (bool)stat );
432     BOOST_CHECK_EQUAL( true, stat.size() == 0 );
433
434     unlink(".foobar");
435 }
436
437 BOOST_AUTO_TEST_SUITE_END()