LCOV - code coverage report
Current view: top level - opt/homebrew/include/boost/test/utils/runtime - parameter.hpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 101 196 51.5 %
Date: 2026-06-25 07:23:43 Functions: 128 168 76.2 %

          Line data    Source code
       1             : //  (C) Copyright Gennadiy Rozental 2001.
       2             : //  Distributed under the Boost Software License, Version 1.0.
       3             : //  (See accompanying file LICENSE_1_0.txt or copy at
       4             : //  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        : $RCSfile$
       9             : //
      10             : //  Version     : $Revision$
      11             : //
      12             : //  Description : formal parameter definition
      13             : // ***************************************************************************
      14             : 
      15             : #ifndef BOOST_TEST_UTILS_RUNTIME_PARAMETER_HPP
      16             : #define BOOST_TEST_UTILS_RUNTIME_PARAMETER_HPP
      17             : 
      18             : // Boost.Test Runtime parameters
      19             : #include <boost/test/utils/runtime/fwd.hpp>
      20             : #include <boost/test/utils/runtime/modifier.hpp>
      21             : #include <boost/test/utils/runtime/argument.hpp>
      22             : #include <boost/test/utils/runtime/argument_factory.hpp>
      23             : 
      24             : // Boost.Test
      25             : #include <boost/test/utils/class_properties.hpp>
      26             : #include <boost/test/utils/foreach.hpp>
      27             : #include <boost/test/utils/setcolor.hpp>
      28             : 
      29             : // Boost
      30             : #include <boost/function.hpp>
      31             : #include <boost/algorithm/cxx11/all_of.hpp>
      32             : 
      33             : // STL
      34             : #include <algorithm>
      35             : 
      36             : #include <boost/test/detail/suppress_warnings.hpp>
      37             : 
      38             : namespace boost {
      39             : namespace runtime {
      40             : 
      41             : inline
      42           0 : std::ostream& commandline_pretty_print(
      43             :     std::ostream& ostr, 
      44             :     std::string const& prefix, 
      45             :     std::string const& to_print) {
      46             :     
      47           0 :     const int split_at = 80;
      48             : 
      49           0 :     std::string::size_type current = 0;
      50             : 
      51           0 :     while(current < to_print.size()) {
      52             : 
      53             :         // discards spaces at the beginning
      54           0 :         std::string::size_type startpos = to_print.find_first_not_of(" \t\n", current);
      55           0 :         current += startpos - current;
      56             : 
      57           0 :         bool has_more_lines = (current + split_at) < to_print.size();
      58             : 
      59           0 :         if(has_more_lines) {
      60           0 :           std::string::size_type endpos = to_print.find_last_of(" \t\n", current + split_at);
      61           0 :           std::string sub(to_print.substr(current, endpos - current));
      62           0 :           ostr << prefix << sub;
      63           0 :           ostr << "\n";
      64           0 :           current += endpos - current;
      65           0 :         }
      66             :         else 
      67             :         {
      68           0 :           ostr << prefix << to_print.substr(current, split_at);
      69           0 :           current += split_at;
      70             :         }
      71             :     }
      72           0 :     return ostr;
      73           0 : }
      74             : 
      75             : // ************************************************************************** //
      76             : // **************           runtime::parameter_cla_id          ************** //
      77             : // ************************************************************************** //
      78             : // set of attributes identifying the parameter in the command line
      79             : 
      80       10804 : struct parameter_cla_id {
      81       20732 :     parameter_cla_id( cstring prefix, cstring tag, cstring value_separator, bool negatable )
      82       10366 :     : m_prefix( prefix.begin(), prefix.size() )
      83       10366 :     , m_tag( tag.begin(), tag.size() )
      84       10366 :     , m_value_separator( value_separator.begin(), value_separator.size() )
      85       10366 :     , m_negatable( negatable )
      86       10366 :     {
      87             : 
      88       10366 :         BOOST_TEST_I_ASSRT( algorithm::all_of( m_prefix.begin(), m_prefix.end(), valid_prefix_char ),
      89             :                             invalid_cla_id() << "Parameter " << m_tag
      90             :                                              << " has invalid characters in prefix." );
      91             : 
      92       10366 :         BOOST_TEST_I_ASSRT( algorithm::all_of( m_tag.begin(), m_tag.end(), valid_name_char ),
      93             :                             invalid_cla_id() << "Parameter " << m_tag
      94             :                                              << " has invalid characters in name." );
      95             : 
      96       10366 :         BOOST_TEST_I_ASSRT( algorithm::all_of( m_value_separator.begin(), m_value_separator.end(), valid_separator_char ),
      97             :                             invalid_cla_id() << "Parameter " << m_tag
      98             :                                              << " has invalid characters in value separator." );
      99       20732 :     }
     100             : 
     101       28178 :     static bool             valid_prefix_char( char c )
     102             :     {
     103       28178 :         return c == '-' || c == '/' ;
     104             :     }
     105        8176 :     static bool             valid_separator_char( char c )
     106             :     {
     107        8176 :         return c == '=' || c == ':' || c == ' ' || c == '\0';
     108             :     }
     109      102200 :     static bool             valid_name_char( char c )
     110             :     {
     111      102200 :         return std::isalnum( c ) || c == '+' || c == '_' || c == '?';
     112             :     }
     113             : 
     114             :     std::string             m_prefix;
     115             :     std::string             m_tag;
     116             :     std::string             m_value_separator;
     117             :     bool                    m_negatable;
     118             : };
     119             : 
     120             : typedef std::vector<parameter_cla_id> param_cla_ids;
     121             : 
     122             : // ************************************************************************** //
     123             : // **************             runtime::basic_param             ************** //
     124             : // ************************************************************************** //
     125             : 
     126             : cstring const help_prefix("////");
     127             : 
     128        4088 : class basic_param {
     129             :     typedef function<void (cstring)>            callback_type;
     130             :     typedef unit_test::readwrite_property<bool> bool_property;
     131             : 
     132             : protected:
     133             :     /// Constructor with modifiers
     134             :     template<typename Modifiers>
     135        8176 :     basic_param( cstring name, bool is_optional, bool is_repeatable, Modifiers const& m )
     136        4088 :     : p_name( name.begin(), name.end() )
     137        4088 :     , p_description( nfp::opt_get( m, description, std::string() ) )
     138        4088 :     , p_help( nfp::opt_get( m, runtime::help, std::string() ) )
     139        4088 :     , p_env_var( nfp::opt_get( m, env_var, std::string() ) )
     140        4088 :     , p_value_hint( nfp::opt_get( m, value_hint, std::string() ) )
     141        4088 :     , p_optional( is_optional )
     142        4088 :     , p_repeatable( is_repeatable )
     143        4088 :     , p_has_optional_value( m.has( optional_value ) )
     144        4088 :     , p_has_default_value( m.has( default_value ) || is_repeatable )
     145        4088 :     , p_callback( nfp::opt_get( m, callback, callback_type() ) )
     146        4088 :     {
     147        4088 :         add_cla_id( help_prefix, name, ":" );
     148        4088 :     }
     149             : 
     150             : public:
     151        4088 :     BOOST_TEST_DEFAULTED_FUNCTION(virtual ~basic_param(), {})
     152             : 
     153             :     // Pubic properties
     154             :     std::string const       p_name;
     155             :     std::string const       p_description;
     156             :     std::string const       p_help;
     157             :     std::string const       p_env_var;
     158             :     std::string const       p_value_hint;
     159             :     bool const              p_optional;
     160             :     bool const              p_repeatable;
     161             :     bool_property           p_has_optional_value;
     162             :     bool_property           p_has_default_value;
     163             :     callback_type const     p_callback;
     164             : 
     165             :     /// interface for cloning typed parameters
     166             :     virtual basic_param_ptr clone() const = 0;
     167             : 
     168             :     /// Access methods
     169       86724 :     param_cla_ids const&    cla_ids() const { return m_cla_ids; }
     170        7446 :     void                    add_cla_id( cstring prefix, cstring tag, cstring value_separator )
     171             :     {
     172        7446 :         add_cla_id_impl( prefix, tag, value_separator, false, true );
     173        7446 :     }
     174             : 
     175             :     /// interface for producing argument values for this parameter
     176             :     virtual void            produce_argument( cstring token, bool negative_form, arguments_store& store ) const = 0;
     177             :     virtual void            produce_default( arguments_store& store ) const = 0;
     178             : 
     179             :     /// interfaces for help message reporting
     180           0 :     virtual void            usage( std::ostream& ostr, cstring negation_prefix_, bool use_color = true )
     181             :     {
     182             :         namespace utils = unit_test::utils;
     183             :         namespace ut_detail = unit_test::ut_detail;
     184             : 
     185             :         // 
     186           0 :         ostr  << "  ";
     187             :         {
     188             : 
     189           0 :           BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::GREEN );
     190           0 :           ostr << p_name;
     191           0 :         }
     192             : 
     193           0 :         ostr << '\n';
     194             : 
     195           0 :         if( !p_description.empty() ) {
     196           0 :           commandline_pretty_print(ostr, "    ", p_description) << '\n';
     197           0 :         }
     198             : 
     199           0 :         BOOST_TEST_FOREACH( parameter_cla_id const&, id, cla_ids() ) {
     200           0 :             if( id.m_prefix == help_prefix )
     201           0 :                 continue;
     202             : 
     203           0 :             ostr << "    " << id.m_prefix;
     204             : 
     205           0 :             if( id.m_negatable )
     206           0 :                 cla_name_help( ostr, id.m_tag, negation_prefix_, use_color );
     207             :             else
     208           0 :                 cla_name_help( ostr, id.m_tag, "", use_color );
     209             : 
     210           0 :             BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::YELLOW );
     211           0 :             bool optional_value_ = false;
     212             : 
     213           0 :             if( p_has_optional_value ) {
     214           0 :                 optional_value_ = true;
     215           0 :                 ostr << '[';
     216           0 :             }
     217             : 
     218             : 
     219           0 :             if( id.m_value_separator.empty() )
     220           0 :                 ostr << ' ';
     221             :             else {
     222           0 :                 ostr << id.m_value_separator;
     223             :             }
     224             : 
     225           0 :             value_help( ostr );
     226             : 
     227           0 :             if( optional_value_ )
     228           0 :                 ostr << ']';
     229             : 
     230           0 :             ostr << '\n';
     231           0 :         }
     232           0 :     }
     233             : 
     234           0 :     virtual void            help( std::ostream& ostr, cstring negation_prefix_, bool use_color = true )
     235             :     {
     236           0 :         usage( ostr, negation_prefix_, use_color );
     237             : 
     238           0 :         if( !p_help.empty() ) {
     239           0 :             ostr << '\n';
     240           0 :             commandline_pretty_print(ostr, "  ", p_help);
     241           0 :         }
     242           0 :     }
     243             : 
     244             : protected:
     245       10366 :     void                    add_cla_id_impl( cstring prefix,
     246             :                                              cstring tag,
     247             :                                              cstring value_separator,
     248             :                                              bool negatable,
     249             :                                              bool validate_value_separator )
     250             :     {
     251       10366 :         BOOST_TEST_I_ASSRT( !tag.is_empty(),
     252             :                             invalid_cla_id() << "Parameter can't have an empty name." );
     253             : 
     254       10366 :         BOOST_TEST_I_ASSRT( !prefix.is_empty(),
     255             :                             invalid_cla_id() << "Parameter " << tag
     256             :                                              << " can't have an empty prefix." );
     257             : 
     258       10366 :         BOOST_TEST_I_ASSRT( !value_separator.is_empty(),
     259             :                             invalid_cla_id() << "Parameter " << tag
     260             :                                              << " can't have an empty value separator." );
     261             : 
     262             :         // We trim value separator from all the spaces, so token end will indicate separator
     263       10366 :         value_separator.trim();
     264       10366 :         BOOST_TEST_I_ASSRT( !validate_value_separator || !value_separator.is_empty() || !p_has_optional_value,
     265             :                             invalid_cla_id() << "Parameter " << tag
     266             :                                              << " with optional value attribute can't use space as value separator." );
     267             : 
     268       10366 :         m_cla_ids.push_back( parameter_cla_id( prefix, tag, value_separator, negatable ) );
     269       10366 :     }
     270             : 
     271             : private:
     272             :     /// interface for usage/help customization
     273           0 :     virtual void            cla_name_help( std::ostream& ostr, cstring cla_tag, cstring /*negation_prefix_*/, bool /*use_color*/ = true) const
     274             :     {
     275           0 :         ostr << cla_tag;
     276           0 :     }
     277           0 :     virtual void            value_help( std::ostream& ostr ) const
     278             :     {
     279           0 :         if( p_value_hint.empty() )
     280           0 :             ostr << "<value>";
     281             :         else
     282           0 :             ostr << p_value_hint;
     283           0 :     }
     284             : 
     285             :     // Data members
     286             :     param_cla_ids       m_cla_ids;
     287             : };
     288             : 
     289             : // ************************************************************************** //
     290             : // **************              runtime::parameter              ************** //
     291             : // ************************************************************************** //
     292             : 
     293             : enum args_amount {
     294             :     OPTIONAL_PARAM,   // 0-1
     295             :     REQUIRED_PARAM,   // exactly 1
     296             :     REPEATABLE_PARAM  // 0-N
     297             : };
     298             : 
     299             : //____________________________________________________________________________//
     300             : 
     301             : template<typename ValueType, args_amount a = runtime::OPTIONAL_PARAM, bool is_enum = false>
     302        1606 : class parameter : public basic_param {
     303             : public:
     304             :     /// Constructor with modifiers
     305             : #ifndef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
     306             :     template<typename Modifiers=nfp::no_params_type>
     307        3504 :     parameter( cstring name, Modifiers const& m = nfp::no_params )
     308             : #else
     309             :     template<typename Modifiers>
     310             :     parameter( cstring name, Modifiers const& m )
     311             : #endif
     312        2190 :     : basic_param( name, a != runtime::REQUIRED_PARAM, a == runtime::REPEATABLE_PARAM, m )
     313        2190 :     , m_arg_factory( m )
     314        3504 :     {
     315        2190 :         BOOST_TEST_I_ASSRT( !m.has( default_value ) || a == runtime::OPTIONAL_PARAM,
     316             :                             invalid_param_spec() << "Parameter " << name
     317             :                                                  << " is not optional and can't have default_value." );
     318             : 
     319        2190 :         BOOST_TEST_I_ASSRT( !m.has( optional_value ) || !this->p_repeatable,
     320             :                             invalid_param_spec() << "Parameter " << name
     321             :                                                  << " is repeatable and can't have optional_value." );
     322        3504 :     }
     323             : 
     324             : private:
     325        1314 :     basic_param_ptr clone() const BOOST_OVERRIDE
     326             :     {
     327        1314 :         return basic_param_ptr( new parameter( *this ) );
     328           0 :     }
     329         292 :     void    produce_argument( cstring token, bool , arguments_store& store ) const BOOST_OVERRIDE
     330             :     {
     331         292 :         m_arg_factory.produce_argument( token, this->p_name, store );
     332         292 :     }
     333        1168 :     void    produce_default( arguments_store& store ) const BOOST_OVERRIDE
     334             :     {
     335        1168 :         if( !this->p_has_default_value )
     336           0 :             return;
     337             : 
     338        1168 :         m_arg_factory.produce_default( this->p_name, store );
     339        1168 :     }
     340             : 
     341             :     // Data members
     342             :     typedef argument_factory<ValueType, is_enum, a == runtime::REPEATABLE_PARAM> factory_t;
     343             :     factory_t       m_arg_factory;
     344             : };
     345             : 
     346             : //____________________________________________________________________________//
     347             : 
     348             : class option : public basic_param {
     349             : public:
     350             :     /// Constructor with modifiers
     351             : #ifndef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
     352             :     template<typename Modifiers=nfp::no_params_type>
     353        3796 :     option( cstring name, Modifiers const& m = nfp::no_params )
     354             : #else
     355             :     template<typename Modifiers>
     356             :     option( cstring name, Modifiers const& m )
     357             : #endif
     358        1898 :     : basic_param( name, true, false, nfp::opt_append( nfp::opt_append( m, optional_value = true), default_value = false) )
     359        1898 :     , m_arg_factory( nfp::opt_append( nfp::opt_append( m, optional_value = true), default_value = false) )
     360        3796 :     {
     361        3796 :     }
     362             : 
     363        2920 :     void            add_cla_id( cstring prefix, cstring tag, cstring value_separator, bool negatable = false )
     364             :     {
     365        2920 :         add_cla_id_impl( prefix, tag, value_separator, negatable, false );
     366        2920 :     }
     367             : 
     368             : private:
     369        1898 :     basic_param_ptr clone() const BOOST_OVERRIDE
     370             :     {
     371        1898 :         return basic_param_ptr( new option( *this ) );
     372           0 :     }
     373             : 
     374         146 :     void    produce_argument( cstring token, bool negative_form, arguments_store& store ) const BOOST_OVERRIDE
     375             :     {
     376         146 :         if( token.empty() )
     377           0 :             store.set( p_name, !negative_form );
     378             :         else {
     379         146 :             BOOST_TEST_I_ASSRT( !negative_form,
     380             :                                 format_error( p_name ) << "Can't set value to negative form of the argument." );
     381             : 
     382         146 :             m_arg_factory.produce_argument( token, p_name, store );
     383             :         }
     384         146 :     }
     385             : 
     386        1752 :     void    produce_default( arguments_store& store ) const BOOST_OVERRIDE
     387             :     {
     388        1752 :         m_arg_factory.produce_default( p_name, store );
     389        1752 :     }
     390           0 :     void    cla_name_help( std::ostream& ostr, cstring cla_tag, cstring negation_prefix_, bool use_color = true ) const BOOST_OVERRIDE
     391             :     {
     392             :         namespace utils = unit_test::utils;
     393             :         namespace ut_detail = unit_test::ut_detail;
     394             : 
     395           0 :         if( !negation_prefix_.is_empty() ) {
     396           0 :             BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::YELLOW );
     397           0 :             ostr << '[' << negation_prefix_ << ']';
     398           0 :         }
     399           0 :         ostr << cla_tag;
     400           0 :     }
     401           0 :     void    value_help( std::ostream& ostr ) const BOOST_OVERRIDE
     402             :     {
     403           0 :         if( p_value_hint.empty() )
     404           0 :             ostr << "<boolean value>";
     405             :         else
     406           0 :             ostr << p_value_hint;
     407           0 :     }
     408             : 
     409             :     // Data members
     410             :     typedef argument_factory<bool, false, false> factory_t;
     411             :     factory_t       m_arg_factory;
     412             : };
     413             : 
     414             : //____________________________________________________________________________//
     415             : 
     416             : template<typename EnumType, args_amount a = runtime::OPTIONAL_PARAM>
     417         876 : class enum_parameter : public parameter<EnumType, a, true> {
     418             :     typedef parameter<EnumType, a, true> base;
     419             : public:
     420             :     /// Constructor with modifiers
     421             : #ifndef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
     422             :     template<typename Modifiers=nfp::no_params_type>
     423        2628 :     enum_parameter( cstring name, Modifiers const& m = nfp::no_params )
     424             : #else
     425             :     template<typename Modifiers>
     426             :     enum_parameter( cstring name, Modifiers const& m )
     427             : #endif
     428         876 :     : base( name, m )
     429        1752 :     {
     430             : #ifdef BOOST_TEST_CLA_NEW_API
     431         876 :         auto const& values = m[enum_values<EnumType>::value];
     432         876 :         auto it = values.begin();
     433             : #else
     434             :         std::vector<std::pair<cstring, EnumType> > const& values = m[enum_values<EnumType>::value];
     435             :         typename std::vector<std::pair<cstring, EnumType> >::const_iterator it = values.begin();
     436             : #endif
     437        4818 :         while( it != values.end() ) {
     438        3942 :             m_valid_names.push_back( it->first );
     439        3942 :             ++it;
     440             :         }
     441        1752 :     }
     442             : 
     443             : private:
     444         876 :     basic_param_ptr clone() const BOOST_OVERRIDE
     445             :     {
     446         876 :         return basic_param_ptr( new enum_parameter( *this ) );
     447           0 :     }
     448             : 
     449           0 :     void    value_help( std::ostream& ostr ) const BOOST_OVERRIDE
     450             :     {
     451           0 :         if( this->p_value_hint.empty() ) {
     452           0 :             ostr << "<";
     453           0 :             bool first = true;
     454           0 :             BOOST_TEST_FOREACH( cstring, name, m_valid_names ) {
     455           0 :                 if( first )
     456           0 :                     first = false;
     457             :                 else
     458           0 :                     ostr << '|';
     459           0 :                 ostr << name;
     460           0 :             }
     461           0 :             ostr << ">";
     462           0 :         }
     463             :         else
     464           0 :             ostr << this->p_value_hint;
     465           0 :     }
     466             : 
     467             :     // Data members
     468             :     std::vector<cstring>    m_valid_names;
     469             : };
     470             : 
     471             : 
     472             : // ************************************************************************** //
     473             : // **************           runtime::parameters_store          ************** //
     474             : // ************************************************************************** //
     475             : 
     476             : class parameters_store {
     477             :     struct lg_compare {
     478       37960 :         bool operator()( cstring lh, cstring rh ) const
     479             :         {
     480       75920 :             return std::lexicographical_compare(lh.begin(), lh.end(),
     481       37960 :                                                 rh.begin(), rh.end());
     482             :         }
     483             :     };
     484             : public:
     485             : 
     486             :     typedef std::map<cstring, basic_param_ptr, lg_compare> storage_type;
     487             : 
     488             :     /// Adds parameter into the persistent store
     489        4088 :     void                    add( basic_param const& in )
     490             :     {
     491        4088 :         basic_param_ptr p = in.clone();
     492             : 
     493        4088 :         BOOST_TEST_I_ASSRT( m_parameters.insert( std::make_pair( cstring(p->p_name), p ) ).second,
     494             :                             duplicate_param() << "Parameter " << p->p_name << " is duplicate." );
     495        4088 :     }
     496             : 
     497             :     /// Returns true if there is no parameters registered
     498         146 :     bool                    is_empty() const    { return m_parameters.empty(); }
     499             :     /// Returns map of all the registered parameter
     500       76212 :     storage_type const&     all() const         { return m_parameters; }
     501             :     /// Returns true if parameter with specified name is registered
     502             :     bool                    has( cstring name ) const
     503             :     {
     504             :         return m_parameters.find( name ) != m_parameters.end();
     505             :     }
     506             :     /// Returns map of all the registered parameter
     507             :     basic_param_ptr         get( cstring name ) const
     508             :     {
     509             :         storage_type::const_iterator const& found = m_parameters.find( name );
     510             :         BOOST_TEST_I_ASSRT( found != m_parameters.end(),
     511             :                             unknown_param() << "Parameter " << name << " is unknown." );
     512             : 
     513             :         return found->second;
     514             :     }
     515             : 
     516             : private:
     517             :     // Data members
     518             :     storage_type            m_parameters;
     519             : };
     520             : 
     521             : } // namespace runtime
     522             : } // namespace boost
     523             : 
     524             : #include <boost/test/detail/enable_warnings.hpp>
     525             : 
     526             : #endif // BOOST_TEST_UTILS_RUNTIME_PARAMETER_HPP

Generated by: LCOV version 1.16