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