NumericFileComparison.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 #ifndef NUMERICFILECOMPARISON_HPP_
00029 #define NUMERICFILECOMPARISON_HPP_
00030 
00031 #include "OutputFileHandler.hpp"
00032 #define A_WORD DBL_MAX
00033 #define NOTHING_TO_READ DBL_MIN
00034 
00037 class NumericFileComparison
00038 {
00039 private:
00040     std::string mFilename1; 
00041     std::string mFilename2; 
00043     std::ifstream* mpFile1; 
00044     std::ifstream* mpFile2; 
00045 public:
00053     NumericFileComparison(std::string fileName1, std::string fileName2):
00054         mFilename1(fileName1),
00055         mFilename2(fileName2)
00056     {
00057         mpFile1 = new std::ifstream(fileName1.c_str());
00058         // If it doesn't exist - throw exception
00059         if (!mpFile1->is_open())
00060         {
00061             mpFile1 = NULL;
00062             EXCEPTION("Couldn't open file: " + fileName1);
00063         }
00064 
00065         mpFile2 = new std::ifstream(fileName2.c_str());
00066         // If it doesn't exist - throw exception
00067         if (!mpFile2->is_open())
00068         {
00069             mpFile1->close();
00070             mpFile1 = NULL;
00071             mpFile2 = NULL;
00072             EXCEPTION("Couldn't open file: " + fileName2);
00073         }
00074     }
00078     ~NumericFileComparison()
00079     {
00080         if (mpFile1)
00081         {
00082             mpFile1->close();
00083         }
00084         if (mpFile2)
00085         {
00086             mpFile2->close();
00087         }
00088         delete mpFile1;
00089         delete mpFile2;
00090     }
00098     bool CompareFiles(double absTolerance=DBL_EPSILON, unsigned ignoreFirstFewLines=0)
00099     {
00100         double data1;
00101         double data2;
00102         unsigned failures = 0;
00103         double max_error = 0.0;
00104         unsigned max_failures = 10;
00105 
00106         for (unsigned line_number=0; line_number<ignoreFirstFewLines; line_number++)
00107         {
00108             char buffer[1024];
00109             mpFile1->getline(buffer, 1024);
00110             mpFile2->getline(buffer, 1024);
00111             TS_ASSERT(!mpFile1->fail()); //Here we are assuming that there a least "ignoreFirstFewLines" lines
00112             TS_ASSERT(!mpFile2->fail()); // and that they are lines of no more than 1024 characters
00113         }
00114 
00115         do
00116         {
00117             if (!(*mpFile1>>data1))
00118             {
00119                 //Cannot read the next token from file as a number, so try a word instead
00120                 std::string word;
00121                 mpFile1->clear();//reset the "failbit"
00122                 if (*mpFile1>>word)
00123                 {
00124                     data1=A_WORD;
00125                     if (word == "#" || word == "!")
00126                     {
00127                         //Ignore comment (up to 1024 characters until newline)
00128                         mpFile1->ignore(1024, '\n');
00129                     }
00130                 }
00131                 else
00132                 {
00133                     mpFile1->clear();//reset the "failbit"
00134                     data1=NOTHING_TO_READ;
00135                 }
00136             }
00137             if (!(*mpFile2>>data2))
00138             {
00139                 //Cannot read the next token from file as a number, so try a word instead
00140                 std::string word;
00141                 mpFile2->clear();//reset the "failbit"
00142                 if (*mpFile2>>word)
00143                 {
00144                     data2=A_WORD;
00145                     if (word == "#" || word == "!")
00146                     {
00147                         //Ignore comment (up to 1024 characters until newline)
00148                         mpFile2->ignore(1024, '\n');
00149                     }
00150                 }
00151                 else
00152                 {
00153                     mpFile2->clear();//reset the "failbit"
00154                     data2=NOTHING_TO_READ;
00155                 }
00156             }
00157 
00158             double error = fabs(data1 - data2);
00159             if ( error > absTolerance )
00160             {
00161                 failures++;
00162                 // Force CxxTest error
00163                 TS_ASSERT_DELTA(data1, data2, absTolerance);
00164                 if (error > max_error)
00165                 {
00166                     max_error = error;
00167                 }
00168             }
00169             if (failures > max_failures)
00170             {
00171                 break; // Don't clog the screen
00172             }
00173         }
00174         while (data1 != NOTHING_TO_READ && data2 != NOTHING_TO_READ); //If either is a NOTHING_TO_READ, then it means that there's nothing to read from the file
00175 
00176         // Force CxxTest error if there were any major differences
00177         TS_ASSERT_LESS_THAN(max_error, absTolerance);
00178         //If that assertion tripped...
00179         if (max_error >= absTolerance)
00180         {
00181 #define COVERAGE_IGNORE
00182             //Report the paths to the files
00183             TS_TRACE("Files " + mFilename1 + " and " + mFilename2 + " numerically differ.");
00184 #undef COVERAGE_IGNORE
00185         }
00186         return (failures==0);
00187     }
00188 };
00189 
00190 #endif /*NUMERICFILECOMPARISON_HPP_*/

Generated on Mon Apr 18 11:35:28 2011 for Chaste by  doxygen 1.5.5