1 /*
2  *
3  * Copyright (c) 2004
4  * John Maddock
5  *
6  * Use, modification and distribution are subject to the
7  * Boost Software License, Version 1.0. (See accompanying file
8  * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9  *
10  */
11 
12  /*
13   *   LOCATION:    see http://www.boost.org for most recent version.
14   *   FILE         test_icu.cpp
15   *   VERSION      see <boost/version.hpp>
16   *   DESCRIPTION: Test code for Unicode regexes with ICU support.
17   */
18 
19 //
20 // We can only build this if we have ICU support:
21 //
22 #include <boost/regex/config.hpp>
23 #if defined(BOOST_HAS_ICU) && !defined(BOOST_NO_STD_WSTRING)
24 
25 #include <boost/regex/icu.hpp>
26 #include <boost/mpl/int.hpp>
27 #include "test.hpp"
28 
29 namespace unnecessary_fix{
30 //
31 // Some outrageously broken std lib's don't have a conforming
32 // back_insert_iterator, which means we can't use the std version
33 // as an argument to regex_replace, sigh... use our own:
34 //
35 template <class Seq>
36 class back_insert_iterator
37 {
38 private:
39    Seq* container;
40 public:
41    typedef const typename Seq::value_type value_type;
42    typedef Seq                  container_type;
43    typedef void                     difference_type;
44    typedef void                     pointer;
45    typedef void                     reference;
46    typedef std::output_iterator_tag iterator_category;
47 
back_insert_iterator(Seq & x)48    explicit back_insert_iterator(Seq& x) : container(&x) {}
operator =(const value_type & val)49    back_insert_iterator& operator=(const value_type& val)
50    {
51       container->push_back(val);
52       return *this;
53    }
operator *()54    back_insert_iterator& operator*() { return *this; }
operator ++()55    back_insert_iterator& operator++() { return *this; }
operator ++(int)56    back_insert_iterator  operator++(int) { return *this; }
57 };
58 
59 template <class Seq>
back_inserter(Seq & x)60 inline back_insert_iterator<Seq> back_inserter(Seq& x)
61 {
62    return back_insert_iterator<Seq>(x);
63 }
64 
65 }
66 
67 //
68 // compare two match_results struct's for equality,
69 // converting the iterator as needed:
70 //
71 template <class MR1, class MR2>
compare_result(const MR1 & w1,const MR2 & w2,boost::mpl::int_<2> const *)72 void compare_result(const MR1& w1, const MR2& w2, boost::mpl::int_<2> const*)
73 {
74    typedef typename MR2::value_type MR2_value_type;
75    typedef typename MR2_value_type::const_iterator MR2_iterator_type;
76    typedef boost::u16_to_u32_iterator<MR2_iterator_type> iterator_type;
77    //typedef typename MR1::size_type size_type;
78    if(w1.size() != w2.size())
79    {
80       BOOST_REGEX_TEST_ERROR("Size mismatch in match_results class", UChar32);
81    }
82    for(int i = 0; i < (int)w1.size(); ++i)
83    {
84       if(w1[i].matched)
85       {
86          if(w2[i].matched == 0)
87          {
88             BOOST_REGEX_TEST_ERROR("Matched mismatch in match_results class", UChar32);
89          }
90          if((w1.position(i) != std::distance(iterator_type(w2.prefix().first), iterator_type(w2[i].first))) || (w1.length(i) != std::distance(iterator_type(w2[i].first), iterator_type(w2[i].second))))
91          {
92             BOOST_REGEX_TEST_ERROR("Iterator mismatch in match_results class", UChar32);
93          }
94       }
95       else if(w2[i].matched)
96       {
97          BOOST_REGEX_TEST_ERROR("Matched mismatch in match_results class", UChar32);
98       }
99    }
100    //
101    // We don't have a way to access a list of named sub-expressions since we only store
102    // hashes, but "abc" and "N" are common names used in our tests, so check those:
103    //
104    if (w1["abc"].matched)
105    {
106       if (w2["abc"].matched == 0)
107       {
108          BOOST_REGEX_TEST_ERROR("Matched mismatch in match_results class", UChar32);
109       }
110       if ((w1.position("abc") != std::distance(iterator_type(w2.prefix().first), iterator_type(w2["abc"].first))) || (w1.length("abc") != std::distance(iterator_type(w2["abc"].first), iterator_type(w2["abc"].second))))
111       {
112          BOOST_REGEX_TEST_ERROR("Iterator mismatch in match_results class", UChar32);
113       }
114    }
115    else if (w2["abc"].matched)
116    {
117       BOOST_REGEX_TEST_ERROR("Matched mismatch in match_results class", UChar32);
118    }
119    if (w1["N"].matched)
120    {
121       if (w2["N"].matched == 0)
122       {
123          BOOST_REGEX_TEST_ERROR("Matched mismatch in match_results class", UChar32);
124       }
125       if ((w1.position("N") != std::distance(iterator_type(w2.prefix().first), iterator_type(w2["N"].first))) || (w1.length("N") != std::distance(iterator_type(w2["N"].first), iterator_type(w2["N"].second))))
126       {
127          BOOST_REGEX_TEST_ERROR("Iterator mismatch in match_results class", UChar32);
128       }
129    }
130    else if (w2["N"].matched)
131    {
132       BOOST_REGEX_TEST_ERROR("Matched mismatch in match_results class", UChar32);
133    }
134 }
135 template <class MR1, class MR2>
compare_result(const MR1 & w1,const MR2 & w2,boost::mpl::int_<1> const *)136 void compare_result(const MR1& w1, const MR2& w2, boost::mpl::int_<1> const*)
137 {
138    typedef typename MR2::value_type MR2_value_type;
139    typedef typename MR2_value_type::const_iterator MR2_iterator_type;
140    typedef boost::u8_to_u32_iterator<MR2_iterator_type> iterator_type;
141    //typedef typename MR1::size_type size_type;
142    if(w1.size() != w2.size())
143    {
144       BOOST_REGEX_TEST_ERROR("Size mismatch in match_results class", UChar32);
145    }
146    for(int i = 0; i < (int)w1.size(); ++i)
147    {
148       if(w1[i].matched)
149       {
150          if(w2[i].matched == 0)
151          {
152             BOOST_REGEX_TEST_ERROR("Matched mismatch in match_results class", UChar32);
153          }
154          if((w1.position(i) != std::distance(iterator_type(w2.prefix().first), iterator_type(w2[i].first))) || (w1.length(i) != std::distance(iterator_type(w2[i].first), iterator_type(w2[i].second))))
155          {
156             BOOST_REGEX_TEST_ERROR("Iterator mismatch in match_results class", UChar32);
157          }
158       }
159       else if(w2[i].matched)
160       {
161          BOOST_REGEX_TEST_ERROR("Matched mismatch in match_results class", UChar32);
162       }
163    }
164 }
165 
test_icu_grep(const boost::u32regex & r,const std::vector<::UChar32> & search_text)166 void test_icu_grep(const boost::u32regex& r, const std::vector< ::UChar32>& search_text)
167 {
168    typedef std::vector< ::UChar32>::const_iterator const_iterator;
169    typedef boost::u32regex_iterator<const_iterator> test_iterator;
170    boost::regex_constants::match_flag_type opts = test_info<wchar_t>::match_options();
171    const int* answer_table = test_info<wchar_t>::answer_table();
172    test_iterator start(search_text.begin(), search_text.end(), r, opts), end;
173    test_iterator copy(start);
174    const_iterator last_end = search_text.begin();
175    while(start != end)
176    {
177       if(start != copy)
178       {
179          BOOST_REGEX_TEST_ERROR("Failed iterator != comparison.", wchar_t);
180       }
181       if(!(start == copy))
182       {
183          BOOST_REGEX_TEST_ERROR("Failed iterator == comparison.", wchar_t);
184       }
185       test_result(*start, search_text.begin(), answer_table);
186       // test $` and $' :
187       if(start->prefix().first != last_end)
188       {
189          BOOST_REGEX_TEST_ERROR("Incorrect position for start of $`", wchar_t);
190       }
191       if(start->prefix().second != (*start)[0].first)
192       {
193          BOOST_REGEX_TEST_ERROR("Incorrect position for end of $`", wchar_t);
194       }
195       if(start->prefix().matched != (start->prefix().first != start->prefix().second))
196       {
197          BOOST_REGEX_TEST_ERROR("Incorrect position for matched member of $`", wchar_t);
198       }
199       if(start->suffix().first != (*start)[0].second)
200       {
201          BOOST_REGEX_TEST_ERROR("Incorrect position for start of $'", wchar_t);
202       }
203       if(start->suffix().second != search_text.end())
204       {
205          BOOST_REGEX_TEST_ERROR("Incorrect position for end of $'", wchar_t);
206       }
207       if(start->suffix().matched != (start->suffix().first != start->suffix().second))
208       {
209          BOOST_REGEX_TEST_ERROR("Incorrect position for matched member of $'", wchar_t);
210       }
211       last_end = (*start)[0].second;
212       ++start;
213       ++copy;
214       // move on the answer table to next set of answers;
215       if(*answer_table != -2)
216          while(*answer_table++ != -2){}
217    }
218    if(answer_table[0] >= 0)
219    {
220       // we should have had a match but didn't:
221       BOOST_REGEX_TEST_ERROR("Expected match was not found.", wchar_t);
222    }
223 }
224 
test_icu(const wchar_t &,const test_regex_search_tag &)225 void test_icu(const wchar_t&, const test_regex_search_tag& )
226 {
227    boost::u32regex r;
228    if(*test_locale::c_str())
229    {
230       U_NAMESPACE_QUALIFIER Locale l(test_locale::c_str());
231       if(l.isBogus())
232          return;
233       r.imbue(l);
234    }
235 
236    std::vector< ::UChar32> expression;
237 #ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
238    expression.assign(test_info<wchar_t>::expression().begin(), test_info<wchar_t>::expression().end());
239 #else
240    std::copy(test_info<wchar_t>::expression().begin(), test_info<wchar_t>::expression().end(), std::back_inserter(expression));
241 #endif
242    boost::regex_constants::syntax_option_type syntax_options = test_info<UChar32>::syntax_options();
243 #ifndef BOOST_NO_EXCEPTIONS
244    try
245 #endif
246    {
247 #if !defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(__IBMCPP__)
248       r.assign(expression.begin(), expression.end(), syntax_options);
249 #else
250       if(expression.size())
251          r.assign(&*expression.begin(), expression.size(), syntax_options);
252       else
253          r.assign(static_cast<UChar32 const*>(0), expression.size(), syntax_options);
254 #endif
255       if(r.status())
256       {
257          BOOST_REGEX_TEST_ERROR("Expression did not compile when it should have done, error code = " << r.status(), UChar32);
258       }
259       std::vector< ::UChar32> search_text;
260 #ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
261       search_text.assign(test_info<wchar_t>::search_text().begin(), test_info<wchar_t>::search_text().end());
262 #else
263       std::copy(test_info<wchar_t>::search_text().begin(), test_info<wchar_t>::search_text().end(), std::back_inserter(search_text));
264 #endif
265       boost::regex_constants::match_flag_type opts = test_info<wchar_t>::match_options();
266       const int* answer_table = test_info<wchar_t>::answer_table();
267       boost::match_results<std::vector< ::UChar32>::const_iterator> what;
268       if(boost::u32regex_search(
269          const_cast<std::vector< ::UChar32>const&>(search_text).begin(),
270          const_cast<std::vector< ::UChar32>const&>(search_text).end(),
271          what,
272          r,
273          opts))
274       {
275          test_result(what, const_cast<std::vector< ::UChar32>const&>(search_text).begin(), answer_table);
276       }
277       else if(answer_table[0] >= 0)
278       {
279          // we should have had a match but didn't:
280          BOOST_REGEX_TEST_ERROR("Expected match was not found.", UChar32);
281       }
282 
283       if(0 == *test_locale::c_str())
284       {
285          //
286          // Now try UTF-16 construction:
287          //
288          typedef boost::u32_to_u16_iterator<std::vector<UChar32>::const_iterator> u16_conv;
289          std::vector<UChar> expression16, text16;
290          boost::match_results<std::vector<UChar>::const_iterator> what16;
291          boost::match_results<const UChar*> what16c;
292 #ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
293          expression16.assign(u16_conv(expression.begin()), u16_conv(expression.end()));
294          text16.assign(u16_conv(search_text.begin()), u16_conv(search_text.end()));
295 #else
296          expression16.clear();
297          std::copy(u16_conv(expression.begin()), u16_conv(expression.end()), std::back_inserter(expression16));
298          text16.clear();
299          std::copy(u16_conv(search_text.begin()), u16_conv(search_text.end()), std::back_inserter(text16));
300 #endif
301          r = boost::make_u32regex(expression16.begin(), expression16.end(), syntax_options);
302          if(boost::u32regex_search(const_cast<const std::vector<UChar>&>(text16).begin(), const_cast<const std::vector<UChar>&>(text16).end(), what16, r, opts))
303          {
304             compare_result(what, what16, static_cast<boost::mpl::int_<2> const*>(0));
305          }
306          else if(answer_table[0] >= 0)
307          {
308             // we should have had a match but didn't:
309             BOOST_REGEX_TEST_ERROR("Expected match was not found.", UChar32);
310          }
311          if(std::find(expression16.begin(), expression16.end(), 0) == expression16.end())
312          {
313             expression16.push_back(0);
314             r = boost::make_u32regex(&*expression16.begin(), syntax_options);
315             if(std::find(text16.begin(), text16.end(), 0) == text16.end())
316             {
317                text16.push_back(0);
318                if(boost::u32regex_search((const UChar*)&*text16.begin(), what16c, r, opts))
319                {
320                   compare_result(what, what16c, static_cast<boost::mpl::int_<2> const*>(0));
321                }
322                else if(answer_table[0] >= 0)
323                {
324                   // we should have had a match but didn't:
325                   BOOST_REGEX_TEST_ERROR("Expected match was not found.", UChar32);
326                }
327             }
328          }
329          //
330          // Now try UTF-8 construction:
331          //
332          typedef boost::u32_to_u8_iterator<std::vector<UChar32>::const_iterator, unsigned char> u8_conv;
333          std::vector<unsigned char> expression8, text8;
334          boost::match_results<std::vector<unsigned char>::const_iterator> what8;
335          boost::match_results<const unsigned char*> what8c;
336 #ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
337          expression8.assign(u8_conv(expression.begin()), u8_conv(expression.end()));
338          text8.assign(u8_conv(search_text.begin()), u8_conv(search_text.end()));
339 #else
340          expression8.clear();
341          std::copy(u8_conv(expression.begin()), u8_conv(expression.end()), std::back_inserter(expression8));
342          text8.clear();
343          std::copy(u8_conv(search_text.begin()), u8_conv(search_text.end()), std::back_inserter(text8));
344 #endif
345          r = boost::make_u32regex(expression8.begin(), expression8.end(), syntax_options);
346          if(boost::u32regex_search(const_cast<const std::vector<unsigned char>&>(text8).begin(), const_cast<const std::vector<unsigned char>&>(text8).end(), what8, r, opts))
347          {
348             compare_result(what, what8, static_cast<boost::mpl::int_<1> const*>(0));
349          }
350          else if(answer_table[0] >= 0)
351          {
352             // we should have had a match but didn't:
353             BOOST_REGEX_TEST_ERROR("Expected match was not found.", UChar32);
354          }
355          if(std::find(expression8.begin(), expression8.end(), 0) == expression8.end())
356          {
357             expression8.push_back(0);
358             r = boost::make_u32regex(&*expression8.begin(), syntax_options);
359             if(std::find(text8.begin(), text8.end(), 0) == text8.end())
360             {
361                text8.push_back(0);
362                if(boost::u32regex_search((const unsigned char*)&*text8.begin(), what8c, r, opts))
363                {
364                   compare_result(what, what8c, static_cast<boost::mpl::int_<1> const*>(0));
365                }
366                else if(answer_table[0] >= 0)
367                {
368                   // we should have had a match but didn't:
369                   BOOST_REGEX_TEST_ERROR("Expected match was not found.", UChar32);
370                }
371             }
372          }
373       }
374       //
375       // finally try a grep:
376       //
377       test_icu_grep(r, search_text);
378    }
379 #ifndef BOOST_NO_EXCEPTIONS
380    catch(const boost::bad_expression& e)
381    {
382       BOOST_REGEX_TEST_ERROR("Expression did not compile when it should have done: " << e.what(), UChar32);
383    }
384    catch(const std::runtime_error& e)
385    {
386       BOOST_REGEX_TEST_ERROR("Received an unexpected std::runtime_error: " << e.what(), UChar32);
387    }
388    catch(const std::exception& e)
389    {
390       BOOST_REGEX_TEST_ERROR("Received an unexpected std::exception: " << e.what(), UChar32);
391    }
392    catch(...)
393    {
394       BOOST_REGEX_TEST_ERROR("Received an unexpected exception of unknown type", UChar32);
395    }
396 #endif
397 }
398 
test_icu(const wchar_t &,const test_invalid_regex_tag &)399 void test_icu(const wchar_t&, const test_invalid_regex_tag&)
400 {
401    //typedef boost::u16_to_u32_iterator<std::wstring::const_iterator, ::UChar32> conv_iterator;
402    std::vector< ::UChar32> expression;
403 #ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
404    expression.assign(test_info<wchar_t>::expression().begin(), test_info<wchar_t>::expression().end());
405 #else
406    std::copy(test_info<wchar_t>::expression().begin(), test_info<wchar_t>::expression().end(), std::back_inserter(expression));
407 #endif
408    boost::regex_constants::syntax_option_type syntax_options = test_info<wchar_t>::syntax_options();
409    boost::u32regex r;
410    if(*test_locale::c_str())
411    {
412       U_NAMESPACE_QUALIFIER Locale l(test_locale::c_str());
413       if(l.isBogus())
414          return;
415       r.imbue(l);
416    }
417    //
418    // try it with exceptions disabled first:
419    //
420 #ifndef BOOST_NO_EXCEPTIONS
421    try
422 #endif
423    {
424 #if !defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(__IBMCPP__)
425       if(0 == r.assign(expression.begin(), expression.end(), syntax_options | boost::regex_constants::no_except).status())
426 #else
427       if(expression.size())
428          r.assign(&*expression.begin(), expression.size(), syntax_options | boost::regex_constants::no_except);
429       else
430          r.assign(static_cast<UChar32 const*>(0), static_cast<boost::u32regex::size_type>(0), syntax_options | boost::regex_constants::no_except);
431       if(0 == r.status())
432 #endif
433       {
434          BOOST_REGEX_TEST_ERROR("Expression compiled when it should not have done so.", wchar_t);
435       }
436    }
437 #ifndef BOOST_NO_EXCEPTIONS
438    catch(...)
439    {
440       BOOST_REGEX_TEST_ERROR("Unexpected exception thrown.", wchar_t);
441    }
442 #endif
443    //
444    // now try again with exceptions:
445    //
446    bool have_catch = false;
447 #ifndef BOOST_NO_EXCEPTIONS
448    try
449 #endif
450    {
451 #if !defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(__IBMCPP__)
452       r.assign(expression.begin(), expression.end(), syntax_options);
453 #else
454       if(expression.size())
455          r.assign(&*expression.begin(), expression.size(), syntax_options);
456       else
457          r.assign(static_cast<UChar32 const*>(0), static_cast<boost::u32regex::size_type>(0), syntax_options);
458 #endif
459 #ifdef BOOST_NO_EXCEPTIONS
460       if(r.status())
461          have_catch = true;
462 #endif
463    }
464 #ifndef BOOST_NO_EXCEPTIONS
465    catch(const boost::bad_expression&)
466    {
467       have_catch = true;
468    }
469    catch(const std::runtime_error& e)
470    {
471       have_catch = true;
472       BOOST_REGEX_TEST_ERROR("Expected a bad_expression exception, but a std::runtime_error instead: " << e.what(), wchar_t);
473    }
474    catch(const std::exception& e)
475    {
476       have_catch = true;
477       BOOST_REGEX_TEST_ERROR("Expected a bad_expression exception, but a std::exception instead: " << e.what(), wchar_t);
478    }
479    catch(...)
480    {
481       have_catch = true;
482       BOOST_REGEX_TEST_ERROR("Expected a bad_expression exception, but got an exception of unknown type instead", wchar_t);
483    }
484 #endif
485    if(!have_catch)
486    {
487       // oops expected exception was not thrown:
488       BOOST_REGEX_TEST_ERROR("Expected an exception, but didn't find one.", wchar_t);
489    }
490 
491    if(0 == *test_locale::c_str())
492    {
493       //
494       // Now try UTF-16 construction:
495       //
496       typedef boost::u32_to_u16_iterator<std::vector<UChar32>::const_iterator> u16_conv;
497       std::vector<UChar> expression16;
498 #ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
499       expression16.assign(u16_conv(expression.begin()), u16_conv(expression.end()));
500 #else
501       std::copy(u16_conv(expression.begin()), u16_conv(expression.end()), std::back_inserter(expression16));
502 #endif
503       if(0 == boost::make_u32regex(expression16.begin(), expression16.end(), syntax_options | boost::regex_constants::no_except).status())
504       {
505          BOOST_REGEX_TEST_ERROR("Expression compiled when it should not have done so.", wchar_t);
506       }
507       if(std::find(expression16.begin(), expression16.end(), 0) == expression16.end())
508       {
509          expression16.push_back(0);
510          if(0 == boost::make_u32regex(&*expression16.begin(), syntax_options | boost::regex_constants::no_except).status())
511          {
512             BOOST_REGEX_TEST_ERROR("Expression compiled when it should not have done so.", wchar_t);
513          }
514       }
515       //
516       // Now try UTF-8 construction:
517       //
518       typedef boost::u32_to_u8_iterator<std::vector<UChar32>::const_iterator> u8_conv;
519       std::vector<unsigned char> expression8;
520 #ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
521       expression8.assign(u8_conv(expression.begin()), u8_conv(expression.end()));
522 #else
523       std::copy(u8_conv(expression.begin()), u8_conv(expression.end()), std::back_inserter(expression8));
524 #endif
525       if(0 == boost::make_u32regex(expression8.begin(), expression8.end(), syntax_options | boost::regex_constants::no_except).status())
526       {
527          BOOST_REGEX_TEST_ERROR("Expression compiled when it should not have done so.", wchar_t);
528       }
529       if(std::find(expression8.begin(), expression8.end(), 0) == expression8.end())
530       {
531          expression8.push_back(0);
532          if(0 == boost::make_u32regex(&*expression8.begin(), syntax_options | boost::regex_constants::no_except).status())
533          {
534             BOOST_REGEX_TEST_ERROR("Expression compiled when it should not have done so.", wchar_t);
535          }
536       }
537    }
538 }
539 
test_icu(const wchar_t &,const test_regex_replace_tag &)540 void test_icu(const wchar_t&, const test_regex_replace_tag&)
541 {
542    std::vector< ::UChar32> expression;
543 #ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
544    expression.assign(test_info<wchar_t>::expression().begin(), test_info<wchar_t>::expression().end());
545 #else
546    std::copy(test_info<wchar_t>::expression().begin(), test_info<wchar_t>::expression().end(), std::back_inserter(expression));
547 #endif
548    boost::regex_constants::syntax_option_type syntax_options = test_info<UChar32>::syntax_options();
549    boost::u32regex r;
550 #ifndef BOOST_NO_EXCEPTIONS
551    try
552 #endif
553    {
554 #if !defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(__IBMCPP__)
555       r.assign(expression.begin(), expression.end(), syntax_options);
556 #else
557       if(expression.size())
558          r.assign(&*expression.begin(), expression.size(), syntax_options);
559       else
560          r.assign(static_cast<UChar32 const*>(0), static_cast<boost::u32regex::size_type>(0), syntax_options);
561 #endif
562       if(r.status())
563       {
564          BOOST_REGEX_TEST_ERROR("Expression did not compile when it should have done, error code = " << r.status(), UChar32);
565       }
566       typedef std::vector<UChar32> string_type;
567       string_type search_text;
568       boost::regex_constants::match_flag_type opts = test_info<UChar32>::match_options();
569       string_type format_string;
570       string_type result_string;
571 #ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
572       search_text.assign(test_info<UChar32>::search_text().begin(), test_info<UChar32>::search_text().end());
573       format_string.assign(test_info<UChar32>::format_string().begin(), test_info<UChar32>::format_string().end());
574       format_string.push_back(0);
575       result_string.assign(test_info<UChar32>::result_string().begin(), test_info<UChar32>::result_string().end());
576 #else
577       std::copy(test_info<UChar32>::search_text().begin(), test_info<UChar32>::search_text().end(), std::back_inserter(search_text));
578       std::copy(test_info<UChar32>::format_string().begin(), test_info<UChar32>::format_string().end(), std::back_inserter(format_string));
579       format_string.push_back(0);
580       std::copy(test_info<UChar32>::result_string().begin(), test_info<UChar32>::result_string().end(), std::back_inserter(result_string));
581 #endif
582       string_type result;
583 
584       boost::u32regex_replace(unnecessary_fix::back_inserter(result), search_text.begin(), search_text.end(), r, &*format_string.begin(), opts);
585       if(result != result_string)
586       {
587          BOOST_REGEX_TEST_ERROR("regex_replace generated an incorrect string result", UChar32);
588       }
589       //
590       // Mixed mode character encoding:
591       //
592       if(0 == *test_locale::c_str())
593       {
594          //
595          // Now try UTF-16 construction:
596          //
597          typedef boost::u32_to_u16_iterator<std::vector<UChar32>::const_iterator> u16_conv;
598          std::vector<UChar> expression16, text16, format16, result16, found16;
599 #ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
600          expression16.assign(u16_conv(expression.begin()), u16_conv(expression.end()));
601          text16.assign(u16_conv(search_text.begin()), u16_conv(search_text.end()));
602          format16.assign(u16_conv(format_string.begin()), u16_conv(format_string.end()));
603          result16.assign(u16_conv(result_string.begin()), u16_conv(result_string.end()));
604 #else
605          std::copy(u16_conv(expression.begin()), u16_conv(expression.end()), std::back_inserter(expression16));
606          std::copy(u16_conv(search_text.begin()), u16_conv(search_text.end()), std::back_inserter(text16));
607          std::copy(u16_conv(format_string.begin()), u16_conv(format_string.end()), std::back_inserter(format16));
608          std::copy(u16_conv(result_string.begin()), u16_conv(result_string.end()), std::back_inserter(result16));
609 #endif
610          r = boost::make_u32regex(expression16.begin(), expression16.end(), syntax_options);
611          boost::u32regex_replace(unnecessary_fix::back_inserter(found16), text16.begin(), text16.end(), r, &*format16.begin(), opts);
612          if(result16 != found16)
613          {
614             BOOST_REGEX_TEST_ERROR("u32regex_replace with UTF-16 string returned incorrect result", UChar32);
615          }
616          //
617          // Now with UnicodeString:
618          //
619          U_NAMESPACE_QUALIFIER UnicodeString expression16u, text16u, format16u, result16u, found16u;
620          if(expression16.size())
621             expression16u.setTo(&*expression16.begin(), expression16.size());
622          if(text16.size())
623             text16u.setTo(&*text16.begin(), text16.size());
624          format16u.setTo(&*format16.begin(), format16.size()-1);
625          if(result16.size())
626             result16u.setTo(&*result16.begin(), result16.size());
627          r = boost::make_u32regex(expression16.begin(), expression16.end(), syntax_options);
628          found16u = boost::u32regex_replace(text16u, r, format16u, opts);
629          if(result16u != found16u)
630          {
631             BOOST_REGEX_TEST_ERROR("u32regex_replace with UTF-16 string returned incorrect result", UChar32);
632          }
633 
634          //
635          // Now try UTF-8 construction:
636          //
637          typedef boost::u32_to_u8_iterator<std::vector<UChar32>::const_iterator, unsigned char> u8_conv;
638          std::vector<char> expression8, text8, format8, result8, found8;
639 #ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
640          expression8.assign(u8_conv(expression.begin()), u8_conv(expression.end()));
641          text8.assign(u8_conv(search_text.begin()), u8_conv(search_text.end()));
642          format8.assign(u8_conv(format_string.begin()), u8_conv(format_string.end()));
643          result8.assign(u8_conv(result_string.begin()), u8_conv(result_string.end()));
644 #else
645          std::copy(u8_conv(expression.begin()), u8_conv(expression.end()), std::back_inserter(expression8));
646          std::copy(u8_conv(search_text.begin()), u8_conv(search_text.end()), std::back_inserter(text8));
647          std::copy(u8_conv(format_string.begin()), u8_conv(format_string.end()), std::back_inserter(format8));
648          std::copy(u8_conv(result_string.begin()), u8_conv(result_string.end()), std::back_inserter(result8));
649 #endif
650          r = boost::make_u32regex(expression8.begin(), expression8.end(), syntax_options);
651          boost::u32regex_replace(unnecessary_fix::back_inserter(found8), text8.begin(), text8.end(), r, &*format8.begin(), opts);
652          if(result8 != found8)
653          {
654             BOOST_REGEX_TEST_ERROR("u32regex_replace with UTF-8 string returned incorrect result", UChar32);
655          }
656          //
657          // Now with std::string and UTF-8:
658          //
659          std::string expression8s, text8s, format8s, result8s, found8s;
660          if(expression8.size())
661             expression8s.assign(&*expression8.begin(), expression8.size());
662          if(text8.size())
663             text8s.assign(&*text8.begin(), text8.size());
664          format8s.assign(&*format8.begin(), format8.size()-1);
665          if(result8.size())
666             result8s.assign(&*result8.begin(), result8.size());
667          r = boost::make_u32regex(expression8.begin(), expression8.end(), syntax_options);
668          found8s = boost::u32regex_replace(text8s, r, format8s, opts);
669          if(result8s != found8s)
670          {
671             BOOST_REGEX_TEST_ERROR("u32regex_replace with UTF-8 string returned incorrect result", UChar32);
672          }
673       }
674    }
675 #ifndef BOOST_NO_EXCEPTIONS
676    catch(const boost::bad_expression& e)
677    {
678       BOOST_REGEX_TEST_ERROR("Expression did not compile when it should have done: " << e.what(), UChar32);
679    }
680    catch(const std::runtime_error& e)
681    {
682       BOOST_REGEX_TEST_ERROR("Received an unexpected std::runtime_error: " << e.what(), UChar32);
683    }
684    catch(const std::exception& e)
685    {
686       BOOST_REGEX_TEST_ERROR("Received an unexpected std::exception: " << e.what(), UChar32);
687    }
688    catch(...)
689    {
690       BOOST_REGEX_TEST_ERROR("Received an unexpected exception of unknown type", UChar32);
691    }
692 #endif
693 }
694 
695 #else
696 
697 #include "test.hpp"
698 
test_icu(const wchar_t &,const test_regex_search_tag &)699 void test_icu(const wchar_t&, const test_regex_search_tag&){}
test_icu(const wchar_t &,const test_invalid_regex_tag &)700 void test_icu(const wchar_t&, const test_invalid_regex_tag&){}
test_icu(const wchar_t &,const test_regex_replace_tag &)701 void test_icu(const wchar_t&, const test_regex_replace_tag&){}
702 
703 #endif
704 
705