1 ///////////////////////////////////////////////////////////////////////////////
2 // test_symbols.cpp
3 //
4 // Copyright 2008 David Jenkins.
5 // Copyright 2008 Eric Niebler.
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See
8 // accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10
11 #include <string>
12 #include <map>
13 #include <boost/version.hpp>
14 #include <boost/xpressive/xpressive_static.hpp>
15 #include <boost/xpressive/regex_actions.hpp>
16 #include <boost/test/unit_test.hpp>
17
18 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
19
20 namespace xp = boost::xpressive;
21
22 ///////////////////////////////////////////////////////////////////////////////
23 // test1
24 // simple action which builds a *translated* string
test1()25 void test1()
26 {
27 using namespace boost::xpressive;
28
29 local<std::string> result;
30 std::string str("foo bar baz foo bar baz");
31 std::map<std::string,std::string> map1;
32 map1["foo"] = "1";
33 map1["bar"] = "2";
34 map1["baz"] = "3";
35
36 sregex rx = skip(_s) (+(a1=map1)
37 [ result += if_else(length(result) > 0, ",", "") + a1 ]
38 );
39
40 if(!regex_match(str, rx))
41 {
42 BOOST_ERROR("oops");
43 }
44 else
45 {
46 BOOST_CHECK_EQUAL(result.get(), "1,2,3,1,2,3");
47 }
48 }
49
50 ///////////////////////////////////////////////////////////////////////////////
51 // test2
52 // find longest match in symbol table
test2()53 void test2()
54 {
55 using namespace boost::xpressive;
56
57 local<std::string> result;
58 std::string str("foobarbazfoobazbazfoobazbar");
59 std::map<std::string,std::string> map1;
60 map1["foo"] = "1";
61 map1["bar"] = "2";
62 map1["baz"] = "3";
63 map1["foobaz"] = "4";
64 map1["foobazbaz"] = "5";
65
66 sregex rx = skip(_s) (+(a1=map1)
67 [ result += if_else(length(result) > 0, ",", "") + a1 ]
68 );
69
70 if(!regex_match(str, rx))
71 {
72 BOOST_ERROR("oops");
73 }
74 else
75 {
76 BOOST_CHECK_EQUAL(result.get(), "1,2,3,5,4,2");
77 }
78 }
79
80 ///////////////////////////////////////////////////////////////////////////////
81 // test3
82 // *map* string to int, push back into list, use alternate ->* syntax
test3()83 void test3()
84 {
85 using namespace boost::xpressive;
86
87 std::list<int> result;
88 std::string str("foo bar baz bop");
89 std::map<std::string,int> map1;
90 map1["foo"] = 1;
91 map1["bar"] = 23;
92 map1["baz"] = 456;
93 map1["bop"] = 7890;
94
95 #if BOOST_VERSION >= 103500
96 sregex rx = skip(_s) (+(a1=map1)
97 [ xp::ref(result)->*push_back( a1 ) ]
98 );
99 #else
100 sregex rx = skip(_s) (+(a1=map1)
101 [ push_back(xp::ref(result), a1 ) ]
102 );
103 #endif
104
105 if(!regex_match(str, rx))
106 {
107 BOOST_ERROR("oops");
108 }
109 else
110 {
111 BOOST_REQUIRE_EQUAL(result.size(), 4u);
112 BOOST_CHECK_EQUAL(*result.begin(), 1);
113 BOOST_CHECK_EQUAL(*++result.begin(), 23);
114 BOOST_CHECK_EQUAL(*++++result.begin(), 456);
115 BOOST_CHECK_EQUAL(*++++++result.begin(), 7890);
116 }
117 }
118
119 ///////////////////////////////////////////////////////////////////////////////
120 // test4
121 // use two input maps to build an output map, with a late-bound action argument.
test4()122 void test4()
123 {
124 using namespace boost::xpressive;
125 placeholder< std::map<std::string, int> > const _map = {};
126
127 std::string str("aaa=>1 bbb=>2 ccc=>3");
128 std::map<std::string,std::string> map1;
129 map1["aaa"] = "foo";
130 map1["bbb"] = "bar";
131 map1["ccc"] = "baz";
132 std::map<std::string,int> map2;
133 map2["1"] = 1;
134 map2["2"] = 23;
135 map2["3"] = 456;
136
137 sregex pair = ( (a1=map1) >> "=>" >> (a2= map2) )[ _map[a1] = a2 ];
138 sregex rx = pair >> *(+_s >> pair);
139
140 smatch what;
141 std::map<std::string, int> result;
142 what.let(_map = result); // bind the argument!
143
144 if(!regex_match(str, what, rx))
145 {
146 BOOST_ERROR("oops");
147 }
148 else
149 {
150 BOOST_REQUIRE_EQUAL(result.size(), 3u);
151 BOOST_CHECK_EQUAL(result["foo"], 1);
152 BOOST_CHECK_EQUAL(result["bar"], 23);
153 BOOST_CHECK_EQUAL(result["baz"], 456);
154 }
155 }
156
157 ///////////////////////////////////////////////////////////////////////////////
158 // test5
159 // test nine maps and attributes
test5()160 void test5()
161 {
162 using namespace boost::xpressive;
163
164 local<int> result(0);
165 std::string str("abcdefghi");
166 std::map<std::string,int> map1;
167 std::map<std::string,int> map2;
168 std::map<std::string,int> map3;
169 std::map<std::string,int> map4;
170 std::map<std::string,int> map5;
171 std::map<std::string,int> map6;
172 std::map<std::string,int> map7;
173 std::map<std::string,int> map8;
174 std::map<std::string,int> map9;
175 map1["a"] = 1;
176 map2["b"] = 2;
177 map3["c"] = 3;
178 map4["d"] = 4;
179 map5["e"] = 5;
180 map6["f"] = 6;
181 map7["g"] = 7;
182 map8["h"] = 8;
183 map9["i"] = 9;
184
185 sregex rx =
186 (a1=map1)[ result += a1 ]
187 >> (a2=map2)[ result += a2 ]
188 >> (a3=map3)[ result += a3 ]
189 >> (a4=map4)[ result += a4 ]
190 >> (a5=map5)[ result += a5 ]
191 >> (a6=map6)[ result += a6 ]
192 >> (a7=map7)[ result += a7 ]
193 >> (a8=map8)[ result += a8 ]
194 >> (a9=map9)[ result += a9 ];
195
196 if(!regex_match(str, rx))
197 {
198 BOOST_ERROR("oops");
199 }
200 else
201 {
202 BOOST_CHECK_EQUAL(result.get(), 45);
203 }
204 }
205
206 ///////////////////////////////////////////////////////////////////////////////
207 // test6
208 // test case-sensitivity
test6()209 void test6()
210 {
211 using namespace boost::xpressive;
212
213 local<std::string> result;
214 std::map<std::string,std::string> map1;
215 map1["a"] = "1";
216 map1["A"] = "2";
217 map1["b"] = "3";
218 map1["B"] = "4";
219 std::string str("a A b B a A b B");
220 sregex rx = skip(_s)(
221 icase(a1= map1) [ result = a1 ]
222 >> repeat<3>( (icase(a1= map1) [ result += ',' + a1 ]) )
223 >> repeat<4>( ((a1= map1) [ result += ',' + a1 ]) )
224 );
225 if(!regex_match(str, rx))
226 {
227 BOOST_ERROR("oops");
228 }
229 else
230 {
231 BOOST_CHECK_EQUAL(result.get(), "1,1,3,3,1,2,3,4");
232 }
233 }
234
235 ///////////////////////////////////////////////////////////////////////////////
236 // test7
237 // test multiple mutually-exclusive maps and default attribute value
test7()238 void test7()
239 {
240 using namespace boost::xpressive;
241
242 local<std::string> result;
243 std::map<std::string,std::string> map1;
244 map1["a"] = "1";
245 map1["b"] = "2";
246 std::map<std::string,std::string> map2;
247 map2["c"] = "3";
248 map2["d"] = "4";
249 std::string str("abcde");
250 sregex rx = *((a1= map1) | (a1= map2) | 'e') [ result += (a1 | "9") ];
251 if(!regex_match(str, rx))
252 {
253 BOOST_ERROR("oops");
254 }
255 else
256 {
257 BOOST_CHECK_EQUAL(result.get(), "12349");
258 }
259 }
260
261 #ifndef BOOST_XPRESSIVE_NO_WREGEX
262 struct City
263 {
264 std::wstring name;
265 char const* nickname;
266 int population;
267 };
268
BOOST_TYPEOF_REGISTER_TYPE(City)269 BOOST_TYPEOF_REGISTER_TYPE(City)
270
271 ///////////////////////////////////////////////////////////////////////////////
272 // test8
273 // test wide strings with structure result
274 void test8()
275 {
276 using namespace boost::xpressive;
277
278 City cities[] = {
279 {L"Chicago", "The Windy City", 945000},
280 {L"New York", "The Big Apple", 16626000},
281 {L"\u041c\u043E\u0441\u043A\u0432\u0430", "Moscow", 9299000}
282 };
283 int const nbr_cities = sizeof(cities)/sizeof(*cities);
284
285 std::map<std::wstring, City> map1;
286 for(int i=0; i<nbr_cities; ++i)
287 {
288 map1[cities[i].name] = cities[i];
289 }
290
291 std::wstring str(L"Chicago \u041c\u043E\u0441\u043A\u0432\u0430");
292 local<City> result1, result2;
293 wsregex rx = (a1= map1)[ result1 = a1 ] >> +_s
294 >> (a1= map1)[ result2 = a1 ];
295 if(!regex_match(str, rx))
296 {
297 BOOST_ERROR("oops");
298 }
299 else
300 {
301 BOOST_CHECK_EQUAL(result1.get().nickname, "The Windy City");
302 BOOST_CHECK_EQUAL(result2.get().nickname, "Moscow");
303 }
304 }
305 #else
test8()306 void test8()
307 {
308 // This test is empty
309 }
310 #endif
311
312 ///////////////////////////////////////////////////////////////////////////////
313 // test9
314 // test "not before" using a map
test9()315 void test9()
316 {
317 using namespace boost::xpressive;
318
319 std::string result;
320 std::string str("foobar");
321 std::map<std::string,int> map1;
322 map1["foo"] = 1;
323 sregex rx = ~before((a1=map1)[a1]) >>
324 (s1=*_w)[ xp::ref(result) = s1 ];
325 if(!regex_match(str, rx))
326 {
327 BOOST_CHECK_EQUAL(result, "");
328 }
329 else
330 {
331 BOOST_ERROR("oops");
332 }
333 }
334
335 using namespace boost::unit_test;
336
337 ///////////////////////////////////////////////////////////////////////////////
338 // init_unit_test_suite
339 //
init_unit_test_suite(int argc,char * argv[])340 test_suite* init_unit_test_suite( int argc, char* argv[] )
341 {
342 test_suite *test = BOOST_TEST_SUITE("test_symbols");
343 test->add(BOOST_TEST_CASE(&test1));
344 test->add(BOOST_TEST_CASE(&test2));
345 test->add(BOOST_TEST_CASE(&test3));
346 test->add(BOOST_TEST_CASE(&test4));
347 test->add(BOOST_TEST_CASE(&test5));
348 test->add(BOOST_TEST_CASE(&test6));
349 test->add(BOOST_TEST_CASE(&test7));
350 test->add(BOOST_TEST_CASE(&test8));
351 test->add(BOOST_TEST_CASE(&test9));
352 return test;
353 }
354
355