Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bsls_bsltestutil
[Package bsls]

Provide test utilities for bsl that do not use <iostream>. More...

Namespaces

namespace  bsls

Detailed Description

Outline
Purpose:
Provide test utilities for bsl that do not use <iostream>.
Classes:
bsls::BslTestUtil utilities to aid writing bsl test drivers
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 \n BSLS_BSLTESTUTIL_L_ : current line number BSLS_BSLTESTUTIL_T_ : print tab without \n
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 {
      // This utility class provides sample functionality to demonstrate how
      // a test driver might be written validating its only method.

      static int fortyTwo();
          // Return the integer value '42'.
  };

  inline
  int BslExampleUtil::fortyTwo()
  {
      return 42;
  }

  }  // close package namespace
Then, we can write a test driver for this component. We start by providing the standard BDE assert test macro:
  // ========================================================================
  //                       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:
  // ========================================================================
  //                       STANDARD BDE TEST DRIVER MACROS
  // ------------------------------------------------------------------------
  #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   // Quote identifier literally.
  #define P   BSLS_BSLTESTUTIL_P   // Print identifier and value.
  #define P_  BSLS_BSLTESTUTIL_P_  // 'P(X)' without '\n'.
  #define T_  BSLS_BSLTESTUTIL_T_  // Print a tab (w/o newline).
  #define L_  BSLS_BSLTESTUTIL_L_  // current Line number
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:
  value = 42
Example 2: Adding Support For A New User-Defined Type:
First, we define a new user-defined type, MyType:
  namespace xyza {

  class MyType {
      // This elided class provides a type intended to show how the macros in
      // 'bsls_bsltestutil' can be extended to support a new user-defined
      // type.

    private:
      // DATA
      int d_value;  // the value of MyType

      // ...

    public:
      // CREATORS

      // ...

      explicit MyType(int value);
          // Create a 'MyType' object with 'd_value' set to the specified
          // 'value'.

      // ACCESSORS

      // ...

      int value() const;
          // Return the value of 'd_value'.

      // ...
  };

  // ...

  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());
  }

  }  // close namespace xyza
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:
  obj = MyType<9>
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 {
      // DATA
      char   *d_address;
      size_t  d_size;
      Block  *d_next;

      // ...
  };

  class BlockList {
      // ...

      // DATA
      Block *d_head;

      // ...

    public:
      // CREATORS
      BlockList();
      ~BlockList();

      // MANIPULATORS

      Block *begin();
      Block *end();

      void addBlock(size_t size);

      // ...

      // ACCESSORS
      int length();

      // ...
  };

  }  // close namespace xyza
Then, we write a test driver for this component.
  // ...

  // ========================================================================
  //                       STANDARD BDE TEST DRIVER MACROS
  // ------------------------------------------------------------------------

  // ...
Here, after defining the standard BDE test macros, we define a macro, ZU for the platform-specific printf format string for size_t:
  // ========================================================================
  //                          PRINTF FORMAT MACROS
  // ------------------------------------------------------------------------
  #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 }
  }