Chaste Commit::baa90ac2819b962188b7562f2326be23c47859a7
FileComparison.hpp
1/*
2
3Copyright (c) 2005-2024, University of Oxford.
4All rights reserved.
5
6University of Oxford means the Chancellor, Masters and Scholars of the
7University of Oxford, having an administrative office at Wellington
8Square, Oxford OX1 2JD, UK.
9
10This file is part of Chaste.
11
12Redistribution and use in source and binary forms, with or without
13modification, are permitted provided that the following conditions are met:
14 * Redistributions of source code must retain the above copyright notice,
15 this list of conditions and the following disclaimer.
16 * Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
19 * Neither the name of the University of Oxford nor the names of its
20 contributors may be used to endorse or promote products derived from this
21 software without specific prior written permission.
22
23THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34*/
35#ifndef FILECOMPARISON_HPP_
36#define FILECOMPARISON_HPP_
37
38#include "AbstractFileComparison.hpp"
39#include <vector>
40#include <boost/foreach.hpp>
41
42#include <cxxtest/TestSuite.h>
43
50{
51private:
54
57
62 std::vector<std::string> mCommentLineStarts;
63
65 std::vector<std::string> mIgnorableContent;
66
67public:
77 FileComparison(std::string fileName1, std::string fileName2, bool calledCollectively=true, bool suppressOutput = false)
78 : AbstractFileComparison(fileName1, fileName2, calledCollectively, suppressOutput),
81 {
83 }
84
94 FileComparison(const FileFinder& rFileName1, const FileFinder& rFileName2, bool calledCollectively=true, bool suppressOutput = false)
95 : AbstractFileComparison(rFileName1, rFileName2, calledCollectively, suppressOutput),
98 {
100 }
101
108 {
109 mCommentLineStarts.push_back("#");
110 mCommentLineStarts.push_back("!");
111 mCommentLineStarts.push_back("Created by Chaste");
112 mCommentLineStarts.push_back("<!-- Created by Chaste");
113 }
114
122 void SetIgnoreCommentLines(bool ignore=true)
123 {
124 mIgnoreCommentLines = ignore;
125 if (!ignore)
126 {
127 mCommentLineStarts.clear();
128 }
129 }
130
137 void IgnoreBlankLines(bool ignore=true)
138 {
139 mIgnoreBlankLines = ignore;
140 }
141
148 void SetIgnoreLinesBeginningWith(std::string lineStart)
149 {
150 mIgnoreCommentLines = true;
151 mCommentLineStarts.push_back(lineStart);
152 }
153
160 void IgnoreLinesContaining(const std::string& rIgnorableText)
161 {
162 mIgnorableContent.push_back(rIgnorableText);
163 }
164
171 bool CompareFiles(unsigned ignoreFirstFewLines=0, bool doTsAssert=true)
172 {
173 // Usually only the master process does the checking, this can be switched off in the constructor.
175 {
176 return true;
177 }
178
179 std::string data1;
180 std::string data2;
181 unsigned failures = 0;
182 unsigned max_display_failures = 10;
183
184 SkipHeaderLines(ignoreFirstFewLines);
185
186 bool files_empty = false;
187 do
188 {
189 std::string buffer1;
190 std::string buffer2;
191 getline(*mpFile1, buffer1);
192 getline(*mpFile2, buffer2);
193
195 {
196 // Keep reading lines until we see non-blank, end-of-file or read error
197 while (buffer1.empty() && mpFile1->good())
198 {
199 getline(*mpFile1, buffer1);
200 }
201 while (buffer2.empty() && mpFile2->good())
202 {
203 getline(*mpFile2, buffer2);
204 }
205 }
206
208 {
209 bool skip_this_line = false;
210 for (unsigned i=0; i<mCommentLineStarts.size(); i++)
211 {
212 // Check for lines starting with a comment symbol
213 size_t found1 = buffer1.find(mCommentLineStarts[i]);
214 size_t found2 = buffer2.find(mCommentLineStarts[i]);
215 if (found1 == 0 && found2 == 0)
216 {
217 skip_this_line = true;
218 break;
219 }
220 }
221 if (skip_this_line)
222 {
223 continue;
224 }
225 }
226
227 // Check for lines containing ignorable text
228 if (!mIgnorableContent.empty())
229 {
230 bool skip_this_line = false;
231 BOOST_FOREACH(const std::string& rText, mIgnorableContent)
232 {
233 size_t found1 = buffer1.find(rText);
234 size_t found2 = buffer2.find(rText);
235 if (found1 != std::string::npos && found2 != std::string::npos)
236 {
237 skip_this_line = true;
238 break;
239 }
240 }
241 if (skip_this_line)
242 {
243 continue;
244 }
245 }
246
247 if (!(buffer1==buffer2) && !files_empty)
248 {
249 if (failures++ < max_display_failures && !mSuppressOutput)
250 {
251 // Display error
252 std::stringstream message;
253 message << "Line " << mLineNum << " differs in files " << mFilename1 << " and " << mFilename2;
254
255 TS_TRACE(message.str());
256 TS_TRACE( buffer1 );
257 TS_TRACE( buffer2 );
258 }
259 }
260 mLineNum++;
261 }
262 while (mpFile1->good() && mpFile2->good());
263 // If either is not good(), then it means that there's nothing to read from the file, or a file input error.
264
265 if (doTsAssert)
266 {
267 // Force CxxTest error if there were any major differences
268 TS_ASSERT_EQUALS(failures, 0u);
269 // If that assertion tripped...
270 if (failures > 0u && !mSuppressOutput)
271 {
272 // Report the paths to the files
273 TS_TRACE("Files " + mFilename1 + " and " + mFilename2 + " differ.");
274 }
275 }
276
277 ResetFiles();
278
279 return (failures==0);
280 }
281};
282
283#endif /*FILECOMPARISON_HPP_*/
void SkipHeaderLines(unsigned numLinesToSkip)
void IgnoreBlankLines(bool ignore=true)
void SetIgnoreCommentLines(bool ignore=true)
void SetIgnoreLinesBeginningWith(std::string lineStart)
std::vector< std::string > mCommentLineStarts
std::vector< std::string > mIgnorableContent
FileComparison(const FileFinder &rFileName1, const FileFinder &rFileName2, bool calledCollectively=true, bool suppressOutput=false)
void IgnoreLinesContaining(const std::string &rIgnorableText)
bool CompareFiles(unsigned ignoreFirstFewLines=0, bool doTsAssert=true)
FileComparison(std::string fileName1, std::string fileName2, bool calledCollectively=true, bool suppressOutput=false)
static bool AmMaster()