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