1#include <string>
2#if !defined (STLPORT) || !defined (_STLP_USE_NO_IOSTREAMS)
3#  include <fstream>
4#  include <iostream>
5#  include <iomanip>
6#  include <sstream>
7#  include <vector>
8#  include <stdexcept>
9
10#include <stdio.h>
11
12#  include "full_streambuf.h"
13#  include "cppunit/cppunit_proxy.h"
14
15#  if !defined (STLPORT) || defined(_STLP_USE_NAMESPACES)
16using namespace std;
17#  endif
18
19//The macro value gives approximately the generated file
20//size in Go
21//#define CHECK_BIG_FILE 4
22
23#  if (!defined(STLPORT) && (defined (__GNUC__) && (__GNUC__ > 3))) || \
24      (defined (STLPORT) && !defined (_STLP_NO_CUSTOM_IO) && !defined (_STLP_NO_MEMBER_TEMPLATES) && \
25                            !((defined (_STLP_MSVC) && (_STLP_MSVC < 1300)) || \
26                              (defined (__GNUC__) && (__GNUC__ < 3)) || \
27                              (defined (__SUNPRO_CC)) || \
28                              (defined (__DMC__) && defined (_DLL))))
29#    define DO_CUSTOM_FACET_TEST
30#  endif
31
32//
33// TestCase class
34//
35class FstreamTest : public CPPUNIT_NS::TestCase
36{
37  CPPUNIT_TEST_SUITE(FstreamTest);
38  CPPUNIT_TEST(output);
39  CPPUNIT_TEST(input);
40  CPPUNIT_TEST(input_char);
41  CPPUNIT_TEST(io);
42  CPPUNIT_TEST(err);
43  CPPUNIT_TEST(tellg);
44  CPPUNIT_TEST(tellp);
45  CPPUNIT_TEST(seek);
46  CPPUNIT_TEST(buf);
47  CPPUNIT_TEST(rdbuf);
48  CPPUNIT_TEST(streambuf_output);
49  CPPUNIT_TEST(win32_file_format);
50  CPPUNIT_TEST(null_stream);
51#  if defined (STLPORT) && (defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
52  CPPUNIT_IGNORE;
53#  endif
54  CPPUNIT_TEST(null_buf);
55#  if !defined (STLPORT) || !defined (_STLP_WIN32)
56  CPPUNIT_TEST(offset);
57#  endif
58#  if defined (CHECK_BIG_FILE)
59  CPPUNIT_TEST(big_file);
60#  endif
61#  if !defined (DO_CUSTOM_FACET_TEST)
62  CPPUNIT_IGNORE;
63#  endif
64  CPPUNIT_TEST(custom_facet);
65  CPPUNIT_TEST_SUITE_END();
66
67  protected:
68    void output();
69    void input();
70    void input_char();
71    void io();
72    void err();
73    void tellg();
74    void tellp();
75    void seek();
76    void buf();
77    void rdbuf();
78    void streambuf_output();
79    void win32_file_format();
80    void null_stream();
81    void null_buf();
82#  if !defined (STLPORT) || !defined (_STLP_WIN32)
83    void offset();
84#  endif
85    void custom_facet();
86#  if defined (CHECK_BIG_FILE)
87    void big_file();
88#  endif
89};
90
91CPPUNIT_TEST_SUITE_REGISTRATION(FstreamTest);
92
93//
94// tests implementation
95//
96void FstreamTest::output()
97{
98  ofstream f( "test_file.txt" );
99
100#if 1
101  CPPUNIT_ASSERT (f.good());
102  f << 1;
103  CPPUNIT_ASSERT (f.good());
104  f << '\n';
105  CPPUNIT_ASSERT (f.good());
106  f << 2.0;
107  CPPUNIT_ASSERT (f.good());
108  f << '\n';
109  CPPUNIT_ASSERT (f.good());
110  f << "abcd\n";
111  CPPUNIT_ASSERT (f.good());
112  f << "ghk lm\n";
113  CPPUNIT_ASSERT (f.good());
114  f << "abcd ef";
115  CPPUNIT_ASSERT (f.good());
116#else
117  f << 1 << '\n' << 2.0 << '\n' << "abcd\n" << "ghk lm\n" << "abcd ef";
118  CPPUNIT_ASSERT (f.good());
119#endif
120  // CPPUNIT_ASSERT( s.str() == "1\n2\nabcd\nghk lm\nabcd ef" );
121}
122
123void FstreamTest::input()
124{
125  {
126    ifstream f( "test_file.txt" );
127    int i = 0;
128    f >> i;
129    CPPUNIT_ASSERT( f.good() );
130    CPPUNIT_ASSERT( i == 1 );
131    double d = 0.0;
132    f >> d;
133    CPPUNIT_ASSERT( f.good() );
134    CPPUNIT_ASSERT( d == 2.0 );
135    string str;
136    f >> str;
137    CPPUNIT_ASSERT( f.good() );
138    CPPUNIT_ASSERT( str == "abcd" );
139    char c;
140    f.get(c); // extract newline, that not extracted by operator >>
141    CPPUNIT_ASSERT( f.good() );
142    CPPUNIT_ASSERT( c == '\n' );
143    getline( f, str );
144    CPPUNIT_ASSERT( f.good() );
145    CPPUNIT_ASSERT( str == "ghk lm" );
146    getline( f, str );
147    CPPUNIT_ASSERT( f.eof() );
148    CPPUNIT_ASSERT( str == "abcd ef" );
149  }
150#if defined (STLPORT) && !defined (_STLP_USE_WIN32_IO)
151  {
152    ifstream in("/tmp");
153    if (in.good()) {
154      string s;
155      getline(in, s);
156      CPPUNIT_ASSERT( in.fail() );
157    }
158  }
159#endif
160}
161
162void FstreamTest::input_char()
163{
164  char buf[16] = { 0, '1', '2', '3' };
165  ifstream s( "test_file.txt" );
166  s >> buf;
167
168  CPPUNIT_ASSERT( buf[0] == '1' );
169  CPPUNIT_ASSERT( buf[1] == 0 );
170  CPPUNIT_ASSERT( buf[2] == '2' );
171}
172
173void FstreamTest::io()
174{
175  basic_fstream<char,char_traits<char> > f( "test_file.txt", ios_base::in | ios_base::out | ios_base::trunc );
176
177  CPPUNIT_ASSERT( f.is_open() );
178
179  f << 1 << '\n' << 2.0 << '\n' << "abcd\n" << "ghk lm\n" << "abcd ef";
180
181  // f.flush();
182  f.seekg( 0, ios_base::beg );
183
184  int i = 0;
185  f >> i;
186  CPPUNIT_ASSERT( f.good() );
187  CPPUNIT_ASSERT( i == 1 );
188  double d = 0.0;
189  f >> d;
190  CPPUNIT_ASSERT( d == 2.0 );
191  string s;
192  f >> s;
193  CPPUNIT_ASSERT( f.good() );
194  CPPUNIT_ASSERT( s == "abcd" );
195  char c;
196  f.get(c); // extract newline, that not extracted by operator >>
197  CPPUNIT_ASSERT( f.good() );
198  CPPUNIT_ASSERT( c == '\n' );
199  getline( f, s );
200  CPPUNIT_ASSERT( f.good() );
201  CPPUNIT_ASSERT( s == "ghk lm" );
202  getline( f, s );
203  CPPUNIT_ASSERT( !f.fail() );
204  CPPUNIT_ASSERT( s == "abcd ef" );
205  CPPUNIT_ASSERT( f.eof() );
206}
207
208void FstreamTest::err()
209{
210  basic_fstream<char,char_traits<char> > f( "test_file.txt", ios_base::in | ios_base::out | ios_base::trunc );
211
212  CPPUNIT_ASSERT( f.is_open() );
213
214  int i = 9;
215  f << i;
216  CPPUNIT_ASSERT( f.good() );
217  i = 0;
218  f.seekg( 0, ios_base::beg );
219  f >> i;
220  CPPUNIT_ASSERT( !f.fail() );
221  CPPUNIT_ASSERT( i == 9 );
222  f >> i;
223  CPPUNIT_ASSERT( f.fail() );
224  CPPUNIT_ASSERT( f.eof() );
225  CPPUNIT_ASSERT( i == 9 );
226}
227
228void FstreamTest::tellg()
229{
230  {
231    // bogus ios_base::binary is for Wins
232    ofstream of("test_file.txt", ios_base::out | ios_base::binary | ios_base::trunc);
233    CPPUNIT_ASSERT( of.is_open() );
234
235    for (int i = 0; i < 50; ++i) {
236      of << "line " << setiosflags(ios_base::right) << setfill('0') << setw(2) << i << "\n";
237      CPPUNIT_ASSERT( !of.fail() );
238    }
239    of.close();
240  }
241
242  {
243    // bogus ios_base::binary is for Wins
244    ifstream is("test_file.txt", ios_base::in | ios_base::binary);
245    CPPUNIT_ASSERT( is.is_open() );
246    char buf[64];
247
248    // CPPUNIT_ASSERT( is.tellg() == 0 );
249    streampos p = 0;
250    for (int i = 0; i < 50; ++i) {
251      is.read(buf, 0);
252      CPPUNIT_ASSERT( is.gcount() == 0 );
253      CPPUNIT_ASSERT( is.tellg() == p );
254      is.read( buf, 8 );
255      CPPUNIT_ASSERT( !is.fail() );
256      CPPUNIT_ASSERT( is.gcount() == 8 );
257      p += 8;
258    }
259  }
260
261  {
262    // bogus ios_base::binary is for Wins
263    ifstream is("test_file.txt", ios_base::in | ios_base::binary);
264    CPPUNIT_ASSERT( is.is_open() );
265
266    streampos p = 0;
267    for (int i = 0; i < 50; ++i) {
268      CPPUNIT_ASSERT( !is.fail() );
269      is.tellg();
270      CPPUNIT_ASSERT( is.tellg() == p );
271      p += 8;
272      is.seekg( p, ios_base::beg  );
273      CPPUNIT_ASSERT( !is.fail() );
274    }
275  }
276
277  {
278    // bogus ios_base::binary is for Wins
279    ifstream is("test_file.txt", ios_base::in | ios_base::binary);
280    CPPUNIT_ASSERT( is.is_open() );
281
282    streampos p = 0;
283    for (int i = 0; i < 50; ++i) {
284      CPPUNIT_ASSERT( is.tellg() == p );
285      p += 8;
286      is.seekg( 8, ios_base::cur );
287      CPPUNIT_ASSERT( !is.fail() );
288    }
289  }
290}
291
292void FstreamTest::tellp()
293{
294  {
295    ofstream o( "test_file.txt" );
296
297    o << "123456";
298
299    CPPUNIT_CHECK( o.rdbuf()->pubseekoff( 0, ios_base::cur, ios_base::out ) == ofstream::pos_type(6) );
300    CPPUNIT_CHECK( o.tellp() == ofstream::pos_type(6) );
301  }
302  {
303    ofstream o( "test_file.txt" );
304
305    o << "123456789";
306
307    CPPUNIT_CHECK( o.rdbuf()->pubseekoff( 0, ios_base::cur, ios_base::out ) == ofstream::pos_type(9) );
308    CPPUNIT_CHECK( o.tellp() == ofstream::pos_type(9) );
309  }
310  /* According to the standard
311     ofstream o( "test_file.txt", ios_base::app | ios_base::out )
312     should give the same effect as fopen( "test_file.txt", "a" ).
313     Problem is fopen( "test_file.txt", "a" ) has a bit different behaviour
314     on different platforms, and this difference is not covered by specification.
315     After fopen( "test_file.txt", "a" ) in this context ftell( f ) == 9 for
316     Linux and Mac OS X (I expect the same for others POSIX-like platforms too);
317     on Windows (independently from version?) ftell( f ) == 0, i.e. write pointer not
318     shifted to EOF (but shifted to EOF just before write, as described in the specs).
319
320     It isn't specifications violation, neither for Linux and Mac OS X nor for Windows.
321
322     The code below is intended to demonstrate ambiguity (dependance from fopen implementation).
323   */
324  {
325    #ifdef WIN32
326    //In Windows, stlport and fopen use kernel32.CreateFile for open.
327    //File position is at BOF after open, unless we open with ios_base::ate
328    long expected_pos = 0;
329    #else
330    //On UNIX flavours, stlport and fopen use unix's open
331    //File position is at EOF after open
332    //
333    //3rd possible scenario, "other platforms" - _STLP_USE_STDIO_IO
334    //stlport uses fopen here. This case may fail this test, since the file position after
335    //fopen is implementation-dependent
336    long expected_pos = 9;
337    #endif
338    ofstream o( "test_file.txt", ios_base::app | ios_base::out );
339    CPPUNIT_CHECK( o.rdbuf()->pubseekoff( 0, ios_base::cur, ios_base::out ) == ofstream::pos_type(expected_pos) );
340    CPPUNIT_CHECK( o.tellp() == ofstream::pos_type(expected_pos) );
341  }
342  { // for reference, to test fopen/ftell behaviour in append mode:
343    #ifdef WIN32
344    long expected_pos = 0;
345    #else
346    long expected_pos = 9;
347    #endif
348    FILE* f = fopen( "test_file.txt", "a" );
349    CPPUNIT_ASSERT( f != NULL );
350    CPPUNIT_CHECK( ftell( f ) == expected_pos );
351    fclose( f );
352  }
353  {
354    //In append mode, file is positioned at EOF just before a write.
355    // After a write, file is at EOF. This is implementation-independent.
356    ofstream o( "test_file.txt", ios_base::app | ios_base::out );
357    o << "X";
358    CPPUNIT_CHECK( o.rdbuf()->pubseekoff( 0, ios_base::cur, ios_base::out ) == ofstream::pos_type(10) );
359    CPPUNIT_CHECK( o.tellp() == ofstream::pos_type(10) );
360  }
361}
362
363void FstreamTest::buf()
364{
365  fstream ss( "test_file.txt", ios_base::in | ios_base::out | ios_base::binary | ios_base::trunc );
366
367  ss << "1234567\n89\n";
368  ss.seekg( 0, ios_base::beg );
369  char buf[10];
370  buf[7] = 'x';
371  ss.get( buf, 10 );
372  CPPUNIT_ASSERT( !ss.fail() );
373  CPPUNIT_ASSERT( buf[0] == '1' );
374  CPPUNIT_ASSERT( buf[1] == '2' );
375  CPPUNIT_ASSERT( buf[2] == '3' );
376  CPPUNIT_ASSERT( buf[3] == '4' );
377  CPPUNIT_ASSERT( buf[4] == '5' );
378  CPPUNIT_ASSERT( buf[5] == '6' );
379  CPPUNIT_ASSERT( buf[6] == '7' ); // 27.6.1.3 paragraph 10, paragraph 7
380  CPPUNIT_ASSERT( buf[7] == 0 ); // 27.6.1.3 paragraph 8
381  char c;
382  ss.get(c);
383  CPPUNIT_ASSERT( !ss.fail() );
384  CPPUNIT_ASSERT( c == '\n' ); // 27.6.1.3 paragraph 10, paragraph 7
385  ss.get(c);
386  CPPUNIT_ASSERT( !ss.fail() );
387  CPPUNIT_ASSERT( c == '8' );
388}
389
390void FstreamTest::seek()
391{
392  {
393    // Test in binary mode:
394    {
395      fstream s( "test_file.txt", ios_base::in | ios_base::out | ios_base::binary | ios_base::trunc );
396      CPPUNIT_ASSERT( s );
397
398      s << "1234567890\n";
399      CPPUNIT_ASSERT( s );
400    }
401
402    char b1[] = { 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x' };
403    fstream s( "test_file.txt", ios_base::in | ios_base::out | ios_base::binary );
404    CPPUNIT_ASSERT( s );
405
406    int chars_read = (int)s.rdbuf()->sgetn( b1, sizeof(b1) );
407    CPPUNIT_CHECK( chars_read == 11 );
408    CPPUNIT_CHECK( b1[9] == '0' );
409    CPPUNIT_ASSERT( s.rdbuf()->pubseekoff( 0, ios_base::cur ) == fstream::pos_type(chars_read) );
410    CPPUNIT_ASSERT( s.rdbuf()->pubseekoff( -chars_read, ios_base::cur ) == fstream::pos_type(0) );
411
412    char b2[10] = { 'y', 'y', 'y', 'y', 'y', 'y', 'y', 'y', 'y', 'y' };
413
414    CPPUNIT_ASSERT( s.rdbuf()->sgetn( b2, 10 ) == 10 );
415    CPPUNIT_CHECK( b2[9] == '0' );
416  }
417
418  {
419    // Test in text mode:
420    {
421      fstream s( "test_file.txt", ios_base::in | ios_base::out | ios_base::trunc );
422      CPPUNIT_ASSERT( s );
423
424      s << "1234567890\n";
425      CPPUNIT_ASSERT( s );
426    }
427
428    char b1[] = { 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x' };
429    fstream s( "test_file.txt", ios_base::in | ios_base::out );
430    CPPUNIT_ASSERT( s );
431
432    int chars_read = (int)s.rdbuf()->sgetn( b1, sizeof(b1) );
433    CPPUNIT_CHECK( chars_read == 11 );
434    CPPUNIT_CHECK( b1[9] == '0' );
435
436    fstream::pos_type pos = s.rdbuf()->pubseekoff(0, ios_base::cur);
437    // Depending on how '\n' is written in file, file position can be greater or equal to the number of chars_read read.
438    streamoff offset = pos;
439    CPPUNIT_ASSERT( offset >= chars_read );
440    offset = s.rdbuf()->pubseekoff( -offset, ios_base::cur );
441    CPPUNIT_ASSERT( offset == 0 );
442
443    char b2[10] = { 'y', 'y', 'y', 'y', 'y', 'y', 'y', 'y', 'y', 'y' };
444
445    CPPUNIT_ASSERT( s.rdbuf()->sgetn( b2, 5 ) == 5 );
446    CPPUNIT_CHECK( b2[4] == '5' );
447
448    pos = s.rdbuf()->pubseekoff(0, ios_base::cur);
449    CPPUNIT_ASSERT( pos == fstream::pos_type(5) );
450    CPPUNIT_ASSERT( s.rdbuf()->pubseekoff(-5, ios_base::cur) == fstream::pos_type(0) );
451  }
452
453#if !defined (STLPORT) || \
454    (!defined (_STLP_NO_WCHAR_T) && defined (_STLP_USE_EXCEPTIONS))
455  {
456    // Test with a wariable encoding:
457    locale loc;
458    try
459    {
460      locale tmp(locale::classic(), new codecvt_byname<wchar_t, char, mbstate_t>(".UTF8"));
461      loc = tmp;
462    }
463    catch (const runtime_error&)
464    {
465      // Localization no supported so no test:
466      return;
467    }
468
469    {
470      wfstream s( "test_file.txt", ios_base::in | ios_base::out | ios_base::trunc );
471      CPPUNIT_ASSERT( s );
472      s.imbue(loc);
473      CPPUNIT_ASSERT( s );
474
475      s << L"1234567890\n";
476      CPPUNIT_ASSERT( s );
477    }
478
479    wchar_t b1[] = { L'x', L'x', L'x', L'x', L'x', L'x', L'x', L'x', L'x', L'x', L'x', L'x', L'x', L'x', L'x', L'x', L'x', L'x', L'x', L'x' };
480    wfstream s( "test_file.txt", ios_base::in | ios_base::out );
481    CPPUNIT_ASSERT( s );
482    s.imbue(loc);
483    CPPUNIT_ASSERT( s );
484
485    int chars_read = (int)s.rdbuf()->sgetn( b1, sizeof(b1) / sizeof(wchar_t) );
486    CPPUNIT_CHECK( chars_read == 11 );
487    CPPUNIT_CHECK( b1[9] == L'0' );
488
489    fstream::pos_type pos = s.rdbuf()->pubseekoff(0, ios_base::cur);
490    // Depending on how '\n' is written in file, file position can be greater or equal to the number of chars_read read.
491    streamoff off = pos;
492    CPPUNIT_ASSERT( off >= chars_read );
493    off = s.rdbuf()->pubseekoff(-off, ios_base::cur);
494    CPPUNIT_ASSERT( off == -1 );
495    off = s.rdbuf()->pubseekoff(0, ios_base::beg);
496    CPPUNIT_ASSERT( off == 0 );
497
498    wchar_t b2[10] = { L'y', L'y', L'y', L'y', L'y', L'y', L'y', L'y', L'y', L'y' };
499
500    CPPUNIT_ASSERT( s.rdbuf()->sgetn( b2, 5 ) == 5 );
501    CPPUNIT_CHECK( b2[4] == L'5' );
502
503    pos = s.rdbuf()->pubseekoff(0, ios_base::cur);
504    CPPUNIT_ASSERT( pos == fstream::pos_type(5) );
505    //CPPUNIT_ASSERT( s.rdbuf()->pubseekoff(-5, ios_base::cur) == fstream::pos_type(0) );
506  }
507#endif
508}
509
510void FstreamTest::rdbuf()
511{
512  fstream ss( "test_file.txt", ios_base::in | ios_base::out | ios_base::binary | ios_base::trunc );
513
514  ss << "1234567\n89\n";
515  ss.seekg( 0, ios_base::beg );
516
517  ostringstream os;
518  ss.get( *os.rdbuf(), '\n' );
519  CPPUNIT_ASSERT( !ss.fail() );
520  char c;
521  ss.get(c);
522  CPPUNIT_ASSERT( !ss.fail() );
523  CPPUNIT_ASSERT( c == '\n' ); // 27.6.1.3 paragraph 12
524  CPPUNIT_ASSERT( os.str() == "1234567" );
525}
526
527void FstreamTest::streambuf_output()
528{
529  {
530    ofstream ofstr("test_file.txt", ios_base::binary);
531    if (!ofstr)
532      //No test if we cannot create the file
533      return;
534    ofstr << "01234567890123456789";
535    CPPUNIT_ASSERT( ofstr );
536  }
537
538  {
539    ifstream in("test_file.txt", ios_base::binary);
540    CPPUNIT_ASSERT( in );
541
542    full_streambuf full_buf(10);
543    ostream out(&full_buf);
544    CPPUNIT_ASSERT( out );
545
546    out << in.rdbuf();
547    CPPUNIT_ASSERT( out );
548    CPPUNIT_ASSERT( in );
549    CPPUNIT_ASSERT( full_buf.str() == "0123456789" );
550
551    out << in.rdbuf();
552    CPPUNIT_ASSERT( out.fail() );
553    CPPUNIT_ASSERT( in );
554
555    ostringstream ostr;
556    ostr << in.rdbuf();
557    CPPUNIT_ASSERT( ostr );
558    CPPUNIT_ASSERT( in );
559    CPPUNIT_ASSERT( ostr.str() == "0123456789" );
560  }
561
562#  if !defined (STLPORT) || defined (_STLP_USE_EXCEPTIONS)
563  {
564    //If the output stream buffer throws:
565    ifstream in("test_file.txt", ios_base::binary);
566    CPPUNIT_ASSERT( in );
567
568    full_streambuf full_buf(10, true);
569    ostream out(&full_buf);
570    CPPUNIT_ASSERT( out );
571
572    out << in.rdbuf();
573    CPPUNIT_ASSERT( out.bad() );
574    CPPUNIT_ASSERT( in );
575    //out is bad we have no guaranty on what has been extracted:
576    //CPPUNIT_ASSERT( full_buf.str() == "0123456789" );
577
578    out.clear();
579    out << in.rdbuf();
580    CPPUNIT_ASSERT( out.fail() && out.bad() );
581    CPPUNIT_ASSERT( in );
582
583    ostringstream ostr;
584    ostr << in.rdbuf();
585    CPPUNIT_ASSERT( ostr );
586    CPPUNIT_ASSERT( in );
587    CPPUNIT_ASSERT( ostr.str() == "0123456789" );
588  }
589#  endif
590}
591
592void FstreamTest::win32_file_format()
593{
594  const char* file_name = "win32_file_format.tmp";
595  const size_t nb_lines = 2049;
596  {
597    ofstream out(file_name);
598    CPPUNIT_ASSERT( out.good() );
599    out << 'a';
600    for (size_t i = 0; i < nb_lines - 1; ++i) {
601      out << '\n';
602    }
603    out << '\r';
604    CPPUNIT_ASSERT( out.good() );
605  }
606  {
607    ifstream in(file_name);
608    CPPUNIT_ASSERT( in.good() );
609    string line, last_line;
610    size_t nb_read_lines = 0;
611    while (getline(in, line)) {
612      ++nb_read_lines;
613      last_line = line;
614    }
615    CPPUNIT_ASSERT( in.eof() );
616    CPPUNIT_ASSERT( nb_read_lines == nb_lines );
617    CPPUNIT_ASSERT( !last_line.empty() && (last_line[0] == '\r') );
618  }
619}
620
621#if defined (DO_CUSTOM_FACET_TEST)
622struct my_state {
623  char dummy;
624};
625
626struct my_traits : public char_traits<char> {
627  typedef my_state state_type;
628  typedef fpos<state_type> pos_type;
629};
630
631#if !defined (STLPORT)
632//STLport grant a default implementation, other Standard libs implementation
633//do not necessarily do the same:
634namespace std {
635  template <>
636  class codecvt<char, char, my_state>
637    : public locale::facet, public codecvt_base {
638  public:
639    typedef char intern_type;
640    typedef char extern_type;
641    typedef my_state state_type;
642
643    explicit codecvt(size_t __refs = 0) : locale::facet(__refs) {}
644    result out(state_type&,
645               const intern_type*  __from,
646               const intern_type*,
647               const intern_type*& __from_next,
648               extern_type*        __to,
649               extern_type*,
650               extern_type*&       __to_next) const
651    { __from_next = __from; __to_next   = __to; return noconv; }
652
653    result in (state_type&,
654               const extern_type*  __from,
655               const extern_type*,
656               const extern_type*& __from_next,
657               intern_type*        __to,
658               intern_type*,
659               intern_type*&       __to_next) const
660    { __from_next = __from; __to_next = __to; return noconv; }
661
662    result unshift(state_type&,
663                   extern_type* __to,
664                   extern_type*,
665                   extern_type*& __to_next) const
666    { __to_next = __to; return noconv; }
667
668    int encoding() const throw()
669    { return 1; }
670
671    bool always_noconv() const throw()
672    { return true; }
673
674    int length(const state_type&,
675               const extern_type* __from,
676               const extern_type* __end,
677               size_t __max) const
678    { return (int)min(static_cast<size_t>(__end - __from), __max); }
679
680    int max_length() const throw()
681    { return 1; }
682
683    static locale::id id;
684  };
685
686  locale::id codecvt<char, char, my_state>::id;
687}
688#  else
689#    if defined (__BORLANDC__) && (__BORLANDC__ < 0x590)
690template <>
691locale::id codecvt<char, char, my_state>::id;
692#    endif
693#  endif
694#endif
695
696void FstreamTest::custom_facet()
697{
698#if defined (DO_CUSTOM_FACET_TEST)
699  const char* fileName = "test_file.txt";
700  //File preparation:
701  {
702    ofstream ofstr(fileName, ios_base::binary);
703    ofstr << "0123456789";
704    CPPUNIT_ASSERT( ofstr );
705  }
706
707  {
708    typedef basic_ifstream<char, my_traits> my_ifstream;
709    typedef basic_string<char, my_traits> my_string;
710
711    my_ifstream ifstr(fileName);
712    CPPUNIT_ASSERT( ifstr );
713
714#  if !defined (STLPORT) || defined (_STLP_USE_EXCEPTIONS)
715    ifstr.imbue(locale::classic());
716    CPPUNIT_ASSERT( ifstr.fail() && !ifstr.bad() );
717    ifstr.clear();
718#  endif
719    typedef codecvt<char, char, my_state> my_codecvt;
720    locale my_loc(locale::classic(), new my_codecvt());
721    // Check that my_codecvt has not replace default codecvt:
722    CPPUNIT_ASSERT( (has_facet<my_codecvt>(my_loc)) );
723    CPPUNIT_ASSERT( (has_facet<codecvt<char, char, mbstate_t> >(my_loc)) );
724#  if !defined (STLPORT) || !defined (_STLP_NO_WCHAR_T)
725    CPPUNIT_ASSERT( (has_facet<codecvt<wchar_t, char, mbstate_t> >(my_loc)) );
726#  endif
727    ifstr.imbue(my_loc);
728    CPPUNIT_ASSERT( ifstr.good() );
729    /*
730    my_string res;
731    ifstr >> res;
732    CPPUNIT_ASSERT( !ifstr.fail() );
733    CPPUNIT_ASSERT( !ifstr.bad() );
734    CPPUNIT_ASSERT( ifstr.eof() );
735    CPPUNIT_ASSERT( res == "0123456789" );
736    */
737  }
738#endif
739}
740
741#  if defined (CHECK_BIG_FILE)
742void FstreamTest::big_file()
743{
744  vector<pair<streamsize, streamoff> > file_pos;
745
746  //Big file creation:
747  {
748    ofstream out("big_file.txt");
749    CPPUNIT_ASSERT( out );
750
751    //We are going to generate a file with the following schema for the content:
752    //0(1019 times)0000  //1023 characters + 1 charater for \n (for some platforms it will be a 1 ko line)
753    //0(1019 times)0001
754    //...
755    //0(1019 times)1234
756    //...
757
758    //Generation of the number of loop:
759    streamoff nb = 1;
760    for (int i = 0; i < 20; ++i) {
761      //This assertion check that the streamoff can at least represent the necessary integers values
762      //for this test:
763      CPPUNIT_ASSERT( (nb << 1) > nb );
764      nb <<= 1;
765    }
766    CPPUNIT_ASSERT( nb * CHECK_BIG_FILE >= nb );
767    nb *= CHECK_BIG_FILE;
768
769    //Preparation of the ouput stream state:
770    out << setiosflags(ios_base::right) << setfill('*');
771    for (streamoff index = 0; index < nb; ++index) {
772      if (index % 1024 == 0) {
773        file_pos.push_back(make_pair(out.tellp(), index));
774        CPPUNIT_ASSERT( file_pos.back().first != streamsize(-1) );
775        if (file_pos.size() > 1) {
776          CPPUNIT_ASSERT( file_pos[file_pos.size() - 1].first > file_pos[file_pos.size() - 2].first );
777        }
778      }
779      out << setw(1023) << index << '\n';
780    }
781  }
782
783  {
784    ifstream in("big_file.txt");
785    CPPUNIT_ASSERT( in );
786
787    string line;
788    vector<pair<streamsize, streamsize> >::const_iterator pit(file_pos.begin()),
789                                                          pitEnd(file_pos.end());
790    for (; pit != pitEnd; ++pit) {
791      in.seekg((*pit).first);
792      CPPUNIT_ASSERT( in );
793      in >> line;
794      size_t lastStarPos = line.rfind('*');
795      CPPUNIT_ASSERT( atoi(line.substr(lastStarPos + 1).c_str()) == (*pit).second );
796    }
797  }
798
799  /*
800  The following test has been used to check that STLport do not generate
801  an infinite loop when the file size is larger than the streamsize and
802  streamoff representation (32 bits or 64 bits).
803  {
804    ifstream in("big_file.txt");
805    CPPUNIT_ASSERT( in );
806    char tmp[4096];
807    streamsize nb_reads = 0;
808    while ((!in.eof()) && in.good()){
809      in.read(tmp, 4096);
810      nb_reads += in.gcount();
811    }
812  }
813  */
814}
815#  endif
816
817void FstreamTest::null_stream()
818{
819#  if (defined (STLPORT) && defined (_STLP_USE_WIN32_IO)) || \
820      (!defined (STLPORT) && (defined (WIN32) || defined (_WIN32)))
821  const char* nullStreamName = "NUL";
822#  else
823  const char* nullStreamName = "/dev/null";
824#  endif
825  {
826    ofstream nullStream(nullStreamName);
827    CPPUNIT_CHECK( nullStream );
828  }
829
830  {
831    ofstream nullStream(nullStreamName, ios_base::ate);
832    CPPUNIT_CHECK( nullStream );
833  }
834
835  {
836    ofstream nullStream(nullStreamName, ios_base::trunc);
837    CPPUNIT_CHECK( nullStream );
838  }
839
840  {
841    ofstream nullStream(nullStreamName, ios_base::app);
842    CPPUNIT_CHECK( nullStream );
843  }
844
845  {
846    ifstream nullStream(nullStreamName);
847    CPPUNIT_CHECK( nullStream );
848  }
849
850  {
851    ifstream nullStream(nullStreamName, ios_base::ate);
852    CPPUNIT_CHECK( nullStream );
853  }
854
855  {
856    fstream nullStream(nullStreamName);
857    CPPUNIT_CHECK( nullStream );
858  }
859
860  {
861    fstream nullStream(nullStreamName, ios_base::in | ios_base::out | ios_base::ate);
862    CPPUNIT_CHECK( nullStream );
863  }
864
865  {
866    fstream nullStream(nullStreamName, ios_base::in | ios_base::out | ios_base::trunc);
867    CPPUNIT_CHECK( nullStream );
868  }
869}
870
871void FstreamTest::null_buf()
872{
873  /* **********************************************************************************
874
875  testcase for bug #1830513:
876  in _istream.c
877
878  template < class _CharT, class _Traits, class _Is_Delim>
879  streamsize _STLP_CALL __read_unbuffered(basic_istream<_CharT, _Traits>* __that,
880                                          basic_streambuf<_CharT, _Traits>* __buf,
881                                          streamsize _Num, _CharT* __s,
882                                          _Is_Delim __is_delim,
883                                          bool __extract_delim, bool __append_null,
884                                          bool __is_getline)
885
886  can't accept _Num == 0; this is legal case, and may happen from
887
888  template <class _CharT, class _Traits>
889  basic_istream<_CharT, _Traits>&
890  basic_istream<_CharT, _Traits>::getline(_CharT* __s, streamsize __n, _CharT __delim)
891
892  *********************************************************************************** */
893
894  fstream f( "test.txt", ios_base::in | ios_base::out | ios_base::trunc );
895  // string line;
896
897  for ( int i = 0; i < 0x200; ++i ) {
898    f.put( ' ' );
899  }
900
901  // const streambuf *b = f.rdbuf();
902
903  // string s;
904  char buf[1024];
905  buf[0] = 'a';
906  buf[1] = 'b';
907  buf[2] = 'c';
908
909  // getline( f, s );
910  // cerr << f.good() << endl;
911  f.seekg( 0, ios_base::beg );
912  // f.seekg( 0, ios_base::end );
913  // buf[0] = f.get();
914
915  // cerr << (void *)(b->_M_gptr()) << " " << (void *)(b->_M_egptr()) << endl;
916  // cerr << f.good() << endl;
917  // getline( f, s );
918  f.getline( buf, 1 ); // <-- key line
919  CPPUNIT_CHECK( buf[0] == 0 );
920  CPPUNIT_CHECK( f.fail() ); // due to delimiter not found while buffer was exhausted
921}
922
923#  if !defined (STLPORT) || !defined (_STLP_WIN32)
924void FstreamTest::offset()
925{
926#    if (defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE)) && !defined(_STLP_USE_DEFAULT_FILE_OFFSET)
927  CPPUNIT_CHECK( sizeof(streamoff) == 8 );
928#    else
929  CPPUNIT_CHECK( sizeof(streamoff) == sizeof(off_t) );
930#    endif
931}
932#  endif
933
934#endif
935