1 /*=============================================================================
2 Copyright (c) 1998-2003 Joel de Guzman
3 Copyright (c) 2003 Martin Wille
4 http://spirit.sourceforge.net/
5
6 Use, modification and distribution is subject to the Boost Software
7 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8 http://www.boost.org/LICENSE_1_0.txt)
9 =============================================================================*/
10 #include <iostream>
11 #include <string>
12 #include <boost/detail/lightweight_test.hpp>
13 #include <boost/spirit/include/classic_core.hpp>
14 #include <boost/spirit/include/classic_symbols.hpp>
15 #include <boost/swap.hpp>
16 #include "symbols.hpp"
17
18 ///////////////////////////////////////////////////////////////////////////////
19 using namespace std;
20 using namespace BOOST_SPIRIT_CLASSIC_NS;
21
22 ///////////////////////////////////////////////////////////////////////////////
23
equal(IteratorT p,IteratorT q)24 template <typename IteratorT> bool equal(IteratorT p, IteratorT q)
25 {
26 while (*p && *p == *q) {
27 ++p;
28 ++q;
29 }
30 return *p == *q;
31 }
32
33 template <class SymbolsT, typename CharT>
docheck(SymbolsT const & sym,CharT const * candidate,bool hit,CharT const * result,int length)34 void docheck(
35 SymbolsT const& sym,
36 CharT const* candidate,
37 bool hit,
38 CharT const* result,
39 int length)
40 {
41 parse_info<CharT const*> info = parse(candidate, sym);
42
43 #define correctly_matched hit == info.hit
44 #define correct_match_length unsigned(length) == info.length
45 #define correct_tail equal(candidate + (hit ? 1 : 0) * length, result)
46
47 BOOST_TEST(correctly_matched);
48
49 if (hit) {
50 BOOST_TEST(correct_match_length);
51 BOOST_TEST(correct_tail);
52 }
53 else {
54 BOOST_TEST(correct_tail);
55 }
56 }
57
58 template <typename T> struct store_action
59 {
store_actionstore_action60 store_action(T const& v) : value(v) {}
operator ()store_action61 void operator()(T& v) const { v = value; }
62
63 private:
64 T const value;
65 };
66
store(T const & v)67 template <typename T> store_action<T> store(T const& v) { return v; }
68
69 template <typename T> struct check_action
70 {
check_actioncheck_action71 check_action(T const& v) : value(v) {}
72
73 #define correct_value_stored (v == value)
operator ()check_action74 void operator()(T const& v) const { BOOST_TEST(correct_value_stored); }
75
76 private:
77 T const value;
78 };
79
docheck(T const & v)80 template <typename T> check_action<T> docheck(T const& v) { return v; }
81
default_constructible()82 static void default_constructible()
83 { // this actually a compile time test
84 symbols<int, char, quickbook::tst<int, char> > ns1;
85 symbols<int, wchar_t, quickbook::tst<int, wchar_t> > ws1;
86 symbols<std::string, char, quickbook::tst<std::string, char> > ns2;
87 symbols<std::string, wchar_t, quickbook::tst<std::string, wchar_t> > ws2;
88
89 (void)ns1;
90 (void)ws1;
91 (void)ns2;
92 (void)ws2;
93 }
94
95 typedef symbols<int, char, quickbook::tst<int, char> > nsymbols;
96 typedef symbols<int, wchar_t, quickbook::tst<int, wchar_t> > wsymbols;
97
narrow_match_tests()98 static void narrow_match_tests()
99 {
100 nsymbols sym;
101 sym = "pineapple", "orange", "banana", "applepie", "apple";
102
103 docheck(sym, "pineapple", true, "", 9);
104 docheck(sym, "orange", true, "", 6);
105 docheck(sym, "banana", true, "", 6);
106 docheck(sym, "apple", true, "", 5);
107 docheck(sym, "pizza", false, "pizza", -1);
108 docheck(sym, "steak", false, "steak", -1);
109 docheck(sym, "applepie", true, "", 8);
110 docheck(sym, "bananarama", true, "rama", 6);
111 docheck(sym, "applet", true, "t", 5);
112 docheck(sym, "applepi", true, "pi", 5);
113 docheck(sym, "appl", false, "appl", -1);
114
115 docheck(sym, "pineapplez", true, "z", 9);
116 docheck(sym, "orangez", true, "z", 6);
117 docheck(sym, "bananaz", true, "z", 6);
118 docheck(sym, "applez", true, "z", 5);
119 docheck(sym, "pizzaz", false, "pizzaz", -1);
120 docheck(sym, "steakz", false, "steakz", -1);
121 docheck(sym, "applepiez", true, "z", 8);
122 docheck(sym, "bananaramaz", true, "ramaz", 6);
123 docheck(sym, "appletz", true, "tz", 5);
124 docheck(sym, "applepix", true, "pix", 5);
125 }
126
narrow_copy_ctor_tests()127 static void narrow_copy_ctor_tests()
128 {
129 nsymbols sym;
130 sym = "pineapple", "orange", "banana", "applepie", "apple";
131
132 nsymbols sym2(sym);
133 docheck(sym2, "pineapple", true, "", 9);
134 docheck(sym2, "pizza", false, "pizza", -1);
135 docheck(sym2, "bananarama", true, "rama", 6);
136 }
137
narrow_assigment_operator_tests()138 static void narrow_assigment_operator_tests()
139 {
140 nsymbols sym;
141 sym = "pineapple", "orange", "banana", "applepie", "apple";
142
143 nsymbols sym2;
144 sym2 = sym;
145
146 docheck(sym2, "pineapple", true, "", 9);
147 docheck(sym2, "pizza", false, "pizza", -1);
148 docheck(sym2, "bananarama", true, "rama", 6);
149 }
150
narrow_swap_tests()151 static void narrow_swap_tests()
152 {
153 nsymbols sym, sym2;
154 sym = "pineapple", "orange", "banana", "applepie", "apple";
155 sym2 = "potato", "cucumber", "cauliflower", "carrot";
156
157 boost::swap(sym, sym2);
158
159 docheck(sym2, "pineapple", true, "", 9);
160 docheck(sym2, "pizza", false, "pizza", -1);
161 docheck(sym2, "bananarama", true, "rama", 6);
162 docheck(sym, "potatoe", true, "e", 6);
163 docheck(sym, "cauliflour", false, "cauliflour", -1);
164 }
165
narrow_value_tests()166 static void narrow_value_tests()
167 { // also tests the add member functions
168 nsymbols sym;
169
170 sym = "orange", "banana";
171 sym.add("pineapple", 1234);
172 sym.add("lemon");
173
174 parse("orange", sym[store(12345)]);
175 parse("orange", sym[docheck(12345)]);
176 parse("pineapple", sym[docheck(1234)]);
177 parse("banana", sym[docheck(int())]);
178 parse("lemon", sym[docheck(int())]);
179 }
180
narrow_free_functions_tests()181 static void narrow_free_functions_tests()
182 {
183 nsymbols sym;
184
185 #define add_returned_non_null_value (res != 0)
186 #define add_returned_null (res == 0)
187 #define find_returned_non_null_value (res != 0)
188 #define find_returned_null (res == 0)
189
190 int* res = add(sym, "pineapple");
191 BOOST_TEST(add_returned_non_null_value);
192 res = add(sym, "pineapple");
193 BOOST_TEST(add_returned_null);
194
195 res = find(sym, "pineapple");
196 BOOST_TEST(find_returned_non_null_value);
197 res = find(sym, "banana");
198 BOOST_TEST(find_returned_null);
199 }
200
wide_match_tests()201 static void wide_match_tests()
202 {
203 wsymbols sym;
204 sym = L"pineapple", L"orange", L"banana", L"applepie", L"apple";
205
206 docheck(sym, L"pineapple", true, L"", 9);
207 docheck(sym, L"orange", true, L"", 6);
208 docheck(sym, L"banana", true, L"", 6);
209 docheck(sym, L"apple", true, L"", 5);
210 docheck(sym, L"pizza", false, L"pizza", -1);
211 docheck(sym, L"steak", false, L"steak", -1);
212 docheck(sym, L"applepie", true, L"", 8);
213 docheck(sym, L"bananarama", true, L"rama", 6);
214 docheck(sym, L"applet", true, L"t", 5);
215 docheck(sym, L"applepi", true, L"pi", 5);
216 docheck(sym, L"appl", false, L"appl", -1);
217
218 docheck(sym, L"pineapplez", true, L"z", 9);
219 docheck(sym, L"orangez", true, L"z", 6);
220 docheck(sym, L"bananaz", true, L"z", 6);
221 docheck(sym, L"applez", true, L"z", 5);
222 docheck(sym, L"pizzaz", false, L"pizzaz", -1);
223 docheck(sym, L"steakz", false, L"steakz", -1);
224 docheck(sym, L"applepiez", true, L"z", 8);
225 docheck(sym, L"bananaramaz", true, L"ramaz", 6);
226 docheck(sym, L"appletz", true, L"tz", 5);
227 docheck(sym, L"applepix", true, L"pix", 5);
228 }
229
wide_copy_ctor_tests()230 static void wide_copy_ctor_tests()
231 {
232 wsymbols sym;
233 sym = L"pineapple", L"orange", L"banana", L"applepie", L"apple";
234
235 wsymbols sym2(sym);
236 docheck(sym2, L"pineapple", true, L"", 9);
237 docheck(sym2, L"pizza", false, L"pizza", -1);
238 docheck(sym2, L"bananarama", true, L"rama", 6);
239 }
240
wide_assigment_operator_tests()241 static void wide_assigment_operator_tests()
242 {
243 wsymbols sym;
244 sym = L"pineapple", L"orange", L"banana", L"applepie", L"apple";
245
246 wsymbols sym2;
247 sym2 = sym;
248
249 docheck(sym2, L"pineapple", true, L"", 9);
250 docheck(sym2, L"pizza", false, L"pizza", -1);
251 docheck(sym2, L"bananarama", true, L"rama", 6);
252 }
253
wide_swap_tests()254 static void wide_swap_tests()
255 {
256 wsymbols sym, sym2;
257 sym = L"pineapple", L"orange", L"banana", L"applepie", L"apple";
258 sym2 = L"potato", L"cucumber", L"cauliflower", L"carrot";
259
260 boost::swap(sym, sym2);
261
262 docheck(sym2, L"pineapple", true, L"", 9);
263 docheck(sym2, L"pizza", false, L"pizza", -1);
264 docheck(sym2, L"bananarama", true, L"rama", 6);
265 docheck(sym, L"potatoe", true, L"e", 6);
266 docheck(sym, L"cauliflour", false, L"cauliflour", -1);
267 }
268
wide_value_tests()269 static void wide_value_tests()
270 { // also tests the add member functions
271 wsymbols sym;
272
273 sym = L"orange", L"banana";
274 sym.add(L"pineapple", 1234);
275 sym.add(L"lemon");
276
277 parse(L"orange", sym[store(12345)]);
278 parse(L"orange", sym[docheck(12345)]);
279 parse(L"pineapple", sym[docheck(1234)]);
280 parse(L"banana", sym[docheck(int())]);
281 parse(L"lemon", sym[docheck(int())]);
282 }
283
wide_free_functions_tests()284 static void wide_free_functions_tests()
285 {
286 wsymbols sym;
287
288 int* res = add(sym, L"pineapple");
289 BOOST_TEST(add_returned_non_null_value);
290 res = add(sym, L"pineapple");
291 BOOST_TEST(add_returned_null);
292
293 res = find(sym, L"pineapple");
294 BOOST_TEST(find_returned_non_null_value);
295 res = find(sym, L"banana");
296 BOOST_TEST(find_returned_null);
297 }
298
free_add_find_functions_tests()299 static void free_add_find_functions_tests()
300 {
301 nsymbols sym;
302 BOOST_TEST(*add(sym, "a", 0) == 0);
303 BOOST_TEST(*add(sym, "a2", 1) == 1);
304 BOOST_TEST(add(sym, "a2", 2) == 0);
305 BOOST_TEST(find(sym, "a2"));
306 BOOST_TEST(find(sym, "a"));
307 }
308
309 // The original teneray search tree implementation contained a bug when
310 // inserting duplicate values. I want this implementation to be as
311 // close as possible to the original (so they can be easily switched)
312 // so check that the bug remains the same.
313
314 struct check_parse_value
315 {
check_parse_valuecheck_parse_value316 explicit check_parse_value(int value) : value_(value) {}
317
operator ()check_parse_value318 void operator()(int value) const { BOOST_TEST(value == value_); }
319
320 int value_;
321 };
322
323 // My version is different to the original, if there's an existing value
324 // it replaces it with the new one.
325
duplicate_add_tests()326 static void duplicate_add_tests()
327 {
328 char const* foo1 = "foo";
329 char const* foo2 = foo1 + 3;
330
331 nsymbols sym;
332 sym.add(foo1, foo2, 1);
333 nsymbols sym2 = sym;
334 sym.add(foo1, foo2, 2);
335 sym2.add(foo1, foo2, 3);
336
337 BOOST_TEST(find(sym, "foo") && *find(sym, "foo") == 2);
338 BOOST_TEST(find(sym2, "foo") && *find(sym2, "foo") == 3);
339
340 parse_info<char const*> info;
341
342 info = parse("foo ", sym[check_parse_value(2)]);
343 BOOST_TEST(info.hit && info.length == 3);
344
345 info = parse("foo", sym[check_parse_value(2)]);
346 BOOST_TEST(info.hit && info.length == 3);
347
348 info = parse("foo ", sym2[check_parse_value(3)]);
349 BOOST_TEST(info.hit && info.length == 3);
350
351 info = parse("foo", sym2[check_parse_value(3)]);
352 BOOST_TEST(info.hit && info.length == 3);
353 }
354
main()355 int main()
356 {
357 default_constructible();
358 narrow_match_tests();
359 narrow_copy_ctor_tests();
360 narrow_assigment_operator_tests();
361 narrow_swap_tests();
362 narrow_value_tests();
363 narrow_free_functions_tests();
364 wide_match_tests();
365 wide_copy_ctor_tests();
366 wide_assigment_operator_tests();
367 wide_swap_tests();
368 wide_value_tests();
369 wide_free_functions_tests();
370 free_add_find_functions_tests();
371 duplicate_add_tests();
372
373 return boost::report_errors();
374 }
375