|
#define | BSLS_BSLTESTUTIL_ASSERT(X) do { aSsErT(!(X), #X, __LINE__); } while (false) |
|
#define | BSLS_BSLTESTUTIL_LOOP0_ASSERT BSLS_BSLTESTUTIL_ASSERT |
|
#define | BSLS_BSLTESTUTIL_LOOP_ASSERT(I, X) |
|
#define | BSLS_BSLTESTUTIL_LOOP1_ASSERT BSLS_BSLTESTUTIL_LOOP_ASSERT |
|
#define | BSLS_BSLTESTUTIL_LOOP2_ASSERT(I, J, X) |
|
#define | BSLS_BSLTESTUTIL_LOOP3_ASSERT(I, J, K, X) |
|
#define | BSLS_BSLTESTUTIL_LOOP4_ASSERT(I, J, K, L, X) |
|
#define | BSLS_BSLTESTUTIL_LOOP5_ASSERT(I, J, K, L, M, X) |
|
#define | BSLS_BSLTESTUTIL_LOOP6_ASSERT(I, J, K, L, M, N, X) |
|
#define | BSLS_BSLTESTUTIL_LOOP7_ASSERT(I, J, K, L, M, N, O, X) |
|
#define | BSLS_BSLTESTUTIL_LOOP8_ASSERT(I, J, K, L, M, N, O, V, X) |
|
#define | BSLS_BSLTESTUTIL_EXPAND(X) X |
|
#define | BSLS_BSLTESTUTIL_NUM_ARGS_IMPL(X8, X7, X6, X5, X4, X3, X2, X1, X0, N, ...) N |
|
#define | BSLS_BSLTESTUTIL_NUM_ARGS(...) |
|
#define | BSLS_BSLTESTUTIL_LOOPN_ASSERT_IMPL(N, ...) BSLS_BSLTESTUTIL_EXPAND(BSLS_BSLTESTUTIL_LOOP ## N ## _ASSERT(__VA_ARGS__)) |
|
#define | BSLS_BSLTESTUTIL_LOOPN_ASSERT(N, ...) BSLS_BSLTESTUTIL_LOOPN_ASSERT_IMPL(N, __VA_ARGS__) |
|
#define | BSLS_BSLTESTUTIL_ASSERTV(...) |
|
#define | BSLS_BSLTESTUTIL_Q(X) |
| Quote identifier literally.
|
|
#define | BSLS_BSLTESTUTIL_P(X) |
| Print identifier and its value.
|
|
#define | BSLS_BSLTESTUTIL_P_(X) |
| P(X) without '
'.
|
|
#define | BSLS_BSLTESTUTIL_L_ __LINE__ |
| Current line number.
|
|
#define | BSLS_BSLTESTUTIL_T_ BloombergLP::bsls::BslTestUtil::printTab(); |
| Print a tab (w/o newline).
|
|
#define | BSLS_BSLTESTUTIL_FORMAT_ZU "%zu" |
|
#define | BSLS_BSLTESTUTIL_FORMAT_TD "%td" |
|
#define | BSLS_BSLTESTUTIL_FORMAT_I64 "%lld" |
|
#define | BSLS_BSLTESTUTIL_FORMAT_U64 "%llu" |
|
#define | BSLS_BSLTESTUTIL_FORMAT_PTR "%X" |
|
Outline
Purpose
Provide test utilities for bsl
that do not use <iostream>.
Classes
Macros
- BSLS_BSLTESTUTIL_ASSERT(X): record and print error if
!X
- BSLS_BSLTESTUTIL_LOOP_ASSERT(I, X): print args if
!X
- BSLS_BSLTESTUTIL_LOOP2_ASSERT(I, J, X): print args if
!X
- BSLS_BSLTESTUTIL_LOOP3_ASSERT(I, J, K, X): print args if
!X
- BSLS_BSLTESTUTIL_LOOP4_ASSERT(I, J, K, L, X): print args if
!X
- BSLS_BSLTESTUTIL_LOOP5_ASSERT(I, J, K, L, M, X): print args if
!X
- BSLS_BSLTESTUTIL_LOOP6_ASSERT(I, J, K, L, M, N, X): print args if
!X
- BSLS_BSLTESTUTIL_LOOP7_ASSERT(I, J, K, L, M, N, O, X): print args if
!X
BSLS_BSLTESTUTIL_LOOP8_ASSERT(I, J, K, L, M, N, O,V, X): print args if !X
BSLS_BSLTESTUTIL_Q(X) : quote identifier literally BSLS_BSLTESTUTIL_P(X) : print identifier and value BSLS_BSLTESTUTIL_P_(X): print identifier and value without '
' BSLS_BSLTESTUTIL_L_ : current line number BSLS_BSLTESTUTIL_T_ : print tab without '
'
BSLS_BSLTESTUTIL_FORMAT_ZU : printf
format for size_t
BSLS_BSLTESTUTIL_FORMAT_TD : printf
format for ptrdiff_t
BSLS_BSLTESTUTIL_FORMAT_I64: printf
format for unsigned 64-bit integers BSLS_BSLTESTUTIL_FORMAT_U64: printf
format for signed 64-bit integers BSLS_BSLTESTUTIL_FORMAT_PTR: printf
format for uintptr_t
Description
This component provides standard facilities for components in the bsl
package group to produce test driver output, including the standard printing macros used in BDE-style test drivers (ASSERT
, LOOP_ASSERT
, ASSERTV
, P
, Q
, L
, and T
), and a suite of cross-platform format strings for printing C++ or BDE-specific types with printf
.
Many components in the bsl
package group reside below the standard library; therefore, hierarchical design dictates that the test driver for these components shall not use iostream
(which is part of the standard library), and instead they shall only rely on the printf
function to print objects' values. Using printf
over iostream
has the following disadvantages:
- The
printf
function requires a format string to specify the way to print an object; so, unlike iostream
, printing different types of objects using printf
requires different syntaxes due to the need for different format strings.
- While the format strings for built-in types can be included as part of the standard boiler plate code of the test driver, printing a user-defined type often requires additional code that is not part of the standard boilerplate.
This component provides solutions to these issues by (1) encapsulating all the standard printing macros in a single place, (2) providing a way to extend the supplied macros to support user-defined types, and (3) providing macros that resolve the correct printf
format strings for types that do not have standard, cross-platform format strings of their own.
The macros in this component use a class method template, BslTestUtil::callDebugprint
, to print the value of an object of the parameterized type, along with an optional leading string and an optional trailing string, to the console. The value of the object of the parameterized type will be printed using a free function named debugprint
.
The macros defined in this component natively support built-in types through the debugprint
function overloads for these types defined in this component. The macros can be extended support additional user-defined types by defining function overloads for debugprint
that takes a single parameter of each user-defined type, in the same namespace in which the user-defined type is defined. See the second usage example for more details.
Usage
This section illustrates intended use of this component.
Example 1: Writing a Test Driver
First, we write a component to test, which provides a utility class:
namespace bslabc {
struct BslExampleUtil {
static int fortyTwo();
};
inline
int BslExampleUtil::fortyTwo()
{
return 42;
}
}
Then, we can write a test driver for this component. We start by providing the standard BDE assert test macro:
static int testStatus = 0;
static void aSsErT(bool b, const char *s, int i)
{
if (b) {
printf("Error " __FILE__ "(%d): %s (failed)\n", i, s);
if (testStatus >= 0 && testStatus <= 100) ++testStatus;
}
}
# define ASSERT(X) { aSsErT(!(X), #X, __LINE__); }
Next, we define the standard print and LOOP_ASSERT
macros, as aliases to the macros defined by this component:
#define LOOP_ASSERT BSLS_BSLTESTUTIL_LOOP_ASSERT
#define LOOP2_ASSERT BSLS_BSLTESTUTIL_LOOP2_ASSERT
#define LOOP3_ASSERT BSLS_BSLTESTUTIL_LOOP3_ASSERT
#define LOOP4_ASSERT BSLS_BSLTESTUTIL_LOOP4_ASSERT
#define LOOP5_ASSERT BSLS_BSLTESTUTIL_LOOP5_ASSERT
#define LOOP6_ASSERT BSLS_BSLTESTUTIL_LOOP6_ASSERT
#define LOOP7_ASSERT BSLS_BSLTESTUTIL_LOOP7_ASSERT
#define LOOP8_ASSERT BSLS_BSLTESTUTIL_LOOP8_ASSERT
#define Q BSLS_BSLTESTUTIL_Q
#define P BSLS_BSLTESTUTIL_P
#define P_ BSLS_BSLTESTUTIL_P_
#define T_ BSLS_BSLTESTUTIL_T_
#define L_ BSLS_BSLTESTUTIL_L_
Now, using the (standard) abbreviated macro names we have just defined, we write a test function for the static
fortyTwo
method, to be called from a test case in a test driver.
void testFortyTwo(bool verbose)
{
const int value = bslabc::BslExampleUtil::fortyTwo();
if (verbose) P(value);
LOOP_ASSERT(value, 42 == value);
}
Finally, when testFortyTwo
is called from a test case in verbose mode we observe the console output:
Example 2: Adding Support For A New User-Defined Type
First, we define a new user-defined type, MyType
:
namespace xyza {
class MyType {
private:
int d_value;
public:
explicit MyType(int value);
int value() const;
};
inline
MyType::MyType(int value)
: d_value(value)
{
}
inline
int MyType::value() const
{
return d_value;
}
Then, in the same namespace in which MyType
is defined, we define a function debugprint
that prints the value of a MyType
object to the console. (In this case, we will simply print a string literal for simplicity):
void debugprint(const MyType& obj)
{
printf("MyType<%d>", obj.value());
}
}
Now, using the (standard) abbreviated macro names previously defined, we write a test function for the MyType
constructor, to be called from a test case in a test driver.
void testMyTypeSetValue(bool verbose) {
xyza::MyType obj(9);
if (verbose) P(obj);
LOOP_ASSERT(obj.value(), obj.value() == 9);
}
Finally, when testMyTypeSetValue
is called from a test case in verbose mode we observe the console output:
Example 3: Printing Unusual Types with printf
Suppose we are writing a test driver that needs to print out the contents of a complex data structure in veryVeryVerbose
mode. The complex data structure contains, among other values, an array of block sizes, expressed as size_t
. It would be very cumbersome, and visually confusing, to print each member of the array with either the P_
or Q_
standard output macros, so we elect to print out the array as a single string, following the pattern of [ A, B, C, D, E, ... ]
. This could be easily accomplished with multiple calls to printf
, except that printf
has no cross-platform standard formatting string for size_t
. We can use the BSLS_BSLTESTUTIL_FORMAT_ZU
macro to resolve the appropriate format string for us on each platform.
First, we write a component to test, which provides an a utility that operates on a list of memory blocks. Each block is a structure containing a base address, a block size, and a pointer to the next block in the list.
namespace xyza {
struct Block {
char *d_address;
size_t d_size;
Block *d_next;
};
class BlockList {
Block *d_head;
public:
BlockList();
~BlockList();
Block *begin();
Block *end();
void addBlock(size_t size);
int length();
};
}
Then, we write a test driver for this component.
Here, after defining the standard BDE test macros, we define a macro, ZU
for the platform-specific printf
format string for size_t
:
#define ZU BSLS_BSLTESTUTIL_FORMAT_ZU
Note that, we could use BSLS_BSLTESTUTIL_FORMAT_ZU
as is, but it is more convenient to define ZU
locally as an abbreviation.
Next, we write the test apparatus for the test driver, which includes a support function that prints the list of blocks in a BlockList
in a visually succinct form:
void printBlockList(xyza::BlockList &list)
{
xyza::Block *blockPtr = list.begin();
printf("{\n");
while (blockPtr != list.end()) {
Here, we use ZU
as the format specifier for the size_t
in the printf
invocation. ZU
is the appropriate format specifier for size_t
on each supported platform.
printf("\t{ address: %p,\tsize: " ZU " }",
blockPtr->d_address,
blockPtr->d_size);
blockPtr = blockPtr->d_next;
if (blockPtr) {
printf(",\n");
} else {
printf("\n");
}
}
printf("}\n");
}
Note that because we are looping through a number of blocks, formatting the output directly with printf
produces more readable output than we would get from callling the standard output macros.
Calling printf
directly will yield output similar to:
{
{ address: 0x012345600, size: 32 },
...
}
while the standard output macros would have produced:
{
{ blockPtr->d_address = 0x012345600, blockPtr->d_size: 32 },
...
}
Now, we write a test function for one of our test cases, which provides a detailed trace of BlockList
contents:
void testBlockListConstruction(bool veryVeryVerbose)
{
{
xyza::BlockList bl;
bl.addBlock(42);
bl.addBlock(19);
bl.addBlock(1024);
if (veryVeryVerbose) {
printBlockList(bl);
}
ASSERT(3 == bl.length());
}
}
Finally, when testBlockListConstruction
is called from a test case in veryVeryVerbose
mode, we observe console output similar to:
{
{ address: 0x012345600, size: 42 },
{ address: 0x012345610, size: 19 },
{ address: 0x012345620,
size: 1024 }
}
bsl::size_t size(const TYPE &array)
Return the number of elements in the specified array.
◆ BSLS_BSLTESTUTIL_ASSERT
#define BSLS_BSLTESTUTIL_ASSERT |
( |
|
X | ) |
do { aSsErT(!(X), #X, __LINE__); } while (false) |
◆ BSLS_BSLTESTUTIL_ASSERTV
#define BSLS_BSLTESTUTIL_ASSERTV |
( |
|
... | ) |
|
Value:
#define BSLS_BSLTESTUTIL_NUM_ARGS(...)
Definition bsls_bsltestutil.h:576
#define BSLS_BSLTESTUTIL_LOOPN_ASSERT(N,...)
Definition bsls_bsltestutil.h:583
◆ BSLS_BSLTESTUTIL_EXPAND
#define BSLS_BSLTESTUTIL_EXPAND |
( |
|
X | ) |
X |
◆ BSLS_BSLTESTUTIL_FORMAT_I64
#define BSLS_BSLTESTUTIL_FORMAT_I64 "%lld" |
◆ BSLS_BSLTESTUTIL_FORMAT_PTR
#define BSLS_BSLTESTUTIL_FORMAT_PTR "%X" |
◆ BSLS_BSLTESTUTIL_FORMAT_TD
#define BSLS_BSLTESTUTIL_FORMAT_TD "%td" |
◆ BSLS_BSLTESTUTIL_FORMAT_U64
#define BSLS_BSLTESTUTIL_FORMAT_U64 "%llu" |
◆ BSLS_BSLTESTUTIL_FORMAT_ZU
#define BSLS_BSLTESTUTIL_FORMAT_ZU "%zu" |
◆ BSLS_BSLTESTUTIL_L_
#define BSLS_BSLTESTUTIL_L_ __LINE__ |
◆ BSLS_BSLTESTUTIL_LOOP0_ASSERT
◆ BSLS_BSLTESTUTIL_LOOP1_ASSERT
◆ BSLS_BSLTESTUTIL_LOOP2_ASSERT
#define BSLS_BSLTESTUTIL_LOOP2_ASSERT |
( |
|
I, |
|
|
|
J, |
|
|
|
X |
|
) |
| |
Value: do { \
if (!(X)) { BloombergLP::bsls:: \
BslTestUtil::callDebugprint(I, #I ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(J, #J ": ", "\n"); \
aSsErT(true, #X, __LINE__); } } while (false)
◆ BSLS_BSLTESTUTIL_LOOP3_ASSERT
#define BSLS_BSLTESTUTIL_LOOP3_ASSERT |
( |
|
I, |
|
|
|
J, |
|
|
|
K, |
|
|
|
X |
|
) |
| |
Value: do { \
if (!(X)) { BloombergLP::bsls:: \
BslTestUtil::callDebugprint(I, #I ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(J, #J ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(K, #K ": ", "\n"); \
aSsErT(true, #X, __LINE__); } } while (false)
◆ BSLS_BSLTESTUTIL_LOOP4_ASSERT
#define BSLS_BSLTESTUTIL_LOOP4_ASSERT |
( |
|
I, |
|
|
|
J, |
|
|
|
K, |
|
|
|
L, |
|
|
|
X |
|
) |
| |
Value: do { \
if (!(X)) { BloombergLP::bsls:: \
BslTestUtil::callDebugprint(I, #I ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(J, #J ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(K, #K ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(L, #L ": ", "\n"); \
aSsErT(true, #X, __LINE__); } } while (false)
◆ BSLS_BSLTESTUTIL_LOOP5_ASSERT
#define BSLS_BSLTESTUTIL_LOOP5_ASSERT |
( |
|
I, |
|
|
|
J, |
|
|
|
K, |
|
|
|
L, |
|
|
|
M, |
|
|
|
X |
|
) |
| |
Value: do { \
if (!(X)) { BloombergLP::bsls:: \
BslTestUtil::callDebugprint(I, #I ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(J, #J ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(K, #K ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(L, #L ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(M, #M ": ", "\n"); \
aSsErT(true, #X, __LINE__); } } while (false)
◆ BSLS_BSLTESTUTIL_LOOP6_ASSERT
#define BSLS_BSLTESTUTIL_LOOP6_ASSERT |
( |
|
I, |
|
|
|
J, |
|
|
|
K, |
|
|
|
L, |
|
|
|
M, |
|
|
|
N, |
|
|
|
X |
|
) |
| |
Value: do { \
if (!(X)) { BloombergLP::bsls:: \
BslTestUtil::callDebugprint(I, #I ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(J, #J ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(K, #K ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(L, #L ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(M, #M ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(N, #N ": ", "\n"); \
aSsErT(true, #X, __LINE__); } } while (false)
◆ BSLS_BSLTESTUTIL_LOOP7_ASSERT
#define BSLS_BSLTESTUTIL_LOOP7_ASSERT |
( |
|
I, |
|
|
|
J, |
|
|
|
K, |
|
|
|
L, |
|
|
|
M, |
|
|
|
N, |
|
|
|
O, |
|
|
|
X |
|
) |
| |
Value: do { \
if (!(X)) { BloombergLP::bsls:: \
BslTestUtil::callDebugprint(I, #I ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(J, #J ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(K, #K ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(L, #L ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(M, #M ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(N, #N ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(O, #O ": ", "\n"); \
aSsErT(true, #X, __LINE__); } } while (false)
◆ BSLS_BSLTESTUTIL_LOOP8_ASSERT
#define BSLS_BSLTESTUTIL_LOOP8_ASSERT |
( |
|
I, |
|
|
|
J, |
|
|
|
K, |
|
|
|
L, |
|
|
|
M, |
|
|
|
N, |
|
|
|
O, |
|
|
|
V, |
|
|
|
X |
|
) |
| |
Value: do { \
if (!(X)) { BloombergLP::bsls:: \
BslTestUtil::callDebugprint(I, #I ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(J, #J ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(K, #K ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(L, #L ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(M, #M ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(N, #N ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(O, #O ": ", "\t"); \
BloombergLP::bsls:: \
BslTestUtil::callDebugprint(V, #V ": ", "\n"); \
aSsErT(true, #X, __LINE__); } } while (false)
◆ BSLS_BSLTESTUTIL_LOOP_ASSERT
#define BSLS_BSLTESTUTIL_LOOP_ASSERT |
( |
|
I, |
|
|
|
X |
|
) |
| |
Value: do { \
if (!(X)) { BloombergLP::bsls:: \
BslTestUtil::callDebugprint(I, #I ": ", "\n"); \
aSsErT(true, #X, __LINE__); } } while (false)
◆ BSLS_BSLTESTUTIL_LOOPN_ASSERT
◆ BSLS_BSLTESTUTIL_LOOPN_ASSERT_IMPL
#define BSLS_BSLTESTUTIL_LOOPN_ASSERT_IMPL |
( |
|
N, |
|
|
|
... |
|
) |
| BSLS_BSLTESTUTIL_EXPAND(BSLS_BSLTESTUTIL_LOOP ## N ## _ASSERT(__VA_ARGS__)) |
◆ BSLS_BSLTESTUTIL_NUM_ARGS
#define BSLS_BSLTESTUTIL_NUM_ARGS |
( |
|
... | ) |
|
Value:
__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0, ""))
#define BSLS_BSLTESTUTIL_NUM_ARGS_IMPL(X8, X7, X6, X5, X4, X3, X2, X1, X0, N,...)
Definition bsls_bsltestutil.h:572
#define BSLS_BSLTESTUTIL_EXPAND(X)
Definition bsls_bsltestutil.h:569
◆ BSLS_BSLTESTUTIL_NUM_ARGS_IMPL
#define BSLS_BSLTESTUTIL_NUM_ARGS_IMPL |
( |
|
X8, |
|
|
|
X7, |
|
|
|
X6, |
|
|
|
X5, |
|
|
|
X4, |
|
|
|
X3, |
|
|
|
X2, |
|
|
|
X1, |
|
|
|
X0, |
|
|
|
N, |
|
|
|
... |
|
) |
| N |
◆ BSLS_BSLTESTUTIL_P
#define BSLS_BSLTESTUTIL_P |
( |
|
X | ) |
|
Value: BloombergLP::bsls:: \
BslTestUtil::callDebugprint(X, #X " = ", "\n");
◆ BSLS_BSLTESTUTIL_P_
#define BSLS_BSLTESTUTIL_P_ |
( |
|
X | ) |
|
Value: BloombergLP::bsls:: \
BslTestUtil::callDebugprint(X, #X " = ", ", ");
◆ BSLS_BSLTESTUTIL_Q
#define BSLS_BSLTESTUTIL_Q |
( |
|
X | ) |
|
Value: BloombergLP::bsls:: \
BslTestUtil::printStringNoFlush("<| " #X " |>\n");
◆ BSLS_BSLTESTUTIL_T_
#define BSLS_BSLTESTUTIL_T_ BloombergLP::bsls::BslTestUtil::printTab(); |