Quick Links:

bal | bbl | bdl | bsl

Namespaces | Defines

Component bsls_protocoltest
[Package bsls]

Provide classes and macros for testing abstract protocols. More...

Namespaces

namespace  bsls

Defines

#define BSLS_PROTOCOLTEST_ASSERT(test, methodCall)

Detailed Description

Outline
Purpose:
Provide classes and macros for testing abstract protocols.
Classes:
bsls::ProtocolTestImp provides a framework for testing protocol classes
bsls::ProtocolTest provides tests for protocol class concerns
Macros:
BSLS_PROTOCOLTEST_ASSERT macro for testing protocol methods
Description:
This component provides classes and macros that simplify the creation of test drivers for protocol (i.e., pure abstract interface) classes.
The purpose of a test driver for a protocol class is to verify concerns for that protocol's definition. Although each protocol is different and requires its own test driver, there is a common set of concerns that apply to all protocol classes. This component allows us to verify those concerns in a generic manner.
Each protocol class has to satisfy the following set of requirements (concerns):
  • The protocol is abstract: no objects of it can be created.
  • The protocol has no data members.
  • The protocol has a virtual destructor.
  • All methods of the protocol are pure virtual.
  • All methods of the protocol are publicly accessible.
This protocol test component is intended to verify conformance to these requirements; however, it is not possible to verify all protocol requirements fully within the framework of the C++ language. The following aspects of the above requirements are not verified by this component:
  • Non-creator methods of the protocol are pure virtual.
  • There are no methods in the protocol other than the ones being tested.
Additionally some coding guidelines related to protocols are also not verified:
  • The destructor is not pure virtual.
  • The destructor is not implemented inline.
Usage:
This section illustrates intended use of this component.
Example 1: Testing a Protocol Class:
This example demonstrates how to test a protocol class, ProtocolClass, using this protocol test component. Our ProtocolClass provides two of pure virtual methods (foo and bar), along with a virtual destructor:
  struct ProtocolClass {
      virtual ~ProtocolClass();
      virtual const char *bar(char const *, char const *) = 0;
      virtual int foo(int) const = 0;
  };

  ProtocolClass::~ProtocolClass()
  {
  }
First, we define a test class derived from this protocol, and implement its virtual methods. Rather than deriving the test class from ProtocolClass directly, the test class is derived from bsls::ProtocolTestImp<ProtocolClass> (which, in turn, is derived automatically from ProtocolClass). This special base class implements boilerplate code and provides useful functionality for testing of protocols.
  // ========================================================================
  //                  GLOBAL CLASSES/TYPEDEFS FOR TESTING
  // ------------------------------------------------------------------------

  struct ProtocolClassTestImp : bsls::ProtocolTestImp<ProtocolClass> {
      const char *bar(char const *, char const *) { return markDone(); }
      int foo(int) const                          { return markDone(); }
  };
Notice that in ProtocolClassTestImp we must provide an implementation for every protocol method except for the destructor. The implementation of each method calls the (protected) markDone which is provided by the base class for the purpose of verifying that the method from which it's called is declared as virtual in the protocol class.
Then, in our protocol test case we describe the concerns we have for the protocol class and the plan to test those concerns:
  // ------------------------------------------------------------------------
  // PROTOCOL TEST:
  //   Ensure this class is a properly defined protocol.
  //
  // Concerns:
  //: 1 The protocol is abstract: no objects of it can be created.
  //:
  //: 2 The protocol has no data members.
  //:
  //: 3 The protocol has a virtual destructor.
  //:
  //: 4 All methods of the protocol are pure virtual.
  //:
  //: 5 All methods of the protocol are publicly accessible.
  //
  // Plan:
  //: 1 Define a concrete derived implementation, 'ProtocolClassTestImp',
  //:   of the protocol.
  //:
  //: 2 Create an object of the 'bsls::ProtocolTest' class template
  //:   parameterized by 'ProtocolClassTestImp', and use it to verify
  //:   that:
  //:
  //:   1 The protocol is abstract. (C-1)
  //:
  //:   2 The protocol has no data members. (C-2)
  //:
  //:   3 The protocol has a virtual destructor. (C-3)
  //:
  //: 3 Use the 'BSLS_PROTOCOLTEST_ASSERT' macro to verify that
  //:   non-creator methods of the protocol are:
  //:
  //:   1 virtual, (C-4)
  //:
  //:   2 publicly accessible. (C-5)
  //
  // Testing:
  //   virtual ~ProtocolClass();
  //   virtual const char *bar(char const *, char const *) = 0;
  //   virtual int foo(int) const = 0;
  // ------------------------------------------------------------------------
Next we print the banner for this test case:
  if (verbose) printf("\nPROTOCOL TEST"
                      "\n=============\n");
Then, we create an object of type bsls::ProtocolTest<ProtocolClassTestImp>, testObj:
  if (verbose) printf("\nCreate a test object.\n");

  bsls::ProtocolTest<ProtocolClassTestImp> testObj(veryVerbose);
Now we use the testObj to test some general concerns about the protocol class.
  if (verbose) printf("\nVerify that the protocol is abstract.\n");

  ASSERT(testObj.testAbstract());

  if (verbose) printf("\nVerify that there are no data members.\n");

  ASSERT(testObj.testNoDataMembers());

  if (verbose) printf("\nVerify that the destructor is virtual.\n");

  ASSERT(testObj.testVirtualDestructor());
Finally we use the testObj to test concerns for each individual method of the protocol class. To test a protocol method we need to call it from inside the BSLS_PROTOCOLTEST_ASSERT macro, and also pass the testObj:
  if (verbose) printf("\nVerify that methods are public and virtual.\n");

  BSLS_PROTOCOLTEST_ASSERT(testObj, foo(77));
  BSLS_PROTOCOLTEST_ASSERT(testObj, bar("", ""));
These steps conclude the protocol testing. If there are any failures, they will be reported via standard test driver assertions (i.e., the standard ASSERT macro).
Implementation Note:
This component has a number of private meta-functions on some platforms, e.g., ProtocolTest_EnableIf, ProtocolTest_IsClass, and ProtocolTest_IsAbstract. These mimic, to a limited extent, standard library meta-functions in the namespace std that are not available on all platforms. For general use, see the bslmf package and the bsl namespace for portable implementations of some of these meta-functions.

Define Documentation

#define BSLS_PROTOCOLTEST_ASSERT (   test,
  methodCall 
)
Value:
do {                                                                      \
        test.method(                                                          \
                "inside BSLS_PROTOCOLTEST_ASSERT("#methodCall")")->methodCall;\
        if (!test.lastStatus()) {                                             \
            ASSERT(0 && "Not a virtual method: "#methodCall);                 \
        }                                                                     \
    } while (0)