Chaste Commit::a9c8bf7350f67d7cf086e6fe3cf5461521554546
FileComparison.hpp
1/*
2
3Copyright (c) 2005-2026, 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
41#include <cxxtest/TestSuite.h>
42
49{
50private:
53
56
61 std::vector<std::string> mCommentLineStarts;
62
64 std::vector<std::string> mIgnorableContent;
65
66public:
76 FileComparison(std::string fileName1, std::string fileName2, bool calledCollectively=true, bool suppressOutput = false)
77 : AbstractFileComparison(fileName1, fileName2, calledCollectively, suppressOutput),
80 {
82 }
83
93 FileComparison(const FileFinder& rFileName1, const FileFinder& rFileName2, bool calledCollectively=true, bool suppressOutput = false)
94 : AbstractFileComparison(rFileName1, rFileName2, calledCollectively, suppressOutput),
97 {
99 }
100
107 {
108 mCommentLineStarts.push_back("#");
109 mCommentLineStarts.push_back("!");
110 mCommentLineStarts.push_back("Created by Chaste");
111 mCommentLineStarts.push_back("<!-- Created by Chaste");
112 }
113
121 void SetIgnoreCommentLines(bool ignore=true)
122 {
123 mIgnoreCommentLines = ignore;
124 if (!ignore)
125 {
126 mCommentLineStarts.clear();
127 }
128 }
129
136 void IgnoreBlankLines(bool ignore=true)
137 {
138 mIgnoreBlankLines = ignore;
139 }
140
147 void SetIgnoreLinesBeginningWith(std::string lineStart)
148 {
149 mIgnoreCommentLines = true;
150 mCommentLineStarts.push_back(lineStart);
151 }
152
159 void IgnoreLinesContaining(const std::string& rIgnorableText)
160 {
161 mIgnorableContent.push_back(rIgnorableText);
162 }
163
170 bool CompareFiles(unsigned ignoreFirstFewLines=0, bool doTsAssert=true)
171 {
172 // Usually only the master process does the checking, this can be switched off in the constructor.
174 {
175 return true;
176 }
177
178 std::string data1;
179 std::string data2;
180 unsigned failures = 0;
181 unsigned max_display_failures = 10;
182
183 SkipHeaderLines(ignoreFirstFewLines);
184
185 bool files_empty = false;
186 do
187 {
188 std::string buffer1;
189 std::string buffer2;
190 getline(*mpFile1, buffer1);
191 getline(*mpFile2, buffer2);
192
194 {
195 // Keep reading lines until we see non-blank, end-of-file or read error
196 while (buffer1.empty() && mpFile1->good())
197 {
198 getline(*mpFile1, buffer1);
199 }
200 while (buffer2.empty() && mpFile2->good())
201 {
202 getline(*mpFile2, buffer2);
203 }
204 }
205
207 {
208 bool skip_this_line = false;
209 for (unsigned i=0; i<mCommentLineStarts.size(); i++)
210 {
211 // Check for lines starting with a comment symbol
212 size_t found1 = buffer1.find(mCommentLineStarts[i]);
213 size_t found2 = buffer2.find(mCommentLineStarts[i]);
214 if (found1 == 0 && found2 == 0)
215 {
216 skip_this_line = true;
217 break;
218 }
219 }
220 if (skip_this_line)
221 {
222 continue;
223 }
224 }
225
226 // Check for lines containing ignorable text
227 if (!mIgnorableContent.empty())
228 {
229 bool skip_this_line = false;
230 for (const std::string& rText : mIgnorableContent)
231 {
232 size_t found1 = buffer1.find(rText);
233 size_t found2 = buffer2.find(rText);
234 if (found1 != std::string::npos && found2 != std::string::npos)
235 {
236 skip_this_line = true;
237 break;
238 }
239 }
240 if (skip_this_line)
241 {
242 continue;
243 }
244 }
245
246 if (!(buffer1==buffer2) && !files_empty)
247 {
248 if (failures++ < max_display_failures && !mSuppressOutput)
249 {
250 // Display error
251 std::stringstream message;
252 message << "Line " << mLineNum << " differs in files " << mFilename1 << " and " << mFilename2;
253
254 TS_TRACE(message.str());
255 TS_TRACE( buffer1 );
256 TS_TRACE( buffer2 );
257 }
258 }
259 mLineNum++;
260 }
261 while (mpFile1->good() && mpFile2->good());
262 // If either is not good(), then it means that there's nothing to read from the file, or a file input error.
263
264 if (doTsAssert)
265 {
266 // Force CxxTest error if there were any major differences
267 TS_ASSERT_EQUALS(failures, 0u);
268 // If that assertion tripped...
269 if (failures > 0u && !mSuppressOutput)
270 {
271 // Report the paths to the files
272 TS_TRACE("Files " + mFilename1 + " and " + mFilename2 + " differ.");
273 }
274 }
275
276 ResetFiles();
277
278 return (failures==0);
279 }
280};
281
282#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()