OTest2
A C++ testing framework
assertionsmapimpl.h
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 
20 #ifndef OTest2_INCLUDE_OTEST2_ASSERTIONSMAPIMPL_H_
21 #define OTest2_INCLUDE_OTEST2_ASSERTIONSMAPIMPL_H_
22 
23 #include <otest2/assertionsmap.h>
24 
25 #include <assert.h>
26 #include <iostream>
27 #include <sstream>
28 #include <string>
29 #include <vector>
30 
31 #include <otest2/assertstream.h>
32 #include <otest2/containertrait.h>
33 #include <otest2/printtraits.h>
34 #include <otest2/typetraits.h>
35 
36 namespace OTest2 {
37 
38 namespace Private {
39 
40 template<template<typename, typename> class Compare_, typename ContainerA_, typename ContainerB_>
42  std::vector<std::string>& messages_,
43  const ContainerA_& a_,
44  const ContainerB_& b_) {
49  typedef Compare_<AValue_, BValue_> Comparator_;
50 
51  Comparator_ cmp_;
52 
53  std::ostringstream first_line_;
54  first_line_ << "the assertion a ";
55  PrintTrait<Comparator_>::print(first_line_, cmp_);
56  first_line_ << " b has ";
57 
58  /* -- compare left map against the right one */
59  auto iter_a_(MapContainerTrait<ContainerA_>::begin(a_));
60  auto end_a_(MapContainerTrait<ContainerA_>::end(a_));
61  while(iter_a_ != end_a_) {
62  /* -- find the key in the second map */
63  auto range_b_(MapContainerTrait<ContainerB_>::equalRange(b_, (*iter_a_).first));
64  if(range_b_.first == range_b_.second) {
65  /* -- the key is not found in the second map */
66  std::ostringstream sos_;
67  sos_ << first_line_.str() << "failed: the item <";
68  PrintTrait<AKey_>::print(sos_, (*iter_a_).first);
69  sos_ << ", ";
70  PrintTrait<AValue_>::print(sos_, (*iter_a_).second);
71  sos_ << "> is not present in the map b";
72 
73  messages_.push_back(sos_.str());
74  return false;
75  }
76 
77  /* -- compare subsequent values with the same key */
78  while(true) {
79  if(iter_a_ == end_a_
80  || !MapContainerTrait<ContainerA_>::keyEqual(a_, (*iter_a_).first, (*range_b_.first).first)) {
81  /* -- the subsequence is shorter in the map a */
82  std::ostringstream sos_;
83  sos_ << first_line_.str() << "failed: the subsequence of items with the key ";
84  PrintTrait<BKey_>::print(sos_, (*range_b_.first).first);
85  sos_ << " is shorter in the map a than in the map b";
86  messages_.push_back(sos_.str());
87 
88  return false;
89  }
90 
91  if(!cmp_((*iter_a_).second, (*range_b_.first).second)) {
92  /* -- the values dont't fit operator */
93  std::ostringstream sos_;
94  sos_ << first_line_.str() << "failed: check a[";
95  PrintTrait<AKey_>::print(sos_, (*iter_a_).first);
96  sos_ << "] ";
98  sos_ << " b[";
99  PrintTrait<BKey_>::print(sos_, (*range_b_.first).first);
100  sos_ << "] has failed";
101  messages_.push_back(sos_.str());
102 
103  sos_.str("");
104  sos_ << "a[";
105  PrintTrait<AKey_>::print(sos_, (*iter_a_).first);
106  sos_ << "] = ";
107  PrintTrait<AValue_>::print(sos_, (*iter_a_).second);
108  messages_.push_back(sos_.str());
109 
110  sos_.str("");
111  sos_ << "b[";
112  PrintTrait<AKey_>::print(sos_, (*range_b_.first).first);
113  sos_ << "] = ";
114  PrintTrait<AValue_>::print(sos_, (*range_b_.first).second);
115  messages_.push_back(sos_.str());
116 
117  return false;
118  }
119 
120  /* -- move to next item in the equality range */
121  ++range_b_.first;
122  if(range_b_.first == range_b_.second) {
123  /* -- end of the range, check the end of the range in the map A */
124  auto iter_a_tmp_(iter_a_);
125  ++iter_a_;
126  if(iter_a_ == end_a_
127  || !MapContainerTrait<ContainerA_>::keyEqual(a_, (*iter_a_).first, (*iter_a_tmp_).first)) {
128  /* -- end of the subsequence in the map A -> OK */
129  break;
130  }
131 
132  std::ostringstream sos_;
133  sos_ << first_line_.str() << "failed: the subsequence of items with the key ";
134  PrintTrait<AKey_>::print(sos_, (*iter_a_).first);
135  sos_ << " is longer in the map a than in the map b";
136  messages_.push_back(sos_.str());
137 
138  return false;
139  }
140 
141  /* -- move to next item in the subsequence */
142  ++iter_a_;
143  }
144  }
145 
146  /* -- Compare right map against the left one. Check just existence
147  * of keys as the key subsequences are already checked. */
148  auto iter_b_(MapContainerTrait<ContainerB_>::begin(b_));
149  auto end_b_(MapContainerTrait<ContainerB_>::end(b_));
150  while(iter_b_ != end_b_) {
151  auto range_a_(MapContainerTrait<ContainerA_>::equalRange(a_, (*iter_b_).first));
152  if(range_a_.first == range_a_.second) {
153  /* -- the key is not found in the first map */
154  std::ostringstream sos_;
155  sos_ << first_line_.str() << "failed: the item <";
156  PrintTrait<BKey_>::print(sos_, (*iter_b_).first);
157  sos_ << ", ";
158  PrintTrait<BValue_>::print(sos_, (*iter_b_).second);
159  sos_ << "> is not present in the map a";
160 
161  messages_.push_back(sos_.str());
162  return false;
163  }
164 
165  /* -- move to next item */
166  ++iter_b_;
167  }
168 
169  std::ostringstream sos_;
170  sos_ << first_line_.str() << "passed";
171  messages_.push_back(sos_.str());
172 
173  return true;
174 }
175 
176 } /* -- namespace Private */
177 
178 template<template<typename, typename> class Compare_, typename ContainerA_, typename ContainerB_>
180  const ContainerA_& a_,
181  const ContainerB_& b_) {
182  std::vector<std::string> messages_;
183  bool result_(Private::compareMaps<Compare_>(messages_, a_, b_));
184  assert(!messages_.empty());
185 
186  AssertStream report_(enterAssertion(result_));
187  for(const auto& message_ : messages_)
188  report_ << message_ << commitMsg();
189  return report_.getResult();
190 }
191 
192 } /* -- namespace OTest2 */
193 
194 #endif /* -- OTest2_INCLUDE_OTEST2_ASSERTIONSMAPIMPL_H_ */
assertstream.h
typetraits.h
OTest2::AssertStream::getResult
bool getResult()
Return the assertion result.
Definition: assertstream.cpp:93
OTest2::MapAssertion::testAssertMap
bool testAssertMap(const ContainerA_ &a_, const ContainerB_ &b_)
Definition: assertionsmapimpl.h:179
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
printtraits.h
containertrait.h
OTest2::PrintTrait::print
static std::ostream & print(std::ostream &os_, typename TypeTrait< Type_ >::BestArg value_)
Definition: printtraits.h:39
OTest2
Definition: assertbean.h:25
OTest2::MapContainerTrait
A trait for access to a map container.
Definition: containertrait.h:167
assertionsmap.h
OTest2::Private::compareMaps
bool compareMaps(std::vector< std::string > &messages_, const ContainerA_ &a_, const ContainerB_ &b_)
Definition: assertionsmapimpl.h:41
OTest2::AssertionParameter
A helper trait - get normalized type of a captured assertion parameter.
Definition: typetraits.h:81
OTest2::AssertStream
Assertion stream.
Definition: assertstream.h:40