FileComparison.hpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 #ifndef FILECOMPARISON_HPP_
00036 #define FILECOMPARISON_HPP_
00037 
00038 #include "AbstractFileComparison.hpp"
00039 #include <vector>
00040 #include <boost/foreach.hpp>
00041 
00047 class FileComparison : public AbstractFileComparison
00048 {
00049 private:
00051     bool mIgnoreCommentLines;
00052 
00054     bool mIgnoreBlankLines;
00055 
00060     std::vector<std::string> mCommentLineStarts;
00061 
00063     std::vector<std::string> mIgnorableContent;
00064 
00065 public:
00075     FileComparison(std::string fileName1, std::string fileName2, bool calledCollectively=true, bool suppressOutput = false)
00076         : AbstractFileComparison(fileName1, fileName2, calledCollectively, suppressOutput),
00077           mIgnoreCommentLines(true),
00078           mIgnoreBlankLines(false)
00079     {
00080         SetupCommentLines();
00081     }
00082 
00092     FileComparison(const FileFinder& rFileName1, const FileFinder& rFileName2, bool calledCollectively=true, bool suppressOutput = false)
00093         : AbstractFileComparison(rFileName1, rFileName2, calledCollectively, suppressOutput),
00094           mIgnoreCommentLines(true),
00095           mIgnoreBlankLines(false)
00096     {
00097         SetupCommentLines();
00098     }
00099 
00105     void SetupCommentLines()
00106     {
00107         mCommentLineStarts.push_back("#");
00108         mCommentLineStarts.push_back("!");
00109         mCommentLineStarts.push_back("Created by Chaste");
00110         mCommentLineStarts.push_back("<!-- Created by Chaste");
00111     }
00112 
00120     void SetIgnoreCommentLines(bool ignore=true)
00121     {
00122         mIgnoreCommentLines = ignore;
00123         if (!ignore)
00124         {
00125             mCommentLineStarts.clear();
00126         }
00127     }
00128 
00135     void IgnoreBlankLines(bool ignore=true)
00136     {
00137         mIgnoreBlankLines = ignore;
00138     }
00139 
00146     void SetIgnoreLinesBeginningWith(std::string lineStart)
00147     {
00148         mIgnoreCommentLines = true;
00149         mCommentLineStarts.push_back(lineStart);
00150     }
00151 
00158     void IgnoreLinesContaining(const std::string& rIgnorableText)
00159     {
00160         mIgnorableContent.push_back(rIgnorableText);
00161     }
00162 
00169     bool CompareFiles(unsigned ignoreFirstFewLines=0, bool doTsAssert=true)
00170     {
00171         // Usually only the master process does the checking, this can be switched off in the constructor.
00172         if (mCalledCollectively && !PetscTools::AmMaster())
00173         {
00174             return true;
00175         }
00176 
00177         std::string data1;
00178         std::string data2;
00179         unsigned failures = 0;
00180         unsigned max_display_failures = 10;
00181 
00182         SkipHeaderLines(ignoreFirstFewLines);
00183 
00184         bool files_empty = false;
00185         do
00186         {
00187             std::string buffer1;
00188             std::string buffer2;
00189             getline(*mpFile1, buffer1);
00190             getline(*mpFile2, buffer2);
00191 
00192             if (mIgnoreBlankLines)
00193             {
00194                 // Keep reading lines until we see non-blank, end-of-file or read error
00195                 while (buffer1.empty() && mpFile1->good())
00196                 {
00197                     getline(*mpFile1, buffer1);
00198                 }
00199                 while (buffer2.empty() && mpFile2->good())
00200                 {
00201                     getline(*mpFile2, buffer2);
00202                 }
00203             }
00204 
00205             if (mIgnoreCommentLines)
00206             {
00207                 bool skip_this_line = false;
00208                 for (unsigned i=0; i<mCommentLineStarts.size(); i++)
00209                 {
00210                     // Check for lines starting with a comment symbol
00211                     size_t found1 = buffer1.find(mCommentLineStarts[i]);
00212                     size_t found2 = buffer2.find(mCommentLineStarts[i]);
00213                     if (found1 == 0 && found2 == 0)
00214                     {
00215                         skip_this_line = true;
00216                         break;
00217                     }
00218                 }
00219                 if (skip_this_line)
00220                 {
00221                     continue;
00222                 }
00223             }
00224 
00225             // Check for lines containing ignorable text
00226             if (!mIgnorableContent.empty())
00227             {
00228                 bool skip_this_line = false;
00229                 BOOST_FOREACH(const std::string& rText, mIgnorableContent)
00230                 {
00231                     size_t found1 = buffer1.find(rText);
00232                     size_t found2 = buffer2.find(rText);
00233                     if (found1 != std::string::npos && found2 != std::string::npos)
00234                     {
00235                         skip_this_line = true;
00236                         break;
00237                     }
00238                 }
00239                 if (skip_this_line)
00240                 {
00241                     continue;
00242                 }
00243             }
00244 
00245             if (!(buffer1==buffer2) && !files_empty)
00246             {
00247                 if (failures++ < max_display_failures && !mSuppressOutput)
00248                 {
00249                     // Display error
00250                     std::stringstream message;
00251                     message << "Line " << mLineNum << " differs in files " << mFilename1 << " and " << mFilename2;
00252 
00253                     TS_TRACE(message.str());
00254                     TS_TRACE( buffer1 );
00255                     TS_TRACE( buffer2 );
00256                 }
00257             }
00258             mLineNum++;
00259         }
00260         while (mpFile1->good() && mpFile2->good());
00261         // If either is not good(), then it means that there's nothing to read from the file, or a file input error.
00262 
00263         if (doTsAssert)
00264         {
00265             // Force CxxTest error if there were any major differences
00266             TS_ASSERT_EQUALS(failures, 0u);
00267             // If that assertion tripped...
00268             if (failures > 0u && !mSuppressOutput)
00269             {
00270 #define COVERAGE_IGNORE
00271                 TS_TRACE("Files " + mFilename1 + " and " + mFilename2 + " differ.");
00272 #undef COVERAGE_IGNORE
00273             }
00274         }
00275 
00276         ResetFiles();
00277 
00278         return (failures==0);
00279     }
00280 };
00281 
00282 #endif /*FILECOMPARISON_HPP_*/

Generated by  doxygen 1.6.2