Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

TestFdStreams.C

Go to the documentation of this file.
00001 #include <assert.h>
00002 #include <string.h>
00003 #include <stdlib.h>
00004 #include <time.h>
00005 #include <sys/types.h>
00006 #include <sys/stat.h>
00007 #include <stdio.h>
00008 #include <limits.h>
00009 
00010 #include "FdStream.H"
00011 
00012 #include <iostream>
00013 #include <fstream>
00014 
00015 #if !defined(__sun__)
00016 extern "C" {
00017 #include <getopt.h>
00018 }
00019 #endif
00020 
00021 using std::cout;
00022 using std::cerr;
00023 using std::endl;
00024 using std::ios;
00025 using std::hex;
00026 using std::dec;
00027 using std::ifstream;
00028 using std::fstream;
00029 using FS::IFdStream;
00030 using FS::FdStream;
00031 
00032 void print_stream_state(std::ostream &out, unsigned int state)
00033 {
00034   bool first = true;
00035   if(state & ios::eofbit)
00036     {
00037       out << "eof";
00038       state &= ~((unsigned int) ios::eofbit);
00039       first = false;
00040     }
00041   if(state & ios::failbit)
00042     {
00043       if(!first)
00044         out << "|";
00045       out << "fail";
00046       state &= ~((unsigned int) ios::failbit);
00047       first = false;
00048     }
00049   if(state & ios::badbit)
00050     {
00051       if(!first)
00052         out << "|";
00053       out << "bad";
00054       state &= ~((unsigned int) ios::badbit);
00055       first = false;
00056     }
00057   if(state != 0)
00058     {
00059       if(!first)
00060         out << "|";
00061       out << "0x" << hex << state << dec;
00062     }
00063 }
00064 
00065 void print_state_if_not_good(const ios &stream,
00066                              const char *name, const char *marker)
00067 {
00068   if(!stream.good())
00069     {
00070       cout << name << " state (" << marker << "): ";
00071       print_stream_state(cout, stream.rdstate());
00072       cout << endl;
00073     }  
00074 }
00075 
00076 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
00077 #define MIN(a, b) (((a) > (b)) ? (b) : (a))
00078 
00079 #define MAX_READ_SIZE (BUFSIZ*2)
00080 
00081 static bool verbose_read = false, verbose_write = false;
00082 
00083 void random_read_test(const char *fname,
00084                       unsigned int count)
00085 {
00086   ifstream test_fstream(fname);
00087   IFdStream test_fdstream(fname);
00088 
00089   struct stat stat_buf;
00090   if(fstat(test_fdstream.fd(), &stat_buf) != 0)
00091     {
00092       cerr << "fstat of \"" << fname << "\"" << endl;
00093       exit(1);
00094     }
00095 
00096   for(unsigned int i = 0; i < count; i++)
00097     {
00098       switch(random() % 2)
00099         {
00100         case 0:
00101           // Perform a read of a random size from both streams and
00102           // compare the results.
00103           {
00104             char f_buf[MAX_READ_SIZE], fd_buf[MAX_READ_SIZE];
00105 
00106             unsigned int rand_read_size = (random() % MAX_READ_SIZE)+1;
00107 
00108             if(verbose_read)
00109               cout << "R[" << i << "]: Read " << rand_read_size
00110                    << " bytes at offset " << test_fstream.tellg() << endl;
00111 
00112             test_fstream.read(f_buf, rand_read_size);
00113             long f_count = test_fstream.gcount();
00114             test_fdstream.read(fd_buf, rand_read_size);
00115             long fd_count = test_fdstream.gcount();
00116             assert(f_count == fd_count);
00117             assert(memcmp(f_buf, fd_buf, f_count) == 0);
00118           }
00119           break;
00120         case 1:
00121           {
00122             unsigned int rand_file_pos = (random() % stat_buf.st_size);
00123 
00124             if(verbose_read)
00125               cout << "R[" << i << "]: Seek to " << rand_file_pos
00126                    << endl;
00127 
00128             test_fstream.seekg(rand_file_pos);
00129             long f_pos = test_fstream.tellg();
00130             test_fdstream.seekg(rand_file_pos);
00131             long fd_pos = test_fdstream.tellg();
00132             assert(f_pos == fd_pos);
00133           }
00134           break;
00135         }
00136     }
00137 }
00138 
00139 void compare_files(const char *fname1, const char *fname2)
00140 {
00141   struct stat stat_buf1, stat_buf2;
00142   if(stat(fname1, &stat_buf1) != 0)
00143     {
00144       cerr << "stat of \"" << fname1 << "\"" << endl;
00145       exit(1);
00146     }
00147   if(stat(fname2, &stat_buf2) != 0)
00148     {
00149       cerr << "stat of \"" << fname2 << "\"" << endl;
00150       exit(1);
00151     }
00152   assert(stat_buf1.st_size == stat_buf2.st_size);
00153 
00154   ifstream stream1(fname1), stream2(fname2);
00155 
00156   while(!stream1.eof())
00157     {
00158       char buf1[MAX_READ_SIZE], buf2[MAX_READ_SIZE];
00159       stream1.read(buf1, MAX_READ_SIZE);
00160       int count1 = stream1.gcount();
00161       stream2.read(buf2, MAX_READ_SIZE);
00162       int count2 = stream2.gcount();
00163       assert(count1 == count2);
00164       if(memcmp(buf1, buf2, count1) != 0)
00165         {
00166           cerr << "Files \"" << fname1 << "\" and \"" << fname2 << "\" differ"
00167                << endl;
00168           for(unsigned int i = 0; i < count1; i++)
00169             {
00170               if(buf1[i] != buf2[i])
00171                 {
00172                   cerr << "Differences start at offset "
00173                        << (((int) stream1.tellg()) - count1 + i) << endl;
00174                   abort();
00175                 }
00176             }
00177         }
00178     }
00179   assert(stream2.eof());
00180 }
00181 
00182 void random_read_write_test(const char *source_fname,
00183                             const char *dest_fname_base,
00184                             unsigned int count)
00185 {
00186   ifstream source(source_fname);
00187   struct stat stat_buf;
00188   if(stat(source_fname, &stat_buf) != 0)
00189     {
00190       cerr << "stat of \"" << source_fname << "\"" << endl;
00191       exit(1);
00192     }
00193 
00194   char fname_buf[FILENAME_MAX];
00195   sprintf(fname_buf, "%s.fstream_rw", dest_fname_base);
00196   char fdname_buf[FILENAME_MAX];
00197   sprintf(fdname_buf, "%s.fdstream_rw", dest_fname_base);
00198 
00199   {
00200     fstream test_fstream(fname_buf, ios::in|ios::out|ios::trunc);
00201     FdStream test_fdstream(fdname_buf, ios::in|ios::out|ios::trunc);
00202 
00203     // The maximum position in the files we've written so far.
00204     unsigned long max_written = 0;
00205 
00206     // What the current seek position in the files should be.
00207     unsigned long current_pos = 0;
00208 
00209     enum { op_seek, op_read, op_write } last_op = op_seek;
00210 
00211     for(unsigned int i = 0; i < count; i++)
00212       {
00213         bool f_good = test_fstream.good(), fd_good = test_fdstream.good();
00214         if((f_good && !fd_good) || (!f_good && fd_good))
00215           {
00216             cerr << "RW[" << i << "]: only one stream is 'good'" << endl
00217                  << "  fstream  : ";
00218             print_stream_state(cerr, test_fstream.rdstate());
00219             cerr << endl
00220                  << "  fdstream : ";
00221             print_stream_state(cerr, test_fdstream.rdstate());
00222             cerr << endl;
00223             abort();
00224           }
00225       
00226         // Pick one of several things to do at random.
00227         unsigned int random_op = random() % 3;
00228         switch(random_op)
00229           {
00230           case 0:
00231             // Perform a read of a random size from both streams and
00232             // compare the results.
00233             {
00234               // Figure out how much we can realistically read at this
00235               // point.
00236               unsigned long max_read_size =
00237                 MIN(MAX_READ_SIZE,
00238                     max_written - current_pos);
00239 
00240               if(max_read_size > 0)
00241                 {
00242                   unsigned int rand_read_size = (random() % max_read_size)+1;
00243 
00244                   if(verbose_write)
00245                     cout << "RW[" << i << "]: Read " << rand_read_size
00246                          << " bytes at offset " << current_pos
00247                          << endl;
00248 
00249                   char f_buf[MAX_READ_SIZE], fd_buf[MAX_READ_SIZE];
00250 
00251                   if(last_op == op_write)
00252                     test_fstream.seekg(test_fstream.tellg());
00253                   test_fstream.read(f_buf, rand_read_size);
00254                   int f_count = test_fstream.gcount();
00255                   test_fdstream.read(fd_buf, rand_read_size);
00256                   int fd_count = test_fdstream.gcount();
00257                   assert(f_count == fd_count);
00258                   if(memcmp(f_buf, fd_buf, f_count) != 0)
00259                     {
00260                       cerr << "RW[" << i << "]: " << rand_read_size
00261                            << " bytes read at offset " << current_pos
00262                            << " don't match."
00263                            << endl;
00264                       for(unsigned int i = 0; i < f_count; i++)
00265                         {
00266                           if(f_buf[i] != fd_buf[i])
00267                             {
00268                               cerr
00269                                 << "Differences in this read start at offset "
00270                                 << (current_pos + i) 
00271                                 << ":" << endl
00272                                 << "  fstream[" << (current_pos + i) << "]  == "
00273                                 << hex << (((unsigned int) f_buf[i]) & 0x00ff) << dec << endl
00274                                 << "  fdstream[" << (current_pos + i) << "] == "
00275                                 << hex << (((unsigned int) fd_buf[i]) & 0x00ff) << dec << endl
00276                                 << "(Actual differences may start earlier.)"
00277                                 << endl;
00278                               abort();
00279                             }
00280                         }
00281                     }
00282 
00283                   // We moved forward that many bytes.
00284                   current_pos += fd_count;
00285 
00286                   last_op = op_read;
00287 
00288                   break;
00289                 }
00290             }
00291             // Note: fall through if we haven't written enough yet.
00292           case 1:
00293             if(max_written > 0)
00294               {
00295                 // Seek to a random location.
00296                 unsigned int rand_file_pos = (random() % max_written);
00297                 if(verbose_write)
00298                   {
00299                     cout << "RW[" << i << "]: Seek to " << rand_file_pos
00300                          << endl;
00301                   }
00302                 test_fstream.seekg(rand_file_pos);
00303                 test_fdstream.seekg(rand_file_pos);
00304                 test_fstream.seekp(rand_file_pos);
00305                 test_fdstream.seekp(rand_file_pos);
00306 
00307                 // We're now at this position.
00308                 current_pos = rand_file_pos;
00309 
00310                 last_op = op_seek;
00311 
00312                 break;
00313               }
00314             // Note: fall through if we haven't written anything yet.
00315           case 2:
00316             {
00317               // Perform a read of a random size from the source and
00318               // write it to both streams.
00319               char read_buf[MAX_READ_SIZE];
00320 
00321               unsigned int rand_read_size = (random() % MAX_READ_SIZE)+1;
00322               unsigned long rand_read_start = (random() %
00323                                                (stat_buf.st_size - rand_read_size));
00324               source.seekg(rand_read_start);
00325               source.read(read_buf, rand_read_size);
00326               int read_count = source.gcount();
00327 
00328               if(verbose_write)
00329                 {
00330                   cout << "RW[" << i << "]: Write " << read_count
00331                        << " bytes from source offset " << rand_read_start
00332                        << " at offset " << current_pos << endl;
00333                 }
00334 
00335               if(last_op == op_read)
00336                 test_fstream.seekp(test_fstream.tellp());
00337               test_fstream.write(read_buf, read_count);
00338               test_fdstream.write(read_buf, read_count);
00339 
00340               // We moved forward that many bytes.
00341               current_pos += read_count;
00342 
00343               // Update out idea of the end-of-file position.
00344               if(current_pos > max_written)
00345                 max_written = current_pos;
00346             }
00347 
00348             last_op = op_write;
00349 
00350             break;
00351           }
00352 
00353         // With some probability, compare the stream positions.  We
00354         // avoid doing this on every operation, as these may cause
00355         // flushes to hapen, which could cause things to be exercised
00356         // less.
00357         unsigned int random_compare = random() % 2;
00358         switch(random_compare)
00359           {
00360           case 0:
00361             {
00362               if(verbose_write)
00363                 cout << "RW[" << i << "]: Check get position" << endl;
00364               unsigned long fd_pos = test_fdstream.tellg();
00365               assert(fd_pos == current_pos);
00366             }
00367             break;
00368           case 1:
00369             {
00370               if(verbose_write)
00371                 cout << "RW[" << i << "]: Check put position" << endl;
00372               unsigned long fd_pos = test_fdstream.tellp();
00373               assert(fd_pos == current_pos);
00374             }
00375             break;
00376           }
00377       }
00378   }
00379 
00380   // Make sure the files turned out the same.
00381   compare_files(fname_buf, fdname_buf);
00382 }
00383 
00384 int main(int argc, char* argv[])
00385 {
00386   unsigned int seed = time(0);
00387   unsigned int count = 10000;
00388   for (;;)
00389     {
00390       char* slash;
00391       int c = getopt(argc, argv, "s:c:vRW");
00392       if (c == EOF) break;
00393       switch (c)
00394       {
00395       case 's':
00396         seed = strtoul(optarg, NULL, 0);
00397         break;
00398       case 'c':
00399         count = strtoul(optarg, NULL, 0);
00400         break;
00401       case 'v':
00402         verbose_read = true;
00403         verbose_write = true;
00404         break;
00405       case 'R':
00406         verbose_read = true;
00407         break;
00408       case 'W':
00409         verbose_write = true;
00410         break;
00411       }
00412     }
00413 
00414   cout << "To reproduce: -s " << seed
00415        << " -c " << count << endl;
00416   srandom(seed);
00417 
00418   for(unsigned int i = optind; i < argc; i++)
00419     {
00420       random_read_test(argv[i], count);
00421       random_read_write_test(argv[i],
00422                              argv[i],
00423                              count);
00424     }
00425 
00426   return 0;
00427 }

Generated on Mon May 8 00:48:30 2006 for Vesta by  doxygen 1.4.2