// bslmt_testutil.h                                                   -*-C++-*-
#ifndef INCLUDED_BSLMT_TESTUTIL
#define INCLUDED_BSLMT_TESTUTIL

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide thread-safe test utilities for multithreaded components.
//
//@CLASSES:
//  bslmt::TestUtil: namespace class for multi-threaded utility functions.
//
//@MACROS:
//  BSLMT_TESTUTIL_ASSERT(X): record and print message if '!X'
//  BSLMT_TESTUTIL_ASSERTV(..., X): record and print args and message if '!X'
//  BSLMT_TESTUTIL_Q(X): quote identifier literally
//  BSLMT_TESTUTIL_P(X): print identifier and value
//  BSLMT_TESTUTIL_P_(X): print identifier and value without '\n'
//  BSLMT_TESTUTIL_L_: current line number
//  BSLMT_TESTUTIL_T_: print tab without '\n'
//  BSLMT_TESTUTIL_GUARD: create a lock guard on the singleton mutex
//  BSLMT_TESTUTIL_GUARDED_STREAM(STREAM): guarded access to 'STREAM'
//  BSLMT_TESTUTIL_COUT: thread-safe access to 'bsl::cout'
//  BSLMT_TESTUTIL_CERR: thread-safe access to 'bsl::cerr'
//
//  BSLMT_TESTUTIL_LOOP_ASSERT
//  BSLMT_TESTUTIL_LOOP2_ASSERT
//  BSLMT_TESTUTIL_LOOP3_ASSERT
//  BSLMT_TESTUTIL_LOOP4_ASSERT
//  BSLMT_TESTUTIL_LOOP5_ASSERT
//  BSLMT_TESTUTIL_LOOP6_ASSERT
//      // Discouraged: use 'ASSERTV'.  Provided for the sake of ease of
//      // migration of test drivers from using 'bsls_bsltestutil' or
//      // 'bslim_testutil'.
//
//  BSLMT_TESTUTIL_OUTPUT_GUARD
//      // !DEPRECATED!: use BSLMT_TESTUTIL_GUARD
//
//  BSLMT_TESTUTIL_NESTED_OUTPUT_GUARD
//      // !DEPRECATED!: use BSLMT_TESTUTIL_GUARD
//
//@SEE_ALSO: bslim_testutil, bsls_bsltestutil
//
//@DESCRIPTION: This component provides a set of macros for the standard BDE
// test driver assert and print facilities (see the macros defined in
// {'bsls_bsltestutil'} and {'bslim_testutil'}) that are suitable for use in
// multi-threaded test drivers.  This component also provides a utility
// 'struct', 'bslmt::TestUtil', that defines a namespace for types and
// functions that are helpful in multi-threaded test drivers.
//
///Simple Output Macros
///--------------------
//: o 'BSLMT_TESTUTIL_Q(X)'
//: o 'BSLMT_TESTUTIL_P(X)'
//: o 'BSLMT_TESTUTIL_P_(X)'
//: o 'BSLMT_TESTUTIL_L_'
//: o 'BSLMT_TESTUTIL_T_'
//
// These macros guarantee:
//
//: 1 The entire output message is not interleaved with those of other threads
//:   using these macros.
//:
//: 2 The output stream (e.g., 'bsl::cout') is not corrupted.  (Since
//:   'bsl::cout' itself was not made thread-safe until C++11 this is a concern
//:   on some of our supported platforms.)
//
///Guarded Stream Output
///---------------------
// This component also defines several additions to the set of standard test
// macros:
//: o 'BSLMT_TESTUTIL_GUARDED_STREAM(STREAM)'
//: o 'BSLMT_TESTUTIL_COUT'
//: o 'BSLMT_TESTUTIL_CERR'
//
// These macros guarantee atomicity of the output for the entire statement up
// to the terminating semi-colon.  For example, if one thread executes:
//..
//  int value = 42;
//  BSLMT_TESTUTIL_COUT << "The value is " << value << "." << bsl::endl;
//..
// and another thread executes;
//..
//  bsl::string name("Barbara");
//  BSLMT_TESTUTIL_COUT << "Hello " << name << "."  << bsl::endl;
//..
// The output will be either:
//..
//  Hello Barbara.
//  The value is 42.
//..
// or
//..
//  The value is 42.
//  Hello Barbara.
//..
// but, despite six separate operations on 'bsl::cout', the lines will not be
// interleaved.
//
// As with the "ASSERT" macros above, these macros do not guarantee thread-safe
// evaluation of any expressions in the output statement.  Thus, if one thread
// is executing:
//..
//  BSLMT_TESTUTIL_COUT << "The value is " << f() << "." << bsl::endl;
//..
// and some other thread is executing:
//..
//  BSLMT_TESTUTIL_COUT << "There are " << g() << " cases." << bsl::endl;
//..
// the two output statements are evaluated serially, but the evaluation of the
// 'f' and 'g' functions may require their own synchronization (if they are
// accessing values that may be in the process of unguarded modification by
// other threads).
//
///Assertion Macros
///----------------
// The macros:
//
//: o BSLMT_TESTUTIL_ASSERT
//: o BSLMT_TESTUTIL_ASSERTV, and
//: o BSLMT_TESTUTIL_LOOP*_ASSERT
//
// work like their counterparts in 'bsls_bsltestutil' and 'bslim_testutil',
// except that all output by a given assert is guaranteed not to be interleaved
// with output from other macros in this component.
//
// These macros provide no synchronization until *after* failure is detected.
// If the boolean expression being evaluated is not thread-safe, the caller of
// the macro must provide synchronization around the macro call.
//
// The 'LOOP*_ASSERT' macros are considered obsolete and are provided to
// facilitate the multi-threading of test drivers written using macros from
// 'bsls_bsltestutil' and 'bslim_testutil'.  Use 'BSLMT_TESTUTIL_ASSERTV'
// instead.
//
///Infrastructure for the Assertion Macros
///- - - - - - - - - - - - - - - - - - - -
// Similarly to the macros defined in {'bsls_bsltestutil'} and
// {'bslim_testutil'}, the assert macros defined here assume that the user has
// defined a global integer variable named 'testStatus' and has defined a
// function:
//..
//  void aSsErT(int c, const char *assertionAsString, int lineNumber);
//..
// that outputs the conventional error message and update 'testStatus' when 'c'
// is non-zero.  If all access to 'testStatus' is through the "ASSERT" macros,
// 'testStatus' can be an ordinary (non-atomic) 'int' and 'aSsErT' need not be
// thread-safe.
//
///Guarding Critical Sections
///--------------------------
// This component also provides a (macro-wrapped) guard object:
//
//: o 'BSLMT_TESTUTIL_GUARD'
//
// which does no output, but rather prevents the interleaving of output from
// the other macros until the guard goes out of scope.  This feature is useful
// in the common situation in which one wants to prevent interleaving of
// several separate uses of the macros.
//
// For example, assuming the conventional shorthand for the standard test
// macros:
//..
//  #define P                        BSLMT_TESTUTIL_P
//  #define P_                       BSLMT_TESTUTIL_P_
//  #define T_                       BSLMT_TESTUTIL_T_
//
//  #define COUT                     BSLMT_TESTUTIL_COUT
//..
// and
//..
//  #define GUARD                    BSLMT_TESTUTIL_GUARD
//..
// consider two threads, one of which executes:
//..
//  int a = 4 * 5, b = 7 / 2, c = 5;
//
//  T_    P_(a);    P_(b);    P(c * 2);
//..
// while the other thread executes:
//..
//  int x = 3 * 7, y = 45, z = 103;
//
//  T_    P_(x);    P_(y);    P(z * 2);
//..
// In total, there are eight output operations on 'bsl::cout'.  Though the
// order of outputs within each thread is guaranteed, there is no guarantee
// that the entire line of output of either thread will be finished before the
// other begins.  One possible result (among other myriad possibilities) is:
//..
//          x = 21,     a = 20, b = 3, y = 45, z = 206
//  c * 2 = 10
//
//..
// Clearly, such output is difficult to interpret.  Fortunately, we have a
// remedy.
//
// The two sets of output operation can be serialized by requiring the creation
// of a 'GUARD' object before each set of output operations, and destroying
// that object afterwards.  The existence of a guard object on the stack of one
// thread blocks the construction of guard objects by *other* threads until the
// existing guard object is destroyed.
//
// The behavior is undefined if guard objects are created anywhere but on the
// stack (i.e., automatic variables).
//
// Our revised (guarded) code can be written this way in one thread:
//..
//  int a = 4 * 5, b = 7 / 2, c = 5;
//  {
//      GUARD;
//
//      T_    P_(a);    P_(b);    P(c * 2);
//  }
//..
// and this way in the other thread:
//..
//  int x = 3 * 7, y = 45, z = 103;
//  {
//      GUARD;
//
//      T_    P_(x);    P_(y);    P(z * 2);
//  }
//..
// Now, possibility of the two threads interleaving this output has been
// eliminated and the output will appear in either this order:
//..
//      a = 20, b = 3, c * 2 = 10
//      x = 21, y = 45, z * 2 = 206
//..
// or this order:
//..
//      x = 21, y = 45, z * 2 = 206
//      a = 20, b = 3, c * 2 = 10
//..
// Note that each *individual* thread can own several guard objects at a given
// time.  (Recall the constructor blocks if guards exist on *other* threads).
// Thus, guarded sections can call, without fear of deadlock, functions that
// may create their own guard objects.
//
// If a guard exists in a thread, more guards can be created in the same thread
// with no effect.  Guards cannot be created in another thread until all of the
// guards have been destroyed.  So the above example could have been:
//..
//  int a = 4 * 5, b = 7 / 2, c = 5;
//  {
//      GUARD;
//      GUARD;
//      GUARD;
//      GUARD;
//
//      T_    P_(a);    P_(b);    P(c * 2);
//  }
//..
// and in the other thread:
//..
//  int x = 3 * 7, y = 45, z = 103;
//  {
//      GUARD;
//
//      T_    P_(x);
//
//      {
//          GUARD;
//
//          P_(y);    P(z * 2);
//      }
//  }
//..
// and the result would have been EXACTLY the same.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Use of Thread-Safe Asserts and Guard in a Test Driver
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// First, we write a function, 'sumOfSquares', to test:
//..
//  namespace xyzde {
//
//  struct SumUtil {
//      // This utility class provides sample functionality to demonstrate how
//      // a multi-threaded test driver might be written.
//
//      // CLASS METHODS
//      static double sumOfSquares(double a,
//                                 double b = 0,
//                                 double c = 0,
//                                 double d = 0);
//          // Return the sum of the squares of one to 4 arguments, the
//          // specified 'a' and the optionally specified 'b', 'c', and 'd'.
//  };
//
//  // CLASS METHODS
//  inline
//  double SumUtil::sumOfSquares(double a,
//                               double b,
//                               double c,
//                               double d)
//  {
//      // Note that there is a bug here in that we have added the cube, rather
//      // than the square, of 'd'.
//
//      double ret = a * a;
//      ret += b * b;
//      ret += c * c;
//      ret += d * d * d;
//      return ret;
//  }
//
//  }  // close namespace xyzde
//..
// Then, we can write a test driver for this component.  We start by providing
// the standard BDE 'ASSERT' test macro, which is not thread-safe, and is the
// same as it is for a test driver using 'bslim_testutil'.  The macros in
// 'bslmt_testutil' ensure that any time this function is called, the global
// mutex has been acquired.
//..
//  // ========================================================================
//  //                       STANDARD BDE ASSERT TEST FUNCTION
//  // ------------------------------------------------------------------------
//  int testStatus = 0;
//
//  void aSsErT(int c, const char *s, int i)
//  {
//      if (c) {
//          bsl::cout << "Error " << __FILE__ << "(" << i << "): " << s
//                    << "    (failed)" << bsl::endl;
//          if (testStatus >= 0 && testStatus <= 100) ++testStatus;
//      }
//  }
//..
// Next, we define the standard output and 'ASSERT*' macros, as aliases to the
// macros defined by this component:
//..
//  // ========================================================================
//  //                       STANDARD BDE TEST DRIVER MACROS
//  // ------------------------------------------------------------------------
//
//  #define ASSERT                   BSLMT_TESTUTIL_ASSERT
//  #define ASSERTV                  BSLMT_TESTUTIL_ASSERTV
//
//  #define LOOP_ASSERT              BSLMT_TESTUTIL_LOOP_ASSERT
//  #define LOOP2_ASSERT             BSLMT_TESTUTIL_LOOP2_ASSERT
//  #define LOOP3_ASSERT             BSLMT_TESTUTIL_LOOP3_ASSERT
//  #define LOOP4_ASSERT             BSLMT_TESTUTIL_LOOP4_ASSERT
//  #define LOOP5_ASSERT             BSLMT_TESTUTIL_LOOP5_ASSERT
//  #define LOOP6_ASSERT             BSLMT_TESTUTIL_LOOP6_ASSERT
//
//  #define GUARD                    BSLMT_TESTUTIL_GUARD
//
//  #define Q                        BSLMT_TESTUTIL_Q
//  #define P                        BSLMT_TESTUTIL_P
//  #define P_                       BSLMT_TESTUTIL_P_
//  #define T_                       BSLMT_TESTUTIL_T_
//  #define L_                       BSLMT_TESTUTIL_L_
//
//  #define GUARDED_STREAM(STREAM)   BSLMT_TESTUTIL_GUARDED_STREAM(STREAM)
//  #define COUT                     BSLMT_TESTUTIL_COUT
//  #define CERR                     BSLMT_TESTUTIL_CERR
//..
// Then, we define global verbosity flags to be used for controlling debug
// traces.  The flags will be set by elided code at the beginning of 'main' to
// determine the level of output verbosity the client wants:
//..
//  // ========================================================================
//  //                     GLOBAL TYPEDEFS/CONSTANTS FOR TESTING
//  // ------------------------------------------------------------------------
//
//  bool  verbose;
//  bool  veryVerbose;
//  bool  veryVeryVerbose;
//  bool  veryVeryVeryVerbose;
//..
// Next begin the usage test case, defining a 'typedef' and some 'enum's used
// by this test case:
//..
//                              // ---------------
//                              // Usage Test Case
//                              // ---------------
//
//  typedef  xyzde::SumUtil SU;
//
//  enum { k_NUM_THREADS =    5,
//         k_HI_LIMIT_X  =  100,
//         k_LO_LIMIT_X  = -100 };
//..
// Then, using our test macros, we write our test functor that can be run
// concurrently to test the static function:
//..
//  struct SumUtilTest {
//      void operator()()
//          // Test 'TestUtil::sumOfSquares' with a variety of randomly
//          // generated arguments.
//      {
//          int    threadIdx;
//          double x[4];                // randomly-generated test values
//..
// Next, we use the 'GUARD' macro to serialize the initialization of
// 'threadIdx' and the 'x' array.  We call 'bsl::srand' and 'bsl::rand', which
// are not thread-safe, so the calls to them must be mutex-guarded.  Because
// all access to 'mainThreadIdx' is guarded by the 'GUARD' call, it does not
// need to be an atomic variable.
//..
//          {
//              GUARD;
//
//              static int mainThreadIdx = 0;
//              threadIdx = mainThreadIdx++;
//
//              unsigned randSeed = (1234567891 + threadIdx) * 3333333333U;
//              bsl::srand(randSeed);
//
//              for (int ii = 0; ii < 4; ++ii) {
//                  // Note that 'bsl::rand' always returns a non-negative
//                  // value.
//
//                  const double characteristic =  bsl::rand() % k_HI_LIMIT_X;
//                  const double mantissa       =
//                             static_cast<double>(bsl::rand() % 1024) / 1024;
//                  const int    sign           = (bsl::rand() & 1) ? +1 : -1;
//
//                  // Note that it is safe to use 'ASSERTV', which redundantly
//                  // locks the mutex, even though the mutex has already been
//                  // acquired by the 'GUARD' call above.
//
//                  ASSERTV(threadIdx,ii, characteristic, 0 <= characteristic);
//                  ASSERTV(threadIdx,ii, characteristic,
//                                              characteristic < k_HI_LIMIT_X);
//                  ASSERTV(threadIdx,ii, mantissa,       0 <= mantissa);
//                  ASSERTV(threadIdx,ii, mantissa,       mantissa < 1);
//
//                  x[ii] = sign * (characteristic + mantissa / 1000);
//              }
//..
// Then we close the block, allowing other threads to do output with the
// 'BSLMT_TESTUTIL_*' macros or enter sections guarded by 'GUARD's.  Now, if we
// want to do output, we have to acquire the critical section again, which we
// can do by using the 'COUT' (aliased to 'BSLMT_TESTUTIL_COUT') macro:
//..
//          }
//
//          if (veryVerbose) COUT << "threadIdx: " << threadIdx <<
//                     ", x[] = { " << x[0] << ", " << x[1] << ", " << x[2] <<
//                                                       ", " << x[3] <<" }\n";
//..
// Next, if any of the 'ASSERTV's following this point fail with no 'GUARD'
// call in scope, they will lock the mutex before doing output.  Note that the
// 'ASSERTV's do not lock the mutex while checking to see if the predicate
// passed to them is 'false'.
//..
//          for (int ii = 0; ii < 4; ++ii) {
//              ASSERTV(threadIdx, ii, x[ii], x[ii] < k_HI_LIMIT_X);
//              ASSERTV(threadIdx, ii, x[ii], k_LO_LIMIT_X < x[ii]);
//          }
//
//          double exp = x[0] * x[0];
//          ASSERTV(x[0], exp, SU::sumOfSquares(x[0]),
//                                              exp == SU::sumOfSquares(x[0]));
//
//          exp += x[1] * x[1];
//          ASSERTV(x[0], x[1], exp, SU::sumOfSquares(x[0], x[1]),
//                                        exp == SU::sumOfSquares(x[0], x[1]));
//
//          exp += x[2] * x[2];
//          ASSERTV(x[0], x[1], x[2], exp, SU::sumOfSquares(x[0], x[1], x[2]),
//                                  exp == SU::sumOfSquares(x[0], x[1], x[2]));
//
//          exp += x[3] * x[3];
//          ASSERTV(x[0], x[1], x[2], x[3], exp,
//                                    SU::sumOfSquares(x[0], x[1], x[2], x[3]),
//                            exp == SU::sumOfSquares(x[0], x[1], x[2], x[3]));
//..
// Then, if we want to do any more output, since the mutex has not been
// acquired at this point, we have to re-acquire it.  We have a choice between
// using 'COUT' again, as we did above, or by using 'GUARD' and 'bsl::cout':
//..
//          if (veryVerbose) {
//              GUARD;
//
//              bsl::cout << "Thread number " << threadIdx << " finishing.\n";
//          }
//      }
//  };
//..
// Next, in 'main', we spawn our threads and let them run:
//..
//  int main()
//  {
//      // ..
//
//      using namespace BloombergLP;
//
//      bslmt::ThreadGroup tg;
//      tg.addThreads(SumUtilTest(), k_NUM_THREADS);
//..
// Then, we join the threads:
//..
//      tg.joinAll();
//..
// Now, we observe output something like this (tabs eliminated, long lines
// wrapped).  Note that each of the five test threads reported a failure:
//..
//  x[0]: 24.0005  x[1]: 80.0001  x[2]: 14.0009  x[3]: 3.00029  exp: 7181.07
//  SU::sumOfSquares(x[0], x[1], x[2], x[3]): 7199.08
//  Error ../../bde/groups/bsl/bslmt/bslmt_testutil.t.cpp(380):
//                  exp == SU::sumOfSquares(x[0], x[1], x[2], x[3])    (failed)
//  x[0]: -81.0006  x[1]: -82.0009  x[2]: 36.0009  x[3]: -59.0002
//  exp: 18062.3  SU::sumOfSquares(x[0], x[1], x[2], x[3]): -190799
//  Error ../../bde/groups/bsl/bslmt/bslmt_testutil.t.cpp(380):
//                  exp == SU::sumOfSquares(x[0], x[1], x[2], x[3])    (failed)
//  x[0]: 46.0001  x[1]: -62.0004  x[2]: 75.0006  x[3]: -66.0008  exp: 15941.3
//  SU::sumOfSquares(x[0], x[1], x[2], x[3]): -275921
//  Error ../../bde/groups/bsl/bslmt/bslmt_testutil.t.cpp(380):
//                  exp == SU::sumOfSquares(x[0], x[1], x[2], x[3])    (failed)
//  x[0]: -18.0003  x[1]: -84.0006  x[2]: 79.0004  x[3]: 76.0007  exp: 19397.3
//  SU::sumOfSquares(x[0], x[1], x[2], x[3]): 452609
//  Error ../../bde/groups/bsl/bslmt/bslmt_testutil.t.cpp(380):
//                  exp == SU::sumOfSquares(x[0], x[1], x[2], x[3])    (failed)
//  x[0]: -55.0006  x[1]: 35.0004  x[2]: 54.0009  x[3]: -45.0002  exp: 9191.21
//  SU::sumOfSquares(x[0], x[1], x[2], x[3]): -83960.1
//  Error ../../bde/groups/bsl/bslmt/bslmt_testutil.t.cpp(380):
//                  exp == SU::sumOfSquares(x[0], x[1], x[2], x[3])    (failed)
//..
// Finally, at the end of 'main' examine 'testStatus'.  If it's greater than 0,
// report that the test failed.  Note that since there is a bug in
// 'SU::sumOfSquares' with 4 args, we expect the last assert in
// 'SumUtil::operator()' to fail 5 times, so the following message will report
// 'test status = 5'.
//..
//
//      if (testStatus > 0) {
//          bsl::cerr << "Error, non-zero test status = " << testStatus << "."
//                    << bsl::endl;
//      }
//
//      return testStatus;
//  }
//..

#include <bslscm_version.h>

#include <bslmt_recursivemutex.h>

#include <bslmf_assert.h>

#include <bsls_keyword.h>
#include <bsls_unspecifiedbool.h>

#include <bsl_iostream.h>
#include <bsl_string.h>

                           // =================
                           // Macro Definitions
                           // =================

#define BSLMT_TESTUTIL_GUARD_NAME_IMPL                                        \
                                  bloomberglp_bslmt_tEsTuTiL_GuArD_ ## __LINE__

#define BSLMT_TESTUTIL_GUARD                                                  \
        BloombergLP::bslmt::TestUtil_Guard BSLMT_TESTUTIL_GUARD_NAME_IMPL
    // Acquire the critical section, and release it when the macro call goes
    // out of scope.  If the critical section is already held by the current
    // thread, this can still be used with no additional effect.

#define BSLMT_TESTUTIL_OUTPUT_GUARD           BSLMT_TESTUTIL_GUARD
#define BSLMT_TESTUTIL_NESTED_OUTPUT_GUARD    BSLMT_TESTUTIL_GUARD

#define BSLMT_TESTUTIL_GUARDED_STREAM(STREAM)                                 \
    for (BSLMT_TESTUTIL_GUARD; BSLMT_TESTUTIL_GUARD_NAME_IMPL;                \
                               BSLMT_TESTUTIL_GUARD_NAME_IMPL = false)        \
        (STREAM)
    // Enable output to the specified 'STREAM' that will not be interleaved
    // with output from 'bslmt_testutil' macros done by other threads.
    // 'STREAM' is expected to be a 'bsl::ostream' object, and this macro call
    // can be output to with the C++ '<<' operator with all output until the
    // terminating ';' occurring as one non-interleaved block.

#define BSLMT_TESTUTIL_COUT    BSLMT_TESTUTIL_GUARDED_STREAM(bsl::cout)
    // Equivalent to call to 'bsl::cout' guarded by a 'BSLMT_TESTUTIL_GUARD'
    // whose scope ends at the end of the statement.

#define BSLMT_TESTUTIL_CERR    BSLMT_TESTUTIL_GUARDED_STREAM(bsl::cerr)
    // Equivalent to call to 'bsl::cerr' guarded by a 'BSLMT_TESTUTIL_GUARD'
    // whose scope ends at the end of the statement.

#define BSLMT_TESTUTIL_LOOP0_ASSERT(X)                                        \
    if (X) ; else do { BSLMT_TESTUTIL_GUARD;                                  \
                       aSsErT(1, #X, __LINE__); } while (false)

#define BSLMT_TESTUTIL_ASSERT(X) BSLMT_TESTUTIL_LOOP0_ASSERT(X)

#define BSLMT_TESTUTIL_LOOP1_ASSERT(I,X)                                      \
    if (X) ; else do { BSLMT_TESTUTIL_GUARD;                                  \
                       bsl::cout << #I << ": " << (I) << "\n";                \
                       aSsErT(1, #X, __LINE__); } while (false)

#define BSLMT_TESTUTIL_LOOP_ASSERT(X) BSLMT_TESTUTIL_LOOP1_ASSERT(X)

#define BSLMT_TESTUTIL_LOOP2_ASSERT(I,J,X)                                    \
    if (X) ; else do { BSLMT_TESTUTIL_GUARD;                                  \
                       bsl::cout << #I << ": " << (I) << "\t"                 \
                                 << #J << ": " << (J) << "\n";                \
                       aSsErT(1, #X, __LINE__); } while (false)

#define BSLMT_TESTUTIL_LOOP3_ASSERT(I,J,K,X)                                  \
    if (X) ; else do { BSLMT_TESTUTIL_GUARD;                                  \
                       bsl::cout << #I << ": " << (I) << "\t"                 \
                                 << #J << ": " << (J) << "\t"                 \
                                 << #K << ": " << (K) << "\n";                \
                       aSsErT(1, #X, __LINE__); } while (false)

#define BSLMT_TESTUTIL_LOOP4_ASSERT(I,J,K,L,X)                                \
    if (X) ; else do { BSLMT_TESTUTIL_GUARD;                                  \
                       bsl::cout << #I << ": " << (I) << "\t"                 \
                                 << #J << ": " << (J) << "\t"                 \
                                 << #K << ": " << (K) << "\t"                 \
                                 << #L << ": " << (L) << "\n";                \
                       aSsErT(1, #X, __LINE__); } while (false)

#define BSLMT_TESTUTIL_LOOP5_ASSERT(I,J,K,L,M,X)                              \
    if (X) ; else do { BSLMT_TESTUTIL_GUARD;                                  \
                       bsl::cout << #I << ": " << (I) << "\t"                 \
                                 << #J << ": " << (J) << "\t"                 \
                                 << #K << ": " << (K) << "\t"                 \
                                 << #L << ": " << (L) << "\t"                 \
                                 << #M << ": " << (M) << "\n";                \
                       aSsErT(1, #X, __LINE__); } while (false)

#define BSLMT_TESTUTIL_LOOP6_ASSERT(I,J,K,L,M,N,X)                            \
    if (X) ; else do { BSLMT_TESTUTIL_GUARD;                                  \
                       bsl::cout << #I << ": " << (I) << "\t"                 \
                                 << #J << ": " << (J) << "\t"                 \
                                 << #K << ": " << (K) << "\t"                 \
                                 << #L << ": " << (L) << "\t"                 \
                                 << #M << ": " << (M) << "\t"                 \
                                 << #N << ": " << (N) << "\n";                \
                       aSsErT(1, #X, __LINE__); } while (false)

// The 'BSLMT_TESTUTIL_EXPAND' macro is required to work around a preprocessor
// issue on Windows that prevents '__VA_ARGS__' from being expanded in the
// definition of 'BSLMT_TESTUTIL_NUM_ARGS'.

#define BSLMT_TESTUTIL_EXPAND(X)                                              \
    X

#define BSLMT_TESTUTIL_NUM_ARGS_IMPL(X6, X5, X4, X3, X2, X1, X0, N, ...)      \
    N

#define BSLMT_TESTUTIL_NUM_ARGS(...)                                          \
    BSLMT_TESTUTIL_EXPAND(BSLMT_TESTUTIL_NUM_ARGS_IMPL(                       \
                                         __VA_ARGS__, 6, 5, 4, 3, 2, 1, 0, ""))

#define BSLMT_TESTUTIL_LOOPN_ASSERT_IMPL(N, ...)                              \
    BSLMT_TESTUTIL_EXPAND(BSLMT_TESTUTIL_LOOP ## N ## _ASSERT(__VA_ARGS__))

#define BSLMT_TESTUTIL_LOOPN_ASSERT(N, ...)                                   \
    BSLMT_TESTUTIL_LOOPN_ASSERT_IMPL(N, __VA_ARGS__)

#define BSLMT_TESTUTIL_ASSERTV(...) BSLMT_TESTUTIL_LOOPN_ASSERT(              \
                             BSLMT_TESTUTIL_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)

// The following four macros guarantee atomicity of their output by implicitly
// creating a GUARD objects.  As with the other macros, these macros can be
// used within the scope of another GUARD object.

#define BSLMT_TESTUTIL_Q(X)                                                   \
    BSLMT_TESTUTIL_COUT << "<| " #X " |>" << bsl::endl
    // Quote identifier literally.

#define BSLMT_TESTUTIL_P(X)                                                   \
    BSLMT_TESTUTIL_COUT << #X " = " << (X) << bsl::endl
    // Print identifier and its value.

#define BSLMT_TESTUTIL_P_(X)                                                  \
    BSLMT_TESTUTIL_COUT << #X " = " << (X) << ", " << bsl::flush
    // 'P(X)' without '\n'

#define BSLMT_TESTUTIL_T_                                                     \
    BSLMT_TESTUTIL_COUT << "\t" << bsl::flush;
    // Print tab (w/o newline).  Do not put in a 'do {} while(false)', as this
    // macro is intended to be called without a terminating ';'.

#define BSLMT_TESTUTIL_L_                                                     \
    __LINE__
    // current Line number


namespace BloombergLP {
namespace bslmt {

                              // ===============
                              // struct TestUtil
                              // ===============

struct TestUtil {
    // This 'struct' provides a namespace for a suite of utility functions that
    // facilitate the creation of BDE-style test drivers.
    //
    // The 'callFunc' function, because it's out-of-line implementation is in
    // the '.cpp' file, can be used to prevent unwanted inlining in test
    // drivers, particularly useful when testing the stack trace functionality.

  private:
    // PRIVATE CLASS METHODS
    static void *identityPtr(void *ptr);
        // Return 'ptr' without modification.  Note that this is NOT an inline
        // function, so that if the caller is not in the same module, the
        // compiler has no way of knowing that it's an identity transform.

  public:
    // CLASS METHODS
    template <class FUNCTION_PTR>
    static FUNCTION_PTR makeFunctionCallNonInline(FUNCTION_PTR functionPtr);
        // Return the specified 'functionPtr' (expected to be a static function
        // pointer) without modification.  The value of 'functionPtr' is
        // transformed through 'identityPtr' so that if the caller is in a
        // different module, the compiler will have no way of knowing that this
        // is an identity function and thus no way of inlining the call.
};

                              // ====================
                              // class TestUtil_Guard
                              // ====================

class TestUtil_Guard {
    // This 'class' defines an object that provides exclusive access to the
    // critical sections defined by this component's macros.  Multiple 'Guard'
    // objects can exist at once, but only in the same thread -- if an attempt
    // is made to construct a 'Guard' while any 'Guard's exist in other
    // threads, the constructor will block until all 'Guard' objects in other
    // threads are destroyed.  The behavior is undefined if a 'Guard' object is
    // anywhere but on the stack.

    // PRIVATE TYPE
    typedef bsls::UnspecifiedBool<TestUtil_Guard> UnspecifiedBool;

  public:
    // PUBLIC TYPE
    typedef UnspecifiedBool::BoolType             BoolType;

  private:
    // DATA
    RecursiveMutex *d_mutex_p;
    bool            d_boolState;    // boolean state assignable by 'operator='
                                    // and observable by casting the object to
                                    // 'bool'.

    // PRIVATE CLASS METHOD
    static RecursiveMutex& singletonMutex();
        // Return a non-'const' reference to the recursive mutex created by the
        // singleton.

  private:
    // NOT IMPLEMENTED
    TestUtil_Guard(const TestUtil_Guard&)            BSLS_KEYWORD_DELETED;
    TestUtil_Guard& operator=(const TestUtil_Guard&) BSLS_KEYWORD_DELETED;

  public:
    // CREATORS
    TestUtil_Guard();
        // Create a guard that locks the mutex in the singleton and saves the
        // address of the singleton mutex.

    ~TestUtil_Guard();
        // Unlock the recursive mutex that was locked by the constructor.

    // MANIPULATOR
    void operator=(bool rhs);
        // Set the boolean state of this object to the specified 'rhs'.

    // ACCESSOR
    operator BoolType() const;
        // Return the boolean state of this 'TestUtil_Guard' object.
};

// ============================================================================
//                           INLINE FUNCTION DEFINITIONS
// ============================================================================

                                // --------
                                // TestUtil
                                // --------

template <class FUNCTION_PTR>
inline
FUNCTION_PTR TestUtil::makeFunctionCallNonInline(FUNCTION_PTR functionPtr)
{
    BSLMF_ASSERT(sizeof(FUNCTION_PTR) == sizeof(void *));

    return reinterpret_cast<FUNCTION_PTR>(
                           identityPtr(reinterpret_cast<void *>(functionPtr)));
}

                             // --------------------
                             // class TestUtil_Guard
                             // --------------------

inline
TestUtil_Guard::TestUtil_Guard()
: d_boolState(true)
{
    (d_mutex_p = &singletonMutex())->lock();
}

inline
TestUtil_Guard::~TestUtil_Guard()
{
    d_mutex_p->unlock();
}

inline
void TestUtil_Guard::operator=(bool rhs)
{
    d_boolState = rhs;
}

inline
TestUtil_Guard::operator TestUtil_Guard::BoolType() const
{
    return UnspecifiedBool::makeValue(d_boolState);
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2018 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------