diff options
Diffstat (limited to 'src/third_party/boost-1.60.0/boost/test/utils/runtime')
10 files changed, 1946 insertions, 0 deletions
diff --git a/src/third_party/boost-1.60.0/boost/test/utils/runtime/argument.hpp b/src/third_party/boost-1.60.0/boost/test/utils/runtime/argument.hpp new file mode 100644 index 00000000000..879ee96f9f0 --- /dev/null +++ b/src/third_party/boost-1.60.0/boost/test/utils/runtime/argument.hpp @@ -0,0 +1,131 @@ +// (C) Copyright Gennadiy Rozental 2001. +// Distributed under 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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : model of actual argument (both typed and abstract interface) +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_ARGUMENT_HPP +#define BOOST_TEST_UTILS_RUNTIME_ARGUMENT_HPP + +// Boost.Test Runtime parameters +#include <boost/test/utils/runtime/fwd.hpp> +#include <boost/test/utils/runtime/errors.hpp> + +// Boost.Test +#include <boost/test/utils/class_properties.hpp> +#include <boost/test/utils/rtti.hpp> +#include <boost/test/utils/basic_cstring/compare.hpp> +#include <boost/test/detail/throw_exception.hpp> + +// STL +#include <cassert> + +#include <boost/test/detail/suppress_warnings.hpp> + +namespace boost { +namespace runtime { + +// ************************************************************************** // +// ************** runtime::argument ************** // +// ************************************************************************** // + +class argument { +public: + // Constructor + argument( rtti::id_t value_type ) + : p_value_type( value_type ) + {} + + // Destructor + virtual ~argument() {} + + // Public properties + rtti::id_t const p_value_type; +}; + +// ************************************************************************** // +// ************** runtime::typed_argument ************** // +// ************************************************************************** // + +template<typename T> +class typed_argument : public argument { +public: + // Constructor + explicit typed_argument( T const& v ) + : argument( rtti::type_id<T>() ) + , p_value( v ) + {} + + unit_test::readwrite_property<T> p_value; +}; + +// ************************************************************************** // +// ************** runtime::arguments_store ************** // +// ************************************************************************** // + +class arguments_store { +public: + typedef std::map<cstring, argument_ptr> storage_type; + + /// Returns number of arguments in the store; mostly used for testing + std::size_t size() const { return m_arguments.size(); } + + /// Clears the store for reuse + void clear() { m_arguments.clear(); } + + /// Returns true if there is an argument corresponding to the specified parameter name + bool has( cstring parameter_name ) const + { + return m_arguments.find( parameter_name ) != m_arguments.end(); + } + + /// Provides types access to argument value by parameter name + template<typename T> + T const& get( cstring parameter_name ) const { + return const_cast<arguments_store*>(this)->get<T>( parameter_name ); + } + + template<typename T> + T& get( cstring parameter_name ) { + storage_type::const_iterator found = m_arguments.find( parameter_name ); + BOOST_TEST_I_ASSRT( found != m_arguments.end(), + access_to_missing_argument() + << "There is no argument provided for parameter " + << parameter_name ); + + argument_ptr arg = found->second; + + BOOST_TEST_I_ASSRT( arg->p_value_type == rtti::type_id<T>(), + arg_type_mismatch() + << "Access with invalid type for argument corresponding to parameter " + << parameter_name ); + + return static_cast<typed_argument<T>&>( *arg ).p_value.value; + } + + /// Set's the argument value for specified parameter name + template<typename T> + void set( cstring parameter_name, T const& value ) + { + m_arguments[parameter_name] = argument_ptr( new typed_argument<T>( value ) ); + } + +private: + // Data members + storage_type m_arguments; +}; + +} // namespace runtime +} // namespace boost + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_UTILS_RUNTIME_ARGUMENT_HPP diff --git a/src/third_party/boost-1.60.0/boost/test/utils/runtime/argument_factory.hpp b/src/third_party/boost-1.60.0/boost/test/utils/runtime/argument_factory.hpp new file mode 100644 index 00000000000..a163deb9a25 --- /dev/null +++ b/src/third_party/boost-1.60.0/boost/test/utils/runtime/argument_factory.hpp @@ -0,0 +1,242 @@ +// (C) Copyright Gennadiy Rozental 2001. +// Distributed under 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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : argument factories for different kinds of parameters +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_ARGUMENT_FACTORY_HPP +#define BOOST_TEST_UTILS_RUNTIME_ARGUMENT_FACTORY_HPP + +// Boost.Test Runtime parameters +#include <boost/test/utils/runtime/errors.hpp> +#include <boost/test/utils/runtime/argument.hpp> + +// Boost.Test +#include <boost/test/utils/basic_cstring/io.hpp> +#include <boost/test/utils/basic_cstring/compare.hpp> +#include <boost/test/utils/string_cast.hpp> + +// Boost +#include <boost/function/function2.hpp> + +// STL +#include <vector> + +#include <boost/test/detail/suppress_warnings.hpp> + +namespace boost { +namespace runtime { + +// ************************************************************************** // +// ************** runtime::value_interpreter ************** // +// ************************************************************************** // + +template<typename ValueType, bool is_enum> +struct value_interpreter; + +//____________________________________________________________________________// + +template<typename ValueType> +struct value_interpreter<ValueType, false> { + template<typename Modifiers> + explicit value_interpreter( Modifiers const& ) {} + + ValueType interpret( cstring param_name, cstring source ) const + { + ValueType res; + if( !unit_test::utils::string_as<ValueType>( source, res ) ) + BOOST_TEST_I_THROW( format_error( param_name ) << source << + " can't be interpreted as value of parameter " << param_name << "." ); + return res; + } +}; + +//____________________________________________________________________________// + +template<> +struct value_interpreter<std::string, false> { + template<typename Modifiers> + explicit value_interpreter( Modifiers const& ) {} + + std::string interpret( cstring, cstring source ) const + { + return std::string( source.begin(), source.size() ); + } +}; + +//____________________________________________________________________________// + +template<> +struct value_interpreter<cstring, false> { + template<typename Modifiers> + explicit value_interpreter( Modifiers const& ) {} + + cstring interpret( cstring, cstring source ) const + { + return source; + } +}; + +//____________________________________________________________________________// + +template<> +struct value_interpreter<bool, false> { + template<typename Modifiers> + explicit value_interpreter( Modifiers const& ) {} + + bool interpret( cstring param_name, cstring source ) const + { + static cstring const s_YES( "YES" ); + static cstring const s_Y( "Y" ); + static cstring const s_NO( "NO" ); + static cstring const s_N( "N" ); + static cstring const s_TRUE( "TRUE" ); + static cstring const s_FALSE( "FALSE" ); + static cstring const s_one( "1" ); + static cstring const s_zero( "0" ); + + source.trim(); + + if( source.is_empty() || + case_ins_eq( source, s_YES ) || + case_ins_eq( source, s_Y ) || + case_ins_eq( source, s_one ) || + case_ins_eq( source, s_TRUE ) ) + return true; + + if( case_ins_eq( source, s_NO ) || + case_ins_eq( source, s_N ) || + case_ins_eq( source, s_zero ) || + case_ins_eq( source, s_FALSE ) ) + return false; + + BOOST_TEST_I_THROW( format_error( param_name ) << source << " can't be interpreted as bool value." ); + } +}; + +//____________________________________________________________________________// + +template<typename EnumType> +struct value_interpreter<EnumType, true> { + template<typename Modifiers> + explicit value_interpreter( Modifiers const& m ) +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) && !defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) + : m_name_to_value( m[enum_values<EnumType>::value] ) + { + } +#else + { + std::vector<std::pair<cstring,EnumType> > const& values = m[enum_values<EnumType>::value]; + + m_name_to_value.insert( values.begin(), values.end() ); + } +#endif + + EnumType interpret( cstring param_name, cstring source ) const + { + typename std::map<cstring,EnumType>::const_iterator found = m_name_to_value.find( source ); + + BOOST_TEST_I_ASSRT( found != m_name_to_value.end(), + format_error( param_name ) << source << + " is not a valid enumeration value name for parameter " << param_name << "." ); + + return found->second; + } + +private: + // Data members + std::map<cstring,EnumType> m_name_to_value; +}; + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** runtime::argument_factory ************** // +// ************************************************************************** // + +template<typename ValueType, bool is_enum, bool repeatable> +class argument_factory; + +//____________________________________________________________________________// + +template<typename ValueType, bool is_enum> +class argument_factory<ValueType, is_enum, false> { +public: + template<typename Modifiers> + explicit argument_factory( Modifiers const& m ) + : m_interpreter( m ) + , m_optional_value( nfp::opt_get( m, optional_value, ValueType() ) ) + , m_default_value( nfp::opt_get( m, default_value, ValueType() ) ) + { + } + + void produce_argument( cstring source, cstring param_name, arguments_store& store ) const + { + store.set( param_name, source.empty() ? m_optional_value : m_interpreter.interpret( param_name, source ) ); + } + + void produce_default( cstring param_name, arguments_store& store ) const + { + store.set( param_name, m_default_value ); + } + +private: + // Data members + typedef value_interpreter<ValueType, is_enum> interp_t; + interp_t m_interpreter; + ValueType m_optional_value; + ValueType m_default_value; +}; + +//____________________________________________________________________________// + +template<typename ValueType, bool is_enum> +class argument_factory<ValueType, is_enum, true> { +public: + template<typename Modifiers> + explicit argument_factory( Modifiers const& m ) + : m_interpreter( m ) + { + } + + void produce_argument( cstring source, cstring param_name, arguments_store& store ) const + { + ValueType value = m_interpreter.interpret( param_name, source ); + + if( store.has( param_name ) ) { + std::vector<ValueType>& values = store.get<std::vector<ValueType> >( param_name ); + values.push_back( value ); + } + else { + std::vector<ValueType> values( 1, value ); + + store.set( param_name, values ); + } + + } + void produce_default( cstring param_name, arguments_store& store ) const + { + store.set( param_name, std::vector<ValueType>() ); + } + +private: + // Data members + value_interpreter<ValueType, is_enum> m_interpreter; +}; + +//____________________________________________________________________________// + +} // namespace runtime +} // namespace boost + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_UTILS_RUNTIME_ARGUMENT_FACTORY_HPP diff --git a/src/third_party/boost-1.60.0/boost/test/utils/runtime/cla/argv_traverser.hpp b/src/third_party/boost-1.60.0/boost/test/utils/runtime/cla/argv_traverser.hpp new file mode 100644 index 00000000000..10fb67bde4d --- /dev/null +++ b/src/third_party/boost-1.60.0/boost/test/utils/runtime/cla/argv_traverser.hpp @@ -0,0 +1,105 @@ +// (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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : defines facility to hide input traversing details +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_ARGV_TRAVERSER_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_ARGV_TRAVERSER_HPP + +// Boost.Test Runtime parameters +#include <boost/test/utils/runtime/fwd.hpp> + +#include <boost/test/detail/suppress_warnings.hpp> + +namespace boost { +namespace runtime { +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::argv_traverser ************** // +// ************************************************************************** // + +class argv_traverser { + typedef char const** argv_type; +public: + /// Constructs traverser based on argc/argv pair + /// argv is taken "by reference" and later can be + /// updated in remainder method + argv_traverser( int argc, argv_type argv ) + : m_argc( argc ) + , m_curr_token( 0 ) + , m_token_size( 0 ) + , m_argv( argv ) + { + // save program name + save_token(); + } + + /// Returns new argc + int remainder() + { + return m_argc; + } + + /// Returns true, if we reached end on input + bool eoi() const + { + return m_curr_token == m_argc; + } + + /// Returns current token in the input + cstring current_token() + { + if( eoi() ) + return cstring(); + + return cstring( m_argv[m_curr_token], m_token_size ); + } + + /// Saves current token for remainder + void save_token() + { + ++m_curr_token; + + if( !eoi() ) + m_token_size = ::strlen( m_argv[m_curr_token] ); + } + + /// Commit current token and iterate to next one + void next_token() + { + if( !eoi() ) { + for( std::size_t i = m_curr_token; i < m_argc-1; ++i ) + m_argv[i] = m_argv[i + 1]; + + --m_argc; + + m_token_size = ::strlen( m_argv[m_curr_token] ); + } + } + +private: + + // Data members + std::size_t m_argc; // total number of arguments + std::size_t m_curr_token; // current token index in argv + std::size_t m_token_size; // current token size + argv_type m_argv; // all arguments +}; + +} // namespace cla +} // namespace runtime +} // namespace boost + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_ARGV_TRAVERSER_HPP diff --git a/src/third_party/boost-1.60.0/boost/test/utils/runtime/cla/parser.hpp b/src/third_party/boost-1.60.0/boost/test/utils/runtime/cla/parser.hpp new file mode 100644 index 00000000000..effde33a52f --- /dev/null +++ b/src/third_party/boost-1.60.0/boost/test/utils/runtime/cla/parser.hpp @@ -0,0 +1,491 @@ +// (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/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 + 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 diff --git a/src/third_party/boost-1.60.0/boost/test/utils/runtime/env/fetch.hpp b/src/third_party/boost-1.60.0/boost/test/utils/runtime/env/fetch.hpp new file mode 100644 index 00000000000..97d54d4905f --- /dev/null +++ b/src/third_party/boost-1.60.0/boost/test/utils/runtime/env/fetch.hpp @@ -0,0 +1,108 @@ +// (C) Copyright Gennadiy Rozental 2001. +// Distributed under 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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : implements fetching absent parameter athuments from environment +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_ENV_FETCH_HPP +#define BOOST_TEST_UTILS_RUNTIME_ENV_FETCH_HPP + +// Boost.Test Runtime parameters +#include <boost/test/utils/runtime/parameter.hpp> +#include <boost/test/utils/runtime/argument.hpp> + +#include <boost/test/detail/suppress_warnings.hpp> + +// C Runtime +#include <stdlib.h> + +namespace boost { +namespace runtime { +namespace env { + +namespace env_detail { + +#ifndef UNDER_CE + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4996) // getenv +#endif + +inline std::pair<cstring,bool> +sys_read_var( cstring var_name ) +{ + using namespace std; + char const* res = getenv( var_name.begin() ); + + return std::make_pair( cstring(res), res != NULL ); +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#else + +inline std::pair<cstring,bool> +sys_read_var( cstring var_name ) +{ + return std::make_pair( cstring(), false ); +} + +#endif + +//____________________________________________________________________________// + +template<typename ReadFunc> +inline void +fetch_absent( parameters_store const& params, runtime::arguments_store& args, ReadFunc read_func ) +{ + BOOST_TEST_FOREACH( parameters_store::storage_type::value_type const&, v, params.all() ) { + basic_param_ptr param = v.second; + + if( args.has( param->p_name ) || param->p_env_var.empty() ) + continue; + + std::pair<cstring,bool> value = read_func( param->p_env_var ); + + if( !value.second ) + continue; + + // Validate against unexpected empty value + BOOST_TEST_I_ASSRT( !value.first.is_empty() || param->p_has_optional_value, + format_error( param->p_name ) + << "Missing an argument value for the parameter " << param->p_name + << " in the environment." ); + + // Produce argument value + param->produce_argument( value.first, false, args ); + + } +} + +//____________________________________________________________________________// + +} // namespace env_detail + +inline void +fetch_absent( parameters_store const& params, runtime::arguments_store& args ) +{ + env_detail::fetch_absent( params, args, &env_detail::sys_read_var ); +} + +} // namespace env +} // namespace runtime +} // namespace boost + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_UTILS_RUNTIME_ENV_FETCH_HPP diff --git a/src/third_party/boost-1.60.0/boost/test/utils/runtime/errors.hpp b/src/third_party/boost-1.60.0/boost/test/utils/runtime/errors.hpp new file mode 100644 index 00000000000..c11686132c4 --- /dev/null +++ b/src/third_party/boost-1.60.0/boost/test/utils/runtime/errors.hpp @@ -0,0 +1,195 @@ +// (C) Copyright Gennadiy Rozental 2001. +// Distributed under 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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : defines runtime parameters setup error +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_INIT_ERROR_HPP +#define BOOST_TEST_UTILS_RUNTIME_INIT_ERROR_HPP + +// Boost.Test Runtime parameters +#include <boost/test/utils/runtime/fwd.hpp> + +// Boost.Test +#include <boost/test/utils/string_cast.hpp> + +// Boost.Test +#include <boost/config.hpp> + +// STL +#include <exception> +#include <vector> + +#include <boost/test/detail/suppress_warnings.hpp> + +namespace boost { +namespace runtime { + +// ************************************************************************** // +// ************** runtime::param_error ************** // +// ************************************************************************** // + +class param_error : public std::exception { +public: + ~param_error() BOOST_NOEXCEPT_OR_NOTHROW {} + + virtual const char * what() const BOOST_NOEXCEPT_OR_NOTHROW + { + return msg.c_str(); + } + + cstring param_name; + std::string msg; + +protected: + explicit param_error( cstring param_name_ ) : param_name( param_name_) {} +}; + +//____________________________________________________________________________// + +class init_error : public param_error { +protected: + explicit init_error( cstring param_name ) : param_error( param_name ) {} + ~init_error() BOOST_NOEXCEPT_OR_NOTHROW {} +}; + +class input_error : public param_error { +protected: + explicit input_error( cstring param_name ) : param_error( param_name ) {} + ~input_error() BOOST_NOEXCEPT_OR_NOTHROW {} +}; + +//____________________________________________________________________________// + +template<typename Derived, typename Base> +class specific_param_error : public Base { +protected: + explicit specific_param_error( cstring param_name ) : Base( param_name ) {} + ~specific_param_error() BOOST_NOEXCEPT_OR_NOTHROW {} +}; + +//____________________________________________________________________________// + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + +template<typename Derived, typename Base> +inline Derived +operator<<(specific_param_error<Derived, Base>&& ex, char const* val) +{ + ex.msg.append( val ); + + return reinterpret_cast<Derived&&>(ex); +} + +//____________________________________________________________________________// + +template<typename Derived, typename Base, typename T> +inline Derived +operator<<(specific_param_error<Derived, Base>&& ex, T const& val) +{ + ex.msg.append( unit_test::utils::string_cast( val ) ); + + return reinterpret_cast<Derived&&>(ex); +} + +//____________________________________________________________________________// + +#else + +template<typename Derived, typename Base> +inline Derived +operator<<(specific_param_error<Derived, Base> const& ex, char const* val) +{ + const_cast<specific_param_error<Derived, Base>&>(ex).msg.append( val ); + + return static_cast<Derived const&>(ex); +} + +//____________________________________________________________________________// + +template<typename Derived, typename Base, typename T> +inline Derived +operator<<(specific_param_error<Derived, Base> const& ex, T const& val) +{ + const_cast<specific_param_error<Derived, Base>&>(ex).msg.append( unit_test::utils::string_cast( val ) ); + + return static_cast<Derived const&>(ex); +} + +//____________________________________________________________________________// + +#endif + +// ************************************************************************** // +// ************** specific exception types ************** // +// ************************************************************************** // + +#define SPECIFIC_EX_TYPE( type, base ) \ +class type : public specific_param_error<type,base> { \ +public: \ + explicit type( cstring param_name = cstring() ) \ + : specific_param_error<type,base>( param_name ) \ + {} \ +} \ +/**/ + +SPECIFIC_EX_TYPE( invalid_cla_id, init_error ); +SPECIFIC_EX_TYPE( duplicate_param, init_error ); +SPECIFIC_EX_TYPE( conflicting_param, init_error ); +SPECIFIC_EX_TYPE( unknown_param, init_error ); +SPECIFIC_EX_TYPE( access_to_missing_argument, init_error ); +SPECIFIC_EX_TYPE( arg_type_mismatch, init_error ); +SPECIFIC_EX_TYPE( invalid_param_spec, init_error ); + +SPECIFIC_EX_TYPE( format_error, input_error ); +SPECIFIC_EX_TYPE( duplicate_arg, input_error ); +SPECIFIC_EX_TYPE( missing_req_arg, input_error ); + +#undef SPECIFIC_EX_TYPE + +class ambiguous_param : public specific_param_error<ambiguous_param, input_error> { +public: +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + explicit ambiguous_param( std::vector<cstring>&& amb_candidates ) + : specific_param_error<ambiguous_param,input_error>( "" ) + , m_amb_candidates( std::move( amb_candidates ) ) {} +#else + explicit ambiguous_param( std::vector<cstring> const& amb_candidates ) + : specific_param_error<ambiguous_param,input_error>( "" ) + , m_amb_candidates( amb_candidates ) {} +#endif + ~ambiguous_param() BOOST_NOEXCEPT_OR_NOTHROW {} + + std::vector<cstring> m_amb_candidates; +}; + +class unrecognized_param : public specific_param_error<unrecognized_param, input_error> { +public: +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + explicit unrecognized_param( std::vector<cstring>&& type_candidates ) + : specific_param_error<unrecognized_param,input_error>( "" ) + , m_typo_candidates( std::move( type_candidates ) ) {} +#else + explicit unrecognized_param( std::vector<cstring> const& type_candidates ) + : specific_param_error<unrecognized_param,input_error>( "" ) + , m_typo_candidates( type_candidates ) {} +#endif + ~unrecognized_param() BOOST_NOEXCEPT_OR_NOTHROW {} + + std::vector<cstring> m_typo_candidates; +}; + +} // namespace runtime +} // namespace boost + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_UTILS_RUNTIME_INIT_ERROR_HPP diff --git a/src/third_party/boost-1.60.0/boost/test/utils/runtime/finalize.hpp b/src/third_party/boost-1.60.0/boost/test/utils/runtime/finalize.hpp new file mode 100644 index 00000000000..181428550c1 --- /dev/null +++ b/src/third_party/boost-1.60.0/boost/test/utils/runtime/finalize.hpp @@ -0,0 +1,56 @@ +// (C) Copyright Gennadiy Rozental 2001. +// Distributed under 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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : runtime parameters initialization final step +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_FINALIZE_HPP +#define BOOST_TEST_UTILS_RUNTIME_FINALIZE_HPP + +// Boost.Test Runtime parameters +#include <boost/test/utils/runtime/parameter.hpp> +#include <boost/test/utils/runtime/argument.hpp> + +// Boost.Test +#include <boost/test/utils/foreach.hpp> + +#include <boost/test/detail/suppress_warnings.hpp> + +namespace boost { +namespace runtime { + +inline void +finalize_arguments( parameters_store const& params, runtime::arguments_store& args ) +{ + BOOST_TEST_FOREACH( parameters_store::storage_type::value_type const&, v, params.all() ) { + basic_param_ptr param = v.second; + + if( !args.has( param->p_name ) ) { + if( param->p_has_default_value ) + param->produce_default( args ); + + if( !args.has( param->p_name ) ) { + BOOST_TEST_I_ASSRT( param->p_optional, + missing_req_arg( param->p_name ) << "Missing argument for required parameter " << param->p_name << "." ); + } + } + + if( args.has( param->p_name ) && !!param->p_callback ) + param->p_callback( param->p_name ); + } +} + +} // namespace runtime +} // namespace boost + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_UTILS_RUNTIME_FINALIZE_HPP diff --git a/src/third_party/boost-1.60.0/boost/test/utils/runtime/fwd.hpp b/src/third_party/boost-1.60.0/boost/test/utils/runtime/fwd.hpp new file mode 100644 index 00000000000..17ae8812226 --- /dev/null +++ b/src/third_party/boost-1.60.0/boost/test/utils/runtime/fwd.hpp @@ -0,0 +1,45 @@ +// (C) Copyright Gennadiy Rozental 2001. +// Distributed under 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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : runtime parameters forward declaration +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_FWD_HPP +#define BOOST_TEST_UTILS_RUNTIME_FWD_HPP + +// Boost.Test +#include <boost/test/detail/config.hpp> +#include <boost/test/utils/basic_cstring/basic_cstring.hpp> +#include <boost/test/utils/basic_cstring/io.hpp> // operator<<(boost::runtime::cstring) + +// Boost +#include <boost/shared_ptr.hpp> + +// STL +#include <map> + +namespace boost { +namespace runtime { + +typedef unit_test::const_string cstring; + +class argument; +typedef shared_ptr<argument> argument_ptr; + +template<typename T> class typed_argument; + +class basic_param; +typedef shared_ptr<basic_param> basic_param_ptr; + +} // namespace runtime +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_FWD_HPP diff --git a/src/third_party/boost-1.60.0/boost/test/utils/runtime/modifier.hpp b/src/third_party/boost-1.60.0/boost/test/utils/runtime/modifier.hpp new file mode 100644 index 00000000000..ed77ca0afe5 --- /dev/null +++ b/src/third_party/boost-1.60.0/boost/test/utils/runtime/modifier.hpp @@ -0,0 +1,101 @@ +// (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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : parameter modifiers +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_MODIFIER_HPP +#define BOOST_TEST_UTILS_RUNTIME_MODIFIER_HPP + +// Boost.Test Runtime parameters +#include <boost/test/utils/runtime/fwd.hpp> + +// Boost.Test +#include <boost/test/utils/named_params.hpp> + +#include <boost/test/detail/suppress_warnings.hpp> + +namespace boost { +namespace runtime { + +// ************************************************************************** // +// ************** environment variable modifiers ************** // +// ************************************************************************** // + +namespace { + +#if !defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) && !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) +#define BOOST_TEST_CLA_NEW_API +#endif + +#ifdef BOOST_TEST_CLA_NEW_API +auto const& description = unit_test::static_constant<nfp::typed_keyword<cstring,struct description_t>>::value; +auto const& help = unit_test::static_constant<nfp::typed_keyword<cstring,struct help_t>>::value; +auto const& env_var = unit_test::static_constant<nfp::typed_keyword<cstring,struct env_var_t>>::value; +auto const& end_of_params = unit_test::static_constant<nfp::typed_keyword<cstring,struct end_of_params_t>>::value; +auto const& negation_prefix = unit_test::static_constant<nfp::typed_keyword<cstring,struct neg_prefix_t>>::value; +auto const& value_hint = unit_test::static_constant<nfp::typed_keyword<cstring,struct value_hint_t>>::value; +auto const& optional_value = unit_test::static_constant<nfp::keyword<struct optional_value_t>>::value; +auto const& default_value = unit_test::static_constant<nfp::keyword<struct default_value_t>>::value; +auto const& callback = unit_test::static_constant<nfp::keyword<struct callback_t>>::value; + +template<typename EnumType> +using enum_values = unit_test::static_constant< + nfp::typed_keyword<std::initializer_list<std::pair<const cstring,EnumType>>, struct enum_values_t> +>; + +#else + +nfp::typed_keyword<cstring,struct description_t> description; +nfp::typed_keyword<cstring,struct help_t> help; +nfp::typed_keyword<cstring,struct env_var_t> env_var; +nfp::typed_keyword<cstring,struct end_of_params_t> end_of_params; +nfp::typed_keyword<cstring,struct neg_prefix_t> negation_prefix; +nfp::typed_keyword<cstring,struct value_hint_t> value_hint; +nfp::keyword<struct optional_value_t> optional_value; +nfp::keyword<struct default_value_t> default_value; +nfp::keyword<struct callback_t> callback; + +template<typename EnumType> +struct enum_values_list { + typedef std::pair<cstring,EnumType> ElemT; + typedef std::vector<ElemT> ValuesT; + + enum_values_list const& + operator()( cstring k, EnumType v ) const + { + const_cast<enum_values_list*>(this)->m_values.push_back( ElemT( k, v ) ); + + return *this; + } + + operator ValuesT const&() const { return m_values; } + +private: + ValuesT m_values; +}; + +template<typename EnumType> +struct enum_values : unit_test::static_constant< + nfp::typed_keyword<enum_values_list<EnumType>, struct enum_values_t> > +{ +}; + +#endif + +} // local namespace + +} // namespace runtime +} // namespace boost + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_UTILS_RUNTIME_MODIFIER_HPP diff --git a/src/third_party/boost-1.60.0/boost/test/utils/runtime/parameter.hpp b/src/third_party/boost-1.60.0/boost/test/utils/runtime/parameter.hpp new file mode 100644 index 00000000000..c1986884938 --- /dev/null +++ b/src/third_party/boost-1.60.0/boost/test/utils/runtime/parameter.hpp @@ -0,0 +1,472 @@ +// (C) Copyright Gennadiy Rozental 2001. +// Distributed under 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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : formal parameter definition +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAMETER_HPP +#define BOOST_TEST_UTILS_RUNTIME_PARAMETER_HPP + +// Boost.Test Runtime parameters +#include <boost/test/utils/runtime/fwd.hpp> +#include <boost/test/utils/runtime/modifier.hpp> +#include <boost/test/utils/runtime/argument.hpp> +#include <boost/test/utils/runtime/argument_factory.hpp> + +// Boost.Test +#include <boost/test/utils/class_properties.hpp> +#include <boost/test/utils/foreach.hpp> + +// Boost +#include <boost/function/function2.hpp> +#include <boost/algorithm/cxx11/all_of.hpp> + +// STL +#include <algorithm> + +#include <boost/test/detail/suppress_warnings.hpp> + +namespace boost { +namespace runtime { + +// ************************************************************************** // +// ************** runtime::parameter_cla_id ************** // +// ************************************************************************** // +// set of attributes identifying the parameter in the command line + +struct parameter_cla_id { + parameter_cla_id( cstring prefix, cstring tag, cstring value_separator, bool negatable ) + : m_prefix( prefix.begin(), prefix.size() ) + , m_tag( tag.begin(), tag.size() ) + , m_value_separator( value_separator.begin(), value_separator.size() ) + , m_negatable( negatable ) + { + + BOOST_TEST_I_ASSRT( algorithm::all_of( m_prefix.begin(), m_prefix.end(), valid_prefix_char ), + invalid_cla_id() << "Parameter " << m_tag + << " has invalid characters in prefix." ); + + BOOST_TEST_I_ASSRT( algorithm::all_of( m_tag.begin(), m_tag.end(), valid_name_char ), + invalid_cla_id() << "Parameter " << m_tag + << " has invalid characters in name." ); + + BOOST_TEST_I_ASSRT( algorithm::all_of( m_value_separator.begin(), m_value_separator.end(), valid_separator_char ), + invalid_cla_id() << "Parameter " << m_tag + << " has invalid characters in value separator." ); + } + + static bool valid_prefix_char( char c ) + { + return c == '-' || c == '/' ; + } + static bool valid_separator_char( char c ) + { + return c == '=' || c == ':' || c == ' ' || c == '\0'; + } + static bool valid_name_char( char c ) + { + return std::isalnum( c ) || c == '+' || c == '_' || c == '?'; + } + + std::string m_prefix; + std::string m_tag; + std::string m_value_separator; + bool m_negatable; +}; + +typedef std::vector<parameter_cla_id> param_cla_ids; + +// ************************************************************************** // +// ************** runtime::basic_param ************** // +// ************************************************************************** // + +cstring const help_prefix("////"); + +class basic_param { + typedef function<void (cstring)> callback_type; + typedef unit_test::readwrite_property<bool> bool_property; + +protected: + /// Constructor with modifiers + template<typename Modifiers> + basic_param( cstring name, bool is_optional, bool is_repeatable, Modifiers const& m ) + : p_name( name.begin(), name.end() ) + , p_description( nfp::opt_get( m, description, std::string() ) ) + , p_help( nfp::opt_get( m, runtime::help, std::string() ) ) + , p_env_var( nfp::opt_get( m, env_var, std::string() ) ) + , p_value_hint( nfp::opt_get( m, value_hint, std::string() ) ) + , p_optional( is_optional ) + , p_repeatable( is_repeatable ) + , p_has_optional_value( m.has( optional_value ) ) + , p_has_default_value( m.has( default_value ) || is_repeatable ) + , p_callback( nfp::opt_get( m, callback, callback_type() ) ) + { + add_cla_id( help_prefix, name, ":" ); + } + +public: + virtual ~basic_param() {} + + // Pubic properties + std::string const p_name; + std::string const p_description; + std::string const p_help; + std::string const p_env_var; + std::string const p_value_hint; + bool const p_optional; + bool const p_repeatable; + bool_property p_has_optional_value; + bool_property p_has_default_value; + callback_type const p_callback; + + /// interface for cloning typed parameters + virtual basic_param_ptr clone() const = 0; + + /// Access methods + param_cla_ids const& cla_ids() const { return m_cla_ids; } + void add_cla_id( cstring prefix, cstring tag, cstring value_separator ) + { + add_cla_id_impl( prefix, tag, value_separator, false, true ); + } + + /// interface for producing argument values for this parameter + virtual void produce_argument( cstring token, bool negative_form, arguments_store& store ) const = 0; + virtual void produce_default( arguments_store& store ) const = 0; + + /// interfaces for help message reporting + virtual void usage( std::ostream& ostr, cstring negation_prefix_ ) + { + ostr << "Parameter: " << p_name << '\n'; + if( !p_description.empty() ) + ostr << ' ' << p_description << '\n'; + + ostr << " Command line formats:\n"; + BOOST_TEST_FOREACH( parameter_cla_id const&, id, cla_ids() ) { + if( id.m_prefix == help_prefix ) + continue; + + ostr << " " << id.m_prefix; + if( id.m_negatable ) + cla_name_help( ostr, id.m_tag, negation_prefix_ ); + else + cla_name_help( ostr, id.m_tag, "" ); + + bool optional_value_ = false; + + if( p_has_optional_value ) { + optional_value_ = true; + ostr << '['; + } + + if( id.m_value_separator.empty() ) + ostr << ' '; + else { + ostr << id.m_value_separator; + } + + value_help( ostr ); + + if( optional_value_ ) + ostr << ']'; + + ostr << '\n'; + } + if( !p_env_var.empty() ) + ostr << " Environment variable: " << p_env_var << '\n'; + } + + virtual void help( std::ostream& ostr, cstring negation_prefix_ ) + { + usage( ostr, negation_prefix_ ); + + if( !p_help.empty() ) + ostr << '\n' << p_help << '\n'; + } + +protected: + void add_cla_id_impl( cstring prefix, + cstring tag, + cstring value_separator, + bool negatable, + bool validate_value_separator ) + { + BOOST_TEST_I_ASSRT( !tag.is_empty(), + invalid_cla_id() << "Parameter can't have an empty name." ); + + BOOST_TEST_I_ASSRT( !prefix.is_empty(), + invalid_cla_id() << "Parameter " << tag + << " can't have an empty prefix." ); + + BOOST_TEST_I_ASSRT( !value_separator.is_empty(), + invalid_cla_id() << "Parameter " << tag + << " can't have an empty value separator." ); + + // We trim value separator from all the spaces, so token end will indicate separator + value_separator.trim(); + BOOST_TEST_I_ASSRT( !validate_value_separator || !value_separator.is_empty() || !p_has_optional_value, + invalid_cla_id() << "Parameter " << tag + << " with optional value attribute can't use space as value separator." ); + + m_cla_ids.push_back( parameter_cla_id( prefix, tag, value_separator, negatable ) ); + } + +private: + /// interface for usage/help customization + virtual void cla_name_help( std::ostream& ostr, cstring cla_tag, cstring negation_prefix_ ) const + { + ostr << cla_tag; + } + virtual void value_help( std::ostream& ostr ) const + { + if( p_value_hint.empty() ) + ostr << "<value>"; + else + ostr << p_value_hint; + } + + // Data members + param_cla_ids m_cla_ids; +}; + +// ************************************************************************** // +// ************** runtime::parameter ************** // +// ************************************************************************** // + +enum args_amount { + OPTIONAL_PARAM, // 0-1 + REQUIRED_PARAM, // exactly 1 + REPEATABLE_PARAM // 0-N +}; + +//____________________________________________________________________________// + +template<typename ValueType, args_amount a = runtime::OPTIONAL_PARAM, bool is_enum = false> +class parameter : public basic_param { +public: + /// Constructor with modifiers +#ifndef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS + template<typename Modifiers=nfp::no_params_type> + parameter( cstring name, Modifiers const& m = nfp::no_params ) +#else + template<typename Modifiers> + parameter( cstring name, Modifiers const& m ) +#endif + : basic_param( name, a != runtime::REQUIRED_PARAM, a == runtime::REPEATABLE_PARAM, m ) + , m_arg_factory( m ) + { + BOOST_TEST_I_ASSRT( !m.has( default_value ) || a == runtime::OPTIONAL_PARAM, + invalid_param_spec() << "Parameter " << name + << " is not optional and can't have default_value." ); + + BOOST_TEST_I_ASSRT( !m.has( optional_value ) || !this->p_repeatable, + invalid_param_spec() << "Parameter " << name + << " is repeatable and can't have optional_value." ); + } + +private: + virtual basic_param_ptr clone() const + { + return basic_param_ptr( new parameter( *this ) ); + } + virtual void produce_argument( cstring token, bool , arguments_store& store ) const + { + m_arg_factory.produce_argument( token, this->p_name, store ); + } + virtual void produce_default( arguments_store& store ) const + { + if( !this->p_has_default_value ) + return; + + m_arg_factory.produce_default( this->p_name, store ); + } + + // Data members + typedef argument_factory<ValueType, is_enum, a == runtime::REPEATABLE_PARAM> factory_t; + factory_t m_arg_factory; +}; + +//____________________________________________________________________________// + +class option : public basic_param { +public: + /// Constructor with modifiers +#ifndef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS + template<typename Modifiers=nfp::no_params_type> + option( cstring name, Modifiers const& m = nfp::no_params ) +#else + template<typename Modifiers> + option( cstring name, Modifiers const& m ) +#endif + : basic_param( name, true, false, nfp::opt_append( nfp::opt_append( m, optional_value = true), default_value = false) ) + , m_arg_factory( nfp::opt_append( nfp::opt_append( m, optional_value = true), default_value = false) ) + { + } + + void add_cla_id( cstring prefix, cstring tag, cstring value_separator, bool negatable = false ) + { + add_cla_id_impl( prefix, tag, value_separator, negatable, false ); + } + +private: + virtual basic_param_ptr clone() const + { + return basic_param_ptr( new option( *this ) ); + } + + virtual void produce_argument( cstring token, bool negative_form, arguments_store& store ) const + { + if( token.empty() ) + store.set( p_name, !negative_form ); + else { + BOOST_TEST_I_ASSRT( !negative_form, + format_error( p_name ) << "Can't set value to negative form of the argument." ); + + m_arg_factory.produce_argument( token, p_name, store ); + } + } + + virtual void produce_default( arguments_store& store ) const + { + m_arg_factory.produce_default( p_name, store ); + } + virtual void cla_name_help( std::ostream& ostr, cstring cla_tag, cstring negation_prefix_ ) const + { + if( negation_prefix_.is_empty() ) + ostr << cla_tag; + else + ostr << '[' << negation_prefix_ << ']' << cla_tag; + } + virtual void value_help( std::ostream& ostr ) const + { + if( p_value_hint.empty() ) + ostr << "<boolean value>"; + else + ostr << p_value_hint; + } + + // Data members + typedef argument_factory<bool, false, false> factory_t; + factory_t m_arg_factory; +}; + +//____________________________________________________________________________// + +template<typename EnumType, args_amount a = runtime::OPTIONAL_PARAM> +class enum_parameter : public parameter<EnumType, a, true> { + typedef parameter<EnumType, a, true> base; +public: + /// Constructor with modifiers +#ifndef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS + template<typename Modifiers=nfp::no_params_type> + enum_parameter( cstring name, Modifiers const& m = nfp::no_params ) +#else + template<typename Modifiers> + enum_parameter( cstring name, Modifiers const& m ) +#endif + : base( name, m ) + { +#ifdef BOOST_TEST_CLA_NEW_API + auto const& values = m[enum_values<EnumType>::value]; + auto it = values.begin(); +#else + std::vector<std::pair<cstring, EnumType> > const& values = m[enum_values<EnumType>::value]; + typename std::vector<std::pair<cstring, EnumType> >::const_iterator it = values.begin(); +#endif + while( it != values.end() ) { + m_valid_names.push_back( it->first ); + ++it; + } + } + +private: + virtual basic_param_ptr clone() const + { + return basic_param_ptr( new enum_parameter( *this ) ); + } + + virtual void value_help( std::ostream& ostr ) const + { + if( this->p_value_hint.empty() ) { + ostr << "<"; + bool first = true; + BOOST_TEST_FOREACH( cstring, name, m_valid_names ) { + if( first ) + first = false; + else + ostr << '|'; + ostr << name; + } + ostr << ">"; + } + else + ostr << this->p_value_hint; + } + + // Data members + std::vector<cstring> m_valid_names; +}; + + +// ************************************************************************** // +// ************** runtime::parameters_store ************** // +// ************************************************************************** // + +class parameters_store { + struct lg_compare { + bool operator()( cstring lh, cstring rh ) const + { + return std::lexicographical_compare(lh.begin(), lh.end(), + rh.begin(), rh.end()); + } + }; +public: + + typedef std::map<cstring, basic_param_ptr, lg_compare> storage_type; + + /// Adds parameter into the persistent store + void add( basic_param const& in ) + { + basic_param_ptr p = in.clone(); + + BOOST_TEST_I_ASSRT( m_parameters.insert( std::make_pair( cstring(p->p_name), p ) ).second, + duplicate_param() << "Parameter " << p->p_name << " is duplicate." ); + } + + /// Returns true if there is no parameters registered + bool is_empty() const { return m_parameters.empty(); } + /// Returns map of all the registered parameter + storage_type const& all() const { return m_parameters; } + /// Returns true if parameter with psecified name is registered + bool has( cstring name ) const + { + return m_parameters.find( name ) != m_parameters.end(); + } + /// Returns map of all the registered parameter + basic_param_ptr get( cstring name ) const + { + storage_type::const_iterator const& found = m_parameters.find( name ); + BOOST_TEST_I_ASSRT( found != m_parameters.end(), + unknown_param() << "Parameter " << name << " is unknown." ); + + return found->second; + } + +private: + // Data members + storage_type m_parameters; +}; + +} // namespace runtime +} // namespace boost + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_UTILS_RUNTIME_PARAMETER_HPP |