allow selecting stdout and stderr with inpipestream
[libi2ncommon] / test / test_tmpfstream.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 module tmpfstream
23  *
24  * (c) Copyright 2010 by Intra2net AG
25  */
26
27 //#define NOISEDEBUG
28
29 #define BOOST_TEST_DYN_LINK
30 #include <boost/test/unit_test.hpp>
31
32 #include <iostream>
33 #include <filefunc.hxx>
34 #include <tmpfstream.hpp>
35
36 #ifdef NOISEDEBUG
37 #define DOUT(msg) std::cout << msg << std::endl
38 #else
39 #define DOUT(msg) do {} while (0)
40 #endif
41
42 using namespace std;
43 using namespace I2n;
44
45 namespace bio = boost::iostreams;
46
47 BOOST_AUTO_TEST_SUITE(TestTmpfstream)
48
49 BOOST_AUTO_TEST_CASE(Tmpofstream)
50 {
51     tmpofstream tmpf("./tmp.XXXXXX");
52
53     BOOST_CHECK_EQUAL( true, tmpf.is_open() );
54     BOOST_CHECK_EQUAL( false, tmpf.get_tmp_filename().empty() );
55
56     Stat stat(tmpf.get_tmp_filename());
57
58     DOUT("filename : " << tmpf.get_tmp_filename());
59
60     BOOST_CHECK_EQUAL( true, (bool)stat );
61     BOOST_CHECK_EQUAL( true, stat.is_regular_file() );
62
63     tmpf << "hello world" << endl;
64
65     tmpf.close();
66     BOOST_CHECK_EQUAL( false, tmpf.is_open() );
67
68     Stat stat2(tmpf.get_tmp_filename());
69
70     DOUT("stated path: " << stat2.path());
71     DOUT("filesize: " << stat2.size());
72
73     BOOST_CHECK_EQUAL( true, stat2.size() > 0 );
74
75     BOOST_CHECK_EQUAL( true, tmpf.unlink() );
76
77     Stat stat3(tmpf.get_tmp_filename());
78     BOOST_CHECK_EQUAL( false, (bool)stat3 );
79
80
81
82 BOOST_AUTO_TEST_CASE(TmpofstreamUnlink)
83 {
84     tmpofstream tmpf("./tmp.XXXXXX");
85
86     BOOST_CHECK_EQUAL( true, tmpf.is_open() );
87
88     Stat stat(tmpf.get_tmp_filename());
89     BOOST_CHECK_EQUAL( true, (bool)stat );
90     BOOST_CHECK_EQUAL( true, stat.is_regular_file() );
91
92     tmpf << "hello world" << endl;
93
94     // keep open but delete file
95     tmpf.unlink();
96     stat.recheck();
97     BOOST_CHECK_EQUAL( false, (bool)stat );
98
99     // writing to already deleted file
100     // POSIX explicitly allows this
101     tmpf << "hello world" << endl;
102     tmpf.flush();
103     BOOST_CHECK_EQUAL( true, tmpf.good() );
104
105     // file still gone after closing
106     tmpf.close();
107     stat.recheck();
108     BOOST_CHECK_EQUAL( false, (bool)stat );
109
110
111 BOOST_AUTO_TEST_CASE(TmpofstreamMove1)
112 {
113     // just to be sure
114     unlink(".foobar");
115
116     tmpofstream tmpf("./tmp.XXXXXX");
117
118     BOOST_CHECK_EQUAL( true, tmpf.is_open() );
119
120     Stat stat(tmpf.get_tmp_filename());
121     BOOST_CHECK_EQUAL( true, (bool)stat );
122     BOOST_CHECK_EQUAL( true, stat.is_regular_file() );
123
124     tmpf << "hello world" << endl;
125     BOOST_CHECK_EQUAL( true, tmpf.sync() );
126
127     BOOST_CHECK_EQUAL( true, tmpf.move(".foobar",false) );
128
129     stat.recheck();
130     BOOST_CHECK_EQUAL( false, (bool)stat );
131
132     Stat stat2(".foobar");
133     BOOST_CHECK_EQUAL( true, (bool)stat2 );
134
135     tmpf.close();
136
137     stat.recheck();
138     BOOST_CHECK_EQUAL( false, (bool)stat );
139
140     stat2.recheck();
141     BOOST_CHECK_EQUAL( true, (bool)stat2 );
142
143     unlink(".foobar");
144
145
146 BOOST_AUTO_TEST_CASE(TmpofstreamMove2)
147 {
148     // just to be sure
149     unlink(".foobar");
150
151     tmpofstream tmpf("./tmp.XXXXXX");
152
153     BOOST_CHECK_EQUAL( true, tmpf.is_open() );
154
155     Stat stat(tmpf.get_tmp_filename());
156     BOOST_CHECK_EQUAL( true, (bool)stat );
157     BOOST_CHECK_EQUAL( true, stat.is_regular_file() );
158
159     tmpf << "hello world" << endl;
160     tmpf.flush();
161
162     BOOST_CHECK_EQUAL( true, tmpf.move(".foobar",true) );
163
164     stat.recheck();
165     BOOST_CHECK_EQUAL( false, (bool)stat );
166
167     Stat stat2(".foobar");
168     BOOST_CHECK_EQUAL( true, (bool)stat2 );
169
170     tmpf.close();
171
172     stat.recheck();
173     BOOST_CHECK_EQUAL( false, (bool)stat );
174
175     stat2.recheck();
176     BOOST_CHECK_EQUAL( true, (bool)stat2 );
177
178     unlink(".foobar");
179
180
181 BOOST_AUTO_TEST_CASE(TmpofstreamMoveOverwrite)
182 {
183     // prepare other file
184     write_file(".foobar","blah");
185
186     tmpofstream tmpf("./tmp.XXXXXX");
187
188     BOOST_CHECK_EQUAL( true, tmpf.is_open() );
189
190     Stat stat(tmpf.get_tmp_filename());
191     BOOST_CHECK_EQUAL( true, (bool)stat );
192     BOOST_CHECK_EQUAL( true, stat.is_regular_file() );
193
194     tmpf << "hello world" << endl;
195     tmpf.flush();
196
197     // no overwrite fails
198     BOOST_CHECK_EQUAL( false, tmpf.move(".foobar",false) );
199
200     // overwrite succeeds
201     BOOST_CHECK_EQUAL( true, tmpf.move(".foobar",true) );
202
203     stat.recheck();
204     BOOST_CHECK_EQUAL( false, (bool)stat );
205
206     Stat stat2(".foobar");
207     BOOST_CHECK_EQUAL( true, (bool)stat2 );
208
209     tmpf.close();
210
211     unlink(".foobar");
212
213
214 BOOST_AUTO_TEST_CASE(TmpofstreamMoveAfterUnlink)
215 {
216     // just to be sure
217     unlink(".foobar");
218
219     tmpofstream tmpf("./tmp.XXXXXX");
220
221     BOOST_CHECK_EQUAL( true, tmpf.is_open() );
222
223     Stat stat(tmpf.get_tmp_filename());
224     BOOST_CHECK_EQUAL( true, (bool)stat );
225     BOOST_CHECK_EQUAL( true, stat.is_regular_file() );
226
227     tmpf << "hello world" << endl;
228     tmpf.flush();
229
230     BOOST_CHECK_EQUAL( true, tmpf.unlink() );
231
232     BOOST_CHECK_EQUAL( true, tmpf.is_unlinked() );
233
234     BOOST_CHECK_EQUAL( false, tmpf.move(".foobar") );
235
236     unlink(".foobar");
237
238
239 BOOST_AUTO_TEST_CASE(TmpofstreamDoubleMove)
240 {
241     // just to be sure
242     unlink(".foobar");
243     unlink(".foobar2");
244
245     tmpofstream tmpf("./tmp.XXXXXX");
246
247     BOOST_CHECK_EQUAL( true, tmpf.is_open() );
248
249     Stat stat(tmpf.get_tmp_filename());
250     BOOST_CHECK_EQUAL( true, (bool)stat );
251
252     tmpf << "hello world" << endl;
253     tmpf.flush();
254
255     BOOST_CHECK_EQUAL( true, tmpf.move(".foobar") );
256
257     stat.recheck();
258     BOOST_CHECK_EQUAL( false, (bool)stat );
259
260     Stat stat2(".foobar");
261     BOOST_CHECK_EQUAL( true, (bool)stat2 );
262
263     BOOST_CHECK_EQUAL( true, tmpf.move(".foobar2") );
264
265     stat.recheck();
266     BOOST_CHECK_EQUAL( false, (bool)stat );
267
268     stat2.recheck();
269     BOOST_CHECK_EQUAL( false, (bool)stat2 );
270
271     Stat stat3(".foobar2");
272     BOOST_CHECK_EQUAL( true, (bool)stat3 );
273
274     tmpf.unlink();
275
276
277 BOOST_AUTO_TEST_CASE(TmpfstreamReadWrite)
278 {
279     tmpfstream tmpf("./tmp.XXXXXX",std::ios_base::out | std::ios_base::in );
280     BOOST_CHECK_EQUAL( true, tmpf.is_open() );
281
282     tmpf << "hello world" << endl;
283
284     tmpf.seekg(0);
285     string input;
286     getline(tmpf,input);
287
288     BOOST_CHECK_EQUAL( "hello world", input );
289
290     tmpf.unlink();
291     tmpf.close();
292 }
293
294 BOOST_AUTO_TEST_CASE(Tmpfcopystream)
295 {
296     write_file(".foobar","blah");
297
298     tmpfcopystream tmpf(".foobar");
299     BOOST_CHECK_EQUAL( true, tmpf.is_open() );
300
301     tmpf << "hello world";
302     tmpf.flush();
303
304     BOOST_CHECK_EQUAL( "blah", read_file(".foobar") );
305
306     tmpf.close();
307     BOOST_CHECK_EQUAL( false, tmpf.is_open() );
308
309     BOOST_CHECK_EQUAL( "hello world", read_file(".foobar") );
310
311     unlink(".foobar");
312 }
313
314 BOOST_AUTO_TEST_CASE(TmpfcopystreamDestructor)
315 {
316     write_file(".foobar","blah");
317
318     {
319         tmpfcopystream tmpf(".foobar");
320         BOOST_CHECK_EQUAL( true, tmpf.is_open() );
321
322         tmpf << "hello world";
323         tmpf.flush();
324
325         BOOST_CHECK_EQUAL( "blah", read_file(".foobar") );
326     }
327
328     BOOST_CHECK_EQUAL( "hello world", read_file(".foobar") );
329
330     unlink(".foobar");
331 }
332
333 BOOST_AUTO_TEST_CASE(TmpfcopystreamAbort)
334 {
335     write_file(".foobar","blah");
336
337     tmpfcopystream tmpf(".foobar");
338     BOOST_CHECK_EQUAL( true, tmpf.is_open() );
339
340     tmpf << "hello world";
341     tmpf.flush();
342
343     // abort the overwriting, keep the old file
344     tmpf.unlink();
345
346     BOOST_CHECK_EQUAL( "blah", read_file(".foobar") );
347
348     unlink(".foobar");
349 }
350
351 BOOST_AUTO_TEST_CASE(TmpfcopystreamChmod)
352 {
353     write_file(".foobar","blah");
354     I2n::chmod(".foobar",0644);
355     Stat stat_orig(".foobar");
356     BOOST_CHECK_EQUAL( 0644, stat_orig.mode() );
357
358     tmpfcopystream tmpf(".foobar");
359
360     tmpf << "hello world";
361     tmpf.flush();
362
363     tmpf.set_filemode_on_close(0640);
364
365     Stat stat_tmp(tmpf.get_tmp_filename());
366     BOOST_CHECK_EQUAL( 0600, stat_tmp.mode() );
367
368     tmpf.close();
369
370     stat_orig.recheck();
371     BOOST_CHECK_EQUAL( 0640, stat_orig.mode() );
372
373     unlink(".foobar");
374 }
375
376 BOOST_AUTO_TEST_CASE(CreateError)
377 {
378     tmpofstream tmpf("/this/dir/really/does/not/exist/tmp.XXXXXX");
379
380     BOOST_CHECK_EQUAL( false, tmpf.is_open() );
381 }
382
383 BOOST_AUTO_TEST_SUITE_END()