BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslfmt_mockparsecontext.h
Go to the documentation of this file.
1/// @file bslfmt_mockparsecontext.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslfmt_mockparsecontext.h -*-C++-*-
8
9#ifndef INCLUDED_BSLFMT_MOCKPARSECONTEXT
10#define INCLUDED_BSLFMT_MOCKPARSECONTEXT
11
12#include <bsls_ident.h>
13BSLS_IDENT("$Id: $")
14
15/// @defgroup bslfmt_mockparsecontext bslfmt_mockparsecontext
16/// @brief Provide mock context to test formatter specializations
17/// @addtogroup bsl
18/// @{
19/// @addtogroup bslfmt
20/// @{
21/// @addtogroup bslfmt_mockparsecontext
22/// @{
23///
24/// <h1> Outline </h1>
25/// * <a href="#bslfmt_mockparsecontext-purpose"> Purpose</a>
26/// * <a href="#bslfmt_mockparsecontext-classes"> Classes </a>
27/// * <a href="#bslfmt_mockparsecontext-description"> Description </a>
28/// * <a href="#bslfmt_mockparsecontext-usage"> Usage </a>
29/// * <a href="#bslfmt_mockparsecontext-example-1-testing-formatter-s-parse-method"> Example 1: Testing Formatter's parse Method </a>
30///
31/// # Purpose {#bslfmt_mockparsecontext-purpose}
32/// Provide mock context to test formatter specializations
33///
34/// # Classes {#bslfmt_mockparsecontext-classes}
35///
36/// - MockParseContext: parsing context for use in formatter tests
37///
38/// # Description {#bslfmt_mockparsecontext-description}
39/// This component provides a class that holds the format string
40/// parsing state and is used for formatter testing.
41///
42/// ## Usage {#bslfmt_mockparsecontext-usage}
43///
44///
45/// This section illustrates intended usage of this component.
46///
47/// ### Example 1: Testing Formatter's parse Method {#bslfmt_mockparsecontext-example-1-testing-formatter-s-parse-method}
48///
49///
50/// Suppose we have a formatter for our custom type representing a month and we
51/// want to test it. The following example demonstrates how we can test its
52/// `parse` method using `bslfmt::MockParseContext`.
53///
54/// First, we define our `Month` class:
55/// @code
56/// /// This class implements a complex-constrained, value-semantic type for
57/// /// representing months.
58/// class Month {
59/// private:
60/// // DATA
61/// int d_index; // month's index
62///
63/// public:
64/// // CREATORS
65///
66/// /// Create an object having the value represented by the specified
67/// /// `index`.
68/// Month(int index)
69/// : d_index(index)
70/// {
71/// assert((1 <= index) && (12 >= index));
72/// }
73///
74/// // ACCESSORS
75///
76/// /// Return the index of this month.
77/// int index() const { return d_index; }
78/// };
79/// @endcode
80/// Then, we define our custom formatter for this class. In it, two methods are
81/// necessary: `parse` and `format`. The `parse` method parses the format
82/// string itself to determine the formatting to be used by the `format` method,
83/// which writes the formatted object into user-supplied output iterator.
84/// @code
85/// /// This struct is a base class for `bsl::formatter` specializations for
86/// /// the `Month` class.
87/// template <class t_CHAR>
88/// struct MonthFormatter {
89/// @endcode
90/// The convenience of using the `bsl::format` function is that the users can
91/// come up with the description language themselves. In our case, for
92/// simplicity, we will present month in two formats - numeric ("03") and verbal
93/// ("March"). Accordingly, to indicate the desired type, we will use one of
94/// the two letters in the format description: 'n' ('N') or 'v' ('V').
95/// Additionally, user can specify minimal width of the output either string via
96/// digit in the format specification or via additional parameter for
97/// `bsl::format` function.
98/// @code
99/// // TYPES
100/// enum Format {
101/// e_NUMERIC, // "03"
102/// e_VERBAL // "March"
103/// };
104///
105/// typedef bslfmt::FormatterSpecificationNumericValue NumericValue;
106///
107/// // DATA
108/// Format d_format; // output format
109/// NumericValue d_rawWidth; // minimal output width
110///
111/// public:
112/// // CREATORS
113///
114/// /// Create a formatter that outputs values in the `e_NUMERIC` format.
115/// /// Thus, numeric is the default format for the `Month` object.
116/// BSLS_KEYWORD_CONSTEXPR_CPP20 MonthFormatter()
117/// : d_format(e_NUMERIC)
118/// {
119/// }
120///
121/// // MANIPULATORS
122///
123/// /// Parse the specified `context` and return end iterator of parsed
124/// /// range.
125/// template <class t_PARSE_CONTEXT>
126/// BSLS_KEYWORD_CONSTEXPR_CPP20 typename t_PARSE_CONTEXT::iterator parse(
127/// t_PARSE_CONTEXT& context)
128/// {
129/// @endcode
130/// `MockParseContext` completely repeats the interface and behavior of the
131/// `bslfmt::basic_format_parse_context`, but provides an additional accessor
132/// that allows users to get information about the parsing process. Therefore
133/// users do not need to declare a separate overload of `parse` for test
134/// purposes as long as their formatter's `parse` method is templated.
135/// @code
136/// typename t_PARSE_CONTEXT::const_iterator current = context.begin();
137/// typename t_PARSE_CONTEXT::const_iterator end = context.end();
138///
139/// // Handling empty string or empty specification
140/// if (current == end || *current == '}') {
141/// return context.begin(); // RETURN
142/// }
143///
144/// d_rawWidth.parse(&current, end, false);
145/// // Non-relative widths must be strictly positive.
146/// if (d_rawWidth == NumericValue(NumericValue::e_VALUE, 0)) {
147/// BSLS_THROW(bsl::format_error("Field widths must be > 0."));
148/// }
149///
150/// if (d_rawWidth.category() == NumericValue::e_ARG_ID) {
151/// context.check_arg_id(d_rawWidth.value());
152/// }
153/// else if (d_rawWidth.category() == NumericValue::e_NEXT_ARG) {
154/// d_rawWidth = NumericValue(
155/// NumericValue::e_ARG_ID,
156/// static_cast<int>(context.next_arg_id()));
157/// }
158///
159/// if (current == end || *current == '}') {
160/// return context.begin(); // RETURN
161/// }
162///
163/// // Reading format specification
164/// switch (*current) {
165/// case 'V':
166/// case 'v': {
167/// d_format = e_VERBAL;
168/// } break;
169/// case 'N':
170/// case 'n': {
171/// // `e_NUMERIC` value is assigned at object construction
172/// } break;
173/// default: {
174/// BSLS_THROW(bsl::format_error(
175/// "Unexpected symbol in format specification")); // THROW
176/// }
177/// }
178///
179/// // Move the iterator to the next position and check that there are
180/// // no extra characters in the description.
181///
182/// ++current;
183///
184/// if (current != end && *current != '}') {
185/// BSLS_THROW(bsl::format_error(
186/// "Too many symbols in format specification")); // THROW
187/// }
188///
189/// context.advance_to(current);
190/// return context.begin();
191/// }
192/// @endcode
193/// To reduce the size of this example, we will omit the implementation of the
194/// `format` method as it is not essential for our purposes.
195/// @code
196/// };
197/// @endcode
198/// Finally, we can test the operation of the `parse` function for different
199/// input specifications:
200/// @code
201/// typedef bslfmt::MockParseContext<char> Context;
202/// typedef Context::iterator ContextIterator;
203///
204/// {
205/// MonthFormatter<char> formatter;
206/// Context context("v");
207///
208/// ContextIterator iterator = formatter.parse(context);
209///
210/// assert(context.end() == iterator);
211/// @endcode
212/// Since width is not presented in the format specification, we don't expect
213/// our context to change its indexing mode.
214/// @code
215/// assert(Context::e_UNKNOWN == context.indexingMode());
216/// }
217/// {
218/// MonthFormatter<char> formatter;
219/// Context context("8v");
220///
221/// ContextIterator iterator = formatter.parse(context);
222///
223/// assert(context.end() == iterator);
224/// assert(Context::e_UNKNOWN == context.indexingMode());
225/// }
226/// {
227/// MonthFormatter<char> formatter;
228/// Context context("{}v", 1);
229///
230/// ContextIterator iterator = formatter.parse(context);
231///
232/// assert(context.end() == iterator);
233/// @endcode
234/// And here it is assumed that the width will be determined by the next
235/// parameter of the `bsl::format` function. The indexing mode of the context
236/// changes accordingly.
237/// @code
238/// assert(Context::e_AUTOMATIC == context.indexingMode());
239/// }
240/// {
241/// MonthFormatter<char> formatter;
242/// Context context("{1}v", 2);
243///
244/// ContextIterator iterator = formatter.parse(context);
245///
246/// assert(context.end() == iterator);
247/// @endcode
248/// Here we explicitly indicate the ordinal number of the `bsl::format`
249/// parameter storing the width value.
250/// @code
251/// assert(Context::e_MANUAL == context.indexingMode());
252/// }
253///
254/// @endcode
255/// @}
256/** @} */
257/** @} */
258
259/** @addtogroup bsl
260 * @{
261 */
262/** @addtogroup bslfmt
263 * @{
264 */
265/** @addtogroup bslfmt_mockparsecontext
266 * @{
267 */
268
269#include <bslscm_version.h>
270
271#include <bslfmt_formaterror.h>
272
273#include <bsls_exceptionutil.h>
274#include <bsls_keyword.h>
275
276#include <bslstl_array.h>
277#include <bslstl_stringview.h>
278
279
280namespace bslfmt {
281
282 // ======================
283 // class MockParseContext
284 // ======================
285
286/// This class template provides an access to the format specification current
287/// parsing state.
288///
289/// See @ref bslfmt_mockparsecontext
290template <class t_CHAR>
292
293 public:
294 // TYPES
295 typedef
298
299 /// Argument indexing mode
301 e_UNKNOWN, // default mode
302 e_MANUAL, // manual mode
303 e_AUTOMATIC // automatic mode
304 };
305
306 private:
307 // DATA
308 iterator d_begin; // beginning of the format spec
309 iterator d_end; // end of the format spec
310 IndexingMode d_indexingMode; // current indexing mode
311 size_t d_next_arg_id; // argument index
312 size_t d_num_args; // number of arguments
313
314 private:
315 // NOT IMPLEMENTED
318
319 public:
320 // TYPES
321 typedef t_CHAR char_type;
322
323 // CREATORS
324 /// Create an object having the specified `fmt` as a format specification
325 /// and the specified `numArgs`.
328 size_t numArgs = 0) BSLS_KEYWORD_NOEXCEPT;
329
330 // MANIPULATORS
331
332 /// Update the held iterator to the unparsed portion of the format string
333 /// to be the specified `it`. Subsequent calls to `begin` will return this
334 /// value.
336
337 /// Enter automatic indexing mode and return the next argument index.
338 /// Throw `bslfmt::format_error` if this object has already entered manual
339 /// indexing mode.
341
342 /// Check whether the specified `id` is in range of number of arguments and
343 /// enter manual indexing mode. Throw `bslfmt::format_error` if this
344 /// object has already entered automatic indexing mode.
346
347 // ACCESSORS
348
349 /// Return an iterator to the beginning of the format specification.
352
353 /// Return an iterator to the end of the format specification.
356
357 /// Return the current indexing mode.
360};
361
362// ============================================================================
363// INLINE DEFINITIONS
364// ============================================================================
365
366 // ----------------------
367 // class MockParseContext
368 // ----------------------
369
370// CREATORS
371template <class t_CHAR>
374 bsl::basic_string_view<t_CHAR> fmt,
375 size_t numArgs) BSLS_KEYWORD_NOEXCEPT
376: d_begin(fmt.begin())
377, d_end(fmt.end())
378, d_indexingMode(e_UNKNOWN)
379, d_next_arg_id(0)
380, d_num_args(numArgs)
381{
382}
383
384// MANIPULATORS
385template <class t_CHAR>
391
392template <class t_CHAR>
395{
396 if (e_MANUAL == d_indexingMode) {
397 BSLS_THROW(format_error("mixing of automatic and manual indexing"));
398 }
399 if (d_next_arg_id >= d_num_args) {
400 BSLS_THROW(format_error("number of conversion specifiers exceeds "
401 "number of arguments"));
402 }
403 if (e_UNKNOWN == d_indexingMode) {
404 d_indexingMode = e_AUTOMATIC;
405 }
406 return d_next_arg_id++;
407}
408
409template <class t_CHAR>
412{
413 if (e_AUTOMATIC == d_indexingMode) {
414 BSLS_THROW(format_error("mixing of automatic and manual indexing"));
415 }
416 if (id >= d_num_args) {
417 BSLS_THROW(format_error("invalid argument index"));
418 }
419 if (e_UNKNOWN == d_indexingMode) {
420 d_indexingMode = e_MANUAL;
421 }
422}
423
424// ACCESSORS
425template <class t_CHAR>
429{
430 return d_begin;
431}
432
433template <class t_CHAR>
437{
438 return d_end;
439}
440
441template <class t_CHAR>
445{
446 return d_indexingMode;
447}
448
449} // close package namespace
450
451
452
453#endif // INCLUDED_BSLFMT_MOCKPARSECONTEXT
454
455// ----------------------------------------------------------------------------
456// Copyright 2024 Bloomberg Finance L.P.
457//
458// Licensed under the Apache License, Version 2.0 (the "License");
459// you may not use this file except in compliance with the License.
460// You may obtain a copy of the License at
461//
462// http://www.apache.org/licenses/LICENSE-2.0
463//
464// Unless required by applicable law or agreed to in writing, software
465// distributed under the License is distributed on an "AS IS" BASIS,
466// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
467// See the License for the specific language governing permissions and
468// limitations under the License.
469// ----------------------------- END-OF-FILE ----------------------------------
470
471
472/** @} */
473/** @} */
474/** @} */
Definition bslstl_stringview.h:471
const value_type * const_iterator
Definition bslstl_stringview.h:481
Definition bslfmt_mockparsecontext.h:291
BSLS_KEYWORD_CONSTEXPR_CPP20 size_t next_arg_id()
Definition bslfmt_mockparsecontext.h:394
BSLS_KEYWORD_CONSTEXPR_CPP20 const_iterator end() const BSLS_KEYWORD_NOEXCEPT
Return an iterator to the end of the format specification.
Definition bslfmt_mockparsecontext.h:436
BSLS_KEYWORD_CONSTEXPR_CPP20 const_iterator begin() const BSLS_KEYWORD_NOEXCEPT
Return an iterator to the beginning of the format specification.
Definition bslfmt_mockparsecontext.h:428
t_CHAR char_type
Definition bslfmt_mockparsecontext.h:321
IndexingMode
Argument indexing mode.
Definition bslfmt_mockparsecontext.h:300
@ e_UNKNOWN
Definition bslfmt_mockparsecontext.h:301
@ e_MANUAL
Definition bslfmt_mockparsecontext.h:302
@ e_AUTOMATIC
Definition bslfmt_mockparsecontext.h:303
BSLS_KEYWORD_CONSTEXPR_CPP20 void check_arg_id(size_t id)
Definition bslfmt_mockparsecontext.h:411
BSLS_KEYWORD_CONSTEXPR_CPP20 IndexingMode indexingMode() const BSLS_KEYWORD_NOEXCEPT
Return the current indexing mode.
Definition bslfmt_mockparsecontext.h:444
const_iterator iterator
Definition bslfmt_mockparsecontext.h:297
BSLS_KEYWORD_CONSTEXPR_CPP20 void advance_to(const_iterator it)
Definition bslfmt_mockparsecontext.h:387
bsl::basic_string_view< t_CHAR >::const_iterator const_iterator
Definition bslfmt_mockparsecontext.h:296
Definition bslfmt_formaterror.h:118
#define BSLS_THROW(X)
Definition bsls_exceptionutil.h:374
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_CONSTEXPR_CPP20
Definition bsls_keyword.h:645
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:651
#define BSLS_KEYWORD_NOEXCEPT
Definition bsls_keyword.h:674
Definition bdlat_valuetypefunctions.h:939
Definition bslfmt_enablestreamedformatter.h:130