]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/include/boost/spirit/home/x3/support/utility/testing.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / spirit / include / boost / spirit / home / x3 / support / utility / testing.hpp
1 /*=============================================================================
2 Copyright (c) 2001-2015 Joel de Guzman
3
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 =============================================================================*/
7 #if !defined(BOOST_SPIRIT_X3_TEST_UTILITIES)
8 #define BOOST_SPIRIT_X3_TEST_UTILITIES
9
10 #include <boost/regex.hpp>
11 #include <boost/filesystem.hpp>
12 #include <boost/filesystem/fstream.hpp>
13
14 namespace boost { namespace spirit { namespace x3 { namespace testing
15 {
16 namespace fs = boost::filesystem;
17
18 ////////////////////////////////////////////////////////////////////////////
19 // compare
20 //
21 // Compares the contents of in with the template tem. The template
22 // may include embedded regular expressions marked up within re_prefix
23 // and re_suffix tags. For example, given the default RE markup, this
24 // template <%[0-9]+%> will match any integer in in. The function
25 // will return the first non-matching position. The flag full_match
26 // indicates a full match. It is possible for returned pos to be
27 // at the end of in (in.end()) while still returning full_match ==
28 // false. In that case, we have a partial match.
29 ////////////////////////////////////////////////////////////////////////////
30
31 template <typename Iterator>
32 struct compare_result
33 {
34 compare_result(
35 Iterator pos
36 , bool full_match
37 ) : pos(pos), full_match(full_match) {}
38
39 Iterator pos;
40 bool full_match;
41 };
42
43 template <typename Range>
44 compare_result<typename Range::const_iterator>
45 compare(
46 Range const& in
47 , Range const& tem
48 , char const* re_prefix = "<%"
49 , char const* re_suffix = "%>"
50 );
51
52 ////////////////////////////////////////////////////////////////////////////
53 // compare
54 //
55 // 1) Call f, given the contents of input_path loaded in a string.
56 // The result of calling f is the output string.
57 // 2) Compare the result of calling f with expected template
58 // file (expect_path) using the low-level compare utility
59 // abive
60 ////////////////////////////////////////////////////////////////////////////
61 template <typename F>
62 bool compare(
63 fs::path input_path, fs::path expect_path
64 , F f
65 , char const* re_prefix = "<%"
66 , char const* re_suffix = "%>"
67 );
68
69 ////////////////////////////////////////////////////////////////////////////
70 // for_each_file
71 //
72 // For each *.input and *.expect file in a given directory,
73 // call the function f, passing in the *.input and *.expect paths.
74 ////////////////////////////////////////////////////////////////////////////
75 template <typename F>
76 int for_each_file(fs::path p, F f);
77
78 ////////////////////////////////////////////////////////////////////////////
79 // load_file
80 //
81 // Load file into a string.
82 ////////////////////////////////////////////////////////////////////////////
83 std::string load(fs::path p);
84
85 ////////////////////////////////////////////////////////////////////////////
86 // Implementation
87 ////////////////////////////////////////////////////////////////////////////
88
89 template <typename Iterator>
90 inline bool is_regex(
91 Iterator& first
92 , Iterator last
93 , std::string& re
94 , char const* re_prefix
95 , char const* re_suffix
96 )
97 {
98 boost::regex e(re_prefix + std::string("(.*?)") + re_suffix);
99 boost::match_results<Iterator> what;
100 if (boost::regex_search(
101 first, last, what, e
102 , boost::match_default | boost::match_continuous))
103 {
104 re = what[1].str();
105 first = what[0].second;
106 return true;
107 }
108 return false;
109 }
110
111 template <typename Range>
112 inline compare_result<typename Range::const_iterator>
113 compare(
114 Range const& in
115 , Range const& tem
116 , char const* re_prefix
117 , char const* re_suffix
118 )
119 {
120 typedef typename Range::const_iterator iter_t;
121 typedef compare_result<iter_t> compare_result_t;
122
123 iter_t in_first = in.begin();
124 iter_t in_last = in.end();
125 iter_t tem_first = tem.begin();
126 iter_t tem_last = tem.end();
127 std::string re;
128
129 while (in_first != in_last && tem_first != tem_last)
130 {
131 if (is_regex(tem_first, tem_last, re, re_prefix, re_suffix))
132 {
133 boost::match_results<iter_t> what;
134 boost::regex e(re);
135 if (!boost::regex_search(
136 in_first, in_last, what, e
137 , boost::match_default | boost::match_continuous))
138 {
139 // RE mismatch: exit now.
140 return compare_result_t(in_first, false);
141 }
142 else
143 {
144 // RE match: gobble the matching string.
145 in_first = what[0].second;
146 }
147 }
148 else
149 {
150 // Char by char comparison. Exit if we have a mismatch.
151 if (*in_first++ != *tem_first++)
152 return compare_result_t(in_first, false);
153 }
154 }
155
156 // Ignore trailing spaces in template
157 bool has_trailing_nonspaces = false;
158 while (tem_first != tem_last)
159 {
160 if (!std::isspace(*tem_first++))
161 {
162 has_trailing_nonspaces = true;
163 break;
164 }
165 }
166 while (in_first != in_last)
167 {
168 if (!std::isspace(*in_first++))
169 {
170 has_trailing_nonspaces = true;
171 break;
172 }
173 }
174 // return a full match only if the template is fully matched and if there
175 // are no more characters to match in the source
176 return compare_result_t(in_first, !has_trailing_nonspaces);
177 }
178
179 template <typename F>
180 inline int for_each_file(fs::path p, F f)
181 {
182 try
183 {
184 if (fs::exists(p) && fs::is_directory(p))
185 {
186 for (auto i = fs::directory_iterator(p); i != fs::directory_iterator(); ++i)
187 {
188 auto ext = fs::extension(i->path());
189 if (ext == ".input")
190 {
191 auto input_path = i->path();
192 auto expect_path = input_path;
193 expect_path.replace_extension(".expect");
194 f(input_path, expect_path);
195 }
196 }
197 }
198 else
199 {
200 std::cerr << "Directory: " << fs::absolute(p) << " does not exist." << std::endl;
201 return 1;
202 }
203 }
204
205 catch (const fs::filesystem_error& ex)
206 {
207 std::cerr << ex.what() << '\n';
208 return 1;
209 }
210 return 0;
211 }
212
213 inline std::string load(fs::path p)
214 {
215 boost::filesystem::ifstream file(p);
216 if (!file)
217 return "";
218 std::string contents((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
219 return contents;
220 }
221
222 template <typename F>
223 inline bool compare(
224 fs::path input_path, fs::path expect_path
225 , F f
226 , char const* re_prefix
227 , char const* re_suffix
228 )
229 {
230 std::string output = f(load(input_path), input_path);
231 std::string expected = load(expect_path);
232
233 auto result = compare(output, expected);
234 if (!result.full_match)
235 {
236 std::cout << "=============================================" << std::endl;
237 std::cout << "==== Mismatch Found:" << std::endl;
238 int line = 1;
239 int col = 1;
240 for (auto i = output.begin(); i != result.pos; ++i)
241 {
242 if (*i == '\n')
243 {
244 line++;
245 col = 0;
246 }
247 ++col;
248 }
249
250 std::cerr
251 << "==== File: " << expect_path
252 << ", Line: " << line
253 << ", Column: " << col
254 << std::endl;
255 std::cerr << "=============================================" << std::endl;
256
257 // Print output
258 std::cerr << output;
259 std::cerr << "=============================================" << std::endl;
260 std::cerr << "==== End" << std::endl;
261 std::cerr << "=============================================" << std::endl;
262 return false;
263 }
264 return true;
265 }
266
267 }}}}
268
269 #endif