C++Spec 1.0.0
BDD testing for C++
Loading...
Searching...
No Matches
pretty_matchers.hpp
Go to the documentation of this file.
1
2#pragma once
3
4#include <algorithm>
5#include <regex>
6#include <string>
7#include <utility>
8#include <vector>
9
10#include "prettyprint.hpp"
11#include "util.hpp"
12
13namespace CppSpec {
14
15namespace Matchers {
16template <typename A, typename E>
17class MatcherBase;
18}
19
27struct Pretty {
28 std::string _name;
29 [[nodiscard]] std::string name(const std::string& name) const;
30 [[nodiscard]] std::string name_to_sentence(const std::string& name) const;
31 static std::string split_words(const std::string& sym);
32 static std::string underscore(const std::string& camel_cased_word);
33 static std::string last(const std::string& s, char delim);
34 static std::string improve_hash_formatting(const std::string& inspect_string);
35
36 template <Util::is_streamable T>
37 static std::string to_word(const T& item);
38
39 template <typename T>
40 static std::string to_word(const T& item);
41
42 template <typename T>
43 static std::string to_word_type(const T& item);
44
45 template <typename A, typename E>
46 static std::string to_word(const Matchers::MatcherBase<A, E>& matcher);
47
48 template <class T>
49 static std::string to_sentence(const T& item);
50
51 template <class T>
52 static std::string to_sentence(const std::vector<T>& words);
53
54 template <typename T>
55 static std::string inspect_object(const T& object);
56};
57
66template <typename T>
67inline std::string Pretty::to_sentence(const std::vector<T>& objects) {
68 std::vector<std::string> words;
69 for (const auto& object : objects) {
70 words.push_back(to_word(object));
71 }
72
73 std::stringstream ss;
74 switch (words.size()) {
75 case 0:
76 return "";
77 case 1:
78 ss << " " << words[0];
79 break;
80 case 2:
81 ss << " " << words[0] << " and " << words[1];
82 break;
83 default:
84 ss << " ";
85 for (size_t i = 0; i < words.size() - 1; ++i) {
86 if (i != 0) {
87 ss << ", ";
88 }
89 ss << words[i];
90 }
91 ss << ", and " << words.back();
92 break;
93 }
94
95 return ss.str();
96}
97
105template <typename T>
106inline std::string Pretty::to_sentence(const T& item) {
107 return to_sentence(std::vector{item});
108}
109
121template <Util::is_streamable T>
122inline std::string Pretty::to_word(const T& item) {
123 std::ostringstream oss;
124 oss << item; // use operator<< to convert and append
125 return oss.str();
126}
127
128template <>
129inline std::string Pretty::to_word<bool>(const bool& item) {
130 return item ? "true" : "false";
131}
132
133template <>
134inline std::string Pretty::to_word<std::true_type>(const std::true_type& /* item */) {
135 return "true";
136}
137
138template <>
139inline std::string Pretty::to_word<std::false_type>(const std::false_type& /* item */) {
140 return "false";
141}
142
150template <typename T>
151inline std::string Pretty::to_word(const T& item) {
152 std::stringstream ss;
153 // Ruby-style inspect for objects without an overloaded operator<<
154 ss << "#<" << Util::demangle(typeid(item).name()) << ":" << &item << ">";
155 return ss.str();
156}
157
169template <typename A, typename E>
170inline std::string Pretty::to_word(const Matchers::MatcherBase<A, E>& matcher) {
171 std::string description = matcher.description();
172 if (description.empty()) {
173 return "[No description]";
174 }
175 return description;
176}
177
178template <typename T>
179inline std::string Pretty::to_word_type(const T& item) {
180 std::string word = to_word(item);
181 if constexpr (Util::is_streamable<T>) {
182 word += " : " + Util::demangle(typeid(T).name());
183 }
184 return word;
185}
186
187inline std::string Pretty::name_to_sentence(const std::string& n) const {
188 return split_words(name(n));
189}
190
191inline std::string Pretty::name(const std::string& name) const {
192 if (_name.empty()) {
193 return last(name, ':');
194 }
195 return _name;
196}
197
198inline std::string Pretty::split_words(const std::string& sym) {
199 return std::regex_replace(sym, std::regex("_"), " ");
200}
201
202inline std::string Pretty::underscore(const std::string& word) {
203 std::string str = std::regex_replace(word, std::regex("([A-Z]+)([A-Z][a-z])"), "$1_$2");
204 str = std::regex_replace(str, std::regex("([a-z\\d])([A-Z])"), "$1_$2");
205 str = std::regex_replace(str, std::regex("-"), "_");
206 std::ranges::transform(str, str.begin(), ::tolower);
207 return str;
208}
209
210inline std::string Pretty::last(const std::string& s, const char delim) {
211 std::vector<std::string> elems;
212 std::stringstream ss(s);
213 std::string item;
214 while (getline(ss, item, delim)) {
215 if (!item.empty()) {
216 elems.push_back(item);
217 }
218 }
219 return elems.back();
220}
221
222inline std::string Pretty::improve_hash_formatting(const std::string& inspect_string) {
223 return std::regex_replace(inspect_string, std::regex("(\\S)=>(\\S)"), "$1 => $2");
224}
225
233template <typename O>
234inline std::string Pretty::inspect_object(const O& o) {
235 return std::format("({}) => {}", Util::demangle(typeid(o).name()), to_word(o));
236}
237
245template <>
246inline std::string Pretty::inspect_object<const char*>(const char* const& o) {
247 return std::format("(const char *) => \"{}\"", o);
248}
249
257template <>
258inline std::string Pretty::inspect_object<std::string>(const std::string& o) {
259 return std::format("(std::string) => \"{}\"", o);
260}
261
262template <>
263inline std::string Pretty::inspect_object<std::string_view>(const std::string_view& o) {
264 return std::format("(std::string_view) => \"{}\"", o);
265}
266
267} // namespace CppSpec
the base class for all Matcher classes and objects
Definition matcher_base.hpp:37
virtual std::string description()
Get the description of the Matcher.
Definition matcher_base.hpp:138
Checks whether T can be streamed.
Definition util.hpp:81
A helper base class that assists in pretty-printing various objects.
Definition pretty_matchers.hpp:27
static std::string to_word(const T &item)
Formats an object as a string when operator<< is available.
Definition pretty_matchers.hpp:122
static std::string to_sentence(const T &item)
Take a single object and format it as a sentance.
Definition pretty_matchers.hpp:106
Utility functions and classes.
std::string demangle(const char *name)
Definition util.hpp:38