Line data Source code
1 : // (C) Copyright Gennadiy Rozental 2001.
2 : // Use, modification, and distribution are subject to the
3 : // Boost Software License, Version 1.0. (See accompanying file
4 : // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 :
6 : // See http://www.boost.org/libs/test for the library home page.
7 : //
8 : //!@file
9 : //!@brief CLA parser
10 : // ***************************************************************************
11 :
12 : #ifndef BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_HPP
13 : #define BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_HPP
14 :
15 : // Boost.Test Runtime parameters
16 : #include <boost/test/utils/runtime/argument.hpp>
17 : #include <boost/test/utils/runtime/modifier.hpp>
18 : #include <boost/test/utils/runtime/parameter.hpp>
19 :
20 : #include <boost/test/utils/runtime/cla/argv_traverser.hpp>
21 :
22 : // Boost.Test
23 : #include <boost/test/utils/foreach.hpp>
24 : #include <boost/test/utils/algorithm.hpp>
25 : #include <boost/test/detail/throw_exception.hpp>
26 : #include <boost/test/detail/global_typedef.hpp>
27 :
28 : #include <boost/algorithm/cxx11/all_of.hpp> // !! ?? unnecessary after cxx11
29 :
30 : // STL
31 : // !! ?? #include <unordered_set>
32 : #include <set>
33 : #include <iostream>
34 :
35 : #include <boost/test/detail/suppress_warnings.hpp>
36 :
37 : namespace boost {
38 : namespace runtime {
39 : namespace cla {
40 :
41 : // ************************************************************************** //
42 : // ************** runtime::cla::parameter_trie ************** //
43 : // ************************************************************************** //
44 :
45 : namespace rt_cla_detail {
46 :
47 : struct parameter_trie;
48 : typedef shared_ptr<parameter_trie> parameter_trie_ptr;
49 : typedef std::map<char,parameter_trie_ptr> trie_per_char;
50 : typedef std::vector<boost::reference_wrapper<parameter_cla_id const> > param_cla_id_list;
51 :
52 : struct parameter_trie {
53 167024 : parameter_trie() : m_has_final_candidate( false ) {}
54 :
55 : /// If subtrie corresponding to the char c exists returns it otherwise creates new
56 98550 : parameter_trie_ptr make_subtrie( char c )
57 : {
58 98550 : trie_per_char::const_iterator it = m_subtrie.find( c );
59 :
60 98550 : if( it == m_subtrie.end() )
61 83074 : it = m_subtrie.insert( std::make_pair( c, parameter_trie_ptr( new parameter_trie ) ) ).first;
62 :
63 98550 : return it->second;
64 0 : }
65 :
66 : /// Creates series of sub-tries per characters in a string
67 : parameter_trie_ptr make_subtrie( cstring s )
68 : {
69 : parameter_trie_ptr res;
70 :
71 : BOOST_TEST_FOREACH( char, c, s )
72 : res = (res ? res->make_subtrie( c ) : make_subtrie( c ));
73 :
74 : return res;
75 : }
76 :
77 : /// Registers candidate parameter for this subtrie. If final, it needs to be unique
78 98550 : void add_candidate_id( parameter_cla_id const& param_id, basic_param_ptr param_candidate, bool final )
79 : {
80 98550 : BOOST_TEST_I_ASSRT( !m_has_final_candidate && (!final || m_id_candidates.empty()),
81 : conflicting_param() << "Parameter cla id " << param_id.m_tag << " conflicts with the "
82 : << "parameter cla id " << m_id_candidates.back().get().m_tag );
83 :
84 98550 : m_has_final_candidate = final;
85 98550 : m_id_candidates.push_back( ref(param_id) );
86 :
87 98550 : if( m_id_candidates.size() == 1 )
88 83074 : m_param_candidate = param_candidate;
89 : else
90 15476 : m_param_candidate.reset();
91 98550 : }
92 :
93 : /// Gets subtrie for specified char if present or nullptr otherwise
94 3066 : parameter_trie_ptr get_subtrie( char c ) const
95 : {
96 3066 : trie_per_char::const_iterator it = m_subtrie.find( c );
97 :
98 3066 : return it != m_subtrie.end() ? it->second : parameter_trie_ptr();
99 : }
100 :
101 : // Data members
102 : trie_per_char m_subtrie;
103 : param_cla_id_list m_id_candidates;
104 : basic_param_ptr m_param_candidate;
105 : bool m_has_final_candidate;
106 : };
107 :
108 : // ************************************************************************** //
109 : // ************** runtime::cla::report_foreing_token ************** //
110 : // ************************************************************************** //
111 :
112 : static void
113 0 : report_foreing_token( cstring program_name, cstring token )
114 : {
115 0 : std::cerr << "Boost.Test WARNING: token \"" << token << "\" does not correspond to the Boost.Test argument \n"
116 0 : << " and should be placed after all Boost.Test arguments and the -- separator.\n"
117 0 : << " For example: " << program_name << " --random -- " << token << "\n";
118 0 : }
119 :
120 : } // namespace rt_cla_detail
121 :
122 : // ************************************************************************** //
123 : // ************** runtime::cla::parser ************** //
124 : // ************************************************************************** //
125 :
126 : class parser {
127 : public:
128 : /// Initializes a parser and builds internal trie representation used for
129 : /// parsing based on the supplied parameters
130 : #ifndef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
131 : template<typename Modifiers=nfp::no_params_type>
132 292 : parser( parameters_store const& parameters, Modifiers const& m = nfp::no_params )
133 : #else
134 : template<typename Modifiers>
135 : parser( parameters_store const& parameters, Modifiers const& m )
136 : #endif
137 146 : {
138 146 : nfp::opt_assign( m_end_of_param_indicator, m, end_of_params );
139 146 : nfp::opt_assign( m_negation_prefix, m, negation_prefix );
140 :
141 146 : BOOST_TEST_I_ASSRT( algorithm::all_of( m_end_of_param_indicator.begin(),
142 : m_end_of_param_indicator.end(),
143 : parameter_cla_id::valid_prefix_char ),
144 : invalid_cla_id() << "End of parameters indicator can only consist of prefix characters." );
145 :
146 146 : BOOST_TEST_I_ASSRT( algorithm::all_of( m_negation_prefix.begin(),
147 : m_negation_prefix.end(),
148 : parameter_cla_id::valid_name_char ),
149 : invalid_cla_id() << "Negation prefix can only consist of prefix characters." );
150 :
151 146 : build_trie( parameters );
152 292 : }
153 :
154 : // input processing method
155 : int
156 146 : parse( int argc, char** argv, runtime::arguments_store& res )
157 : {
158 : // save program name for help message
159 146 : m_program_name = argv[0];
160 146 : cstring path_sep( "\\/" );
161 :
162 292 : cstring::iterator it = unit_test::utils::find_last_of( m_program_name.begin(), m_program_name.end(),
163 146 : path_sep.begin(), path_sep.end() );
164 146 : if( it != m_program_name.end() )
165 146 : m_program_name.trim_left( it + 1 );
166 :
167 : // Set up the traverser
168 146 : argv_traverser tr( argc, (char const**)argv );
169 :
170 : // Loop till we reach end of input
171 584 : while( !tr.eoi() ) {
172 584 : cstring curr_token = tr.current_token();
173 :
174 584 : cstring prefix;
175 584 : cstring name;
176 584 : cstring value_separator;
177 584 : bool negative_form = false;
178 :
179 : // Perform format validations and split the argument into prefix, name and separator
180 : // False return value indicates end of params indicator is met
181 584 : if( !validate_token_format( curr_token, prefix, name, value_separator, negative_form ) ) {
182 : // get rid of "end of params" token
183 146 : tr.next_token();
184 146 : break;
185 : }
186 :
187 : // Locate trie corresponding to found prefix and skip it in the input
188 438 : trie_ptr curr_trie = m_param_trie[prefix];
189 :
190 438 : if( !curr_trie ) {
191 : // format_error() << "Unrecognized parameter prefix in the argument " << tr.current_token()
192 0 : rt_cla_detail::report_foreing_token( m_program_name, curr_token );
193 0 : tr.save_token();
194 0 : continue;
195 : }
196 :
197 438 : curr_token.trim_left( prefix.size() );
198 :
199 : // Locate parameter based on a name and skip it in the input
200 438 : locate_result locate_res = locate_parameter( curr_trie, name, curr_token );
201 438 : parameter_cla_id const& found_id = locate_res.first;
202 438 : basic_param_ptr found_param = locate_res.second;
203 :
204 438 : if( negative_form ) {
205 0 : BOOST_TEST_I_ASSRT( found_id.m_negatable,
206 : format_error( found_param->p_name )
207 : << "Parameter tag " << found_id.m_tag << " is not negatable." );
208 :
209 0 : curr_token.trim_left( m_negation_prefix.size() );
210 0 : }
211 :
212 438 : curr_token.trim_left( name.size() );
213 :
214 438 : bool should_go_to_next = true;
215 438 : cstring value;
216 :
217 :
218 : // Skip validations if parameter has optional value and we are at the end of token
219 438 : if( !value_separator.is_empty() || !found_param->p_has_optional_value ) {
220 :
221 : // we are given a separator or there is no optional value
222 :
223 : // Validate and skip value separator in the input
224 438 : BOOST_TEST_I_ASSRT( found_id.m_value_separator == value_separator,
225 : format_error( found_param->p_name )
226 : << "Invalid separator for the parameter "
227 : << found_param->p_name
228 : << " in the argument " << tr.current_token() );
229 :
230 438 : curr_token.trim_left( value_separator.size() );
231 :
232 : // Deduce value source
233 438 : value = curr_token;
234 438 : if( value.is_empty() ) {
235 292 : tr.next_token();
236 292 : value = tr.current_token();
237 292 : }
238 :
239 438 : BOOST_TEST_I_ASSRT( !value.is_empty(),
240 : format_error( found_param->p_name )
241 : << "Missing an argument value for the parameter "
242 : << found_param->p_name
243 : << " in the argument " << tr.current_token() );
244 438 : }
245 0 : else if( (value_separator.is_empty() && found_id.m_value_separator.empty()) ) {
246 : // Deduce value source
247 0 : value = curr_token;
248 0 : if( value.is_empty() ) {
249 0 : tr.next_token(); // tokenization broke the value, we check the next one
250 :
251 0 : if(!found_param->p_has_optional_value) {
252 : // there is no separator and there is no optional value
253 : // we look for the value on the next token
254 : // example "-t XXXX" (no default)
255 : // and we commit this value as being the passed value
256 0 : value = tr.current_token();
257 0 : }
258 : else {
259 : // there is no separator and the value is optional
260 : // we check the next token
261 : // example "-c" (defaults to true)
262 : // and commit this as the value if this is not a token
263 0 : cstring value_check = tr.current_token();
264 :
265 0 : cstring prefix_test, name_test, value_separator_test;
266 : bool negative_form_test;
267 0 : if( validate_token_format( value_check, prefix_test, name_test, value_separator_test, negative_form_test )
268 0 : && m_param_trie[prefix_test]) {
269 : // this is a token, we consume what we have
270 0 : should_go_to_next = false;
271 0 : }
272 : else {
273 : // this is a value, we commit it
274 0 : value = value_check;
275 : }
276 : }
277 0 : }
278 0 : }
279 :
280 : // Validate against argument duplication
281 438 : BOOST_TEST_I_ASSRT( !res.has( found_param->p_name ) || found_param->p_repeatable,
282 : duplicate_arg( found_param->p_name )
283 : << "Duplicate argument value for the parameter "
284 : << found_param->p_name
285 : << " in the argument " << tr.current_token() );
286 :
287 : // Produce argument value
288 438 : found_param->produce_argument( value, negative_form, res );
289 :
290 438 : if(should_go_to_next) {
291 438 : tr.next_token();
292 438 : }
293 438 : }
294 :
295 : // generate the remainder and return it's size
296 146 : return tr.remainder();
297 0 : }
298 :
299 : // help/usage/version
300 : void
301 0 : version( std::ostream& ostr )
302 : {
303 0 : ostr << "Boost.Test module ";
304 :
305 : #if defined(BOOST_TEST_MODULE)
306 : // we do not want to refer to the master test suite there
307 0 : ostr << '\'' << BOOST_TEST_STRINGIZE( BOOST_TEST_MODULE ).trim( "\"" ) << "' ";
308 : #endif
309 :
310 0 : ostr << "in executable '" << m_program_name << "'\n";
311 0 : ostr << "Compiled from Boost version "
312 0 : << BOOST_VERSION/100000 << "."
313 0 : << BOOST_VERSION/100 % 1000 << "."
314 0 : << BOOST_VERSION % 100 ;
315 0 : ostr << " with ";
316 : #if defined(BOOST_TEST_INCLUDED)
317 0 : ostr << "header-only inclusion of";
318 : #elif defined(BOOST_TEST_DYN_LINK)
319 : ostr << "dynamic linking to";
320 : #else
321 : ostr << "static linking to";
322 : #endif
323 0 : ostr << " Boost.Test\n";
324 0 : ostr << "- Compiler: " << BOOST_COMPILER << '\n'
325 0 : << "- Platform: " << BOOST_PLATFORM << '\n'
326 0 : << "- STL : " << BOOST_STDLIB;
327 0 : ostr << std::endl;
328 0 : }
329 :
330 : void
331 0 : usage(std::ostream& ostr,
332 : cstring param_name = cstring(),
333 : bool use_color = true)
334 : {
335 : namespace utils = unit_test::utils;
336 : namespace ut_detail = unit_test::ut_detail;
337 :
338 0 : if( !param_name.is_empty() ) {
339 0 : basic_param_ptr param = locate_parameter( m_param_trie[help_prefix], param_name, "" ).second;
340 0 : param->usage( ostr, m_negation_prefix );
341 0 : }
342 : else {
343 0 : ostr << "\n The program '" << m_program_name << "' is a Boost.Test module containing unit tests.";
344 :
345 : {
346 0 : BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::ORIGINAL );
347 0 : ostr << "\n\n Usage\n ";
348 0 : }
349 :
350 : {
351 0 : BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::GREEN );
352 0 : ostr << m_program_name << " [Boost.Test argument]... ";
353 0 : }
354 0 : if( !m_end_of_param_indicator.empty() ) {
355 0 : BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::YELLOW );
356 0 : ostr << '[' << m_end_of_param_indicator << " [custom test module argument]...]";
357 0 : }
358 : }
359 :
360 0 : ostr << "\n\n Use\n ";
361 : {
362 :
363 0 : BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::GREEN );
364 0 : ostr << m_program_name << " --help";
365 0 : }
366 0 : ostr << "\n or ";
367 : {
368 0 : BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::GREEN );
369 0 : ostr << m_program_name << " --help=<parameter name>";
370 0 : }
371 0 : ostr << "\n for detailed help on Boost.Test parameters.\n";
372 0 : }
373 :
374 : void
375 0 : help(std::ostream& ostr,
376 : parameters_store const& parameters,
377 : cstring param_name,
378 : bool use_color = true)
379 : {
380 : namespace utils = unit_test::utils;
381 : namespace ut_detail = unit_test::ut_detail;
382 :
383 0 : if( !param_name.is_empty() ) {
384 0 : basic_param_ptr param = locate_parameter( m_param_trie[help_prefix], param_name, "" ).second;
385 0 : param->help( ostr, m_negation_prefix, use_color);
386 : return;
387 0 : }
388 :
389 0 : usage(ostr, cstring(), use_color);
390 :
391 0 : ostr << "\n\n";
392 : {
393 0 : BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::ORIGINAL );
394 0 : ostr << " Command line flags:\n";
395 0 : }
396 0 : runtime::commandline_pretty_print(
397 0 : ostr,
398 0 : " ",
399 0 : "The command line flags of Boost.Test are listed below. "
400 : "All parameters are optional. You can specify parameter value either "
401 : "as a command line argument or as a value of its corresponding environment "
402 : "variable. If a flag is specified as a command line argument and an environment variable "
403 : "at the same time, the command line takes precedence. "
404 : "The command line argument "
405 : "support name guessing, and works with shorter names as long as those are not ambiguous."
406 : );
407 :
408 0 : if( !m_end_of_param_indicator.empty() ) {
409 0 : ostr << "\n\n All the arguments after the '";
410 : {
411 0 : BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::YELLOW );
412 0 : ostr << m_end_of_param_indicator;
413 0 : }
414 0 : ostr << "' are ignored by Boost.Test.";
415 0 : }
416 :
417 :
418 : {
419 0 : BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::ORIGINAL );
420 0 : ostr << "\n\n Environment variables:\n";
421 0 : }
422 0 : runtime::commandline_pretty_print(
423 0 : ostr,
424 0 : " ",
425 0 : "Every argument listed below may also be set by a corresponding environment"
426 : "variable. For an argument '--argument_x=<value>', the corresponding "
427 : "environment variable is 'BOOST_TEST_ARGUMENT_X=value"
428 : );
429 :
430 :
431 :
432 0 : ostr << "\n\n The following parameters are supported:\n";
433 :
434 0 : BOOST_TEST_FOREACH(
435 : parameters_store::storage_type::value_type const&,
436 : v,
437 : parameters.all() )
438 : {
439 0 : basic_param_ptr param = v.second;
440 0 : ostr << "\n";
441 0 : param->usage( ostr, m_negation_prefix, use_color);
442 0 : }
443 :
444 0 : }
445 :
446 : private:
447 : typedef rt_cla_detail::parameter_trie_ptr trie_ptr;
448 : typedef rt_cla_detail::trie_per_char trie_per_char;
449 : typedef std::map<cstring,trie_ptr> str_to_trie;
450 :
451 : void
452 146 : build_trie( parameters_store const& parameters )
453 : {
454 : // Iterate over all parameters
455 8322 : BOOST_TEST_FOREACH( parameters_store::storage_type::value_type const&, v, parameters.all() ) {
456 4088 : basic_param_ptr param = v.second;
457 :
458 : // Register all parameter's ids in trie.
459 24820 : BOOST_TEST_FOREACH( parameter_cla_id const&, id, param->cla_ids() ) {
460 : // This is the trie corresponding to the prefix.
461 10366 : trie_ptr next_trie = m_param_trie[id.m_prefix];
462 10366 : if( !next_trie )
463 438 : next_trie = m_param_trie[id.m_prefix] = trie_ptr( new rt_cla_detail::parameter_trie );
464 :
465 : // Build the trie, by following name's characters
466 : // and register this parameter as candidate on each level
467 108916 : for( size_t index = 0; index < id.m_tag.size(); ++index ) {
468 98550 : next_trie = next_trie->make_subtrie( id.m_tag[index] );
469 :
470 98550 : next_trie->add_candidate_id( id, param, index == (id.m_tag.size() - 1) );
471 98550 : }
472 10366 : }
473 4088 : }
474 146 : }
475 :
476 : bool
477 584 : validate_token_format( cstring token, cstring& prefix, cstring& name, cstring& separator, bool& negative_form )
478 : {
479 : // Match prefix
480 584 : cstring::iterator it = token.begin();
481 1460 : while( it != token.end() && parameter_cla_id::valid_prefix_char( *it ) )
482 876 : ++it;
483 :
484 584 : prefix.assign( token.begin(), it );
485 :
486 584 : if( prefix.empty() )
487 0 : return true;
488 :
489 : // Match name
490 3650 : while( it != token.end() && parameter_cla_id::valid_name_char( *it ) )
491 3066 : ++it;
492 :
493 584 : name.assign( prefix.end(), it );
494 :
495 584 : if( name.empty() ) {
496 146 : if( prefix == m_end_of_param_indicator )
497 146 : return false;
498 :
499 0 : BOOST_TEST_I_THROW( format_error() << "Invalid format for an actual argument " << token );
500 : }
501 :
502 : // Match value separator
503 584 : while( it != token.end() && parameter_cla_id::valid_separator_char( *it ) )
504 146 : ++it;
505 :
506 438 : separator.assign( name.end(), it );
507 :
508 : // Match negation prefix
509 438 : negative_form = !m_negation_prefix.empty() && ( name.substr( 0, m_negation_prefix.size() ) == m_negation_prefix );
510 438 : if( negative_form )
511 0 : name.trim_left( m_negation_prefix.size() );
512 :
513 438 : return true;
514 584 : }
515 :
516 : // C++03: cannot have references as types
517 : typedef std::pair<parameter_cla_id, basic_param_ptr> locate_result;
518 :
519 : locate_result
520 438 : locate_parameter( trie_ptr curr_trie, cstring name, cstring token )
521 : {
522 438 : std::vector<trie_ptr> typo_candidates;
523 438 : std::vector<trie_ptr> next_typo_candidates;
524 438 : trie_ptr next_trie;
525 :
526 6570 : BOOST_TEST_FOREACH( char, c, name ) {
527 3066 : if( curr_trie ) {
528 : // locate next subtrie corresponding to the char
529 3066 : next_trie = curr_trie->get_subtrie( c );
530 :
531 3066 : if( next_trie )
532 3066 : curr_trie = next_trie;
533 : else {
534 : // Initiate search for typo candicates. We will account for 'wrong char' typo
535 : // 'missing char' typo and 'extra char' typo
536 0 : BOOST_TEST_FOREACH( trie_per_char::value_type const&, typo_cand, curr_trie->m_subtrie ) {
537 : // 'wrong char' typo
538 0 : typo_candidates.push_back( typo_cand.second );
539 :
540 : // 'missing char' typo
541 0 : if( (next_trie = typo_cand.second->get_subtrie( c )) )
542 0 : typo_candidates.push_back( next_trie );
543 0 : }
544 :
545 : // 'extra char' typo
546 0 : typo_candidates.push_back( curr_trie );
547 :
548 0 : curr_trie.reset();
549 : }
550 3066 : }
551 : else {
552 : // go over existing typo candidates and see if they are still viable
553 0 : BOOST_TEST_FOREACH( trie_ptr, typo_cand, typo_candidates ) {
554 0 : trie_ptr next_typo_cand = typo_cand->get_subtrie( c );
555 :
556 0 : if( next_typo_cand )
557 0 : next_typo_candidates.push_back( next_typo_cand );
558 0 : }
559 :
560 0 : next_typo_candidates.swap( typo_candidates );
561 0 : next_typo_candidates.clear();
562 : }
563 3066 : }
564 :
565 438 : if( !curr_trie ) {
566 0 : std::vector<cstring> typo_candidate_names;
567 0 : std::set<parameter_cla_id const*> unique_typo_candidate; // !! ?? unordered_set
568 0 : typo_candidate_names.reserve( typo_candidates.size() );
569 : // !! ?? unique_typo_candidate.reserve( typo_candidates.size() );
570 :
571 0 : BOOST_TEST_FOREACH( trie_ptr, trie_cand, typo_candidates ) {
572 : // avoid ambiguos candidate trie
573 0 : if( trie_cand->m_id_candidates.size() > 1 )
574 0 : continue;
575 :
576 0 : BOOST_TEST_FOREACH( parameter_cla_id const&, param_cand, trie_cand->m_id_candidates ) {
577 0 : if( !unique_typo_candidate.insert( ¶m_cand ).second )
578 0 : continue;
579 :
580 0 : typo_candidate_names.push_back( param_cand.m_tag );
581 0 : }
582 0 : }
583 :
584 : #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
585 0 : BOOST_TEST_I_THROW( unrecognized_param( std::move(typo_candidate_names) )
586 : << "An unrecognized parameter in the argument "
587 : << token );
588 : #else
589 : BOOST_TEST_I_THROW( unrecognized_param( typo_candidate_names )
590 : << "An unrecognized parameter in the argument "
591 : << token );
592 : #endif
593 0 : }
594 :
595 438 : if( curr_trie->m_id_candidates.size() > 1 ) {
596 0 : std::vector<cstring> amb_names;
597 0 : BOOST_TEST_FOREACH( parameter_cla_id const&, param_id, curr_trie->m_id_candidates )
598 0 : amb_names.push_back( param_id.m_tag );
599 :
600 : #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
601 0 : BOOST_TEST_I_THROW( ambiguous_param( std::move( amb_names ) )
602 : << "An ambiguous parameter name in the argument " << token );
603 : #else
604 : BOOST_TEST_I_THROW( ambiguous_param( amb_names )
605 : << "An ambiguous parameter name in the argument " << token );
606 : #endif
607 0 : }
608 :
609 438 : return locate_result( curr_trie->m_id_candidates.back().get(), curr_trie->m_param_candidate );
610 438 : }
611 :
612 : // Data members
613 : cstring m_program_name;
614 : std::string m_end_of_param_indicator;
615 : std::string m_negation_prefix;
616 : str_to_trie m_param_trie;
617 : };
618 :
619 : } // namespace cla
620 : } // namespace runtime
621 : } // namespace boost
622 :
623 : #include <boost/test/detail/enable_warnings.hpp>
624 :
625 : #endif // BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_HPP
|