523 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			523 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
								 | 
							
								//  (C) Copyright Gennadiy Rozental 2001.
							 | 
						||
| 
								 | 
							
								//  Use, modification, and distribution are subject to the
							 | 
						||
| 
								 | 
							
								//  Boost Software License, Version 1.0. (See accompanying file
							 | 
						||
| 
								 | 
							
								//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//  See http://www.boost.org/libs/test for the library home page.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//!@file
							 | 
						||
| 
								 | 
							
								//!@brief CLA parser
							 | 
						||
| 
								 | 
							
								// ***************************************************************************
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_HPP
							 | 
						||
| 
								 | 
							
								#define BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_HPP
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Boost.Test Runtime parameters
							 | 
						||
| 
								 | 
							
								#include <boost/test/utils/runtime/argument.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/test/utils/runtime/modifier.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/test/utils/runtime/parameter.hpp>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <boost/test/utils/runtime/cla/argv_traverser.hpp>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Boost.Test
							 | 
						||
| 
								 | 
							
								#include <boost/test/utils/foreach.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/test/utils/algorithm.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/test/detail/throw_exception.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/test/detail/global_typedef.hpp>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <boost/algorithm/cxx11/all_of.hpp> // !! ?? unnecessary after cxx11
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// STL
							 | 
						||
| 
								 | 
							
								// !! ?? #include <unordered_set>
							 | 
						||
| 
								 | 
							
								#include <set>
							 | 
						||
| 
								 | 
							
								#include <iostream>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <boost/test/detail/suppress_warnings.hpp>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace boost {
							 | 
						||
| 
								 | 
							
								namespace runtime {
							 | 
						||
| 
								 | 
							
								namespace cla {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ************************************************************************** //
							 | 
						||
| 
								 | 
							
								// **************         runtime::cla::parameter_trie         ************** //
							 | 
						||
| 
								 | 
							
								// ************************************************************************** //
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace rt_cla_detail {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct parameter_trie;
							 | 
						||
| 
								 | 
							
								typedef shared_ptr<parameter_trie> parameter_trie_ptr;
							 | 
						||
| 
								 | 
							
								typedef std::map<char,parameter_trie_ptr> trie_per_char;
							 | 
						||
| 
								 | 
							
								typedef std::vector<boost::reference_wrapper<parameter_cla_id const> > param_cla_id_list;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct parameter_trie {
							 | 
						||
| 
								 | 
							
								    parameter_trie() : m_has_final_candidate( false ) {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /// If subtrie corresponding to the char c exists returns it otherwise creates new
							 | 
						||
| 
								 | 
							
								    parameter_trie_ptr  make_subtrie( char c )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        trie_per_char::const_iterator it = m_subtrie.find( c );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if( it == m_subtrie.end() )
							 | 
						||
| 
								 | 
							
								            it = m_subtrie.insert( std::make_pair( c, parameter_trie_ptr( new parameter_trie ) ) ).first;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return it->second;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /// Creates series of sub-tries per characters in a string
							 | 
						||
| 
								 | 
							
								    parameter_trie_ptr  make_subtrie( cstring s )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        parameter_trie_ptr res;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        BOOST_TEST_FOREACH( char, c, s )
							 | 
						||
| 
								 | 
							
								            res = (res ? res->make_subtrie( c ) : make_subtrie( c ));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return res;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /// Registers candidate parameter for this subtrie. If final, it needs to be unique
							 | 
						||
| 
								 | 
							
								    void                add_candidate_id( parameter_cla_id const& param_id, basic_param_ptr param_candidate, bool final )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        BOOST_TEST_I_ASSRT( !m_has_final_candidate && (!final || m_id_candidates.empty()),
							 | 
						||
| 
								 | 
							
								          conflicting_param() << "Parameter cla id " << param_id.m_tag << " conflicts with the "
							 | 
						||
| 
								 | 
							
								                              << "parameter cla id " << m_id_candidates.back().get().m_tag );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        m_has_final_candidate = final;
							 | 
						||
| 
								 | 
							
								        m_id_candidates.push_back( ref(param_id) );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if( m_id_candidates.size() == 1 )
							 | 
						||
| 
								 | 
							
								            m_param_candidate = param_candidate;
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            m_param_candidate.reset();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /// Gets subtrie for specified char if present or nullptr otherwise
							 | 
						||
| 
								 | 
							
								    parameter_trie_ptr  get_subtrie( char c ) const
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        trie_per_char::const_iterator it = m_subtrie.find( c );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return it != m_subtrie.end() ? it->second : parameter_trie_ptr();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Data members
							 | 
						||
| 
								 | 
							
								    trie_per_char       m_subtrie;
							 | 
						||
| 
								 | 
							
								    param_cla_id_list   m_id_candidates;
							 | 
						||
| 
								 | 
							
								    basic_param_ptr     m_param_candidate;
							 | 
						||
| 
								 | 
							
								    bool                m_has_final_candidate;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ************************************************************************** //
							 | 
						||
| 
								 | 
							
								// **************      runtime::cla::report_foreing_token      ************** //
							 | 
						||
| 
								 | 
							
								// ************************************************************************** //
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void 
							 | 
						||
| 
								 | 
							
								report_foreing_token( cstring program_name, cstring token )
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    std::cerr << "Boost.Test WARNING: token \"" << token << "\" does not correspond to the Boost.Test argument \n"
							 | 
						||
| 
								 | 
							
								              << "                    and should be placed after all Boost.Test arguments and the -- separator.\n"
							 | 
						||
| 
								 | 
							
								              << "                    For example: " << program_name << " --random -- " << token << "\n"; 
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								} // namespace rt_cla_detail
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ************************************************************************** //
							 | 
						||
| 
								 | 
							
								// **************             runtime::cla::parser             ************** //
							 | 
						||
| 
								 | 
							
								// ************************************************************************** //
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class parser {
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								    /// Initializes a parser and builds internal trie representation used for
							 | 
						||
| 
								 | 
							
								    /// parsing based on the supplied parameters
							 | 
						||
| 
								 | 
							
								#ifndef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
							 | 
						||
| 
								 | 
							
								    template<typename Modifiers=nfp::no_params_type>
							 | 
						||
| 
								 | 
							
								    parser( parameters_store const& parameters, Modifiers const& m = nfp::no_params )
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								    template<typename Modifiers>
							 | 
						||
| 
								 | 
							
								    parser( parameters_store const& parameters, Modifiers const& m )
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        nfp::opt_assign( m_end_of_param_indicator, m, end_of_params );
							 | 
						||
| 
								 | 
							
								        nfp::opt_assign( m_negation_prefix, m, negation_prefix );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        BOOST_TEST_I_ASSRT( algorithm::all_of( m_end_of_param_indicator.begin(),
							 | 
						||
| 
								 | 
							
								                                               m_end_of_param_indicator.end(),
							 | 
						||
| 
								 | 
							
								                                               parameter_cla_id::valid_prefix_char ),
							 | 
						||
| 
								 | 
							
								                            invalid_cla_id() << "End of parameters indicator can only consist of prefix characters." );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        BOOST_TEST_I_ASSRT( algorithm::all_of( m_negation_prefix.begin(),
							 | 
						||
| 
								 | 
							
								                                               m_negation_prefix.end(),
							 | 
						||
| 
								 | 
							
								                                               parameter_cla_id::valid_name_char ),
							 | 
						||
| 
								 | 
							
								                            invalid_cla_id() << "Negation prefix can only consist of prefix characters." );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        build_trie( parameters );
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // input processing method
							 | 
						||
| 
								 | 
							
								    int
							 | 
						||
| 
								 | 
							
								    parse( int argc, char** argv, runtime::arguments_store& res )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        // save program name for help message
							 | 
						||
| 
								 | 
							
								        m_program_name = argv[0];
							 | 
						||
| 
								 | 
							
								        cstring path_sep( "\\/" );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        cstring::iterator it = unit_test::utils::find_last_of( m_program_name.begin(), m_program_name.end(),
							 | 
						||
| 
								 | 
							
								                                                                path_sep.begin(), path_sep.end() );
							 | 
						||
| 
								 | 
							
								        if( it != m_program_name.end() )
							 | 
						||
| 
								 | 
							
								            m_program_name.trim_left( it + 1 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Set up the traverser
							 | 
						||
| 
								 | 
							
								        argv_traverser tr( argc, (char const**)argv );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Loop till we reach end of input
							 | 
						||
| 
								 | 
							
								        while( !tr.eoi() ) {
							 | 
						||
| 
								 | 
							
								            cstring curr_token = tr.current_token();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            cstring prefix;
							 | 
						||
| 
								 | 
							
								            cstring name;
							 | 
						||
| 
								 | 
							
								            cstring value_separator;
							 | 
						||
| 
								 | 
							
								            bool    negative_form = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Perform format validations and split the argument into prefix, name and separator
							 | 
						||
| 
								 | 
							
								            // False return value indicates end of params indicator is met
							 | 
						||
| 
								 | 
							
								            if( !validate_token_format( curr_token, prefix, name, value_separator, negative_form ) ) {
							 | 
						||
| 
								 | 
							
								                // get rid of "end of params" token
							 | 
						||
| 
								 | 
							
								                tr.next_token();
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Locate trie corresponding to found prefix and skip it in the input
							 | 
						||
| 
								 | 
							
								            trie_ptr curr_trie = m_param_trie[prefix];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if( !curr_trie ) {
							 | 
						||
| 
								 | 
							
								                //  format_error() << "Unrecognized parameter prefix in the argument " << tr.current_token()
							 | 
						||
| 
								 | 
							
								                rt_cla_detail::report_foreing_token( m_program_name, curr_token );
							 | 
						||
| 
								 | 
							
								                tr.save_token();
							 | 
						||
| 
								 | 
							
								                continue;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            curr_token.trim_left( prefix.size() );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Locate parameter based on a name and skip it in the input
							 | 
						||
| 
								 | 
							
								            locate_result locate_res = locate_parameter( curr_trie, name, curr_token );
							 | 
						||
| 
								 | 
							
								            parameter_cla_id const& found_id    = locate_res.first;
							 | 
						||
| 
								 | 
							
								            basic_param_ptr         found_param = locate_res.second;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if( negative_form ) {
							 | 
						||
| 
								 | 
							
								                BOOST_TEST_I_ASSRT( found_id.m_negatable,
							 | 
						||
| 
								 | 
							
								                                    format_error( found_param->p_name ) 
							 | 
						||
| 
								 | 
							
								                                        << "Parameter tag " << found_id.m_tag << " is not negatable." );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                curr_token.trim_left( m_negation_prefix.size() );
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            curr_token.trim_left( name.size() );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            cstring value;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Skip validations if parameter has optional value and we are at the end of token
							 | 
						||
| 
								 | 
							
								            if( !value_separator.is_empty() || !found_param->p_has_optional_value ) {
							 | 
						||
| 
								 | 
							
								                // Validate and skip value separator in the input
							 | 
						||
| 
								 | 
							
								                BOOST_TEST_I_ASSRT( found_id.m_value_separator == value_separator,
							 | 
						||
| 
								 | 
							
								                                    format_error( found_param->p_name ) 
							 | 
						||
| 
								 | 
							
								                                        << "Invalid separator for the parameter "
							 | 
						||
| 
								 | 
							
								                                        << found_param->p_name
							 | 
						||
| 
								 | 
							
								                                        << " in the argument " << tr.current_token() );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                curr_token.trim_left( value_separator.size() );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Deduce value source
							 | 
						||
| 
								 | 
							
								                value = curr_token;
							 | 
						||
| 
								 | 
							
								                if( value.is_empty() ) {
							 | 
						||
| 
								 | 
							
								                    tr.next_token();
							 | 
						||
| 
								 | 
							
								                    value = tr.current_token();
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                BOOST_TEST_I_ASSRT( !value.is_empty(),
							 | 
						||
| 
								 | 
							
								                                    format_error( found_param->p_name )
							 | 
						||
| 
								 | 
							
								                                        << "Missing an argument value for the parameter "
							 | 
						||
| 
								 | 
							
								                                        << found_param->p_name
							 | 
						||
| 
								 | 
							
								                                        << " in the argument " << tr.current_token() );
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Validate against argument duplication
							 | 
						||
| 
								 | 
							
								            BOOST_TEST_I_ASSRT( !res.has( found_param->p_name ) || found_param->p_repeatable,
							 | 
						||
| 
								 | 
							
								                                duplicate_arg( found_param->p_name )
							 | 
						||
| 
								 | 
							
								                                    << "Duplicate argument value for the parameter "
							 | 
						||
| 
								 | 
							
								                                    << found_param->p_name
							 | 
						||
| 
								 | 
							
								                                    << " in the argument " << tr.current_token() );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Produce argument value
							 | 
						||
| 
								 | 
							
								            found_param->produce_argument( value, negative_form, res );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            tr.next_token();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // generate the remainder and return it's size
							 | 
						||
| 
								 | 
							
								        return tr.remainder();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // help/usage/version
							 | 
						||
| 
								 | 
							
								    void
							 | 
						||
| 
								 | 
							
								    version( std::ostream& ostr )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								       ostr << "Boost.Test module ";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined(BOOST_TEST_MODULE)
							 | 
						||
| 
								 | 
							
								       // we do not want to refer to the master test suite there
							 | 
						||
| 
								 | 
							
								       ostr << '\'' << BOOST_TEST_STRINGIZE( BOOST_TEST_MODULE ).trim( "\"" ) << "' ";
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								       ostr << "in executable '" << m_program_name << "'\n";
							 | 
						||
| 
								 | 
							
								       ostr << "Compiled from Boost version "
							 | 
						||
| 
								 | 
							
								            << BOOST_VERSION/100000      << "."
							 | 
						||
| 
								 | 
							
								            << BOOST_VERSION/100 % 1000  << "."
							 | 
						||
| 
								 | 
							
								            << BOOST_VERSION % 100       ;
							 | 
						||
| 
								 | 
							
								       ostr << " with ";
							 | 
						||
| 
								 | 
							
								#if defined(BOOST_TEST_INCLUDED)
							 | 
						||
| 
								 | 
							
								       ostr << "single header inclusion of";
							 | 
						||
| 
								 | 
							
								#elif defined(BOOST_TEST_DYN_LINK)
							 | 
						||
| 
								 | 
							
								       ostr << "dynamic linking to";
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								       ostr << "static linking to";
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								       ostr << " Boost.Test\n";
							 | 
						||
| 
								 | 
							
								       ostr << "- Compiler: " << BOOST_COMPILER << '\n'
							 | 
						||
| 
								 | 
							
								            << "- Platform: " << BOOST_PLATFORM << '\n'
							 | 
						||
| 
								 | 
							
								            << "- STL     : " << BOOST_STDLIB;
							 | 
						||
| 
								 | 
							
								       ostr << std::endl;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    void
							 | 
						||
| 
								 | 
							
								    usage( std::ostream& ostr, cstring param_name = cstring() )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if( !param_name.is_empty() ) {
							 | 
						||
| 
								 | 
							
								            basic_param_ptr param = locate_parameter( m_param_trie[help_prefix], param_name, "" ).second;
							 | 
						||
| 
								 | 
							
								            param->usage( ostr, m_negation_prefix );
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								            ostr << "Usage: " << m_program_name << " [Boost.Test argument]... ";
							 | 
						||
| 
								 | 
							
								            if( !m_end_of_param_indicator.empty() )
							 | 
						||
| 
								 | 
							
								                ostr << m_end_of_param_indicator << " [custom test module argument]...";
							 | 
						||
| 
								 | 
							
								            ostr << "\n";
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ostr << "\nFor detailed help on Boost.Test parameters use:\n"
							 | 
						||
| 
								 | 
							
								             << "  " << m_program_name << " --help\n"
							 | 
						||
| 
								 | 
							
								             << "or\n"
							 | 
						||
| 
								 | 
							
								             << "  " << m_program_name << " --help=<parameter name>\n";
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    void
							 | 
						||
| 
								 | 
							
								    help( std::ostream& ostr, parameters_store const& parameters, cstring param_name )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if( !param_name.is_empty() ) {
							 | 
						||
| 
								 | 
							
								            basic_param_ptr param = locate_parameter( m_param_trie[help_prefix], param_name, "" ).second;
							 | 
						||
| 
								 | 
							
								            param->help( ostr, m_negation_prefix );
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ostr << "Usage: " << m_program_name << " [Boost.Test argument]... ";
							 | 
						||
| 
								 | 
							
								        if( !m_end_of_param_indicator.empty() )
							 | 
						||
| 
								 | 
							
								            ostr << m_end_of_param_indicator << " [custom test module argument]...";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ostr << "\n\nBoost.Test arguments correspond to parameters listed below. "
							 | 
						||
| 
								 | 
							
								                "All parameters are optional. You can use specify parameter value either "
							 | 
						||
| 
								 | 
							
								                "as a command line argument or as a value of corresponding environment "
							 | 
						||
| 
								 | 
							
								                "variable. In case if argument for the same parameter is specified in both "
							 | 
						||
| 
								 | 
							
								                "places, command line is taking precedence. Command line argument format "
							 | 
						||
| 
								 | 
							
								                "supports parameter name guessing, so you can use any unambiguous "
							 | 
						||
| 
								 | 
							
								                "prefix to identify a parameter.";
							 | 
						||
| 
								 | 
							
								        if( !m_end_of_param_indicator.empty() )
							 | 
						||
| 
								 | 
							
								            ostr << " All the arguments after the " << m_end_of_param_indicator << " are ignored by the Boost.Test.";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ostr << "\n\nBoost.Test supports following parameters:\n";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        BOOST_TEST_FOREACH( parameters_store::storage_type::value_type const&, v, parameters.all() ) {
							 | 
						||
| 
								 | 
							
								            basic_param_ptr param = v.second;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            param->usage( ostr, m_negation_prefix );
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ostr << "\nUse --help=<parameter name> to display detailed help for specific parameter.\n";
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								private:
							 | 
						||
| 
								 | 
							
								    typedef rt_cla_detail::parameter_trie_ptr   trie_ptr;
							 | 
						||
| 
								 | 
							
								    typedef rt_cla_detail::trie_per_char        trie_per_char;
							 | 
						||
| 
								 | 
							
								    typedef std::map<cstring,trie_ptr>          str_to_trie;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    void
							 | 
						||
| 
								 | 
							
								    build_trie( parameters_store const& parameters )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        // Iterate over all parameters
							 | 
						||
| 
								 | 
							
								        BOOST_TEST_FOREACH( parameters_store::storage_type::value_type const&, v, parameters.all() ) {
							 | 
						||
| 
								 | 
							
								            basic_param_ptr param = v.second;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Register all parameter's ids in trie.
							 | 
						||
| 
								 | 
							
								            BOOST_TEST_FOREACH( parameter_cla_id const&, id, param->cla_ids() ) {
							 | 
						||
| 
								 | 
							
								                // This is the trie corresponding to the prefix.
							 | 
						||
| 
								 | 
							
								                trie_ptr next_trie = m_param_trie[id.m_prefix];
							 | 
						||
| 
								 | 
							
								                if( !next_trie )
							 | 
						||
| 
								 | 
							
								                    next_trie = m_param_trie[id.m_prefix] = trie_ptr( new rt_cla_detail::parameter_trie );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Build the trie, by following name's characters
							 | 
						||
| 
								 | 
							
								                // and register this parameter as candidate on each level
							 | 
						||
| 
								 | 
							
								                for( size_t index = 0; index < id.m_tag.size(); ++index ) {
							 | 
						||
| 
								 | 
							
								                    next_trie = next_trie->make_subtrie( id.m_tag[index] );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    next_trie->add_candidate_id( id, param, index == (id.m_tag.size() - 1) );
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool
							 | 
						||
| 
								 | 
							
								    validate_token_format( cstring token, cstring& prefix, cstring& name, cstring& separator, bool& negative_form )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        // Match prefix
							 | 
						||
| 
								 | 
							
								        cstring::iterator it = token.begin();
							 | 
						||
| 
								 | 
							
								        while( it != token.end() && parameter_cla_id::valid_prefix_char( *it ) )
							 | 
						||
| 
								 | 
							
								            ++it;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        prefix.assign( token.begin(), it );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if( prefix.empty() )
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Match name
							 | 
						||
| 
								 | 
							
								        while( it != token.end() && parameter_cla_id::valid_name_char( *it ) )
							 | 
						||
| 
								 | 
							
								            ++it;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        name.assign( prefix.end(), it );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if( name.empty() ) {
							 | 
						||
| 
								 | 
							
								            if( prefix == m_end_of_param_indicator )
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            BOOST_TEST_I_THROW( format_error() << "Invalid format for an actual argument " << token );
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Match value separator
							 | 
						||
| 
								 | 
							
								        while( it != token.end() && parameter_cla_id::valid_separator_char( *it ) )
							 | 
						||
| 
								 | 
							
								            ++it;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        separator.assign( name.end(), it );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Match negation prefix
							 | 
						||
| 
								 | 
							
								        negative_form = !m_negation_prefix.empty() && ( name.substr( 0, m_negation_prefix.size() ) == m_negation_prefix );
							 | 
						||
| 
								 | 
							
								        if( negative_form )
							 | 
						||
| 
								 | 
							
								            name.trim_left( m_negation_prefix.size() );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // C++03: cannot have references as types
							 | 
						||
| 
								 | 
							
								    typedef std::pair<parameter_cla_id, basic_param_ptr> locate_result;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    locate_result
							 | 
						||
| 
								 | 
							
								    locate_parameter( trie_ptr curr_trie, cstring name, cstring token )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        std::vector<trie_ptr> typo_candidates;
							 | 
						||
| 
								 | 
							
								        std::vector<trie_ptr> next_typo_candidates;
							 | 
						||
| 
								 | 
							
								        trie_ptr next_trie;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        BOOST_TEST_FOREACH( char, c, name ) {
							 | 
						||
| 
								 | 
							
								            if( curr_trie ) {
							 | 
						||
| 
								 | 
							
								                // locate next subtrie corresponding to the char
							 | 
						||
| 
								 | 
							
								                next_trie = curr_trie->get_subtrie( c );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if( next_trie )
							 | 
						||
| 
								 | 
							
								                    curr_trie = next_trie;
							 | 
						||
| 
								 | 
							
								                else {
							 | 
						||
| 
								 | 
							
								                    // Initiate search for typo candicates. We will account for 'wrong char' typo
							 | 
						||
| 
								 | 
							
								                    // 'missing char' typo and 'extra char' typo
							 | 
						||
| 
								 | 
							
								                    BOOST_TEST_FOREACH( trie_per_char::value_type const&, typo_cand, curr_trie->m_subtrie ) {
							 | 
						||
| 
								 | 
							
								                        // 'wrong char' typo
							 | 
						||
| 
								 | 
							
								                        typo_candidates.push_back( typo_cand.second );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        // 'missing char' typo
							 | 
						||
| 
								 | 
							
								                        if( (next_trie = typo_cand.second->get_subtrie( c )) )
							 | 
						||
| 
								 | 
							
								                            typo_candidates.push_back( next_trie );
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    // 'extra char' typo
							 | 
						||
| 
								 | 
							
								                    typo_candidates.push_back( curr_trie );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    curr_trie.reset();
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else {
							 | 
						||
| 
								 | 
							
								                // go over existing typo candidates and see if they are still viable
							 | 
						||
| 
								 | 
							
								                BOOST_TEST_FOREACH( trie_ptr, typo_cand, typo_candidates ) {
							 | 
						||
| 
								 | 
							
								                    trie_ptr next_typo_cand = typo_cand->get_subtrie( c );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    if( next_typo_cand )
							 | 
						||
| 
								 | 
							
								                        next_typo_candidates.push_back( next_typo_cand );
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                next_typo_candidates.swap( typo_candidates );
							 | 
						||
| 
								 | 
							
								                next_typo_candidates.clear();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if( !curr_trie ) {
							 | 
						||
| 
								 | 
							
								            std::vector<cstring> typo_candidate_names;
							 | 
						||
| 
								 | 
							
								            std::set<parameter_cla_id const*> unique_typo_candidate; // !! ?? unordered_set
							 | 
						||
| 
								 | 
							
								            typo_candidate_names.reserve( typo_candidates.size() );
							 | 
						||
| 
								 | 
							
								// !! ??            unique_typo_candidate.reserve( typo_candidates.size() );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            BOOST_TEST_FOREACH( trie_ptr, trie_cand, typo_candidates ) {
							 | 
						||
| 
								 | 
							
								                // avoid ambiguos candidate trie
							 | 
						||
| 
								 | 
							
								                if( trie_cand->m_id_candidates.size() > 1 )
							 | 
						||
| 
								 | 
							
								                    continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                BOOST_TEST_FOREACH( parameter_cla_id const&, param_cand, trie_cand->m_id_candidates ) {
							 | 
						||
| 
								 | 
							
								                    if( !unique_typo_candidate.insert( ¶m_cand ).second )
							 | 
						||
| 
								 | 
							
								                        continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    typo_candidate_names.push_back( param_cand.m_tag );
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
							 | 
						||
| 
								 | 
							
								            BOOST_TEST_I_THROW( unrecognized_param( std::move(typo_candidate_names) )
							 | 
						||
| 
								 | 
							
								                                << "An unrecognized parameter in the argument "
							 | 
						||
| 
								 | 
							
								                                << token );
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								            BOOST_TEST_I_THROW( unrecognized_param( typo_candidate_names )
							 | 
						||
| 
								 | 
							
								                                << "An unrecognized parameter in the argument "
							 | 
						||
| 
								 | 
							
								                                << token );
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if( curr_trie->m_id_candidates.size() > 1 ) {
							 | 
						||
| 
								 | 
							
								            std::vector<cstring> amb_names;
							 | 
						||
| 
								 | 
							
								            BOOST_TEST_FOREACH( parameter_cla_id const&, param_id, curr_trie->m_id_candidates )
							 | 
						||
| 
								 | 
							
								                amb_names.push_back( param_id.m_tag );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
							 | 
						||
| 
								 | 
							
								            BOOST_TEST_I_THROW( ambiguous_param( std::move( amb_names ) )
							 | 
						||
| 
								 | 
							
								                                << "An ambiguous parameter name in the argument " << token );
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								            BOOST_TEST_I_THROW( ambiguous_param( amb_names )
							 | 
						||
| 
								 | 
							
								                                << "An ambiguous parameter name in the argument " << token );
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return locate_result( curr_trie->m_id_candidates.back().get(), curr_trie->m_param_candidate );
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Data members
							 | 
						||
| 
								 | 
							
								    cstring     m_program_name;
							 | 
						||
| 
								 | 
							
								    std::string m_end_of_param_indicator;
							 | 
						||
| 
								 | 
							
								    std::string m_negation_prefix;
							 | 
						||
| 
								 | 
							
								    str_to_trie m_param_trie;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								} // namespace cla
							 | 
						||
| 
								 | 
							
								} // namespace runtime
							 | 
						||
| 
								 | 
							
								} // namespace boost
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <boost/test/detail/enable_warnings.hpp>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif // BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_HPP
							 |