From b9647726c68fa2db99f7aef1d183994ba776a1a8 Mon Sep 17 00:00:00 2001 From: Harold Bott Date: Tue, 28 Jan 2025 09:55:25 -0500 Subject: [PATCH] Support BSLS_REVIEW failures in fuzz tests DRQS 174557082 (#4785) --- groups/bsl/bsls/bsls_fuzztest.cpp | 95 ++- groups/bsl/bsls/bsls_fuzztest.h | 254 ++++--- groups/bsl/bsls/bsls_fuzztest.t.cpp | 717 +++++++++++------- groups/bsl/bsls/bsls_fuzztest_testutil.cpp | 41 + groups/bsl/bsls/bsls_fuzztest_testutil.h | 78 ++ groups/bsl/bsls/bsls_fuzztest_testutil.t.cpp | 199 +++++ .../bsls/bsls_fuzztestpreconditionexception.h | 114 ++- .../bsls_fuzztestpreconditionexception.t.cpp | 344 ++++----- groups/bsl/bsls/bsls_preconditions.h | 17 +- groups/bsl/bsls/bsls_preconditions.t.cpp | 38 +- groups/bsl/bsls/doc/bsls.txt | 20 +- groups/bsl/bsls/package/bsls.mem | 5 +- 12 files changed, 1255 insertions(+), 667 deletions(-) create mode 100644 groups/bsl/bsls/bsls_fuzztest_testutil.cpp create mode 100644 groups/bsl/bsls/bsls_fuzztest_testutil.h create mode 100644 groups/bsl/bsls/bsls_fuzztest_testutil.t.cpp diff --git a/groups/bsl/bsls/bsls_fuzztest.cpp b/groups/bsl/bsls/bsls_fuzztest.cpp index 59a56701bc..f06c8b94d2 100644 --- a/groups/bsl/bsls/bsls_fuzztest.cpp +++ b/groups/bsl/bsls/bsls_fuzztest.cpp @@ -18,29 +18,50 @@ const char *FuzzTestPreconditionTracker::s_file_p = ""; bool FuzzTestPreconditionTracker::s_isInFirstPreconditionBlock = false; int FuzzTestPreconditionTracker::s_level = 0; -Assert::ViolationHandler -FuzzTestHandlerGuard::s_originalAssertionHandler = &Assert::failByAbort; - +FuzzTestHandlerGuard +*FuzzTestHandlerGuard::s_currentFuzzTestHandlerGuard_p = NULL; // --------------------------------- // class FuzzTestPreconditionTracker // --------------------------------- // CLASS METHODS +void FuzzTestPreconditionTracker::handleAssertViolation( + const AssertViolation& violation) +{ + if (s_isInFirstPreconditionBlock && (1 == s_level)) { + // Prior to `END`, an assertion was triggered. We still must verify + // that this assertion did not come from a different component. That + // check is done in `handleException`. + FuzzTestPreconditionException exception(violation.comment(), + violation.fileName(), + violation.lineNumber(), + violation.assertLevel(), + false); + BSLS_THROW(exception); + } + else { + Assert::ViolationHandler vh = + FuzzTestHandlerGuard::instance()->getOriginalAssertionHandler(); + vh(violation); + } +} + void FuzzTestPreconditionTracker::handleException( const FuzzTestPreconditionException& exception) { const char *exceptionComponent = NULL; - size_t exceptionNameLength = 0; + std::size_t exceptionNameLength = 0; + const char *fileName = exception.filename(); - // Check that the assertion comes from a component with a valid BDE-style - // name. + // Check that the assertion/review failure comes from a component with a + // valid BDE-style name. if (0 == bsls::BslSourceNameParserUtil::getComponentName( &exceptionComponent, &exceptionNameLength, - exception.assertViolation().fileName())) { + fileName)) { const char *currentComponent = NULL; - size_t currentNameLength = 0; + std::size_t currentNameLength = 0; // Check that the current component has a valid BDE-style name. if (0 == bsls::BslSourceNameParserUtil::getComponentName( ¤tComponent, ¤tNameLength, s_file_p)) { @@ -54,25 +75,22 @@ void FuzzTestPreconditionTracker::handleException( } } // If we reach here, the component names are different or not BDE-style. - Assert::ViolationHandler vh = - FuzzTestHandlerGuard::getOriginalAssertionHandler(); - vh(exception.assertViolation()); -} - -void FuzzTestPreconditionTracker::handlePreconditionViolation( - const AssertViolation& violation) -{ - if (s_isInFirstPreconditionBlock && (1 == s_level)) { - // Prior to 'END', an assertion was triggered. We still must verify - // that this assertion did not come from a different component. That - // check is done in 'handleException'. - FuzzTestPreconditionException exception(violation); - BSLS_THROW(exception); + if (exception.isReview()) { + Review::ViolationHandler vh = + FuzzTestHandlerGuard::instance()->getOriginalReviewHandler(); + vh(ReviewViolation(exception.expression(), + exception.filename(), + exception.lineNumber(), + exception.level(), + 0)); } else { Assert::ViolationHandler vh = - FuzzTestHandlerGuard::getOriginalAssertionHandler(); - vh(violation); + FuzzTestHandlerGuard::instance()->getOriginalAssertionHandler(); + vh(AssertViolation(exception.expression(), + exception.filename(), + exception.lineNumber(), + exception.level())); } } @@ -89,6 +107,35 @@ void FuzzTestPreconditionTracker::handlePreconditionsEnd() } } +void FuzzTestPreconditionTracker::handleReviewViolation( + const ReviewViolation& violation) +{ + if (s_isInFirstPreconditionBlock && (1 == s_level)) { + // Prior to `END`, a review was triggered. We still must verify that + // this review did not come from a different component. That check is + // done in `handleException`. + FuzzTestPreconditionException exception(violation.comment(), + violation.fileName(), + violation.lineNumber(), + violation.reviewLevel(), + true); + BSLS_THROW(exception); + } + else { + // We want the execution to end here, so we call the original handler + // for assertion violations (not review violations). This is because + // the default review violation handler logs the violation and + // continues. Note that this is acceptable because this function is + // intended to be invoked in test drivers only. + Assert::ViolationHandler vh = + FuzzTestHandlerGuard::instance()->getOriginalAssertionHandler(); + vh(AssertViolation(violation.comment(), + violation.fileName(), + violation.lineNumber(), + violation.reviewLevel())); + } +} + void FuzzTestPreconditionTracker::initStaticState(const char *fileName) { s_file_p = fileName; diff --git a/groups/bsl/bsls/bsls_fuzztest.h b/groups/bsl/bsls/bsls_fuzztest.h index d2b9cddbca..557393401c 100644 --- a/groups/bsl/bsls/bsls_fuzztest.h +++ b/groups/bsl/bsls/bsls_fuzztest.h @@ -9,7 +9,7 @@ BSLS_IDENT("$Id: $") // //@CLASSES: // bsls::FuzzTestPreconditionTracker: utility for tracking assert violations -// bsls::FuzzTestHandlerGuard: guard for fuzz testing assert-handler +// bsls::FuzzTestHandlerGuard: guard for fuzz testing assert-/review-handler // //@MACROS: // BSLS_FUZZTEST_EVALUATE(EXPRESSION): wrapper for narrow contract function @@ -27,30 +27,31 @@ BSLS_IDENT("$Id: $") // data we pass to the function (as this may be error-prone and might introduce // bias into the tested input) we must address the issue that we will often // invoke the function out of contract, and this will cause the function to -// assert, and the test to end prematurely. The macros defined in this +// assert/review, and the test to end prematurely. The macros defined in this // component solve this issue by detecting the location of precondition // violations. Functions with narrow contracts that are to be tested must be // decorated with the `BSLS_PRECONDITIONS_BEGIN` and `BSLS_PRECONDITIONS_END` // macros. These macros must be placed just before and after the function -// preconditions are checked. +// whose preconditions are checked. // // All these macros are intended to be used in fuzzing builds in which // `BDE_ACTIVATE_FUZZ_TESTING` is defined. For our purposes, those -// preconditions that fail in the function under test (i.e., the one invoked -// by `BSLS_FUZZTEST_EVALUATE`) are treated differently from all other +// preconditions that fail in the function under test (i.e., the one invoked by +// `BSLS_FUZZTEST_EVALUATE`) are treated differently from all other // precondition failures. We refer to these preconditions as "top-level" -// preconditions. If a top-level precondition fails -- and the assertion is -// not from another component -- the execution will continue: we do not wish to -// stop the fuzz test if we simply invoked the narrow contract function under -// test out of contract. We wish to detect only subsequent assertions (i.e., -// not in the top-level), or assertions from other components. +// preconditions. If a top-level precondition fails -- and the +// assertion/review is not from another component -- the execution will +// continue: we do not wish to stop the fuzz test if we simply invoked the +// narrow contract function under test out of contract. We wish to detect only +// subsequent assertions/reviews (i.e., not in the top-level), or +// assertions/reviews from other components. // -// The `BSLS_FUZZTEST_EVALUATE_RAW` macro does not check if the assertion -// originates from another component, though, like the non-`RAW` version, it -// ignores only top-level assertions. This behavior is desirable in cases in -// which a function delegates its implementation and associated precondition -// checks to a different component. In such cases, a precondition failure -// ought not cause the fuzz test to end. +// The `BSLS_FUZZTEST_EVALUATE_RAW` macro does not check if the +// assertion/review originates from another component, though, like the +// non-`RAW` version, it ignores only top-level assertions/reviews. This +// behavior is desirable in cases in which a function delegates its +// implementation and associated precondition checks to a different component. +// In such cases, a precondition failure ought not cause the fuzz test to end. // ///Usage ///----- @@ -65,14 +66,16 @@ BSLS_IDENT("$Id: $") // In this example, we illustrate the intended usage of two macros: // `BSLS_FUZZTEST_EVALUATE` and `BSLS_FUZZTEST_EVALUATE_RAW`. // -// First, in order to illustrate the use of `BSLS_FUZZTEST_EVALUATE`, we -// define two functions that implement the `sqrt` function, both decorated -// with the precondition `BEGIN` and `END` macros. `mySqrt` forwards its -// argument to `newtonsSqrt`, which has a slightly more restrictive -// precondition: `mySqrt` accepts 0, while `newtonsSqrt` does not. +// First, in order to illustrate the use of `BSLS_FUZZTEST_EVALUATE`, we define +// two functions that implement the `sqrt` function, both decorated with the +// precondition `BEGIN` and `END` macros. `mySqrt` forwards its argument to +// `newtonsSqrt`, which has a slightly more restrictive precondition: `mySqrt` +// accepts 0, while `newtonsSqrt` does not. // ``` // /// Return the square root of the specified `x` according to Newton's // /// method. The behavior is undefined unless `x > 0`. +// /// Return the square root of the specified `x` according to Newton's +// /// method. The behavior is undefined unless `x > 0`. // double newtonsSqrt(double x) // { // BSLS_PRECONDITIONS_BEGIN(); @@ -88,6 +91,8 @@ BSLS_IDENT("$Id: $") // // /// Return the square root of the specified `x`. The behavior is undefined // /// unless `x >= 0`. +// /// Return the square root of the specified `x`. The behavior is undefined +// /// unless `x >= 0`. // double mySqrt(double x) // { // BSLS_PRECONDITIONS_BEGIN(); @@ -97,39 +102,23 @@ BSLS_IDENT("$Id: $") // } // ``` // Then, for the illustration of `BSLS_FUZZTEST_EVALUATE_RAW`, we define a -// class, `Timer`, containing a `start` function that uses in its -// implementation a narrow contract function, `setInterval`, from another -// component, `bsls::TimeInterval`. This function, `setInterval`, has -// precondition checks that are surrounded by `BEGIN` and `END`. +// narrow function that uses a narrow function, `triggerAssert`, from another +// component, `bsls::FuzzTest_TestUtil`. This function, `triggerAssert`, +// always triggers an assertion failure. // ``` -// /// This class implements a simple interval timer. -// class Timer -// { -// private: -// // DATA -// bsls::TimeInterval d_timeout; // timeout seconds and nanoseconds -// -// public: -// // MANIPULATORS -// -// /// Start the countdown with a timer having the value given by the -// /// sum of the specified integral number of `seconds` and -// /// `nanoseconds`. The behavior is undefined unless the total -// /// number of seconds in the resulting time interval can be -// /// represented with a 64-bit signed integer (see -// /// `TimeInterval::isValid`). -// void start(bsls::Types::Int64 seconds, int nanoseconds) -// { -// d_timeout.setInterval(seconds, nanoseconds); -// //... -// } -// }; +// /// Invoke `triggerAssert` from `bsls::FuzzTest_TestUtil`. The behavior is +// /// undefined if `triggerAssert` fails. +// void invokeTriggerAssert() +// { +// bsls::FuzzTest_TestUtil::triggerAssert(); +// //... +// } // ``` // Next, implement `LLVMFuzzerTestOneInput`. We first select the test case // number based on the supplied fuzz data. // ``` -// /// Use the specified `data` array of `size` bytes as input to methods -// /// of this component and return zero. +// /// Use the specified `data` array of `size` bytes as input to methods of +// /// this component and return zero. // extern "C" // int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) // { @@ -150,11 +139,11 @@ BSLS_IDENT("$Id: $") // ``` // case 2: { // // ---------------------------------------------------------------- -// // 'mySqrt' +// // `mySqrt` // // // // Concerns: -// // 1. That `mySqrt` does not invoke the original assertion handler -// // for any `input` value. +// // 1. That `mySqrt` does not invoke the original assertion handler +// // for any `input` value. // // // // Testing: double mySqrt(double x); // // ---------------------------------------------------------------- @@ -188,25 +177,14 @@ BSLS_IDENT("$Id: $") // ``` // case 1: { // // ---------------------------------------------------------------- -// // 'Timer::start' +// // `invokeTriggerAssert` // // // // Concerns: -// // 1. That 'start', when invoked with the 'RAW' macro, does not -// // invoke the original assertion handler. +// // 1. That `invokeTriggerAssert`, when invoked with the `RAW` +// // macro, does not invoke the original assertion handler. // // -// // Testing: -// // void Timer::start(Int64 seconds, int nanoseconds); +// // Testing: void invokeTriggerAssert(); // // ---------------------------------------------------------------- -// -// if (size < sizeof(bsls::Types::Int64) + sizeof(int)) { -// return 0; // RETURN -// } -// bsls::Types::Int64 seconds; -// int nanoseconds; -// memcpy(&seconds, data, sizeof(bsls::Types::Int64)); -// memcpy(&nanoseconds, -// data + sizeof(bsls::Types::Int64), -// sizeof(int)); // ``` // Now, we set up the handler guard that installs the precondition handlers. // ``` @@ -215,22 +193,19 @@ BSLS_IDENT("$Id: $") // Finally, we invoke the function under test with the // `BSLS_FUZZTEST_EVALUATE_RAW` macro. // ``` -// Timer t; -// BSLS_FUZZTEST_EVALUATE_RAW(t.start(seconds, nanoseconds)); +// BSLS_FUZZTEST_EVALUATE_RAW(invokeTriggerAssert()); // ``` -// If the total number of seconds resulting from the sum of `seconds` and -// `nanoseconds` cannot be represented with a 64-bit signed integer, a -// top-level assertion failure from a different component will occur. Because -// we have invoked `start` with the `RAW` macro, a component name check will -// not be performed, and execution will continue. +// Here a top-level assertion failure from a different component will occur. +// Because we have invoked `invokeTriggerAssert` with the `RAW` macro, a +// component name check will not be performed, and execution will continue. // ``` // } break; -// default: { +// default: { // } break; // } // // if (testStatus > 0) { -// BSLS_ASSERT_INVOKE("FUZZ TEST FAILURES"); +// BSLS_REVIEW_INVOKE("FUZZ TEST FAILURES"); // } // // return 0; @@ -242,6 +217,7 @@ BSLS_IDENT("$Id: $") #include #include #include +#include // ================= // Macro Definitions @@ -310,41 +286,50 @@ struct FuzzTestPreconditionTracker { private: // CLASS DATA - static const char *s_file_p; // filename passed to 'initStaticState' + static const char *s_file_p; // filename passed to `initStaticState` static bool s_isInFirstPreconditionBlock; // flag indicating whether the first - // 'BEGIN/END' block has been closed + // `BEGIN/END` block has been closed - static int s_level; // nesting level of 'BEGIN'/'END' call + static int s_level; // nesting level of `BEGIN`/`END` call public: // CLASS METHODS - /// Invoke the assertion handler returned by - /// `FuzzTestHandlerGuard::getOriginalAssertionHandler` if the assertion - /// violation wrapped by the specified `exception` was encountered in a - /// component different from one supplied to `initStaticState`, and do - /// nothing otherwise. - static void handleException( - const FuzzTestPreconditionException& exception); - /// Throw a `FuzzTestPreconditionException` constructed from the specified /// `violation` if the assertion violation occurred after the first /// invocation of `handlePreconditionsBegin` but before the first /// invocation of `handlePreconditionsEnd`, and invoke the assertion /// handler returned by `FuzzTestHandlerGuard::getOriginalAssertionHandler` /// otherwise. - static void handlePreconditionViolation(const AssertViolation& violation); + static void handleAssertViolation(const AssertViolation& violation); + + /// Invoke the assertion/review handler returned by + /// `FuzzTestHandlerGuard::getOriginalAssertionHandler` or + /// `FuzzTestHandlerGuard::getOriginalReviewHandler` if the + /// assertion/review violation wrapped by the specified `exception` was + /// encountered in a component different from one supplied to + /// `initStaticState`, and do nothing otherwise. + static void handleException( + const FuzzTestPreconditionException& exception); - /// Increment the assertion block depth level counter. + /// Increment the assertion/review block depth level counter. static void handlePreconditionsBegin(); - /// Decrement the assertion block depth level counter and record that the - /// first precondition block has ended if the depth level changed to 0. - /// The behavior is undefined unless the depth level is positive. + /// Decrement the assertion/review block depth level counter and record + /// that the first precondition block has ended if the depth level changed + /// to 0. The behavior is undefined unless the depth level is positive. static void handlePreconditionsEnd(); + /// Throw a `FuzzTestPreconditionException` constructed from the specified + /// `violation` if the review violation occurred after the first invocation + /// of `handlePreconditionsBegin` but before the first invocation of + /// `handlePreconditionsEnd`, and invoke the assertion handler (not review + /// handler) returned by + /// `FuzzTestHandlerGuard::getOriginalAssertionHandler` otherwise. + static void handleReviewViolation(const ReviewViolation& violation); + /// Store the specified `fileName` from the caller that invokes the /// top-level function under test (via `BSLS_FUZZTEST_EVALUATE(X)`), and /// set the state to reflect that any precondition begin macro encountered @@ -356,35 +341,59 @@ struct FuzzTestPreconditionTracker { // class FuzzTestHandlerGuard // ========================== -/// This class provides a guard that will install and uninstall three handlers, -/// one for assertion failure, one for `BSLS_PRECONDITIONS_BEGIN`, and one for -/// `BSLS_PRECONDITIONS_END`, within the protected scope. +/// This class provides a guard that will install and uninstall four handlers, +/// one for assertion failure, one for review failure, one for +/// `BSLS_PRECONDITIONS_BEGIN`, and one for `BSLS_PRECONDITIONS_END`, within +/// its protected scope. class FuzzTestHandlerGuard { private: // CLASS DATA - static Assert::ViolationHandler - s_originalAssertionHandler; // original assertion handler + static FuzzTestHandlerGuard + *s_currentFuzzTestHandlerGuard_p; // current fuzz test handler guard + // (owned) + + // DATA + Assert::ViolationHandler + originalAssertionHandler; // original assertion handler + + Review::ViolationHandler + originalReviewHandler; // original review handler public: // CREATORS /// Create a guard object, installing - /// `FuzzTestPreconditionTracker::handlePreconditionViolation` as well as - /// the `BEGIN/END` handler. The behavior is undefined if the current + /// `FuzzTestPreconditionTracker::handleAssertViolation`, + /// `FuzzTestPreconditionTracker::handleReviewViolation`, and the + /// `BEGIN/END` handler. The behavior is undefined if the current /// assertion handler is - /// `FuzzTestPreconditionTracker::handlePreconditionViolation`. + /// `FuzzTestPreconditionTracker::handleAssertViolation` or the current + /// review handler is `FuzzTestPreconditionTracker::handleAssertViolation`. FuzzTestHandlerGuard(); /// Restore the failure handler that was in place when this object was /// created, reset the precondition `BEGIN/END` handlers to no-op, and - /// destroy this guard. + /// destroy this guard. The behavior is undefined unless the current + /// assertion handler is + /// `FuzzTestPreconditionTracker::handleAssertViolation` and the current + /// review handler is + /// `FuzzTestPreconditionTracker::handleAssertViolation`. ~FuzzTestHandlerGuard(); // CLASS METHODS + /// Return the current fuzz test handler guard. The behavior is undefined + /// unless a fuzz test handler guard is currently in scope. + static FuzzTestHandlerGuard *instance(); + + // ACCESSORS + /// Return the original assertion handler. - static Assert::ViolationHandler getOriginalAssertionHandler(); + Assert::ViolationHandler getOriginalAssertionHandler(); + + /// Return the original review handler. + Review::ViolationHandler getOriginalReviewHandler(); }; // ============================================================================ @@ -394,33 +403,64 @@ class FuzzTestHandlerGuard { inline FuzzTestHandlerGuard::FuzzTestHandlerGuard() { - BSLS_ASSERT(&FuzzTestPreconditionTracker::handlePreconditionViolation != + BSLS_ASSERT(&FuzzTestPreconditionTracker::handleAssertViolation != bsls::Assert::violationHandler()); + BSLS_ASSERT(&FuzzTestPreconditionTracker::handleReviewViolation != + bsls::Review::violationHandler()); + PreconditionsHandler::installHandlers( &FuzzTestPreconditionTracker::handlePreconditionsBegin, &FuzzTestPreconditionTracker::handlePreconditionsEnd); - s_originalAssertionHandler = bsls::Assert::violationHandler(); + originalAssertionHandler = bsls::Assert::violationHandler(); bsls::Assert::setViolationHandler( - &FuzzTestPreconditionTracker::handlePreconditionViolation); + &FuzzTestPreconditionTracker::handleAssertViolation); + + originalReviewHandler = bsls::Review::violationHandler(); + + bsls::Review::setViolationHandler( + &FuzzTestPreconditionTracker::handleReviewViolation); + + s_currentFuzzTestHandlerGuard_p = this; } inline FuzzTestHandlerGuard::~FuzzTestHandlerGuard() { + BSLS_ASSERT(&FuzzTestPreconditionTracker::handleAssertViolation == + bsls::Assert::violationHandler()); + + BSLS_ASSERT(&FuzzTestPreconditionTracker::handleReviewViolation == + bsls::Review::violationHandler()); + PreconditionsHandler::installHandlers(&PreconditionsHandler::noOpHandler, &PreconditionsHandler::noOpHandler); - bsls::Assert::setViolationHandler(s_originalAssertionHandler); + bsls::Assert::setViolationHandler(originalAssertionHandler); + bsls::Review::setViolationHandler(originalReviewHandler); + + s_currentFuzzTestHandlerGuard_p = NULL; +} + +inline +FuzzTestHandlerGuard *FuzzTestHandlerGuard::instance() +{ + BSLS_ASSERT(s_currentFuzzTestHandlerGuard_p); + return s_currentFuzzTestHandlerGuard_p; } inline Assert::ViolationHandler FuzzTestHandlerGuard::getOriginalAssertionHandler() { - return s_originalAssertionHandler; + return originalAssertionHandler; } +inline +Review::ViolationHandler FuzzTestHandlerGuard::getOriginalReviewHandler() +{ + return originalReviewHandler; +} } // close package namespace } // close enterprise namespace diff --git a/groups/bsl/bsls/bsls_fuzztest.t.cpp b/groups/bsl/bsls/bsls_fuzztest.t.cpp index 386efa66f0..9cb64349ba 100644 --- a/groups/bsl/bsls/bsls_fuzztest.t.cpp +++ b/groups/bsl/bsls/bsls_fuzztest.t.cpp @@ -4,8 +4,9 @@ #include #include #include +#include #include -#include // to test `RAW` version of macro +#include #include #include // atoi(), rand() @@ -30,12 +31,12 @@ using namespace std; // `out of contract`. In this scenario, if the function under test has a // precondition failure, we verify that the test continues. If, however, the // function invoked by the function under test has a precondition failure, we -// verify that the test halts with an indication of where the assertion +// verify that the test halts with an indication of where the assertion/review // occurred. // // Many of the test cases below are to verify intended behavior in the presence // of nested `BEGIN` invocations. We also test the intended behavior for -// assertions from other components. +// assertions/reviews from other components. // // Note that there are `_IMP` versions of the macros that are intended to be // used when `BDE_ACTIVATE_FUZZ_TESTING` is not defined. We use these `_IMP` @@ -48,14 +49,17 @@ using namespace std; // bsls::FuzzTestHandlerGuard // [ 2] FuzzTestHandlerGuard(); // [ 2] ~FuzzTestHandlerGuard(); -// [ 2] static ViolationHandler getOriginalAssertionHandler() const; +// [ 2] static FuzzTestHandlerGuard *instance(); +// [ 2] Assert::ViolationHandler getOriginalAssertionHandler(); +// [ 2] Review::ViolationHandler getOriginalReviewHandler(); // ---------------------------------------------------------------------------- // bsls::FuzzTestPreconditionTracker -// [ 3] static void handlePreconditionViolation(const AssertViolation &a); -// [ 3] static void initStaticState(const char *fn, int ln); +// [ 3] static void handleAssertViolation(const AssertViolation &a); +// [ 3] static void handleException(const FuzzTestPreconditionException&); // [ 3] static void handlePreconditionsBegin(); // [ 3] static void handlePreconditionsEnd(); -// [ 3] static void handleException(const FuzzTestPreconditionException&); +// [ 3] static void handleReviewViolation(const ReviewViolation &a); +// [ 3] static void initStaticState(const char *fn, int ln); // ---------------------------------------------------------------------------- // [ 1] BREATHING TEST // [ 6] USAGE EXAMPLE @@ -154,43 +158,67 @@ static void printFlags() } namespace test_case_common { -/// Invoke `ti.addInterval` with inputs that will cause it to fail. The -/// behavior is undefined unless `ti.addInterval` succeeds. Note that since -/// we are testing outside the fuzz harness (i.e., we are not in +/// Invoke `FuzzTest_TestUtil::triggerAssert` that will cause it to fail. Note +/// that since we are testing outside the fuzz harness (i.e., we are not in /// `LLVMFuzzerTestOneInput`), we cannot rely on other components employing -/// `BSLS_PRECONDITIONS_BEGIN_IMP` (i.e., client code will employ the -/// non-`IMP` macros). Also note that this function returns a `bool` so it -/// can be invoked from `BSLS_ASSERT`, and the choice of `true` is -/// arbitrary. +/// `BSLS_PRECONDITIONS_BEGIN_IMP` (i.e., client code will employ the non-`IMP` +/// macros). Also note that this function returns a `bool` so it can be +/// invoked from `BSLS_ASSERT`, and the choice of `true` is arbitrary. bool assertInDifferentComponent() { BSLS_PRECONDITIONS_BEGIN_IMP(); - bsls::TimeInterval ti(9e18); - BSLS_ASSERT(ti != ti.addInterval(9e18, 0)); // fails precondition + bsls::FuzzTest_TestUtil::triggerAssert(); BSLS_PRECONDITIONS_END_IMP(); return true; } -/// Invoke `ti.addInterval` with inputs that will cause it to fail. The -/// behavior is undefined unless `ti.addInterval` succeeds. Note that the -/// invocation of `addInterval` is nested within a second level of -/// `BEGIN/END` macros; and that since we are testing outside the fuzz -/// harness (i.e., we are not in `LLVMFuzzerTestOneInput`), we cannot rely -/// on other components employing `BSLS_PRECONDITIONS_BEGIN_IMP` (i.e., -/// client code will employ the non-`IMP` macros). +/// Invoke `FuzzTest_TestUtil::triggerAssert` that will cause it to fail. Note +/// that the invocation of `triggerAssert` is nested within a second level of +/// `BEGIN/END` macros; and that since we are testing outside the fuzz harness +/// (i.e., we are not in `LLVMFuzzerTestOneInput`), we cannot rely on other +/// components employing `BSLS_PRECONDITIONS_BEGIN_IMP` (i.e., client code will +/// employ the non-`IMP` macros). void assertInDifferentComponentInNestedBlock() { BSLS_PRECONDITIONS_BEGIN_IMP(); BSLS_PRECONDITIONS_BEGIN_IMP(); - bsls::TimeInterval ti(9e18); - BSLS_ASSERT(ti != ti.addInterval(9e18, 0)); // fails precondition + bsls::FuzzTest_TestUtil::triggerAssert(); + BSLS_PRECONDITIONS_END_IMP(); + BSLS_PRECONDITIONS_END_IMP(); +} + +/// Invoke `FuzzTest_TestUtil::triggerReview` that will cause it to fail. Note +/// that since we are testing outside the fuzz harness (i.e., we are not in +/// `LLVMFuzzerTestOneInput`), we cannot rely on other components employing +/// `BSLS_PRECONDITIONS_BEGIN_IMP` (i.e., client code will employ the non-`IMP` +/// macros). Also note that this function returns a `bool` so it can be +/// invoked from `BSLS_REVIEW`, and the choice of `true` is arbitrary. +bool reviewInDifferentComponent() +{ + BSLS_PRECONDITIONS_BEGIN_IMP(); + bsls::FuzzTest_TestUtil::triggerReview(); + BSLS_PRECONDITIONS_END_IMP(); + return true; +} + +/// Invoke `FuzzTest_TestUtil::triggerReview` that will cause it to fail. Note +/// that the invocation of `triggerReview` is nested within a second level of +/// `BEGIN/END` macros; and that since we are testing outside the fuzz harness +/// (i.e., we are not in `LLVMFuzzerTestOneInput`), we cannot rely on other +/// components employing `BSLS_PRECONDITIONS_BEGIN_IMP` (i.e., client code will +/// employ the non-`IMP` macros). +void reviewInDifferentComponentInNestedBlock() +{ + BSLS_PRECONDITIONS_BEGIN_IMP(); + BSLS_PRECONDITIONS_BEGIN_IMP(); + bsls::FuzzTest_TestUtil::triggerReview(); BSLS_PRECONDITIONS_END_IMP(); BSLS_PRECONDITIONS_END_IMP(); } } // close namespace test_case_common namespace test_case_4 { -struct AssertLocation { +struct FailureLocation { enum Enum { NONE, FIRST_BLOCK_TOP_LEVEL, @@ -200,15 +228,15 @@ struct AssertLocation { }; /// Invoke the assertion handler at the specified `location`. -void triggerAssertion(AssertLocation::Enum location) +void triggerAssertion(FailureLocation::Enum location) { BSLS_PRECONDITIONS_BEGIN_IMP(); - if (AssertLocation::FIRST_BLOCK_TOP_LEVEL == location) { + if (FailureLocation::FIRST_BLOCK_TOP_LEVEL == location) { BSLS_ASSERT_INVOKE_NORETURN("FIRST_BLOCK_TOP_LEVEL"); } { BSLS_PRECONDITIONS_BEGIN_IMP(); - if (AssertLocation::FIRST_BLOCK_SECOND_LEVEL == location){ + if (FailureLocation::FIRST_BLOCK_SECOND_LEVEL == location){ BSLS_ASSERT_INVOKE_NORETURN("FIRST_BLOCK_SECOND_LEVEL"); } BSLS_PRECONDITIONS_END_IMP(); @@ -216,7 +244,7 @@ void triggerAssertion(AssertLocation::Enum location) BSLS_PRECONDITIONS_END_IMP(); BSLS_PRECONDITIONS_BEGIN_IMP(); - if (AssertLocation::SECOND_BLOCK == location){ + if (FailureLocation::SECOND_BLOCK == location){ BSLS_ASSERT_INVOKE_NORETURN("SECOND_BLOCK"); } BSLS_PRECONDITIONS_END_IMP(); @@ -231,6 +259,38 @@ void triggerAssertionInDifferentComponent() BSLS_PRECONDITIONS_END_IMP(); } +/// Invoke the review handler at the specified `location`. +void triggerReview(FailureLocation::Enum location) +{ + BSLS_PRECONDITIONS_BEGIN_IMP(); + if (FailureLocation::FIRST_BLOCK_TOP_LEVEL == location) { + BSLS_REVIEW_INVOKE("FIRST_BLOCK_TOP_LEVEL"); + } + { + BSLS_PRECONDITIONS_BEGIN_IMP(); + if (FailureLocation::FIRST_BLOCK_SECOND_LEVEL == location){ + BSLS_REVIEW_INVOKE("FIRST_BLOCK_SECOND_LEVEL"); + } + BSLS_PRECONDITIONS_END_IMP(); + } + BSLS_PRECONDITIONS_END_IMP(); + + BSLS_PRECONDITIONS_BEGIN_IMP(); + if (FailureLocation::SECOND_BLOCK == location){ + BSLS_REVIEW_INVOKE("SECOND_BLOCK"); + } + BSLS_PRECONDITIONS_END_IMP(); +} + +/// Do nothing. The behavior is undefined unless invocation to +/// `test_case_common::reviewInDifferentComponent` returns `true`. +void triggerReviewInDifferentComponent() +{ + BSLS_PRECONDITIONS_BEGIN_IMP(); + BSLS_REVIEW(test_case_common::reviewInDifferentComponent()); + BSLS_PRECONDITIONS_END_IMP(); +} + } // close namespace test_case_4 //============================================================================= @@ -271,8 +331,8 @@ void triggerAssertionInDifferentComponent() return guess; } - /// Return the square root of the specified `x`. The behavior is - /// undefined unless `x >= 0`. + /// Return the square root of the specified `x`. The behavior is undefined + /// unless `x >= 0`. double mySqrt(double x) { BSLS_PRECONDITIONS_BEGIN_IMP(); // _IMP ADDED @@ -282,47 +342,30 @@ void triggerAssertionInDifferentComponent() } // ``` // Then, for the illustration of `BSLS_FUZZTEST_EVALUATE_RAW`, we define a -// class, `Timer`, containing a `start` function that uses in its -// implementation a narrow contract function, `setInterval`, from another -// component, `bsls::TimeInterval`. This function, `setInterval`, has -// precondition checks that are surrounded by `BEGIN` and `END`. +// narrow function that uses a narrow function, `triggerAssert`, from another +// component, `bsls::FuzzTest_TestUtil`. This function, `triggerAssert`, +// always triggers an assertion failure. // ``` - - /// This class implements a simple interval timer. - class Timer + /// Invoke `triggerAssert` from `bsls::FuzzTest_TestUtil`. The behavior is + /// undefined if `triggerAssert` fails. + void invokeTriggerAssert() { - private: - // DATA - bsls::TimeInterval d_timeout; // timeout seconds and nanoseconds - - public: - // MANIPULATORS - - /// Start the countdown with a timer having the value given by the - /// sum of the specified integral number of `seconds` and - /// `nanoseconds`. The behavior is undefined unless the total - /// number of seconds in the resulting time interval can be - /// represented with a 64-bit signed integer (see - /// `TimeInterval::isValid`). - void start(bsls::Types::Int64 seconds, int nanoseconds) - { - #ifndef BDE_ACTIVATE_FUZZ_TESTING // ADDED - BSLS_PRECONDITIONS_BEGIN_IMP(); // ADDED - #endif // ADDED - d_timeout.setInterval(seconds, nanoseconds); - #ifndef BDE_ACTIVATE_FUZZ_TESTING // ADDED - BSLS_PRECONDITIONS_END_IMP(); // ADDED - #endif // ADDED - // ... - } - }; + #ifndef BDE_ACTIVATE_FUZZ_TESTING // ADDED + BSLS_PRECONDITIONS_BEGIN_IMP(); // ADDED + #endif // ADDED + bsls::FuzzTest_TestUtil::triggerAssert(); + #ifndef BDE_ACTIVATE_FUZZ_TESTING // ADDED + BSLS_PRECONDITIONS_END_IMP(); // ADDED + #endif // ADDED + //... + } // ``` // Next, implement `LLVMFuzzerTestOneInput`. We first select the test case // number based on the supplied fuzz data. // ``` + /// Use the specified `data` array of `size` bytes as input to methods of + /// this component and return zero. extern "C" - /// Use the specified `data` array of `size` bytes as input to methods - /// of this component and return zero. int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { int test; @@ -380,23 +423,14 @@ void triggerAssertionInDifferentComponent() // ``` case 1: { // ---------------------------------------------------------------- - // `Timer::start` + // `invokeTriggerAssert` // // Concerns: - // 1. That `start`, when invoked with the `RAW` macro, does not - // invoke the original assertion handler. + // 1. That `invokeTriggerAssert`, when invoked with the `RAW` + // macro, does not invoke the original assertion handler. // - // Testing: void Timer::start(Int64 seconds, int nanoseconds); + // Testing: void invokeTriggerAssert(); // ---------------------------------------------------------------- - if (size < sizeof(bsls::Types::Int64) + sizeof(int)) { - return 0; // RETURN - } - bsls::Types::Int64 seconds; - int nanoseconds; - memcpy(&seconds, data, sizeof(bsls::Types::Int64)); - memcpy(&nanoseconds, - data + sizeof(bsls::Types::Int64), - sizeof(int)); // ``` // Now, we set up the handler guard that installs the precondition handlers. // ``` @@ -405,15 +439,11 @@ void triggerAssertionInDifferentComponent() // Finally, we invoke the function under test with the // `BSLS_FUZZTEST_EVALUATE_RAW` macro. // ``` - Timer t; - BSLS_FUZZTEST_EVALUATE_RAW_IMP( - t.start(seconds, nanoseconds)); // _IMP ADDED + BSLS_FUZZTEST_EVALUATE_RAW_IMP(invokeTriggerAssert()); //_IMP ADDED // ``` -// If the total number of seconds resulting from the sum of `seconds` and -// `nanoseconds` cannot be represented with a 64-bit signed integer, a -// top-level assertion failure from a different component will occur. Because -// we have invoked `start` with the `RAW` macro, a component name check will -// not be performed, and execution will continue. +// Here a top-level assertion failure from a different component will occur. +// Because we have invoked `invokeTriggerAssert` with the `RAW` macro, a +// component name check will not be performed, and execution will continue. // ``` } break; default: { @@ -421,7 +451,7 @@ void triggerAssertionInDifferentComponent() } if (testStatus > 0) { - BSLS_ASSERT_INVOKE("FUZZ TEST FAILURES"); + BSLS_REVIEW_INVOKE("FUZZ TEST FAILURES"); } return 0; @@ -461,12 +491,12 @@ int main(int argc, char *argv[]) // Extracted from component header file. // // Concerns: - // 1. The usage example provided in the component header file compiles, - // links, and runs as shown. + // 1. The usage example provided in the component header file + // compiles, links, and runs as shown. // // Plan: - // 1. Incorporate usage example from header into test driver, remove - // leading comment characters. (C-1) + // 1. Incorporate usage example from header into test driver, remove + // leading comment characters. (C-1) // // Testing: // USAGE EXAMPLE @@ -475,8 +505,15 @@ int main(int argc, char *argv[]) "=============\n"); #if defined(BDE_BUILD_TARGET_EXC) { - // First, we invoke `LLVMFuzzerTestOneInput` with input that does - // not violate any preconditions. + // First, we invoke `mySqrt` via `LLVMFuzzerTestOneInput` with + // input that does not violate any preconditions. Note that both + // `mySqrt` and `newtonsSqrt` have `BSLS_PRECONDITIONS_BEGIN_IMP` + // and `END_IMP` macros instead of the regular preconditions macros + // used in the usage example in the component header file. We do + // this to achieve the desired behavior: that a *second-level* + // precondition violation occurs, regardless of the ufid (i.e., + // regardless of whether the ufid contains `fuzz`) if and only if + // `mySqrt` is invoked with 0. uint8_t myFuzzData[32]; myFuzzData[0] = 2; // invoke case 2 of `LLVMFuzzerTestOneInput` double val = 4.0; @@ -484,8 +521,8 @@ int main(int argc, char *argv[]) LLVMFuzzerTestOneInput(myFuzzData, 1 + sizeof(double)); } { - // Then, we invoke `LLVMFuzzerTestOneInput` with input that - // violates a top-level precondition, which is handled by the + // Then, we invoke `mySqrt` via `LLVMFuzzerTestOneInput` with input + // that violates a top-level precondition, which is handled by the // macro. uint8_t myFuzzData[32]; myFuzzData[0] = 2; // invoke case 2 of `LLVMFuzzerTestOneInput` @@ -493,27 +530,26 @@ int main(int argc, char *argv[]) memcpy(myFuzzData + 1, &val, sizeof(double)); LLVMFuzzerTestOneInput(myFuzzData, 1 + sizeof(double)); } + { + // Note that we do not invoke `mySqrt` via `LLVMFuzzerTestOneInput` + // with 0, as it will crash the test driver due to the second-level + // precondition violation. + } { // Finally, we invoke a function that fails a precondition in a - // different component. Note that here we invoke `addSeconds`, - // which has conditional inclusion of `BSLS_PRECONDITIONS_BEGIN` - // and `END`. We do this to achieve the desired behavior: that a - // *top-level* precondition violation occurs in a different - // component, regardless of the ufid (i.e., regardless of whether - // the ufid contains `fuzz`). Without the conditional, in a - // fuzzing build, the violation in the other component would occur - // in the second level. - uint8_t myFuzzData[32]; + // different component. Note that here we invoke `triggerAssert` + // from `bsls::FuzzTest_TestUtil` via `invokeTriggerAssert` which + // has conditional inclusion of `BSLS_PRECONDITIONS_BEGIN` and + // `END` added to the usage example in the component header file. + // We do this to achieve the desired behavior: that a *top-level* + // precondition violation occurs in a different component, + // regardless of the ufid (i.e., regardless of whether the ufid + // contains `fuzz`). Without the conditional, in a fuzzing build, + // the violation in the other component would occur in the second + // level. + uint8_t myFuzzData[1]; myFuzzData[0] = 1; // invoke case 1 of `LLVMFuzzerTestOneInput` - bsls::Types::Int64 seconds = 0x7FFFFFFFFFFFFFFFLL; - int nanoseconds = 2e9; - memcpy(myFuzzData + 1, &seconds, sizeof(bsls::Types::Int64)); - memcpy(myFuzzData + 1 + sizeof(bsls::Types::Int64), - &nanoseconds, - sizeof(int)); - LLVMFuzzerTestOneInput( - myFuzzData, - 1 + sizeof(bsls::Types::Int64) + sizeof(int)); + LLVMFuzzerTestOneInput(myFuzzData, 1); } #endif // defined(BDE_BUILD_TARGET_EXC) } break; @@ -522,19 +558,20 @@ int main(int argc, char *argv[]) // BSLS_FUZZTEST_EVALUATE_RAW // // Concerns: - // 1. A top-level assertion failure in another component does not - // invoke the original assertion handler. + // 1. A top-level assertion/review failure in another component does + // not invoke the original assertion/review handler. // - // 2. A second level assertion failure in another component does invoke - // the original assertion handler. + // 2. A second level assertion/review failure in another component + // does invoke the original assertion/review handler. // // Plan: - // 1. Invoke a function that asserts in a different component inside - // a top-level `BEGIN/END` block. Verify that no assert violation - // occurs. + // 1. Invoke a function that asserts/reviews in a different component + // inside a top-level `BEGIN/END` block. Verify that no + // assert/review violation occurs. // - // 2. Invoke a function that asserts in a different component inside - // a nested `BEGIN/END` block. Verify that a violation occurs. + // 2. Invoke a function that asserts/reviews in a different component + // inside a nested `BEGIN/END` block. Verify that a violation + // occurs. // // Testing: // BSLS_FUZZTEST_EVALUATE_RAW @@ -546,13 +583,17 @@ int main(int argc, char *argv[]) bsls::AssertTestHandlerGuard g; bsls::FuzzTestHandlerGuard hG; ASSERT_PASS(BSLS_FUZZTEST_EVALUATE_RAW_IMP( - test_case_common::assertInDifferentComponent())); + test_case_common::assertInDifferentComponent())); + ASSERT_PASS(BSLS_FUZZTEST_EVALUATE_RAW_IMP( + test_case_common::reviewInDifferentComponent())); } { bsls::AssertTestHandlerGuard g; bsls::FuzzTestHandlerGuard hG; ASSERT_FAIL_RAW(BSLS_FUZZTEST_EVALUATE_RAW_IMP( - test_case_common::assertInDifferentComponentInNestedBlock())); + test_case_common::assertInDifferentComponentInNestedBlock())); + ASSERT_FAIL_RAW(BSLS_FUZZTEST_EVALUATE_RAW_IMP( + test_case_common::reviewInDifferentComponentInNestedBlock())); } #endif // defined(BDE_BUILD_TARGET_EXC) } break; @@ -561,47 +602,50 @@ int main(int argc, char *argv[]) // BSLS_FUZZTEST_EVALUATE // // Concerns: - // 1. Invoking a narrow contract function with inputs that violate the - // top-level preconditions does not invoke the original assertion - // handler. - // - // 2. Invoking a narrow contract function with inputs that satisfy the - // top-level preconditions but violate nested preconditions does - // invoke the original assertion handler. The location of the - // subsequent precondition checks does not matter -- whether the - // checks are within the top-level `BSLS_PRECONDITIONS_BEGIN/END` - // block or after. - // - // 3. Invoking a narrow contract function in contract does not invoke - // the original assertion handler. - // - // 4. Invoking a narrow contract function with input that satisfies the - // top-level preconditions but -- within the top-level - // `BSLS_PRECONDITIONS_BEGIN/END` block -- violates the - // preconditions of a function from a different component, does - // invoke the original assertion handler. + // 1. Invoking a narrow contract function with inputs that violate the + // top-level preconditions does not invoke the original + // assertion/review handler. + // + // 2. Invoking a narrow contract function with inputs that satisfy the + // top-level preconditions but violate nested preconditions does + // invoke the original assertion/review handler. The location of + // the subsequent precondition checks does not matter -- whether + // the checks are within the top-level + // `BSLS_PRECONDITIONS_BEGIN/END` block or after. + // + // 3. Invoking a narrow contract function in contract does not invoke + // the original assertion/review handler. + // + // 4. Invoking a narrow contract function with input that satisfies + // the top-level preconditions but -- within the top-level + // `BSLS_PRECONDITIONS_BEGIN/END` block -- violates the + // preconditions of a function from a different component, does + // invoke the original assertion/review handler. // // Plan: - // 1. Invoke a function that contains three different `BEGIN/END` - // blocks with different input arguments: - // - // a. with an input that does not trigger any assertions inside a - // `BEGIN/END` block. Verify that no assert violation occurs. + // 1. Invoke a function that contains three different `BEGIN/END` + // blocks with different input arguments: // - // b. with an input that triggers an assertion inside a top-level - // `BEGIN/END` block. Verify that no assert violation occurs. + // a. with an input that does not trigger any assertions/review + // inside a `BEGIN/END` block. Verify that no assert/review + // violation occurs. // - // c. with an input that triggers an assertion inside a second-level - // `BEGIN/END` block. Verify that a violation occurs. + // b. with an input that triggers an assertion/review inside a + // top-level `BEGIN/END` block. Verify that no assert/review + // violation occurs. // - // d. with an input that triggers an assertion inside a second - // top-level `BEGIN/END` block. Verify that a violation occurs. + // c. with an input that triggers an assertion/review inside a + // second-level `BEGIN/END` block. Verify that a violation + // occurs. // - // 2. Invoke a function with an input that satisfies - // its preconditions and then -- within the initial `BEGIN/END` - // block -- invoke a narrow contract function from another component - // out of contract. Verify that a violation occurs. + // d. with an input that triggers an assertion/review inside a + // second top-level `BEGIN/END` block. Verify that a violation + // occurs. // + // 2. Invoke a function with an input that satisfies its preconditions + // and then -- within the initial `BEGIN/END` block -- invoke a + // narrow contract function from another component out of contract. + // Verify that a violation occurs. // // Testing: // BSLS_FUZZTEST_EVALUATE @@ -612,24 +656,42 @@ int main(int argc, char *argv[]) { bsls::AssertTestHandlerGuard g; bsls::FuzzTestHandlerGuard hG; + ASSERT_PASS( - BSLS_FUZZTEST_EVALUATE_IMP(test_case_4::triggerAssertion( - test_case_4::AssertLocation::NONE))); + BSLS_FUZZTEST_EVALUATE_IMP(test_case_4::triggerAssertion( + test_case_4::FailureLocation::NONE))); ASSERT_PASS( - BSLS_FUZZTEST_EVALUATE_IMP(test_case_4::triggerAssertion( - test_case_4::AssertLocation::FIRST_BLOCK_TOP_LEVEL))); + BSLS_FUZZTEST_EVALUATE_IMP(test_case_4::triggerReview( + test_case_4::FailureLocation::NONE))); + + ASSERT_PASS( + BSLS_FUZZTEST_EVALUATE_IMP(test_case_4::triggerAssertion( + test_case_4::FailureLocation::FIRST_BLOCK_TOP_LEVEL))); + ASSERT_PASS( + BSLS_FUZZTEST_EVALUATE_IMP(test_case_4::triggerReview( + test_case_4::FailureLocation::FIRST_BLOCK_TOP_LEVEL))); + + ASSERT_FAIL( + BSLS_FUZZTEST_EVALUATE_IMP(test_case_4::triggerAssertion( + test_case_4::FailureLocation::FIRST_BLOCK_SECOND_LEVEL))); ASSERT_FAIL( - BSLS_FUZZTEST_EVALUATE_IMP(test_case_4::triggerAssertion( - test_case_4::AssertLocation::FIRST_BLOCK_SECOND_LEVEL))); + BSLS_FUZZTEST_EVALUATE_IMP(test_case_4::triggerReview( + test_case_4::FailureLocation::FIRST_BLOCK_SECOND_LEVEL))); + + ASSERT_FAIL( + BSLS_FUZZTEST_EVALUATE_IMP(test_case_4::triggerAssertion( + test_case_4::FailureLocation::SECOND_BLOCK))); ASSERT_FAIL( - BSLS_FUZZTEST_EVALUATE_IMP(test_case_4::triggerAssertion( - test_case_4::AssertLocation::SECOND_BLOCK))); + BSLS_FUZZTEST_EVALUATE_IMP(test_case_4::triggerReview( + test_case_4::FailureLocation::SECOND_BLOCK))); } { bsls::AssertTestHandlerGuard g; bsls::FuzzTestHandlerGuard hG; BSLS_ASSERTTEST_ASSERT_FAIL_RAW(BSLS_FUZZTEST_EVALUATE_IMP( test_case_4::triggerAssertionInDifferentComponent())); + BSLS_ASSERTTEST_ASSERT_FAIL_RAW(BSLS_FUZZTEST_EVALUATE_IMP( + test_case_4::triggerReviewInDifferentComponent())); } #endif // defined(BDE_BUILD_TARGET_EXC) } break; @@ -638,102 +700,105 @@ int main(int argc, char *argv[]) // TESTING FUZZTEST PRECONDITION TRACKER // // Concerns: - // 1. That directly invoking the methods of - // `FuzzTestPreconditionTracker` behaves as expected. + // 1. That directly invoking the methods of + // `FuzzTestPreconditionTracker` behaves as expected. // - // 1. The filename that caused the precondition violation is the same - // as the one reported by the assertion handler. + // a. The filename that caused the precondition violation is the + // same as the one reported by the assertion/review handler. // - // 2. The expression that caused the assertion is the same as the one - // returned by the assertion handler. + // b. The expression that caused the assertion/review is the same as + // the one returned by the assertion/review handler. // - // 3. If the precondition is violated, either a - // `FuzzTestPreconditionException` is thrown or the original - // assertion handler is invoked, as expected. + // c. If the precondition is violated, either a + // `FuzzTestPreconditionException` is thrown or the original + // assertion/review handler is invoked, as expected. // - // 4. Directly invoking `handlePreconditionViolation` results in the - // same behavior as triggering an assertion with `BSLS_ASSERT`. + // d. Directly invoking `handleAssertViolation` or + // `handleReviewViolation` results in the same behavior as + // triggering an assertion/review with `BSLS_ASSERT` or + // `BSLS_REVIEW`. // // Plan: - // 1. Trigger a top-level precondition violation and verify that the - // methods behave as expected. + // 1. Trigger a top-level precondition violation and verify that the + // methods behave as expected. // - // 1. Directly invoke `initStaticState` with the current filename. + // a. Directly invoke `initStaticState` with the current filename. // - // 2. Trigger a top-level precondition violation. + // b. Trigger a top-level precondition violation. // - // 3. Verify that a `FuzzTestPreconditionException` is thrown. + // c. Verify that a `FuzzTestPreconditionException` is thrown. // - // 4. Verify that the filename and triggering expression match the - // expected values. + // d. Verify that the filename and triggering expression match the + // expected values. // - // 2. Trigger a second-level precondition violation and verify that the - // methods behave as expected. + // 2. Trigger a second-level precondition violation and verify that + // the methods behave as expected. // - // 1. Directly invoke `initStaticState` with the current filename. + // a. Directly invoke `initStaticState` with the current filename. // - // 2. Trigger a second-level precondition violation. + // b. Trigger a second-level precondition violation. // - // 3. Verify that the original assertion handler is invoked, which - // throws an `AssertTestException`. + // c. Verify that the original assertion/review handler is invoked, + // which throws an `AssertTestException`. // - // 4. Verify that the filename and triggering expression match the - // expected values. + // d. Verify that the filename and triggering expression match the + // expected values. // - // 3. Trigger a top-level precondition violation from another component - // and verify that the methods behave as expected. + // 3. Trigger a top-level precondition violation from another + // component and verify that the methods behave as expected. // - // 1. Directly invoke `initStaticState` with a different component - // name passed. + // a. Directly invoke `initStaticState` with a different component + // name passed. // - // 2. Trigger a top-level precondition violation. + // b. Trigger a top-level precondition violation. // - // 3. Verify that a `FuzzTestPreconditionException` is thrown. + // c. Verify that a `FuzzTestPreconditionException` is thrown. // - // 4. Verify that the filename and triggering expression match the - // expected values. + // d. Verify that the filename and triggering expression match the + // expected values. // - // 5. Directly invoke `handleException` and thereby verify that the - // original assertion handler is invoked. + // e. Directly invoke `handleException` and thereby verify that the + // original assertion/review handler is invoked. // - // 4. Manually invoke `handlePreconditionViolation` and verify that the - // methods behave as expected. + // 4. Manually invoke `handleAssertViolation`/`handleReviewViolation` + // and verify that the methods behave as expected. // - // 1. Create a dummy `AssertViolation`. + // a. Create a dummy `AssertViolation`/`ReviewViolation`. // - // 2. Directly invoke `initStaticState` with the current filename. + // b. Directly invoke `initStaticState` with the current filename. // - // 3. Manually invoke `handlePreconditionViolation` with the created - // `AssertViolation`. + // c. Manually invoke + // `handleAssertViolation`/`handleReviewViolation` with the + // created `AssertViolation`/`ReviewViolation`. // - // 4. Verify that an `FuzzTestPreconditionException` is thrown. + // d. Verify that an `FuzzTestPreconditionException` is thrown. // - // 5. Verify that the filename and triggering expression match the - // expected values. + // e. Verify that the filename and triggering expression match the + // expected values. // - // 5. Trigger a top-level precondition violation and verify that the - // methods behave as expected. + // 5. Trigger a top-level precondition violation and verify that the + // methods behave as expected. // - // 1. Directly invoke `initStaticState` with the current filename. + // a. Directly invoke `initStaticState` with the current filename. // - // 2. Trigger a top-level precondition violation by ending the - // second-level precondition check with `handlePreconditionsEnd`. + // b. Trigger a top-level precondition violation by ending the + // second-level precondition check with `handlePreconditionsEnd`. // - // 3. Verify that a `FuzzTestPreconditionException` is thrown. + // c. Verify that a `FuzzTestPreconditionException` is thrown. // - // 4. Verify that the filename and triggering expression match the - // expected values. - // - // 5. Directly invoke `handleException` and thereby verify that the - // original assertion handler is invoked. + // d. Verify that the filename and triggering expression match the + // expected values. // + // e. Directly invoke `handleException` and thereby verify that the + // original assertion/review handler is invoked. // // Testing: - // static void initStaticState(const char *fn, int ln); + // static void handleAssertViolation(const AssertViolation &a); + // static void handleException(const FuzzTestPreconditionException&); // static void handlePreconditionsBegin(); // static void handlePreconditionsEnd(); - // static void handleException(const FuzzTestPreconditionException&); - // static void handlePreconditionViolation(const AssertViolation &a); + // static void handleReviewViolation(const ReviewViolation &a); + // static void initStaticState(const char *fn, int ln); // -------------------------------------------------------------------- if (verbose) printf("TESTING FUZZTEST PRECONDITION TRACKER\n" "=====================================\n"); @@ -752,10 +817,8 @@ int main(int argc, char *argv[]) BSLS_ASSERT(1 == 2); BSLS_ASSERT_INVOKE_NORETURN("unreachable"); } catch (bsls::FuzzTestPreconditionException& ftpe) { - ASSERT(0 == strcmp(ftpe.assertViolation().fileName(), - __FILE__)); - ASSERT(0 == - strcmp(ftpe.assertViolation().comment(), "1 == 2")); + ASSERT(0 == strcmp(ftpe.filename(), __FILE__)); + ASSERT(0 == strcmp(ftpe.expression(), "1 == 2")); bsls::FuzzTestPreconditionTracker::handleException(ftpe); }); } @@ -794,17 +857,15 @@ int main(int argc, char *argv[]) BSLS_ASSERT(1 == 2); BSLS_ASSERT_INVOKE_NORETURN("unreachable"); } catch (bsls::FuzzTestPreconditionException& ftpe) { - ASSERT(0 == strcmp(ftpe.assertViolation().fileName(), - __FILE__)); - ASSERT(0 == - strcmp(ftpe.assertViolation().comment(), "1 == 2")); + ASSERT(0 == strcmp(ftpe.filename(), __FILE__)); + ASSERT(0 == strcmp(ftpe.expression(), "1 == 2")); bsls::FuzzTestPreconditionTracker::handleException(ftpe); }); } { if (veryVerbose) printf("TOP-LEVEL PRECONDITION VIOLATION DIRECTLY INVOKING " - "`handlePreconditionViolation`\n"); + "`handleAssertViolation`\n"); bsls::AssertViolation av("Expression that fails", __FILE__, __LINE__, @@ -818,12 +879,11 @@ int main(int argc, char *argv[]) bsls::FuzzTestPreconditionTracker:: handlePreconditionsBegin(); bsls::FuzzTestPreconditionTracker:: - handlePreconditionViolation(av); + handleAssertViolation(av); BSLS_ASSERT_INVOKE_NORETURN("unreachable"); } catch (bsls::FuzzTestPreconditionException& ftpe) { - ASSERT(0 == strcmp(ftpe.assertViolation().fileName(), - __FILE__)); - ASSERT(0 == strcmp(ftpe.assertViolation().comment(), + ASSERT(0 == strcmp(ftpe.filename(), __FILE__)); + ASSERT(0 == strcmp(ftpe.expression(), "Expression that fails")); bsls::FuzzTestPreconditionTracker::handleException(ftpe); }); @@ -848,14 +908,125 @@ int main(int argc, char *argv[]) BSLS_ASSERT(1 == 2); BSLS_ASSERT_INVOKE_NORETURN("unreachable"); } catch (bsls::FuzzTestPreconditionException& ftpe) { - ASSERT(0 == strcmp(ftpe.assertViolation().fileName(), - __FILE__)); - ASSERT(0 == - strcmp(ftpe.assertViolation().comment(), "1 == 2")); + ASSERT(0 == strcmp(ftpe.filename(), __FILE__)); + ASSERT(0 == strcmp(ftpe.expression(), "1 == 2")); bsls::FuzzTestPreconditionTracker::handleException(ftpe); }); } #endif // defined(BSLS_ASSERT_IS_ACTIVE) + +#if defined(BSLS_REVIEW_IS_ACTIVE) + { + if (veryVerbose) + printf("TOP-LEVEL PRECONDITION VIOLATION (SAME ORIGIN)\n"); + bsls::AssertTestHandlerGuard g; + bsls::FuzzTestHandlerGuard hg; + ASSERT_PASS( + bsls::FuzzTestPreconditionTracker::initStaticState(__FILE__); + try { + bsls::FuzzTestPreconditionTracker:: + handlePreconditionsBegin(); + BSLS_REVIEW(1 == 2); + BSLS_REVIEW_INVOKE("unreachable"); + } catch (bsls::FuzzTestPreconditionException& ftpe) { + ASSERT(0 == strcmp(ftpe.filename(), __FILE__)); + ASSERT(0 == strcmp(ftpe.expression(), "1 == 2")); + bsls::FuzzTestPreconditionTracker::handleException(ftpe); + }); + } + { + if (veryVerbose) + printf("SECOND-LEVEL PRECONDITION VIOLATION (SAME ORIGIN)\n"); + bsls::AssertTestHandlerGuard g; + bsls::FuzzTestHandlerGuard hg; + // Note that `ASSERT_FAIL` is not used in this case because we want + // to explicitly catch the `AssertTestException`. + bsls::FuzzTestPreconditionTracker::initStaticState(__FILE__); + try { + bsls::FuzzTestPreconditionTracker::handlePreconditionsBegin(); + BSLS_REVIEW(true); + bsls::FuzzTestPreconditionTracker::handlePreconditionsBegin(); + BSLS_REVIEW(1 == 2); + BSLS_REVIEW_INVOKE("unreachable"); + } + catch (bsls::AssertTestException& ex) { + ASSERT(0 == strcmp(ex.filename(), __FILE__)); + ASSERT(0 == strcmp(ex.expression(), "1 == 2")); + } + } + { + if (veryVerbose) + printf( + "TOP-LEVEL PRECONDITION VIOLATION (DIFFERENT ORIGIN)\n"); + bsls::AssertTestHandlerGuard g; + bsls::FuzzTestHandlerGuard hg; + ASSERT_FAIL( + bsls::FuzzTestPreconditionTracker::initStaticState( + "differentComponent.cpp"); + try { + bsls::FuzzTestPreconditionTracker:: + handlePreconditionsBegin(); + BSLS_REVIEW(1 == 2); + BSLS_REVIEW_INVOKE("unreachable"); + } catch (bsls::FuzzTestPreconditionException& ftpe) { + ASSERT(0 == strcmp(ftpe.filename(), __FILE__)); + ASSERT(0 == strcmp(ftpe.expression(), "1 == 2")); + bsls::FuzzTestPreconditionTracker::handleException(ftpe); + }); + } + { + if (veryVerbose) + printf("TOP-LEVEL PRECONDITION VIOLATION DIRECTLY INVOKING " + "`handleReviewViolation`\n"); + bsls::ReviewViolation rv("Expression that fails", + __FILE__, + __LINE__, + bsls::Review::k_LEVEL_REVIEW, + 0); + + bsls::AssertTestHandlerGuard g; + bsls::FuzzTestHandlerGuard hg; + ASSERT_PASS( + bsls::FuzzTestPreconditionTracker::initStaticState(__FILE__); + try { + bsls::FuzzTestPreconditionTracker:: + handlePreconditionsBegin(); + bsls::FuzzTestPreconditionTracker:: + handleReviewViolation(rv); + BSLS_REVIEW_INVOKE("unreachable"); + } catch (bsls::FuzzTestPreconditionException& ftpe) { + ASSERT(0 == strcmp(ftpe.filename(), __FILE__)); + ASSERT(0 == strcmp(ftpe.expression(), + "Expression that fails")); + bsls::FuzzTestPreconditionTracker::handleException(ftpe); + }); + } + { + if (veryVerbose) + printf("TOP-LEVEL PRECONDITION VIOLATION AFTER NESTED " + "BEGIN/END BLOCK\n"); + bsls::AssertTestHandlerGuard g; + bsls::FuzzTestHandlerGuard hg; + ASSERT_PASS( + bsls::FuzzTestPreconditionTracker::initStaticState(__FILE__); + try { + bsls::FuzzTestPreconditionTracker:: + handlePreconditionsBegin(); + BSLS_REVIEW(true); + bsls::FuzzTestPreconditionTracker:: + handlePreconditionsBegin(); + BSLS_REVIEW(true); + bsls::FuzzTestPreconditionTracker:: + handlePreconditionsEnd(); + BSLS_REVIEW(1 == 2); + BSLS_REVIEW_INVOKE("unreachable"); + } catch (bsls::FuzzTestPreconditionException& ftpe) { + ASSERT(0 == strcmp(ftpe.filename(), __FILE__)); + ASSERT(0 == strcmp(ftpe.expression(), "1 == 2")); + bsls::FuzzTestPreconditionTracker::handleException(ftpe); + }); + } +#endif // defined(BSLS_REVIEW_IS_ACTIVE) #endif // defined(BDE_BUILD_TARGET_EXC) } break; case 2: { @@ -863,66 +1034,74 @@ int main(int argc, char *argv[]) // FUZZTEST HANDLER GUARD // // Concerns: - // 1. That the guard installs handlers at construction. + // 1. That the guard installs handlers at construction. // - // 2. Restores the original handlers at destruction. + // 2. Restores the original handlers at destruction. // // Plan: - // 1. Verify that the original assertion handler is the expected one - // (i.e., `failByAbort`). + // 1. Verify that the original assertion handler is the expected one + // (i.e., `failByAbort`). // - // 2. Create a guard inside a block, and verify, using - // `PreconditionsHandler` and `FuzzTestPreconditionTracker`, that - // the handlers were installed. + // 2. Verify that the original review handler is the expected one + // (i.e., `failByLog`). // - // 3. After the guard goes out of scope, verify that the original - // handlers have been restored. + // 3. Create a guard inside a block, and verify, using + // `PreconditionsHandler` and `FuzzTestPreconditionTracker`, that + // the handlers were installed. + // + // 4. After the guard goes out of scope, verify that the original + // handlers have been restored. // // Testing: // FuzzTestHandlerGuard(); // ~FuzzTestHandlerGuard(); - // static ViolationHandler getOriginalAssertionHandler() const; + // static FuzzTestHandlerGuard *instance(); + // Assert::ViolationHandler getOriginalAssertionHandler(); + // Review::ViolationHandler getOriginalReviewHandler(); // -------------------------------------------------------------------- if (verbose) printf("FUZZTEST HANDLER GUARD\n" "======================\n"); ASSERT(&bsls::Assert::failByAbort == bsls::Assert::violationHandler()); - ASSERT( - bsls::PreconditionsHandler::getBeginHandler() == + ASSERT(&bsls::Review::failByLog == bsls::Review::violationHandler()); + ASSERT(bsls::PreconditionsHandler::getBeginHandler() == + &bsls::PreconditionsHandler::noOpHandler); + ASSERT(bsls::PreconditionsHandler::getEndHandler() == &bsls::PreconditionsHandler::noOpHandler); - ASSERT(bsls::PreconditionsHandler::getEndHandler() == - &bsls::PreconditionsHandler::noOpHandler); { bsls::FuzzTestHandlerGuard hg; + ASSERT(bsls::FuzzTestHandlerGuard::instance() == &hg); ASSERT(&bsls::Assert::failByAbort == - hg.getOriginalAssertionHandler()); - ASSERT(&bsls::FuzzTestPreconditionTracker:: - handlePreconditionViolation == - bsls::Assert::violationHandler()); - ASSERT( - bsls::PreconditionsHandler::getBeginHandler() == + hg.getOriginalAssertionHandler()); + ASSERT(&bsls::Review::failByLog == + hg.getOriginalReviewHandler()); + ASSERT(&bsls::FuzzTestPreconditionTracker::handleAssertViolation == + bsls::Assert::violationHandler()); + ASSERT(&bsls::FuzzTestPreconditionTracker::handleReviewViolation == + bsls::Review::violationHandler()); + ASSERT(bsls::PreconditionsHandler::getBeginHandler() == &bsls::FuzzTestPreconditionTracker::handlePreconditionsBegin); ASSERT(bsls::PreconditionsHandler::getEndHandler() == - &bsls::FuzzTestPreconditionTracker::handlePreconditionsEnd); + &bsls::FuzzTestPreconditionTracker::handlePreconditionsEnd); } ASSERT(&bsls::Assert::failByAbort == bsls::Assert::violationHandler()); - ASSERT( - bsls::PreconditionsHandler::getBeginHandler() == + ASSERT(&bsls::Review::failByLog == bsls::Review::violationHandler()); + ASSERT(bsls::PreconditionsHandler::getBeginHandler() == &bsls::PreconditionsHandler::noOpHandler); ASSERT(bsls::PreconditionsHandler::getEndHandler() == - &bsls::PreconditionsHandler::noOpHandler); + &bsls::PreconditionsHandler::noOpHandler); } break; case 1: { // -------------------------------------------------------------------- // BREATHING TEST // // Concerns: - // 1. This test driver builds on all platforms. + // 1. This test driver builds on all platforms. // // Plan: - // 1. Print out flags in verbose mode. + // 1. Print out flags in verbose mode. // // Testing: // BREATHING TEST diff --git a/groups/bsl/bsls/bsls_fuzztest_testutil.cpp b/groups/bsl/bsls/bsls_fuzztest_testutil.cpp new file mode 100644 index 0000000000..e7ddaccf58 --- /dev/null +++ b/groups/bsl/bsls/bsls_fuzztest_testutil.cpp @@ -0,0 +1,41 @@ +// bsls_fuzztest_testutil.cpp -*-C++-*- + +#include + +#include + +namespace BloombergLP { +namespace bsls { + +void FuzzTest_TestUtil::triggerAssert() +{ + BSLS_PRECONDITIONS_BEGIN(); + BSLS_ASSERT_INVOKE("triggered an assertion violation"); + BSLS_PRECONDITIONS_END(); +} + +void FuzzTest_TestUtil::triggerReview() +{ + BSLS_PRECONDITIONS_BEGIN(); + BSLS_REVIEW_INVOKE("triggered a review violation"); + BSLS_PRECONDITIONS_END(); +} + +} // close package namespace +} // close enterprise namespace + +// ---------------------------------------------------------------------------- +// Copyright 2024 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 ---------------------------------- diff --git a/groups/bsl/bsls/bsls_fuzztest_testutil.h b/groups/bsl/bsls/bsls_fuzztest_testutil.h new file mode 100644 index 0000000000..16302f3951 --- /dev/null +++ b/groups/bsl/bsls/bsls_fuzztest_testutil.h @@ -0,0 +1,78 @@ +// bsls_fuzztest_testutil.h -*-C++-*- +#ifndef INCLUDED_BSLS_FUZZTEST_TESTUTIL +#define INCLUDED_BSLS_FUZZTEST_TESTUTIL + +#include +BSLS_IDENT("$Id: $") + +//@PURPOSE: Provide utilities for `bsls_fuzztest` component. +// +//@DESCRIPTION: The `bsls_fuzztest_testutil` component provides utilities to +// facilitate testing the `bsls_fuzztest` component. +// +///Usage +///----- +// This section illustrates intended use of this component. +// +///Example: Basic Usage of Functions +///- - - - - - - - - - - - - - - - - +// First, we install an `AssertTestHandlerGuard` to catch the violation. +// ``` +// bsls::AssertTestHandlerGuard g; +// ``` +// Then, we trigger an `AssertViolation` by calling `triggerAssert` inside +// `ASSERT_FAIL` and verify that a violation occurs as expected. +// ``` +// ASSERT_FAIL(bsls::FuzzTest_TestUtil::triggerAssert()); +// ``` +// Next, we trigger a `ReviewViolation` by calling `triggerReview` inside +// `ASSERT_FAIL` and verify that a violation occurs as expected. +// ``` +// ASSERT_FAIL(bsls::FuzzTest_TestUtil::triggerReview()); +// ``` + +#include +#include + +namespace BloombergLP { +namespace bsls { + + // ======================= + // class FuzzTest_TestUtil + // ======================= + +/// This utility class provides sample functions to demonstrate an +/// `AssertViolation` or a `ReviewViolation` originating from a different +/// component to facilitate testing of `bsls_fuzztest` component. +struct FuzzTest_TestUtil { + + public: + // CLASS METHODS + + /// Trigger an `AssertViolation` by calling `BSLS_ASSERT_INVOKE`. + static void triggerAssert(); + + /// Trigger a `ReviewViolation` by calling `BSLS_REVIEW_INVOKE`. + static void triggerReview(); +}; + +} // close package namespace +} // close enterprise namespace + +#endif + +// ---------------------------------------------------------------------------- +// Copyright 2024 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 ---------------------------------- diff --git a/groups/bsl/bsls/bsls_fuzztest_testutil.t.cpp b/groups/bsl/bsls/bsls_fuzztest_testutil.t.cpp new file mode 100644 index 0000000000..c9a7e0c68a --- /dev/null +++ b/groups/bsl/bsls/bsls_fuzztest_testutil.t.cpp @@ -0,0 +1,199 @@ +// bsls_fuzztest_testutil.t.cpp -*-C++-*- +#include + +#include +#include +#include +#include +#include + +#include +#include // atoi() + +using namespace BloombergLP; +using namespace std; + +// ============================================================================ +// TEST PLAN +// ---------------------------------------------------------------------------- +// Overview +// -------- +// The component under test consists of a series of static member functions +// that provide facilities for testing `bsls_fuzztest`. +// ---------------------------------------------------------------------------- +// [ 1] BREATHING TEST +// [ 2] USAGE EXAMPLE +// ---------------------------------------------------------------------------- + +// ============================================================================ +// STANDARD BSL ASSERT TEST FUNCTION +// ---------------------------------------------------------------------------- + +namespace { + +int testStatus = 0; + +void aSsErT(bool condition, const char *message, int line) +{ + if (condition) { + printf("Error " __FILE__ "(%d): %s (failed)\n", line, message); + + if (0 <= testStatus && testStatus <= 100) { + ++testStatus; + } + } +} + +} // close unnamed namespace + +// ============================================================================ +// STANDARD BSL TEST DRIVER MACRO ABBREVIATIONS +// ---------------------------------------------------------------------------- + +#define ASSERT BSLS_BSLTESTUTIL_ASSERT +#define ASSERTV BSLS_BSLTESTUTIL_ASSERTV + +#define LOOP_ASSERT BSLS_BSLTESTUTIL_LOOP_ASSERT +#define LOOP0_ASSERT BSLS_BSLTESTUTIL_LOOP0_ASSERT +#define LOOP1_ASSERT BSLS_BSLTESTUTIL_LOOP1_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 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 + +#define STRINGIFY2(...) "" #__VA_ARGS__ +#define STRINGIFY(a) STRINGIFY2(a) + +// ============================================================================ +// NEGATIVE-TEST MACRO ABBREVIATIONS +// ---------------------------------------------------------------------------- + +#define ASSERT_SAFE_PASS(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_PASS(EXPR) +#define ASSERT_SAFE_FAIL(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_FAIL(EXPR) +#define ASSERT_PASS(EXPR) BSLS_ASSERTTEST_ASSERT_PASS(EXPR) +#define ASSERT_FAIL(EXPR) BSLS_ASSERTTEST_ASSERT_FAIL(EXPR) +#define ASSERT_OPT_PASS(EXPR) BSLS_ASSERTTEST_ASSERT_OPT_PASS(EXPR) +#define ASSERT_OPT_FAIL(EXPR) BSLS_ASSERTTEST_ASSERT_OPT_FAIL(EXPR) + +#define ASSERT_SAFE_PASS_RAW(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_PASS_RAW(EXPR) +#define ASSERT_SAFE_FAIL_RAW(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_FAIL_RAW(EXPR) +#define ASSERT_PASS_RAW(EXPR) BSLS_ASSERTTEST_ASSERT_PASS_RAW(EXPR) +#define ASSERT_FAIL_RAW(EXPR) BSLS_ASSERTTEST_ASSERT_FAIL_RAW(EXPR) +#define ASSERT_OPT_PASS_RAW(EXPR) BSLS_ASSERTTEST_ASSERT_OPT_PASS_RAW(EXPR) +#define ASSERT_OPT_FAIL_RAW(EXPR) BSLS_ASSERTTEST_ASSERT_OPT_FAIL_RAW(EXPR) + +// ============================================================================ +// MAIN PROGRAM +// ---------------------------------------------------------------------------- + +int main(int argc, char *argv[]) +{ + int test = argc > 1 ? atoi(argv[1]) : 0; + bool verbose = argc > 2; + bool veryVerbose = argc > 3; + bool veryVeryVerbose = argc > 4; + + (void) veryVerbose; // unused variable warning + (void) veryVeryVerbose; // unused variable warning + + printf( "TEST %s CASE %d\n", __FILE__, test); + + switch (test) { case 0: // Zero is always the leading case. + case 2: { + // -------------------------------------------------------------------- + // USAGE EXAMPLE + // + // Concerns: + // 1. Demonstrate the usage of this component. + // + // Plan: + // 1. Invoke `triggerAssert` and verify that a violation occurs. + // + // 2. Invoke `triggerReview` and verify that a violation occurs. + // -------------------------------------------------------------------- + if (verbose) printf("USAGE EXAMPLE\n" + "=============\n"); + +///Usage +///----- +// This section illustrates intended use of this component. +// +///Example: Basic Usage of Functions +///- - - - - - - - - - - - - - - - - +// First, we install an `AssertTestHandlerGuard` to catch the violation. +// ``` + bsls::AssertTestHandlerGuard g; +// ``` +// Then, we trigger an `AssertViolation` by calling `triggerAssert` inside +// `ASSERT_FAIL` and verify that a violation occurs as expected. +// ``` + ASSERT_FAIL(bsls::FuzzTest_TestUtil::triggerAssert()); +// ``` +// Next, we trigger a `ReviewViolation` by calling `triggerReview` inside +// `ASSERT_FAIL` and verify that a violation occurs as expected. +// ``` + ASSERT_FAIL(bsls::FuzzTest_TestUtil::triggerReview()); +// ``` + } break; + case 1: { + // -------------------------------------------------------------------- + // BREATHING TEST + // + // Concerns: + // 1. A violation is triggered as expected when `triggerAssert` is + // invoked. + // + // 2. A violation is triggered as expected when `triggerReview` is + // invoked. + // + // Plan: + // 1. Invoke `triggerAssert` and verify that a violation occurs. + // + // 2. Invoke `triggerReview` and verify that a violation occurs. + // + // Testing: + // BREATHING TEST + // -------------------------------------------------------------------- + if (verbose) printf("\nBREATHING TEST" + "\n==============\n"); + + bsls::AssertTestHandlerGuard g; + + ASSERT_FAIL(bsls::FuzzTest_TestUtil::triggerAssert()); + ASSERT_FAIL(bsls::FuzzTest_TestUtil::triggerReview()); + } break; + default: { + fprintf(stderr, "WARNING: CASE `%d` NOT FOUND.\n", test); + testStatus = -1; + } + } + + if (testStatus > 0) { + fprintf(stderr, "Error, non-zero test status = %d.\n", testStatus); + } + + return testStatus; +} + +// ---------------------------------------------------------------------------- +// Copyright 2024 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 ---------------------------------- diff --git a/groups/bsl/bsls/bsls_fuzztestpreconditionexception.h b/groups/bsl/bsls/bsls_fuzztestpreconditionexception.h index f42eebb381..247fb9fdd3 100644 --- a/groups/bsl/bsls/bsls_fuzztestpreconditionexception.h +++ b/groups/bsl/bsls/bsls_fuzztestpreconditionexception.h @@ -16,9 +16,9 @@ BSLS_IDENT("$Id: $") // `bsls::FuzzTestPreconditionException`, that provides a mechanism to convey // context information from a failing precondition to a test handler. The // context that is captured consists of the program source of the failing -// expression, the name of the file containing the assertion, the line number -// within that file where the asserted expression may be found, and the level -// of the assertion that has failed. +// expression, the name of the file containing the assertion/review, the line +// number within that file where the asserted/reviewed expression may be found, +// and the level of the assertion/review that has failed. // ///Usage ///----- @@ -30,11 +30,9 @@ BSLS_IDENT("$Id: $") // ``` // #define TEST_PRECONDITION(EXPRESSION) \$ // if (!(EXPRESSION)) { \$ -// bsls::AssertViolation violation(#EXPRESSION, \$ -// __FILE__, \$ -// __LINE__, \$ -// "LEVEL"); \$ -// throw bsls::FuzzTestPreconditionException(violation); \$ +// throw bsls::FuzzTestPreconditionException(#EXPRESSION, __FILE__, \$ +// __LINE__, "LEVEL", \$ +// false); \$ // } // ``` // Next we use the macro inside a try-block, so that we can catch the exception @@ -49,19 +47,18 @@ BSLS_IDENT("$Id: $") // recorded the context of where the assertion failed. // ``` // catch (const bsls::FuzzTestPreconditionException& exception) { -// assert(0 == strcmp("0 != p", -// exception.assertViolation().comment())); -// assert(0 == strcmp(__FILE__, -// exception.assertViolation().fileName())); -// assert(11 == __LINE__ - exception.assertViolation().lineNumber()); -// assert(0 == strcmp("LEVEL", -// exception.assertViolation().assertLevel())); +// assert(0 == strcmp("0 != p", exception.expression())); +// assert(0 == strcmp(__FILE__, exception.filename())); +// assert(9 == __LINE__ - exception.lineNumber()); +// assert(0 == strcmp("LEVEL", exception.level())); +// assert(false == exception.isReview()); // } // ``` #include #include #include +#include namespace BloombergLP { @@ -79,8 +76,11 @@ class FuzzTestPreconditionException { private: // DATA - const AssertViolation d_assertViolation; // from a failed precondition - // check + const char *d_expression; // expression that failed to assert as `true` + const char *d_filename; // name of file where the assert failed + const bool d_isReview; // flag indicating if the failure is a review + const char *d_level; // level of failed assertion or review + const int d_lineNumber; // line number in file where the assert failed private: // NOT IMPLEMENTED @@ -91,9 +91,17 @@ class FuzzTestPreconditionException { // CREATORS /// Create a `FuzzTestPreconditionException` object with the specified - /// `assertViolation`. + /// `expression`, `filename`, `lineNumber`, `level`, and `isReview`. The + /// behavior is undefined unless `0 < line` and all of `expression`, + /// `filename`, and `level` point to valid null-terminated character + /// strings that will remain unmodified for the lifetime of this object + /// (e.g., string literals). explicit BSLS_KEYWORD_CONSTEXPR - FuzzTestPreconditionException(const AssertViolation& assertViolation); + FuzzTestPreconditionException(const char *expression, + const char *filename, + int lineNumber, + const char *level = "UNKNOWN", + const bool isReview = false); #ifdef BSLS_COMPILERFEATURES_SUPPORT_DEFAULTED_FUNCTIONS // To avoid warnings about future incompatibility due to the deleted copy @@ -102,9 +110,10 @@ class FuzzTestPreconditionException { // declared to be explicitly generated. /// Create a `FuzzTestPreconditionException` object that is a copy of - /// the specified `original`, having the same value for the - /// `assertViolation` attribute. Note that this trivial constructor's - /// definition is compiler generated. + /// the specified `original`, having the same values for the + /// `expression`, `filename`, `lineNumber`, `level`, and `isReview` + /// attributes. Note that this trivial constructor's definition is + /// compiler generated. FuzzTestPreconditionException( const FuzzTestPreconditionException& original) = default; @@ -115,9 +124,24 @@ class FuzzTestPreconditionException { // ACCESSORS - /// Return an `AssertViolation` containing the details of the - /// precondition that has failed. - const AssertViolation& assertViolation() const; + /// Return a string containing the program source of the assertion that has + /// failed. + const char *expression() const; + + /// Return a string containing the filename of the source file containing + /// the assertion that has failed. + const char *filename() const; + + /// Return a string containing a representation of the level of assertion + /// or review macro that failed. + const char *level() const; + + /// Return a flag indicating if the failure is a review. + bool isReview() const; + + /// Return the number of the line within the file `filename` containing the + /// assertion that failed. + int lineNumber() const; }; // ============================================================================ @@ -132,16 +156,48 @@ class FuzzTestPreconditionException { BSLS_KEYWORD_CONSTEXPR inline FuzzTestPreconditionException::FuzzTestPreconditionException( - const AssertViolation& assertViolation) -: d_assertViolation(assertViolation) + const char *expression, + const char *filename, + const int lineNumber, + const char *level, + const bool isReview) +: d_expression(expression) +, d_filename(filename) +, d_isReview(isReview) +, d_level(level) +, d_lineNumber(lineNumber) { } // ACCESSORS inline -const AssertViolation& FuzzTestPreconditionException::assertViolation() const +const char *FuzzTestPreconditionException::expression() const +{ + return d_expression; +} + +inline +const char *FuzzTestPreconditionException::filename() const +{ + return d_filename; +} + +inline +const char *FuzzTestPreconditionException::level() const +{ + return d_level; +} + +inline +bool FuzzTestPreconditionException::isReview() const +{ + return d_isReview; +} + +inline +int FuzzTestPreconditionException::lineNumber() const { - return d_assertViolation; + return d_lineNumber; } } // close package namespace diff --git a/groups/bsl/bsls/bsls_fuzztestpreconditionexception.t.cpp b/groups/bsl/bsls/bsls_fuzztestpreconditionexception.t.cpp index a06f81494f..84f2d40152 100644 --- a/groups/bsl/bsls/bsls_fuzztestpreconditionexception.t.cpp +++ b/groups/bsl/bsls/bsls_fuzztestpreconditionexception.t.cpp @@ -16,22 +16,25 @@ using namespace std; // Overview // -------- // `bsls::FuzzTestPreconditionException` is a simple mechanism that -// communicates a `bsls::AssertViolation` from the point where it is created to -// the place where it is consumed. The intended use-case is for this -// CopyConstructible mechanism to be thrown as an exception, so that the -// attributes of `AssertViolation` can be queried in an exception handler. We -// must validate that such an exception object can be created with the desired -// `AssertViolation`; that the `AssertViolation` can be queried and have the -// correct values; that the object can be copied, such as by a `throw` -// expression, and that such a copy will have an `AssertViolation` having the -// same values as the original; that the objects can safely be destroyed -// without any other effect on the system. +// communicates a set of values from the point where is created to the place +// where it is consumed. The intended use-case is for this CopyConstructible +// mechanism to be thrown as an exception, so that the attributes can be +// queried in an exception- handler. We must validate that such an exception +// object can be created with the desired set of attributes; that the +// attributes can be queried and have the correct values; that the object can +// be copied, such as by a `throw` expression, and that such a copy will have +// attributes having the same values as the original; that the objects can +// safely be destroyed without any other effect on the system. // //----------------------------------------------------------------------------- -// [2] bsls::FuzzTestPreconditionException(const AssertViolation& av); +// [2] bsls::FuzzTestPreconditionException(const char*, ... ,const bool); // [3] bsls::FuzzTestPreconditionException(const bsls::FTPE& other); // [2] ~bsls::FuzzTestPreconditionException(); -// [2] const AssertViolation& assertViolation() const; +// [2] const char *expression() const; +// [2] const char *filename() const; +// [2] const char *level() const; +// [2] bool isReview() const; +// [2] int lineNumber() const; //----------------------------------------------------------------------------- // [1] BREATHING TEST // [4] USAGE EXAMPLE @@ -103,12 +106,12 @@ int main(int argc, char *argv[]) // TEST USAGE EXAMPLE // // Concerns: - // 1. The usage example provided in the component header file must - // compile, link, and run on all platforms as shown. + // 1. The usage example provided in the component header file must + // compile, link, and run on all platforms as shown. // // Plan: - // 1. Incorporate usage example from header into driver, remove leading - // comment characters, and replace `assert` with `ASSERT`. + // 1. Incorporate usage example from header into driver, remove + // leading comment characters, and replace `assert` with `ASSERT`. // // Testing: // USAGE EXAMPLE @@ -125,11 +128,9 @@ int main(int argc, char *argv[]) // ``` #define TEST_PRECONDITION(EXPRESSION) \ if (!(EXPRESSION)) { \ - bsls::AssertViolation violation(#EXPRESSION, \ - __FILE__, \ - __LINE__, \ - "LEVEL"); \ - throw bsls::FuzzTestPreconditionException(violation); \ + throw bsls::FuzzTestPreconditionException(#EXPRESSION, __FILE__, \ + __LINE__, "LEVEL", \ + false); \ } // ``` // Next we use the macro inside a try-block, so that we can catch the exception @@ -144,13 +145,11 @@ int main(int argc, char *argv[]) // recorded the context of where the assertion failed. // ``` catch (const bsls::FuzzTestPreconditionException& exception) { - ASSERT(0 == strcmp("0 != p", - exception.assertViolation().comment())); - ASSERT(0 == strcmp(__FILE__, - exception.assertViolation().fileName())); - ASSERT(11 == __LINE__ - exception.assertViolation().lineNumber()); - ASSERT(0 == strcmp("LEVEL", - exception.assertViolation().assertLevel())); + ASSERT(0 == strcmp("0 != p", exception.expression())); + ASSERT(0 == strcmp(__FILE__, exception.filename())); + ASSERT(9 == __LINE__ - exception.lineNumber()); + ASSERT(0 == strcmp("LEVEL", exception.level())); + ASSERT(false == exception.isReview()); } // ``` #else @@ -163,16 +162,16 @@ int main(int argc, char *argv[]) // TEST COPY CONSTRUCTOR // // Concerns: - // 1. That a copy of a `bsls::FuzzTestPreconditionException` object - // might not have the same value as the original object. That the - // source object might be altered by the act of making a copy. + // 1. That a copy of a `bsls::FuzzTestPreconditionException` object + // might not have the same value as the original object. That the + // source object might be altered by the act of making a copy. // // Plan: - // 1. Create a test object `x` with known attribute values. Then - // create `y`, a copy of `x`, and verify that each corresponding - // attribute of `x` and `y` have the same value. Finally, confirm - // that the attributes of `x` still have the initially supplied - // values. + // 1. Create a test object `x` with known attribute values. Then + // create `y`, a copy of `x`, and verify that each corresponding + // attribute of `x` and `y` have the same value. Finally, confirm + // that the attributes of `x` still have the initially supplied + // values. // // Testing: // bsls::FuzzTestPreconditionException(const bsls::FTPE& other); @@ -185,52 +184,39 @@ int main(int argc, char *argv[]) printf("\nCreate test strings for constructing x.\n"); const char *expression = "expression string"; - const char *filename = "filename string"; - const char *level = "level string"; + const char *filename = "filename string"; + const char *level = "level string"; const int lineNumber = 42; + const bool isReview = false; if (verbose) printf("\nCreate test object `x`.\n"); - const bsls::AssertViolation av(expression, - filename, - lineNumber, - level); - const bsls::FuzzTestPreconditionException x(av); + const bsls::FuzzTestPreconditionException x(expression, + filename, + lineNumber, + level, + isReview); - if (verbose) printf("\nCreate test object `y`, a copy of `x`.\n"); + if (verbose) + printf("\nCreate test object `y`, a copy of `x`.\n"); const bsls::FuzzTestPreconditionException y = x; if (veryVerbose) printf("\nConfirm `y` has the same attribute values as `x`.\n"); - ASSERTV(x.assertViolation().comment(), - y.assertViolation().comment(), - x.assertViolation().comment() == - y.assertViolation().comment()); - ASSERTV(x.assertViolation().fileName(), - y.assertViolation().fileName(), - x.assertViolation().fileName() == - y.assertViolation().fileName()); - ASSERTV(x.assertViolation().lineNumber(), - y.assertViolation().lineNumber(), - x.assertViolation().lineNumber() == - y.assertViolation().lineNumber()); - ASSERTV(x.assertViolation().assertLevel(), - y.assertViolation().assertLevel(), - x.assertViolation().assertLevel() == - y.assertViolation().assertLevel()); + ASSERTV(x.expression(), y.expression(), + x.expression() == y.expression()); + ASSERTV(x.filename(), y.filename(), x.filename() == y.filename()); + ASSERTV(x.lineNumber(), y.lineNumber(), + x.lineNumber() == y.lineNumber()); + ASSERTV(x.level(), y.level(), x.level() == y.level()); + ASSERT(x.isReview() == y.isReview()); if (verbose) printf("\nConfirm that `x` has not changed.\n"); - ASSERTV(expression, - x.assertViolation().comment(), - expression == x.assertViolation().comment()); - ASSERTV(filename, - x.assertViolation().fileName(), - filename == x.assertViolation().fileName()); - ASSERTV(x.assertViolation().lineNumber(), - lineNumber == x.assertViolation().lineNumber()); - ASSERTV(level, - x.assertViolation().assertLevel(), - level == x.assertViolation().assertLevel()); + ASSERTV(expression, x.expression(), expression == x.expression()); + ASSERTV(filename, x.filename(), filename == x.filename()); + ASSERTV(x.lineNumber(), 42 == x.lineNumber()); + ASSERTV(level, x.level(), level == x.level()); + ASSERT(isReview == x.isReview()); } break; case 2: { @@ -238,64 +224,59 @@ int main(int argc, char *argv[]) // TEST VALUE CONSTRUCTOR AND PRIMARY INSPECTOR // // Concerns: - // 1. That a `bsls::FuzzTestPreconditionException` object can be - // created with a data member of type `bsls::AssertViolation` with - // attributes having the same values contained in the object of type - // `bsls::AssertViolation` passed to the constructor. That the - // object's data member can be queried, regardless of whether the - // object is `const` or not. That the queried data member has the - // same values as those contained in the object supplied to the - // constructor. That the object can be cleanly destroyed without - // affecting the strings referenced by pointer. + // 1. That a `bsls::FuzzTestPreconditionException` object can be + // created with attributes having the same values passed to the + // constructor. That the object's data member can be queried, + // regardless of whether the object is `const` or not. That the + // queried data member has the same values as those supplied to the + // constructor. That the object can be cleanly destroyed without + // affecting the strings referenced by pointer. // // Plan: - // 1. Construct an object `x` of type - // `bsls::FuzzTestPreconditionException` from a - // `bsls::AssertViolation`, and confirm each attribute of the member - // `AssertViolation` has the respective value passed to the - // constructor. Allow `x` to be destroyed, and confirm the strings - // passed to the constructor can still be reached and have the same - // value. Then construct a second object `y` with different values - // for each attribute than were used constructing `x`. Confirm that - // the attributes for `y` have the respective values passed to the - // constructor, and so distinctly different values than when - // constructing `x`. + // 1. Construct an object `x` of type + // `bsls::FuzzTestPreconditionException`, and confirm each + // attribute has the respective value passed to the constructor. + // Allow `x` to be destroyed, and confirm the strings passed to the + // constructor can still be reached and have the same value. Then + // construct a second object `y` with different values for each + // attribute than were used constructing `x`. Confirm that the + // attributes for `y` have the respective values passed to the + // constructor, and so distinctly different values than when + // constructing `x`. // // Testing: - // bsls::FuzzTestPreconditionException(const AssertViolation& av); + // bsls::FuzzTestPreconditionException(const char*, ... ,const bool); // ~bsls::FuzzTestPreconditionException(); - // const AssertViolation& assertViolation() const; + // const char *expression() const; + // const char *filename() const; + // const char *level() const; + // bool isReview() const; + // int lineNumber() const; // -------------------------------------------------------------------- if (verbose) printf( - "\nTEST VALUE CONSTRUCTOR AND PRIMARY INSPECTORS" - "\n=============================================\n" ); + "\nTEST VALUE CONSTRUCTOR AND PRIMARY INSPECTORS" + "\n=============================================\n" ); const char *exprX = "first expression"; const char *fileX = "first file"; const char *levelX = "LEVEL"; const int lineNumberX = 13; + const bool isReviewX = false; { if (verbose) printf("\nCreate test object `x`.\n"); - bsls::AssertViolation av(exprX, fileX, lineNumberX, levelX); - - bsls::FuzzTestPreconditionException x(av); + bsls::FuzzTestPreconditionException x(exprX, fileX, lineNumberX, + levelX, isReviewX); if (verbose) printf("\nVerify attributes of `x`.\n"); - ASSERTV(exprX, - x.assertViolation().comment(), - exprX == x.assertViolation().comment()); - ASSERTV(fileX, - x.assertViolation().fileName(), - fileX == x.assertViolation().fileName()); - ASSERTV(x.assertViolation().lineNumber(), - lineNumberX == x.assertViolation().lineNumber()); - ASSERTV(levelX, - x.assertViolation().assertLevel(), - levelX == x.assertViolation().assertLevel()); + ASSERTV(exprX, x.expression(), exprX == x.expression()); + ASSERTV(fileX, x.filename(), fileX == x.filename()); + ASSERTV(x.lineNumber(), 13 == x.lineNumber()); + ASSERTV(levelX, x.level(), levelX == x.level()); + ASSERTV(isReviewX == x.isReview()); } if (verbose) @@ -307,40 +288,27 @@ int main(int argc, char *argv[]) const char *fileY = "second file"; const char *levelY = "second level"; const int lineNumberY = 8; + const bool isReviewY = true; { if (verbose) printf("\nCreate second test object `y`.\n"); - bsls::AssertViolation av(exprY, fileY, lineNumberY, levelY); - bsls::FuzzTestPreconditionException y(av); + bsls::FuzzTestPreconditionException y(exprY, fileY, lineNumberY, + levelY, isReviewY); if (verbose) printf("\nVerify attributes of `y`.\n"); - ASSERTV(exprY, - y.assertViolation().comment(), - exprY == y.assertViolation().comment()); - ASSERTV(fileY, - y.assertViolation().fileName(), - fileY == y.assertViolation().fileName()); - ASSERTV(y.assertViolation().lineNumber(), - lineNumberY == y.assertViolation().lineNumber()); - ASSERTV(levelY, - y.assertViolation().assertLevel(), - levelY == y.assertViolation().assertLevel()); - - ASSERTV(exprX, - y.assertViolation().comment(), - exprX != y.assertViolation().comment()); - ASSERTV(fileX, - y.assertViolation().fileName(), - fileX != y.assertViolation().fileName()); - ASSERTV(lineNumberX, - y.assertViolation().lineNumber(), - lineNumberX != y.assertViolation().lineNumber()); - ASSERTV(levelX, - y.assertViolation().assertLevel(), - levelX != y.assertViolation().assertLevel()); + ASSERTV(exprY, y.expression(), exprY == y.expression()); + ASSERTV(fileY, y.filename(), fileY == y.filename()); + ASSERTV(y.lineNumber(), 8 == y.lineNumber()); + ASSERTV(levelY, y.level(), levelY == y.level()); + ASSERT(isReviewY == y.isReview()); + + ASSERTV(exprX, y.expression(), exprX != y.expression()); + ASSERTV(fileX, y.filename(), fileX != y.filename()); + ASSERTV(levelX, y.level(), levelX != y.level()); + ASSERT(isReviewX != y.isReview()); } if (verbose) @@ -354,16 +322,16 @@ int main(int argc, char *argv[]) // BREATHING TEST // // Concerns: - // 1. That basic functionality appears to work as advertised before - // beginning testing in earnest. That an object of this type can be - // thrown as an exception and pass along the information from - // construction to the object caught in an exception-handler. + // 1. That basic functionality appears to work as advertised before + // beginning testing in earnest. That an object of this type can + // be thrown as an exception and pass along the information from + // construction to the object caught in an exception-handler. // // Plan: - // 2. Create a test objects `x` and throw a copy of this as an - // exception. Catch a copy of the exception as `y` in the - // exception-handler, and compare each attribute with the original - // `x`. + // 1. Create a test objects `x` and throw a copy of this as an + // exception. Catch a copy of the exception as `y` in the + // exception-handler, and compare each attribute with the original + // `x`. // // Testing: // BREATHING TEST @@ -373,79 +341,55 @@ int main(int argc, char *argv[]) "\n==============\n"); if (verbose) - printf("\nCreate test strings for constructing x.\n"); + printf("\nCreate test strings for constructing `x`.\n"); const char *expression = "expression string"; const char *filename = "filename string"; const char *level = "level string"; - const int lineNumber = 42; - - if (verbose) printf("\nCreate test object x.\n"); - - const bsls::AssertViolation av(expression, - filename, - lineNumber, - level); - bsls::FuzzTestPreconditionException x(av); - - ASSERTV(expression, - x.assertViolation().comment(), - expression == x.assertViolation().comment()); - ASSERTV(filename, - x.assertViolation().fileName(), - filename == x.assertViolation().fileName()); - ASSERTV(x.assertViolation().lineNumber(), - lineNumber == x.assertViolation().lineNumber()); - ASSERTV(level, - x.assertViolation().assertLevel(), - level == x.assertViolation().assertLevel()); + const int lineNumber = 42; + const bool isReview = false; + + if (verbose) printf("\nCreate test object `x`.\n"); + + bsls::FuzzTestPreconditionException x(expression, filename, lineNumber, + level, isReview); + // Note that the first two tests are intentionally pointer-value + // comparisons and not string comparisons. + ASSERTV(expression, x.expression(), expression == x.expression()); + ASSERTV(filename, x.filename(), filename == x.filename()); + ASSERTV(lineNumber, x.lineNumber(), lineNumber == x.lineNumber()); + ASSERTV(level, x.level(), level == x.level()); + ASSERT(isReview == x.isReview()); #if defined(BDE_BUILD_TARGET_EXC) // This class is created for the express purpose of throwing as an // exception, but this cannot be tested unless exceptions are enabled. if (verbose) - printf("\nThrow and catch a copy of x.\n"); + printf("\nThrow and catch a copy of `x`.\n"); try { throw x; } - catch (bsls::FuzzTestPreconditionException y) { // catch by value, use - // copy constructor - if (veryVerbose) - printf("\n\tCaught y, a copy of x.\n"); - ASSERTV(x.assertViolation().comment(), - y.assertViolation().comment(), - x.assertViolation().comment() == - y.assertViolation().comment()); - ASSERTV(x.assertViolation().fileName(), - y.assertViolation().fileName(), - x.assertViolation().fileName() == - y.assertViolation().fileName()); - ASSERTV(x.assertViolation().lineNumber(), - y.assertViolation().lineNumber(), - x.assertViolation().lineNumber() == - y.assertViolation().lineNumber()); - ASSERTV(x.assertViolation().assertLevel(), - y.assertViolation().assertLevel(), - x.assertViolation().assertLevel() == - y.assertViolation().assertLevel()); + catch (bsls::FuzzTestPreconditionException y) { // catch by value, use + // copy constructor + if (veryVerbose) printf("\n\tCaught `y`, a copy of `x`.\n"); + ASSERTV(x.expression(), y.expression(), + x.expression() == y.expression()); + ASSERTV(x.filename(), y.filename(), x.filename() == y.filename()); + ASSERTV(x.lineNumber(), y.lineNumber(), + x.lineNumber() == y.lineNumber()); + ASSERTV(x.level(), y.level(), x.level() == y.level()); + ASSERT(x.isReview() == y.isReview()); } #endif - if (verbose) - printf("\nConfirm that x has not changed.\n"); - ASSERTV(expression, - x.assertViolation().comment(), - expression == x.assertViolation().comment()); - ASSERTV(filename, - x.assertViolation().fileName(), - filename == x.assertViolation().fileName()); - ASSERTV(x.assertViolation().lineNumber(), - lineNumber == x.assertViolation().lineNumber()); - ASSERTV(level, - x.assertViolation().assertLevel(), - level == x.assertViolation().assertLevel()); + if (verbose) printf("\nConfirm that `x` has not changed.\n"); + ASSERTV(expression, x.expression(), expression == x.expression()); + ASSERTV(filename, x.filename(), filename == x.filename()); + ASSERTV(x.lineNumber(), 42 == x.lineNumber()); + ASSERTV(level, x.level(), level == x.level()); + ASSERT(isReview == x.isReview()); } break; default: { - fprintf(stderr, "WARNING: CASE `%d' NOT FOUND.\n", test); + fprintf(stderr, "WARNING: CASE `%d` NOT FOUND.\n", test); testStatus = -1; } } diff --git a/groups/bsl/bsls/bsls_preconditions.h b/groups/bsl/bsls/bsls_preconditions.h index e8781dd172..30aa047783 100644 --- a/groups/bsl/bsls/bsls_preconditions.h +++ b/groups/bsl/bsls/bsls_preconditions.h @@ -9,7 +9,7 @@ BSLS_IDENT("$Id: $") //@PURPOSE: Provide macros for use in fuzz testing narrow contract functions. // //@CLASSES: -// bsls::PreconditionsHandler: for begin/end callback management functions +// bsls::PreconditionsHandler: for begin/end callback management functions // //@MACROS: // BSLS_PRECONDITIONS_BEGIN: mark the start of function preconditions @@ -41,9 +41,9 @@ BSLS_IDENT("$Id: $") // These macros are to be placed around the function precondition checks, // immediately before and after. // ``` +// /// Return the square root of the specified `x`. The behavior is undefined +// /// unless `x >= 0`. // double mySqrt(double x) -// // Return the square root of the specified 'x'. The behavior is -// // undefined unless 'x >= 0'. // { // BSLS_PRECONDITIONS_BEGIN(); // BSLS_ASSERT(0 <= x); @@ -55,7 +55,7 @@ BSLS_IDENT("$Id: $") // with `BSLS_FUZZTEST_EVALUATE`. #include -#include // 'AtomicTypes' +#include // `AtomicTypes` #include #include @@ -85,7 +85,7 @@ BSLS_IDENT("$Id: $") } \ } while (false) -#else // fuzzing not enabled or 'consteval' not active +#else // fuzzing not enabled or `consteval` not active #define BSLS_PRECONDITIONS_BEGIN() do {} while(false) #define BSLS_PRECONDITIONS_END() do {} while(false) @@ -99,10 +99,9 @@ namespace bsls { // class PreconditionsHandler // =========================== -/// This utility class maintains pointers containing the addresses of -/// functions invoked by the `BSLS_PRECONDITIONS_BEGIN` and -/// `BSLS_PRECONDITIONS_END` macros, and provides methods to -/// manipulate and utilize those functions. +/// This utility class maintains pointers containing the addresses of functions +/// invoked by the `BSLS_PRECONDITIONS_BEGIN` and `BSLS_PRECONDITIONS_END` +/// macros, and provides methods to manipulate and utilize those functions. class PreconditionsHandler { private: diff --git a/groups/bsl/bsls/bsls_preconditions.t.cpp b/groups/bsl/bsls/bsls_preconditions.t.cpp index 2cf3dd7254..f9645d9a44 100644 --- a/groups/bsl/bsls/bsls_preconditions.t.cpp +++ b/groups/bsl/bsls/bsls_preconditions.t.cpp @@ -23,9 +23,9 @@ using namespace std; // these macros before and after the preconditions of a function. // // ---------------------------------------------------------------------------- -// [ 2] static void installHandlers(beginHandler, endHandler); // [ 2] static PreconditionHandlerType getBeginHandler(); // [ 2] static PreconditionHandlerType getEndHandler(); +// [ 2] static void installHandlers(beginHandler, endHandler); // [ 2] static void invokeBeginHandler(); // [ 2] static void invokeEndHandler(); // ---------------------------------------------------------------------------- @@ -220,8 +220,8 @@ namespace usage_example { // immediately before and after. // ``` - /// Return the square root of the specified `x`. The behavior is - /// undefined unless `x >= 0`. + /// Return the square root of the specified `x`. The behavior is undefined + /// unless `x >= 0`. double mySqrt(double x) { BSLS_PRECONDITIONS_BEGIN(); @@ -256,12 +256,12 @@ int main(int argc, char *argv[]) // USAGE EXAMPLE // // Concerns: - // 1. The usage example provided in the component header file must - // compile, link, and run on all platforms as shown. + // 1. The usage example provided in the component header file must + // compile, link, and run on all platforms as shown. // // Plan: - // 1. Incorporate usage example from header into driver, removing - // leading comment characters. + // 1. Incorporate usage example from header into driver, removing + // leading comment characters. // // Testing: // USAGE EXAMPLE @@ -275,26 +275,26 @@ int main(int argc, char *argv[]) // TESTING MACROS AND PRECONDITIONSHANDLER // // Concerns: - // 1. That the handlers are installed via `installHandlers` and invoked - // correctly by `BSLS_PRECONDITIONS_BEGIN` and - // `BSLS_PRECONDITIONS_END` macros. + // 1. That the handlers are installed via `installHandlers` and + // invoked correctly by `BSLS_PRECONDITIONS_BEGIN` and + // `BSLS_PRECONDITIONS_END` macros. // - // 2. That `getBeginHandler` and `getEndHandler` return the previously - // installed handlers. + // 2. That `getBeginHandler` and `getEndHandler` return the previously + // installed handlers. // // Plan: - // 1. Install custom `BEGIN/END` handler functions using - // `PreconditionsHandler::installHandlers`. Then verify that the - // handlers were invoked after calls to the macros. + // 1. Install custom `BEGIN/END` handler functions using + // `PreconditionsHandler::installHandlers`. Then verify that the + // handlers were invoked after calls to the macros. // - // 2. Verify that the handlers were correctly installed. + // 2. Verify that the handlers were correctly installed. // // Testing: - // static void installHandlers(beginHandler, endHandler); // BSLS_PRECONDITIONS_BEGIN // BSLS_PRECONDITIONS_END // static PreconditionHandlerType getBeginHandler(); // static PreconditionHandlerType getEndHandler(); + // static void installHandlers(beginHandler, endHandler); // static void invokeBeginHandler(); // static void invokeEndHandler(); // -------------------------------------------------------------------- @@ -307,10 +307,10 @@ int main(int argc, char *argv[]) // BREATHING TEST // // Concerns: - // 1. This test driver builds on all platforms. + // 1. This test driver builds on all platforms. // // Plan: - // 1. Print out flags in verbose mode. + // 1. Print out flags in verbose mode. // // Testing: // BREATHING TEST diff --git a/groups/bsl/bsls/doc/bsls.txt b/groups/bsl/bsls/doc/bsls.txt index 7c4239189a..f87e896548 100644 --- a/groups/bsl/bsls/doc/bsls.txt +++ b/groups/bsl/bsls/doc/bsls.txt @@ -18,7 +18,7 @@ /Hierarchical Synopsis /--------------------- - The 'bsls' package currently has 86 components having 16 levels of physical + The 'bsls' package currently has 87 components having 16 levels of physical dependency. The list below shows the hierarchical ordering of the components. The order of components within each level is not architecturally significant, just alphabetical. @@ -34,6 +34,7 @@ 14. bsls_alignmentutil bsls_bslexceptionutil bsls_fuzztest + bsls_fuzztest_testutil bsls_stopwatch bsls_timeinterval @@ -287,6 +288,9 @@ : 'bsls_fuzztestpreconditionexception': : Provide an exception type for handling failed preconditions. : +: 'bsls_fuzztest_testutil': +: Provide utilities to facilitate testing the 'bsls_fuzztest' component. +: : 'bsls_ident': : Provide macros for inserting SCM Ids into source files. : @@ -672,16 +676,16 @@ .. #include #include - + #include - + #include #include - + using namespace BloombergLP; - + struct Forwarded; - + // ===================================================================== // Parameter 't' of function 'deduce' is a forwarding reference that is // forwarded to the constructor of local 'tt' to demonstrate being moved @@ -692,7 +696,7 @@ { Forwarded tt(BSLS_COMPILERFEATURES_FORWARD(T, t)); // Perfect forwarding } - + struct Forwarded { // A class to demonstrate whether moving or copying is taking place @@ -700,7 +704,7 @@ Forwarded(const Forwarded&){bsl::cout << "Copy\n";} Forwarded(bslmf::MovableRef){bsl::cout << "Move\n";} }; - + int main() { Forwarded f; diff --git a/groups/bsl/bsls/package/bsls.mem b/groups/bsl/bsls/package/bsls.mem index 9ea621c676..7fb3434f47 100644 --- a/groups/bsl/bsls/package/bsls.mem +++ b/groups/bsl/bsls/package/bsls.mem @@ -16,7 +16,7 @@ bsls_atomicoperations bsls_atomicoperations_all_all_clangintrinsics bsls_atomicoperations_all_all_gccintrinsics bsls_atomicoperations_arm_all_gcc -bsls_atomicoperations_arm32_win_msvc +bsls_atomicoperations_arm32_win_msvc bsls_atomicoperations_arm64_win_msvc bsls_atomicoperations_default bsls_atomicoperations_powerpc_aix_xlc_default @@ -29,7 +29,7 @@ bsls_atomicoperations_sparc64_sun_cc bsls_atomicoperations_x64_all_gcc bsls_atomicoperations_x64_win_msvc bsls_atomicoperations_x86_all_gcc -bsls_atomicoperations_x86_win_msvc +bsls_atomicoperations_x86_win_msvc bsls_blockgrowth bsls_bsldeprecationinformation bsls_bslexceptionutil @@ -51,6 +51,7 @@ bsls_deprecatefeature bsls_exceptionutil bsls_fuzztest bsls_fuzztestpreconditionexception +bsls_fuzztest_testutil bsls_ident bsls_int64 bsls_keyword