OTest2
A C++ testing framework
assertionstext.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2020 Ondrej Starek
3  *
4  * This file is part of OTest2
5  *
6  * OTest2 is free software: you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License,
9  * or (at your option) any later version.
10  *
11  * OTest2 is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14  * License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with OTest2. If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include <assertionstext.h>
20 
21 #include <assert.h>
22 #include <fstream>
23 #include <iomanip>
24 #include <iostream>
25 #include <sstream>
26 #include <string>
27 #include <utility>
28 #include <vector>
29 
30 #include <assertstream.h>
31 #include <difflogblock.h>
32 #include <hirschberg.h>
33 
34 namespace OTest2 {
35 
36 namespace {
37 
38 void slurpFile(
39  std::vector<std::string>& data_,
40  std::istream& is_) {
41  for(std::string line_; std::getline(is_, line_);) {
42  data_.push_back(std::move(line_));
43  }
44 }
45 
46 void formatLine(
47  AssertStream& os_,
48  int left_line_,
49  int right_line_,
50  char change_,
51  const std::string& line_) {
52  os_ << std::setfill('0');
53 
54  /* -- left line number */
55  if(left_line_ >= 0)
56  os_ << std::setw(4) << (left_line_ + 1);
57  else
58  os_ << " ";
59 
60  os_ << ' ';
61 
62  /* -- right line number */
63  if(right_line_ >= 0)
64  os_ << std::setw(4) << (right_line_ + 1);
65  else
66  os_ << " ";
67 
68  switch(change_) {
69  case '>':
70  os_ << foreground(Color::GREEN);
71  break;
72  case '<':
73  os_ << foreground(Color::RED);
74  break;
75  default:
76  break;
77  }
78  os_ << " " << change_ << " : " << line_ << resetAttrs() << commitMsg();
79 }
80 
81 void printSeparator(
82  AssertStream& os_) {
83  os_ << textStyle(Style::DIM)
84  << "........................................"
85  << resetAttrs() << commitMsg();
86 }
87 
88 } /* -- namespace */
89 
90 bool LongTextAssertion::testAssertImpl(
91  std::istream& a_,
92  std::istream& b_) {
93  /* -- read contents of the files */
94  std::vector<std::string> a_data_;
95  slurpFile(a_data_, a_);
96  std::vector<std::string> b_data_;
97  slurpFile(b_data_, b_);
98 
99  /* -- compute the difference */
100  DiffLogBlocks diff_log_;
101  DiffLogBuilderBlock log_builder_(&diff_log_);
102  hirschbergDiff(a_data_, b_data_, log_builder_);
103 
104  bool result_(diff_log_.empty());
105  AssertStream report_(enterAssertion(result_));
106  if(result_) {
107  /* -- There is no difference, the files match */
108  report_ << "the texts are equal" << commitMsg();
109  return report_.getResult();
110  }
111 
112  /* -- The files are different, report the difference */
113  report_ << "the texts are different" << commitMsg();
114 
115  /* -- print the difference */
116  constexpr int CONTEXT(3);
117  bool trailing_context_(false);
118  int left_line_(0);
119  int right_line_(0);
120  std::ostringstream oss_;
121  for(const auto& difference_ : diff_log_) {
122  /* -- print trailing context of previous change */
123  if(trailing_context_) {
124  const int context_end_(left_line_ + CONTEXT);
125  for(;
126  left_line_ < difference_.left_begin && left_line_ < context_end_;
127  ++left_line_, ++right_line_) {
128  assert(right_line_ < difference_.right_begin);
129  formatLine(report_, left_line_, right_line_, ' ', a_data_[left_line_]);
130  }
131  }
132  else
133  trailing_context_ = true;
134 
135  /* -- skip unchanged lines */
136  if(left_line_ < difference_.left_begin - CONTEXT) {
137  assert(right_line_ < difference_.right_begin);
138 
139  printSeparator(report_);
140  left_line_ = difference_.left_begin - CONTEXT;
141  right_line_ = difference_.right_begin - CONTEXT;
142  }
143 
144  /* -- print entering context of the change */
145  for(;
146  left_line_ < difference_.left_begin;
147  ++left_line_, ++right_line_) {
148  assert(right_line_ < difference_.right_begin);
149  formatLine(report_, left_line_, right_line_, ' ', a_data_[left_line_]);
150  }
151 
152  /* -- print the difference */
153  assert(left_line_ == difference_.left_begin);
154  assert(right_line_ == difference_.right_begin);
155  for(; left_line_ < difference_.left_end; ++left_line_) {
156  formatLine(report_, left_line_, -1, '<', a_data_[left_line_]);
157  }
158  for(; right_line_ < difference_.right_end; ++right_line_) {
159  formatLine(report_, -1, right_line_, '>', b_data_[right_line_]);
160  }
161  }
162 
163  /* -- print ending context */
164  const int context_end_(left_line_ + CONTEXT);
165  for(;
166  left_line_ < a_data_.size() && left_line_ < context_end_;
167  ++left_line_, ++right_line_) {
168  assert(right_line_ < b_data_.size());
169  formatLine(report_, left_line_, right_line_, ' ', a_data_[left_line_]);
170  }
171 
172  /* -- skipt the end of the file */
173  if(left_line_ < a_data_.size()) {
174  assert(right_line_ < b_data_.size());
175  printSeparator(report_);
176  }
177 
178  return report_.getResult();
179 }
180 
182  std::istream& a_,
183  std::istream& b_) {
184  return testAssertImpl(a_, b_);
185 }
186 
188  std::istream& a_,
189  const std::string& b_) {
190  std::istringstream str_b_(b_);
191  return testAssertImpl(a_, str_b_);
192 }
193 
195  std::istream& a_,
196  const std::string& file_b_) {
197  std::ifstream str_b_(file_b_);
198  return testAssertImpl(a_, str_b_);
199 }
200 
202  const std::string& a_,
203  std::istream& b_) {
204  std::istringstream str_a_(a_);
205  return testAssertImpl(str_a_, b_);
206 }
207 
209  const std::string& a_,
210  const std::string& b_) {
211  std::istringstream str_a_(a_);
212  std::istringstream str_b_(b_);
213  return testAssertImpl(str_a_, str_b_);
214 }
215 
217  const std::string& a_,
218  const std::string& file_b_) {
219  std::istringstream str_a_(a_);
220  std::ifstream str_b_(file_b_);
221  return testAssertImpl(str_a_, str_b_);
222 }
223 
225  const std::string& file_a_,
226  std::istream& b_) {
227  std::ifstream str_a_(file_a_);
228  return testAssertImpl(str_a_, b_);
229 }
230 
232  const std::string& file_a_,
233  const std::string& b_) {
234  std::ifstream str_a_(file_a_);
235  std::istringstream str_b_(b_);
236  return testAssertImpl(str_a_, str_b_);
237 }
238 
240  const std::string& file_a_,
241  const std::string& file_b_) {
242  std::ifstream str_a_(file_a_);
243  std::ifstream str_b_(file_b_);
244  return testAssertImpl(str_a_, str_b_);
245 }
246 
247 } /* -- namespace OTest2 */
OTest2::resetAttrs
Private::Manipulator resetAttrs()
Reset color and style attributes - manipulator.
Definition: assertstream.cpp:192
OTest2::LongTextAssertion::testAssertLongTextFT
bool testAssertLongTextFT(const std::string &file_a_, const std::string &b_)
Definition: assertionstext.cpp:231
OTest2::LongTextAssertion::testAssertLongTextTF
bool testAssertLongTextTF(const std::string &a_, const std::string &file_b_)
Definition: assertionstext.cpp:216
OTest2::textStyle
Private::Manipulator< Style > textStyle(Style style_)
Text style manipulator.
Definition: assertstream.cpp:187
OTest2::LongTextAssertion::testAssertLongTextSS
bool testAssertLongTextSS(std::istream &a_, std::istream &b_)
Definition: assertionstext.cpp:181
OTest2::Style::DIM
@ DIM
assertstream.h
OTest2::LongTextAssertion::testAssertLongTextTT
bool testAssertLongTextTT(const std::string &a_, const std::string &b_)
Definition: assertionstext.cpp:208
OTest2::hirschbergDiff
void hirschbergDiff(const Type_ left_[], std::size_t left_len_, const Type_ right_[], std::size_t right_len_, DiffLogArray &diff_log_, ScoreFce_ score_fce_=ScoreFce_())
Compute the diff algorithm for specified sequences.
Definition: difflogarray.h:100
OTest2::LongTextAssertion::testAssertLongTextST
bool testAssertLongTextST(std::istream &a_, const std::string &b_)
Definition: assertionstext.cpp:187
OTest2::LongTextAssertion::testAssertLongTextFF
bool testAssertLongTextFF(const std::string &file_a_, const std::string &file_b_)
Definition: assertionstext.cpp:239
OTest2::DiffLogBlocks
std::vector< DiffBlock > DiffLogBlocks
Ordered (indexes into the sequences) list of diff changes.
Definition: difflogblock.h:42
OTest2::AssertContext::enterAssertion
AssertStream enterAssertion(bool result_)
Enter an assertion.
Definition: assertcontext.cpp:45
OTest2::commitMsg
Private::Manipulator commitMsg()
Commit current assertion message.
Definition: assertstream.cpp:201
assertionstext.h
OTest2::Color::GREEN
@ GREEN
OTest2::LongTextAssertion::testAssertLongTextFS
bool testAssertLongTextFS(const std::string &file_a_, std::istream &b_)
Definition: assertionstext.cpp:224
hirschberg.h
OTest2::Color::RED
@ RED
OTest2
Definition: assertbean.h:25
OTest2::LongTextAssertion::testAssertLongTextTS
bool testAssertLongTextTS(const std::string &a_, std::istream &b_)
Definition: assertionstext.cpp:201
difflogblock.h
OTest2::LongTextAssertion::testAssertLongTextSF
bool testAssertLongTextSF(std::istream &a_, const std::string &file_b_)
Definition: assertionstext.cpp:194
OTest2::foreground
Private::Manipulator< Color > foreground(Color color_)
Foreground color manipulator.
Definition: assertstream.cpp:177