BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslim_testutil.h
Go to the documentation of this file.
1/// @file bslim_testutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslim_testutil.h -*-C++-*-
8#ifndef INCLUDED_BSLIM_TESTUTIL
9#define INCLUDED_BSLIM_TESTUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslim_testutil bslim_testutil
15/// @brief Provide test utilities for components above `bsl`.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslim
19/// @{
20/// @addtogroup bslim_testutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslim_testutil-purpose"> Purpose</a>
25/// * <a href="#bslim_testutil-classes"> Classes </a>
26/// * <a href="#bslim_testutil-macros"> Macros </a>
27/// * <a href="#bslim_testutil-description"> Description </a>
28/// * <a href="#bslim_testutil-usage"> Usage </a>
29/// * <a href="#bslim_testutil-example-1-writing-a-test-driver"> Example 1: Writing a Test Driver </a>
30///
31/// # Purpose {#bslim_testutil-purpose}
32/// Provide test utilities for components above `bsl`.
33///
34/// # Classes {#bslim_testutil-classes}
35///
36///
37/// # Macros {#bslim_testutil-macros}
38///
39/// - BSLIM_TESTUTIL_ASSERT(X): record and print error if `!X`
40/// - BSLIM_TESTUTIL_LOOP_ASSERT(I, X): print arguments if `!X`
41/// - BSLIM_TESTUTIL_LOOP2_ASSERT(I, J, X): print arguments if `!X`
42/// - BSLIM_TESTUTIL_LOOP3_ASSERT(I, J, K, X): print arguments if `!X`
43/// - BSLIM_TESTUTIL_LOOP4_ASSERT(I, J, K, L, X): print arguments if `!X`
44/// - BSLIM_TESTUTIL_LOOP5_ASSERT(I, J, K, L, M, X): print arguments if `!X`
45/// - BSLIM_TESTUTIL_LOOP6_ASSERT(I, J, K, L, M, N, X): print arguments if `!X`
46/// - BSLIM_TESTUTIL_LOOP7_ASSERT(I, J, K, L, M, N,O, X): print arguments if `!X`
47/// - BSLIM_TESTUTIL_LOOP8_ASSERT(I, J, K, L,M,N,O,V, X): print arguments if `!X`
48/// - BSLIM_TESTUTIL_ASSERTV(..., X): print generic arguments if `!X`
49/// - BSLIM_TESTUTIL_Q(X): quote identifier literally
50/// - BSLIM_TESTUTIL_P(X): print identifier and value
51/// - BSLIM_TESTUTIL_P_(X): print identifier and value without '\n'
52/// - BSLIM_TESTUTIL_L_: current line number
53/// - BSLIM_TESTUTIL_T_: print tab without '\n'
54///
55/// @see bsls_bsltestutil
56///
57/// # Description {#bslim_testutil-description}
58/// This component provides the standard print macros used in
59/// BDE-style test drivers (`ASSERT`, `LOOP_ASSERT`, `ASSERTV`, `P`, `Q`, `L`,
60/// and `T`) for components above the `bsl` package group.
61///
62/// This component also defines a set of overloads for the insertion operator
63/// (`<<`) to support the streaming of test types defined in the `bsltf`
64/// package. These overloads are required for test drivers above the `bsl`
65/// package group in order to print objects of the `bsltf` types to `bsl::cout`.
66///
67/// This component also defines a pair of methods, `setFunc` and `callFunc`,
68/// that allow a test driver to set and call a function by going through another
69/// compilation unit to preclude the optimizer from inlining the function call.
70///
71/// Note that the 'bsltf' package resides below 'bsl+bslhdrs', in which
72/// 'bsl::cout' is defined; therefore, the components in 'bsltf' cannot directly
73/// define the overloads of the insertion operator to support printing the test
74/// types. Instead, an alternate method supplied in @ref bsls_bsltestutil is used
75/// for test drivers in the 'bsl' package group.
76///
77/// ## Usage {#bslim_testutil-usage}
78///
79///
80/// This section illustrates intended use of this component.
81///
82/// ### Example 1: Writing a Test Driver {#bslim_testutil-example-1-writing-a-test-driver}
83///
84///
85/// First, we write an elided component to test, which provides a utility class:
86/// @code
87/// namespace bdlabc {
88///
89/// struct ExampleUtil {
90/// // This utility class provides sample functionality to demonstrate how
91/// // a test driver might be written validating its only method.
92///
93/// // CLASS METHODS
94/// static int fortyTwo();
95/// // Return the integer value 42.
96/// };
97///
98/// // CLASS METHODS
99/// inline
100/// int ExampleUtil::fortyTwo()
101/// {
102/// return 42;
103/// }
104///
105/// } // close package namespace
106/// @endcode
107/// Then, we can write an elided test driver for this component. We start by
108/// providing the standard BDE assert test macro:
109/// @code
110/// //=========================================================================
111/// // STANDARD BDE ASSERT TEST MACRO
112/// //-------------------------------------------------------------------------
113/// static int testStatus = 0;
114///
115/// static void aSsErT(bool b, const char *s, int i)
116/// {
117/// if (b) {
118/// printf("Error " __FILE__ "(%d): %s (failed)\n", i, s);
119/// fflush(stdout);
120/// if (testStatus >= 0 && testStatus <= 100) ++testStatus;
121/// }
122/// }
123/// @endcode
124/// Next, we define the standard print and 'LOOP_ASSERT' macros, as aliases to
125/// the macros defined by this component:
126/// @code
127/// //=========================================================================
128/// // STANDARD BDE TEST DRIVER MACROS
129/// //-------------------------------------------------------------------------
130///
131/// #define ASSERT BSLIM_TESTUTIL_ASSERT
132/// #define LOOP_ASSERT BSLIM_TESTUTIL_LOOP_ASSERT
133/// #define LOOP0_ASSERT BSLIM_TESTUTIL_LOOP0_ASSERT
134/// #define LOOP1_ASSERT BSLIM_TESTUTIL_LOOP1_ASSERT
135/// #define LOOP2_ASSERT BSLIM_TESTUTIL_LOOP2_ASSERT
136/// #define LOOP3_ASSERT BSLIM_TESTUTIL_LOOP3_ASSERT
137/// #define LOOP4_ASSERT BSLIM_TESTUTIL_LOOP4_ASSERT
138/// #define LOOP5_ASSERT BSLIM_TESTUTIL_LOOP5_ASSERT
139/// #define LOOP6_ASSERT BSLIM_TESTUTIL_LOOP6_ASSERT
140/// #define LOOP7_ASSERT BSLIM_TESTUTIL_LOOP7_ASSERT
141/// #define LOOP8_ASSERT BSLIM_TESTUTIL_LOOP8_ASSERT
142/// #define ASSERTV BSLIM_TESTUTIL_ASSERTV
143///
144/// #define Q BSLIM_TESTUTIL_Q // Quote identifier literally.
145/// #define P BSLIM_TESTUTIL_P // Print identifier and value.
146/// #define P_ BSLIM_TESTUTIL_P_ // P(X) without '\n'.
147/// #define T_ BSLIM_TESTUTIL_T_ // Print a tab (w/o newline).
148/// #define L_ BSLIM_TESTUTIL_L_ // current Line number
149/// @endcode
150/// Now, using the (standard) abbreviated macro names we have just defined, we
151/// write a test function for the 'static' 'fortyTwo' method, to be called from
152/// a test case in the test driver:
153/// @code
154/// void testFortyTwo(bool verbose)
155/// // Test 'bdlabc::ExampleUtil::fortyTwo' in the specified 'verbose'
156/// // verbosity level.
157/// {
158/// const int value = bdlabc::ExampleUtil::fortyTwo();
159/// if (verbose) P(value);
160/// LOOP_ASSERT(value, 42 == value);
161/// }
162/// @endcode
163/// Finally, when 'testFortyTwo' is called from a test case in verbose mode we
164/// observe the console output:
165/// @code
166/// value = 42
167/// @endcode
168/// @}
169/** @} */
170/** @} */
171
172/** @addtogroup bsl
173 * @{
174 */
175/** @addtogroup bslim
176 * @{
177 */
178/** @addtogroup bslim_testutil
179 * @{
180 */
181
182#include <bslscm_version.h>
183
184#include <bslmf_assert.h>
185
186#include <bsl_iostream.h>
187#include <bsl_string.h>
188
189#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
191#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
192
193 // =================
194 // Macro Definitions
195 // =================
196
197#define BSLIM_TESTUTIL_ASSERT(X) \
198 aSsErT(!(X), #X, __LINE__);
199
200#define BSLIM_TESTUTIL_DEBUG_REP(X) BloombergLP::bslim::TestUtil::debugRep(X)
201
202#define BSLIM_TESTUTIL_LOOP0_ASSERT \
203 BSLIM_TESTUTIL_ASSERT
204
205#define BSLIM_TESTUTIL_LOOP_ASSERT(I,X) \
206 if (!(X)) { bsl::cout << #I ": " << BSLIM_TESTUTIL_DEBUG_REP(I) << \
207 " (context)\n"; \
208 aSsErT(1, #X, __LINE__); }
209
210#define BSLIM_TESTUTIL_LOOP1_ASSERT \
211 BSLIM_TESTUTIL_LOOP_ASSERT
212
213#define BSLIM_TESTUTIL_LOOP2_ASSERT(I,J,X) \
214 if (!(X)) { bsl::cout << #I ": " << BSLIM_TESTUTIL_DEBUG_REP(I) << "\t" \
215 << #J ": " << BSLIM_TESTUTIL_DEBUG_REP(J) << \
216 " (context)\n"; \
217 aSsErT(1, #X, __LINE__); }
218
219#define BSLIM_TESTUTIL_LOOP3_ASSERT(I,J,K,X) \
220 if (!(X)) { bsl::cout << #I ": " << BSLIM_TESTUTIL_DEBUG_REP(I) << "\t" \
221 << #J ": " << BSLIM_TESTUTIL_DEBUG_REP(J) << "\t" \
222 << #K ": " << BSLIM_TESTUTIL_DEBUG_REP(K) << \
223 " (context)\n"; \
224 aSsErT(1, #X, __LINE__); }
225
226#define BSLIM_TESTUTIL_LOOP4_ASSERT(I,J,K,L,X) \
227 if (!(X)) { bsl::cout << #I ": " << BSLIM_TESTUTIL_DEBUG_REP(I) << "\t" \
228 << #J ": " << BSLIM_TESTUTIL_DEBUG_REP(J) << "\t" \
229 << #K ": " << BSLIM_TESTUTIL_DEBUG_REP(K) << "\t" \
230 << #L ": " << BSLIM_TESTUTIL_DEBUG_REP(L) << \
231 " (context)\n"; \
232 aSsErT(1, #X, __LINE__); }
233
234#define BSLIM_TESTUTIL_LOOP5_ASSERT(I,J,K,L,M,X) \
235 if (!(X)) { bsl::cout << #I ": " << BSLIM_TESTUTIL_DEBUG_REP(I) << "\t" \
236 << #J ": " << BSLIM_TESTUTIL_DEBUG_REP(J) << "\t" \
237 << #K ": " << BSLIM_TESTUTIL_DEBUG_REP(K) << "\t" \
238 << #L ": " << BSLIM_TESTUTIL_DEBUG_REP(L) << "\t" \
239 << #M ": " << BSLIM_TESTUTIL_DEBUG_REP(M) << \
240 " (context)\n"; \
241 aSsErT(1, #X, __LINE__); }
242
243#define BSLIM_TESTUTIL_LOOP6_ASSERT(I,J,K,L,M,N,X) \
244 if (!(X)) { bsl::cout << #I ": " << BSLIM_TESTUTIL_DEBUG_REP(I) << "\t" \
245 << #J ": " << BSLIM_TESTUTIL_DEBUG_REP(J) << "\t" \
246 << #K ": " << BSLIM_TESTUTIL_DEBUG_REP(K) << "\t" \
247 << #L ": " << BSLIM_TESTUTIL_DEBUG_REP(L) << "\t" \
248 << #M ": " << BSLIM_TESTUTIL_DEBUG_REP(M) << "\t" \
249 << #N ": " << BSLIM_TESTUTIL_DEBUG_REP(N) << \
250 " (context)\n"; \
251 aSsErT(1, #X, __LINE__); }
252
253#define BSLIM_TESTUTIL_LOOP7_ASSERT(I,J,K,L,M,N,O,X) \
254 if (!(X)) { bsl::cout << #I ": " << BSLIM_TESTUTIL_DEBUG_REP(I) << "\t" \
255 << #J ": " << BSLIM_TESTUTIL_DEBUG_REP(J) << "\t" \
256 << #K ": " << BSLIM_TESTUTIL_DEBUG_REP(K) << "\t" \
257 << #L ": " << BSLIM_TESTUTIL_DEBUG_REP(L) << "\t" \
258 << #M ": " << BSLIM_TESTUTIL_DEBUG_REP(M) << "\t" \
259 << #N ": " << BSLIM_TESTUTIL_DEBUG_REP(N) << "\t" \
260 << #O ": " << BSLIM_TESTUTIL_DEBUG_REP(O) << \
261 " (context)\n"; \
262 aSsErT(1, #X, __LINE__); }
263
264#define BSLIM_TESTUTIL_LOOP8_ASSERT(I,J,K,L,M,N,O,V,X) \
265 if (!(X)) { bsl::cout << #I ": " << BSLIM_TESTUTIL_DEBUG_REP(I) << "\t" \
266 << #J ": " << BSLIM_TESTUTIL_DEBUG_REP(J) << "\t" \
267 << #K ": " << BSLIM_TESTUTIL_DEBUG_REP(K) << "\t" \
268 << #L ": " << BSLIM_TESTUTIL_DEBUG_REP(L) << "\t" \
269 << #M ": " << BSLIM_TESTUTIL_DEBUG_REP(M) << "\t" \
270 << #N ": " << BSLIM_TESTUTIL_DEBUG_REP(N) << "\t" \
271 << #O ": " << BSLIM_TESTUTIL_DEBUG_REP(O) << "\t" \
272 << #V ": " << BSLIM_TESTUTIL_DEBUG_REP(V) << \
273 " (context)\n"; \
274 aSsErT(1, #X, __LINE__); }
275
276// The 'BSLIM_TESTUTIL_EXPAND' macro is required to work around a preprocessor
277// issue on Windows that prevents '__VA_ARGS__' from being expanded in the
278// definition of 'BSLIM_TESTUTIL_NUM_ARGS'.
279
280#define BSLIM_TESTUTIL_EXPAND(X) \
281 X
282
283#define BSLIM_TESTUTIL_NUM_ARGS_IMPL(X8, X7, X6, X5, X4, X3, X2, X1, X0, \
284 N, ...) \
285 N
286
287#define BSLIM_TESTUTIL_NUM_ARGS(...) \
288 BSLIM_TESTUTIL_EXPAND(BSLIM_TESTUTIL_NUM_ARGS_IMPL( \
289 __VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0, ""))
290
291#define BSLIM_TESTUTIL_LOOPN_ASSERT_IMPL(N, ...) \
292 BSLIM_TESTUTIL_EXPAND(BSLIM_TESTUTIL_LOOP ## N ## _ASSERT(__VA_ARGS__))
293
294#define BSLIM_TESTUTIL_LOOPN_ASSERT(N, ...) \
295 BSLIM_TESTUTIL_LOOPN_ASSERT_IMPL(N, __VA_ARGS__)
296
297#define BSLIM_TESTUTIL_ASSERTV(...) \
298 BSLIM_TESTUTIL_LOOPN_ASSERT( \
299 BSLIM_TESTUTIL_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)
300
301/// Quote identifier literally.
302#define BSLIM_TESTUTIL_Q(X) \
303 bsl::cout << "<| " #X " |>" << bsl::endl;
304
305/// Print identifier and its value.
306#define BSLIM_TESTUTIL_P(X) \
307 bsl::cout << #X " = " << BSLIM_TESTUTIL_DEBUG_REP(X) << bsl::endl;
308
309/// `P(X)` without `\n`
310#define BSLIM_TESTUTIL_P_(X) \
311 bsl::cout << #X " = " << BSLIM_TESTUTIL_DEBUG_REP(X) << ", " << bsl::flush;
312
313/// current Line number
314#define BSLIM_TESTUTIL_L_ \
315 __LINE__
316
317/// Print tab (w/o newline).
318#define BSLIM_TESTUTIL_T_ \
319 bsl::cout << "\t" << bsl::flush;
320
321
322namespace bslim {
323
324 // ==============
325 // class TestUtil
326 // ==============
327
328/// This `struct` provides a namespace for a suite of utility functions that
329/// facilitate the creation of BDE-style test drivers.
330///
331/// See @ref bslim_testutil
332struct TestUtil {
333
334 private:
335 // PRIVATE CLASS METHODS
336
337 /// Return `ptr` without modification.
338 /// \note Note that this is NOT an inline
339 /// function, so that if the caller is not in the same module, the
340 /// compiler has no way of knowing that it's an identity transform.
341 static void *identityPtr(void *ptr);
342
343 public:
344 // CLASS METHODS
345
346 /// Return `true` if the specified `lhs` has the same value as the
347 /// specified `rhs`, and `false` otherwise. Optionally specify an
348 /// `errorStream` on which, if `lhs` and `rhs` are not the same', a
349 /// description of how the two strings differ will be written. If
350 /// `errorStream` is not supplied, `stdout` is used.
353 bsl::ostream& errorStream = bsl::cout);
354
355 /// Return the specified `functionPtr` (expected to be a static function
356 /// pointer) without modification. The value of `functionPtr` is
357 /// transformed through `identityPtr` so that if the caller is in a
358 /// different module, the compiler will have no way of knowing that this
359 /// is an identity transform and thus no way of inlining the call.
360 ///
361 /// Note: the Windows optimizer is still able to inline the call, it may
362 /// be comparing the result of this function with the argument and
363 /// branching to inline on equality and call on inequality, so the
364 /// Windows optimizer has to be turned off with
365 /// `# pragma optimize("", off)`.
366 ///
367 /// Also note that even with an optimizer that can't figure out that
368 /// this is an identity transform, there is still the possibility of
369 /// chaining the call.
370 template <class FUNCTION_PTR>
371 static FUNCTION_PTR makeFunctionCallNonInline(FUNCTION_PTR functionPtr);
372
373 template <class T>
374 static const T& debugRep(const T& arg) { return arg; }
375 static int debugRep(wchar_t arg) { return arg; }
376};
377
378// ============================================================================
379// INLINE FUNCTION DEFINITIONS
380// ============================================================================
381
382 // --------
383 // TestUtil
384 // --------
385
386template <class FUNCTION_PTR>
387inline
388FUNCTION_PTR TestUtil::makeFunctionCallNonInline(FUNCTION_PTR function)
389{
390 BSLMF_ASSERT(sizeof(FUNCTION_PTR) == sizeof(void *));
391
392 return reinterpret_cast<FUNCTION_PTR>(identityPtr(reinterpret_cast<void *>(
393 function)));
394}
395
396} // close package namespace
397
398
399#endif
400
401// ----------------------------------------------------------------------------
402// Copyright 2012 Bloomberg Finance L.P.
403//
404// Licensed under the Apache License, Version 2.0 (the "License");
405// you may not use this file except in compliance with the License.
406// You may obtain a copy of the License at
407//
408// http://www.apache.org/licenses/LICENSE-2.0
409//
410// Unless required by applicable law or agreed to in writing, software
411// distributed under the License is distributed on an "AS IS" BASIS,
412// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
413// See the License for the specific language governing permissions and
414// limitations under the License.
415// ----------------------------- END-OF-FILE ----------------------------------
416
417/** @} */
418/** @} */
419/** @} */
Definition bslstl_stringref.h:374
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:231
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bslim_formatguard.h:120
Definition bslim_testutil.h:332
static int debugRep(wchar_t arg)
Definition bslim_testutil.h:375
static const T & debugRep(const T &arg)
Definition bslim_testutil.h:374
static FUNCTION_PTR makeFunctionCallNonInline(FUNCTION_PTR functionPtr)
Definition bslim_testutil.h:388
static bool compareText(bslstl::StringRef lhs, bslstl::StringRef rhs, bsl::ostream &errorStream=bsl::cout)