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 <cfloat>
00032 #include <string>
00033 
00034 #include "OutputFileHandler.hpp"
00035 #include "MathsCustomFunctions.hpp"
00036 
00037 #define A_WORD DBL_MAX
00038 #define NOTHING_TO_READ DBL_MIN
00039 
00043 class NumericFileComparison
00044 {
00045 private:
00046 
00047     std::string mFilename1; 
00048     std::string mFilename2; 
00050     std::ifstream* mpFile1; 
00051     std::ifstream* mpFile2; 
00053 public:
00054 
00062     NumericFileComparison(std::string fileName1, std::string fileName2):
00063         mFilename1(fileName1),
00064         mFilename2(fileName2)
00065     {
00066         mpFile1 = new std::ifstream(fileName1.c_str());
00067 
00068         // If it doesn't exist - throw exception
00069         if (!mpFile1->is_open())
00070         {
00071             delete mpFile1;
00072             mpFile1 = NULL;
00073             EXCEPTION("Couldn't open file: " + fileName1);
00074         }
00075 
00076         mpFile2 = new std::ifstream(fileName2.c_str());
00077 
00078         // If it doesn't exist - throw exception
00079         if (!mpFile2->is_open())
00080         {
00081             mpFile1->close();
00082             delete mpFile1;
00083             mpFile1 = NULL;
00084             delete mpFile2;
00085             mpFile2 = NULL;
00086             EXCEPTION("Couldn't open file: " + fileName2);
00087         }
00088     }
00089 
00093     ~NumericFileComparison()
00094     {
00095         if (mpFile1)
00096         {
00097             mpFile1->close();
00098         }
00099         if (mpFile2)
00100         {
00101             mpFile2->close();
00102         }
00103         delete mpFile1;
00104         delete mpFile2;
00105     }
00106 
00116     bool CompareFiles(double absTol=DBL_EPSILON, unsigned ignoreFirstFewLines=0,
00117                       double relTol=DBL_EPSILON)
00118     {
00119         double data1;
00120         double data2;
00121         unsigned failures = 0;
00122         unsigned max_display_failures = 10;
00123 
00124         for (unsigned line_number=0; line_number<ignoreFirstFewLines; line_number++)
00125         {
00126             char buffer[1024];
00127             mpFile1->getline(buffer, 1024);
00128             mpFile2->getline(buffer, 1024);
00129             TS_ASSERT(!mpFile1->fail()); // Here we assume there are at least "ignoreFirstFewLines" lines...
00130             TS_ASSERT(!mpFile2->fail()); // ...and that they are lines of no more than 1024 characters
00131         }
00132 
00133         do
00134         {
00135             if (!(*mpFile1>>data1))
00136             {
00137                 // Cannot read the next token from file as a number, so try a word instead
00138                 std::string word;
00139                 mpFile1->clear(); // reset the "failbit"
00140                 if (*mpFile1 >> word)
00141                 {
00142                     data1 = A_WORD;
00143                     if (word == "#" || word == "!")
00144                     {
00145                         // Ignore comment (up to 1024 characters until newline)
00146                         mpFile1->ignore(1024, '\n');
00147                     }
00148                 }
00149                 else
00150                 {
00151                     mpFile1->clear(); // reset the "failbit"
00152                     data1 = NOTHING_TO_READ;
00153                 }
00154             }
00155             if (!(*mpFile2 >> data2))
00156             {
00157                 // Cannot read the next token from file as a number, so try a word instead
00158                 std::string word;
00159                 mpFile2->clear(); // reset the "failbit"
00160                 if (*mpFile2 >> word)
00161                 {
00162                     data2 = A_WORD;
00163                     if (word == "#" || word == "!")
00164                     {
00165                         // Ignore comment (up to 1024 characters until newline)
00166                         mpFile2->ignore(1024, '\n');
00167                     }
00168                 }
00169                 else
00170                 {
00171                     mpFile2->clear(); // reset the "failbit"
00172                     data2 = NOTHING_TO_READ;
00173                 }
00174             }
00175 
00176             bool ok = CompareDoubles::WithinAnyTolerance(data1, data2, relTol, absTol);
00177             if (!ok)
00178             {
00179                 if (failures++ < max_display_failures)
00180                 {
00181                     // Display error
00182                     CompareDoubles::WithinAnyTolerance(data1, data2, relTol, absTol, true);
00183                 }
00184             }
00185         }
00186         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
00187 
00188         // Force CxxTest error if there were any major differences
00189         TS_ASSERT_EQUALS(failures, 0u);
00190         // If that assertion tripped...
00191         if (failures > 0u)
00192         {
00193 #define COVERAGE_IGNORE
00194             // Report the paths to the files
00195             TS_TRACE("Files " + mFilename1 + " and " + mFilename2 + " numerically differ.");
00196 #undef COVERAGE_IGNORE
00197         }
00198         return (failures==0);
00199     }
00200 };
00201 
00202 #endif /*NUMERICFILECOMPARISON_HPP_*/
Generated on Thu Dec 22 13:00:05 2011 for Chaste by  doxygen 1.6.3