LCOV - code coverage report
Current view: top level - opt/homebrew/include/boost/test/utils/runtime/cla - parser.hpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 117 259 45.2 %
Date: 2026-06-25 07:23:43 Functions: 15 19 78.9 %

          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( &param_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

Generated by: LCOV version 1.16