Mantid
Loading...
Searching...
No Matches
FileComparisonHelper.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8
10#include "MantidKernel/Logger.h"
11
12#include <fstream>
13#include <string>
14
15namespace { // Anonymous namespace
16// Bring typedef back into anonymous namespace
17using streamCharIter = std::istreambuf_iterator<char>;
18
19// Returns if the difference was due to EOL and fixes the position of the
20// stream if it was due to EOL
21bool isEolDifference(streamCharIter &streamOne, streamCharIter &streamTwo) {
22
23 // Check which is the Windows file stream (CR in CRLF)
24 // and advance it by a character so we are back to LF on both
25 if (*streamOne == '\r' && *streamTwo == '\n') {
26
27 ++streamOne;
28 } else if (*streamOne == '\n' && *streamTwo == '\r') {
29 ++streamTwo;
30 } else {
31 // Was not a different EOL so indicate false to that
32 return false;
33 }
34 // We sorted EOL issues - return that this was the issue
35 return true;
36}
37
38// Checks if two char streams are identical whilst accounting for
39// EOL differences
40bool checkCharactersAreIdentical(streamCharIter streamOne, streamCharIter streamTwo) {
41 const char charOne = *streamOne;
42 const char charTwo = *streamTwo;
43
44 // Do comparison first so we do the least ops on good path
45 if (charOne == charTwo) {
46 return true;
47 }
48
49 // Have the handle EOL differences
50 return isEolDifference(streamOne, streamTwo);
51}
52
53void logDifferenceError(char refChar, char testChar, size_t numNewLines, const std::string &seenChars) {
54 const std::string lineNumber = std::to_string(numNewLines);
55
56 // Build our output string
57 std::string outError;
58 (outError += "At line number: ") += lineNumber;
59 (outError += ". Character number: ") += std::to_string(seenChars.size() + 1);
60 (outError += " expected : '") += refChar;
61 (outError += "' found: '") += testChar;
62 ((outError += "\nReference output:\n") += seenChars) += refChar;
63 ((outError += "\nTest output:\n") += seenChars) += testChar;
64
65 Mantid::Kernel::Logger g_log("FileComparisonHelper");
66 g_log.error(outError);
67}
68
69} // End of anonymous namespace
70
71namespace FileComparisonHelper {
85bool areIteratorsEqual(streamCharIter refStream, streamCharIter testStream, streamCharIter refStreamEnd,
86 streamCharIter testStreamEnd) {
87 // Used if we need to display to the user something did not match
88 size_t numNewLines = 0;
89 std::string seenChars;
90
91 while (refStream != refStreamEnd && testStream != testStreamEnd) {
92 // Check individual values of iterators
93 if (!checkCharactersAreIdentical(refStream, testStream)) {
94 logDifferenceError(*refStream, *testStream, numNewLines, seenChars);
95 return false;
96 }
97
98 // Keep track of where the previous EOL is in case we need to log an error
99 if (*refStream == '\n') {
100 seenChars.clear();
101 numNewLines++;
102 } else {
103 seenChars += *refStream;
104 }
105 // Move iterators alone to compare next char
106 refStream++;
107 testStream++;
108 }
109
110 bool areStreamsEqual = true;
111
112 // Lastly check both iterators were the same length as they should both
113 // point to the end value
114 if (refStream != refStreamEnd || testStream != testStreamEnd) {
115 Mantid::Kernel::Logger g_log("FileComparisonHelper");
116 g_log.error("Length of both files were not identical");
117 areStreamsEqual = false;
118 } else if (numNewLines == 0 && seenChars.empty()) {
119 Mantid::Kernel::Logger g_log("FileComparisonHelper");
120 g_log.error("No characters checked in FileComparisonHelper");
121 areStreamsEqual = false;
122 }
123
124 return areStreamsEqual;
125}
126
138bool areFilesEqual(const std::string &referenceFileFullPath, const std::string &outFileFullPath) {
139 std::ifstream refFileStream(referenceFileFullPath, std::ifstream::binary);
140 std::ifstream outFileStream(outFileFullPath, std::ifstream::binary);
141
142 if (refFileStream.fail()) {
143 throw std::runtime_error("Could not open reference file at specified path");
144 }
145
146 if (outFileStream.fail()) {
147 throw std::runtime_error("Could not open output file at specified path");
148 }
149
150 return areFileStreamsEqual(refFileStream, outFileStream);
151}
152
164bool areFileStreamsEqual(std::ifstream &referenceFileStream, std::ifstream &fileToCheck) {
165 // Open iterators for function to run on
166 streamCharIter refIter(referenceFileStream), checkIter(fileToCheck);
167 // Last iterator in istream is equivalent of uninitialized iterator
168 streamCharIter end;
169
170 return areIteratorsEqual(refIter, checkIter, end, end);
171}
172
189bool isEqualToReferenceFile(const std::string &referenceFileName, const std::string &outFileFullPath) {
190 const std::string referenceFilePath = Mantid::API::FileFinder::Instance().getFullPath(referenceFileName);
191
192 if (referenceFilePath.empty()) {
193 throw std::invalid_argument("No reference file with the name: " + referenceFileName +
194 " could be found by FileComparisonHelper");
195 }
196 return areFilesEqual(referenceFilePath, outFileFullPath);
197}
198
199} // Namespace FileComparisonHelper
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
bool areFileStreamsEqual(std::ifstream &referenceFileStream, std::ifstream &fileToCheck)
Checks if two file streams are equal in content and length.
bool isEqualToReferenceFile(const std::string &referenceFileName, const std::string &outFileFullPath)
Attempts to find a reference file with the given name using Mantid then compares content and length o...
std::istreambuf_iterator< char > streamCharIter
FileComparisonHelper provides several helper functions to compare files or file-streams within unit t...
bool areIteratorsEqual(streamCharIter refStream, streamCharIter testStream, streamCharIter refStreamEnd=streamCharIter(), streamCharIter testStreamEnd=streamCharIter())
Compares the length and content of std::streams iterators and returns if they are equal.
bool areFilesEqual(const std::string &referenceFileFullPath, const std::string &outFileFullPath)
Checks if two files are equal in content and length at the specified path.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::string to_string(const wide_integer< Bits, Signed > &n)