From 309503e029cb40ebf84f521d3e70137ec402bfbb Mon Sep 17 00:00:00 2001 From: Steven Breitstein Date: Tue, 21 May 2024 14:16:30 -0400 Subject: [PATCH] Baljsn decoderoptionsutil drqs 175214394 (#4748) * drqs-175214394: 'baljsn_decoderoptionsutil': Initial. * drqs-175214394: 'baljsn.txt': Update package doc. * drqs-175214394: 'baljsn_decoderoptionsutil.h': Revisions per NGR 20240517. * drqs-175214394: 'baljsn_decoderoptionsutil.h': Revisions per NGR 20240521. --- groups/bal/baljsn/baljsn_decoder.h | 3 +- groups/bal/baljsn/baljsn_decoder.t.cpp | 6 +- .../bal/baljsn/baljsn_decoderoptionsutil.cpp | 56 ++++ groups/bal/baljsn/baljsn_decoderoptionsutil.h | 131 +++++++++ .../baljsn/baljsn_decoderoptionsutil.t.cpp | 265 ++++++++++++++++++ groups/bal/baljsn/doc/baljsn.txt | 6 +- groups/bal/baljsn/package/baljsn.mem | 1 + 7 files changed, 463 insertions(+), 5 deletions(-) create mode 100644 groups/bal/baljsn/baljsn_decoderoptionsutil.cpp create mode 100644 groups/bal/baljsn/baljsn_decoderoptionsutil.h create mode 100644 groups/bal/baljsn/baljsn_decoderoptionsutil.t.cpp diff --git a/groups/bal/baljsn/baljsn_decoder.h b/groups/bal/baljsn/baljsn_decoder.h index 08e140c1ec..358dffe934 100644 --- a/groups/bal/baljsn/baljsn_decoder.h +++ b/groups/bal/baljsn/baljsn_decoder.h @@ -10,7 +10,8 @@ BSLS_IDENT("$Id: $") //@CLASSES: // baljsn::Decoder: JSON decoder for 'bdeat'-compliant types // -//@SEE_ALSO: baljsn_encoder, baljsn_parserutil, baljsn_parser +//@SEE_ALSO: baljsn_decoderoptions, balsjn_decoderoptionsutil, +// baljsn_encoder, baljsn_parserutil, baljsn_parser // //@DESCRIPTION: This component provides a class, 'baljsn::Decoder', for // decoding value-semantic objects in the JSON format. In particular, the diff --git a/groups/bal/baljsn/baljsn_decoder.t.cpp b/groups/bal/baljsn/baljsn_decoder.t.cpp index 0b9fa2498f..f4e16a16e5 100644 --- a/groups/bal/baljsn/baljsn_decoder.t.cpp +++ b/groups/bal/baljsn/baljsn_decoder.t.cpp @@ -138,8 +138,8 @@ namespace test = BloombergLP::s_baltst; // [13] FALLBACK ENUMERATORS // [14] DECODING INTS AS ENUMS AND VICE VERSA {DRQS 166048981} // [15] ARRAY HAVING NULLABLE COMPLEX ELEMENTS {DRQS 167908706} -// [17] 'DecoderOptions' CAN BE CONFIGURED FOR STRICT CONFORMANCE -// [18] USAGE EXAMPLE +// [16] 'DecoderOptions' CAN BE CONFIGURED FOR STRICT CONFORMANCE +// [17] USAGE EXAMPLE // ============================================================================ // STANDARD BDE ASSERT TEST FUNCTION @@ -36941,7 +36941,7 @@ int main(int argc, char *argv[]) cout << "TEST " << __FILE__ << " CASE " << test << endl; switch (test) { case 0: // Zero is always the leading case. - case 18: { + case 17: { // -------------------------------------------------------------------- // USAGE EXAMPLE // Extracted from component header file. diff --git a/groups/bal/baljsn/baljsn_decoderoptionsutil.cpp b/groups/bal/baljsn/baljsn_decoderoptionsutil.cpp new file mode 100644 index 0000000000..7f7f278848 --- /dev/null +++ b/groups/bal/baljsn/baljsn_decoderoptionsutil.cpp @@ -0,0 +1,56 @@ +// baljsn_decoderoptionsutil.cpp -*-C++-*- +#include + +#include +BSLS_IDENT_RCSID(baljsn_printutil_cpp,"$Id$ $CSID$") + +#include + +#include + +namespace BloombergLP { +namespace baljsn { + + // ------------------------ + // class DecoderOptionsUtil + // ------------------------ + +void DecoderOptionsUtil::setMode(DecoderOptions *options, Mode mode) +{ + + BSLS_ASSERT(options); + + switch (mode) { + case e_DEFAULT: { + *options = DecoderOptions(); + } break; + case e_STRICT_20240423: { + options->setValidateInputIsUtf8 (true ); + options->setAllowConsecutiveSeparators (false); + options->setAllowFormFeedAsWhitespace (false); + options->setAllowUnescapedControlCharacters(false); + } break; + default: { + BSLS_ASSERT_OPT(!"reachable"); + } break; + } +} + +} // 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/bal/baljsn/baljsn_decoderoptionsutil.h b/groups/bal/baljsn/baljsn_decoderoptionsutil.h new file mode 100644 index 0000000000..6c2801d794 --- /dev/null +++ b/groups/bal/baljsn/baljsn_decoderoptionsutil.h @@ -0,0 +1,131 @@ +// baljsn_decoderoptionsutil.h -*-C++-*- +#ifndef INCLUDED_BALJSN_DECODEROPTIONSUTIL +#define INCLUDED_BALJSN_DECODEROPTIONSUTIL + +#include +BSLS_IDENT("$Id: $") + +//@PURPOSE: Provide a utility for configuring 'baljsn::DecoderOptions'. +// +//@CLASSES: +// baljsn::DecoderOptionsUtil: utility for setting 'baljsn::DecoderOptions' +// +//@SEE_ALSO: baljsn_decoder, baljsn_decoderoptions +// +//@DESCRIPTION: This component provides a 'struct' of utility functions, +// 'baljsn::DecoderOptionsUtil', for configuring 'baljsn::DecoderOptions' +// object. In particular, this utility can be used to set the combination of +// options needed for strict compliance with the JSON grammar (see +// {'baljsn_decoder'|Strict Conformance}). This utility can also be used to +// set a 'baljsn::DecoderOptions' object to its default state. +// +///Modes +///----- +// When a default constructed 'baljsn::DecoderOptions' object is passed to the +// 'decode' methods of a 'baljsn::Decoder', several convenient variances from +// the JSON grammar are tolerated in the JSON document without causing failure. +// Specifically: +//.. +// validateInputIsUtf8 false +// allowConsecutiveSeparators true +// allowFormFeedAsWhitespace true +// allowUnescapedControlCharacters true +//.. +// See {'baljsn_decoderoptions'|Attributes} for examples. Should any of these +// variances be unacceptable, then one can flip individual options. Strict +// compliance (see 'bdljsn_jsontestsuiteutil') with the JSON grammar requires +// that each option named above be flipped to the opposite value: +//.. +// validateInputIsUtf8 true +// allowConsecutiveSeparators false +// allowFormFeedAsWhitespace false +// allowUnescapedControlCharacters false +//.. +// This utility defines the mode +// 'baljsn::DecoderOptionsUtil::e_STRICT_20240423' to allow all four options to +// be set with a single call. +// +// Note that 'baljsn::DecoderOptions' defines other options besides the four +// cited above. Those are *not* changed by setting the +// 'baljsn::DecoderOptionsUtil::e_STRICT_20240423' combination but are set when +// setting the options object using 'baljsn::DecoderOptionsUtil::e_DEFAULT'. +// +///Usage +///----- +// This section illustrates intended use of this component. +// +///Example 1: Setting 'baljsn::DecoderOptions' for Strictness +/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Every call to one of the (non-deprecated) 'decode' functions of +// 'baljsn::Decoder' requires the user to provide a 'baljsn::DecoderOptions' +// object that allows the user to fine-tune the rules used when decoding the +// JSON document. The 'setMode' function of this utility provides a convenient +// way to set the option attributes to a combination that is deemed "strict" +// (i.e., strictly complying with the rules of the JSON grammar). +// +// First, create a 'baljsn::DecoderOptions' object: +//.. +// baljsn::DecoderOptions options; +//.. +// Now, set the option values for strict compliance: +//.. +// baljsn::DecoderOptionsUtil::setMode( +// &options, +// baljsn::DecoderOptionsUtil::e_STRICT_20240423); +//.. +// Finally, should there be a need, 'options' can be adjusted to a laxer set of +// rules by adjusting individual attributes or, if the original set of default +// attributes is needed, by using 'setMode': +//.. +// baljsn::DecoderOptionsUtil::setMode(&options, +// baljsn::DecoderOptionsUtil::e_DEFAULT); +//.. + +#include + +namespace BloombergLP { +namespace baljsn { + +class DecoderOptions; + + // ======================== + // class DecoderOptionsUtil + // ======================== + +struct DecoderOptionsUtil { + // This 'struct' provides a namespace for functions that set + // 'DecoderOptions' to particular configurations. + + public: + // TYPES + enum Mode { + e_DEFAULT = 0 // set to default state + , e_STRICT_20240423 = 1 // set for strictness conformance per 2024-04-23 + }; + + // CLASS METHODS + static void setMode(DecoderOptions *options, Mode mode); + // Set the attributes of the specified 'options' to the configuration + // associated with the specified 'mode'. See {Modes} for details. +}; + +} // 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/bal/baljsn/baljsn_decoderoptionsutil.t.cpp b/groups/bal/baljsn/baljsn_decoderoptionsutil.t.cpp new file mode 100644 index 0000000000..8b2c93b80e --- /dev/null +++ b/groups/bal/baljsn/baljsn_decoderoptionsutil.t.cpp @@ -0,0 +1,265 @@ +// baljsn_decoderoptionsutil.t.cpp -*-C++-*- +#include + +#include + +#include + +#include + +#include // 'bsl::atoi' +#include + +using namespace BloombergLP; +using bsl::cout; +using bsl::cerr; +using bsl::endl; + +// ============================================================================ +// TEST PLAN +// ---------------------------------------------------------------------------- +// Overview +// -------- +// The component under test, 'baljsn_decoderoptionutils, implements a utility +// for setting 'baljsn::DecoderOptions' object to particular configuration. +// Currently there a single function, 'setMode', is provided, and two modes, +// "default" and "strict" are defined. +// +// ---------------------------------------------------------------------------- +// CLASS METHODS +// [ 1] static void setMode(DecoderOptions *options, Mode mode); +// ---------------------------------------------------------------------------- +// [ 2] USAGE EXAMPLE + +// ============================================================================ +// STANDARD BDE ASSERT TEST FUNCTION +// ---------------------------------------------------------------------------- + +namespace { + +int testStatus = 0; + +void aSsErT(bool condition, const char *message, int line) +{ + if (condition) { + cout << "Error " __FILE__ "(" << line << "): " << message + << " (failed)" << endl; + + if (0 <= testStatus && testStatus <= 100) { + ++testStatus; + } + } +} + +} // close unnamed namespace + +// ============================================================================ +// STANDARD BDE TEST DRIVER MACRO ABBREVIATIONS +// ---------------------------------------------------------------------------- + +#define ASSERT BSLIM_TESTUTIL_ASSERT +#define ASSERTV BSLIM_TESTUTIL_ASSERTV + +#define LOOP_ASSERT BSLIM_TESTUTIL_LOOP_ASSERT +#define LOOP0_ASSERT BSLIM_TESTUTIL_LOOP0_ASSERT +#define LOOP1_ASSERT BSLIM_TESTUTIL_LOOP1_ASSERT +#define LOOP2_ASSERT BSLIM_TESTUTIL_LOOP2_ASSERT +#define LOOP3_ASSERT BSLIM_TESTUTIL_LOOP3_ASSERT +#define LOOP4_ASSERT BSLIM_TESTUTIL_LOOP4_ASSERT +#define LOOP5_ASSERT BSLIM_TESTUTIL_LOOP5_ASSERT +#define LOOP6_ASSERT BSLIM_TESTUTIL_LOOP6_ASSERT + +#define Q BSLIM_TESTUTIL_Q // Quote identifier literally. +#define P BSLIM_TESTUTIL_P // Print identifier and value. +#define P_ BSLIM_TESTUTIL_P_ // P(X) without '\n'. +#define T_ BSLIM_TESTUTIL_T_ // Print a tab (w/o newline). +#define L_ BSLIM_TESTUTIL_L_ // current Line number + +// ============================================================================ +// 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) + +// ============================================================================ +// GLOBAL TYPEDEFS/CONSTANTS FOR TESTING +// ---------------------------------------------------------------------------- + +typedef baljsn::DecoderOptionsUtil Util; +typedef baljsn::DecoderOptions Opts; + +// ============================================================================ +// MAIN PROGRAM +// ---------------------------------------------------------------------------- + +int main(int argc, char *argv[]) +{ + int test = argc > 1 ? bsl::atoi(argv[1]) : 0; + bool verbose = argc > 2; + bool veryVerbose = argc > 3; + bool veryVeryVerbose = argc > 4; (void) veryVeryVerbose; + + cout << "TEST " << __FILE__ << " CASE " << test << endl; + + switch (test) { case 0: + case 2: { + // -------------------------------------------------------------------- + // USAGE EXAMPLE + // Extracted from component header file. + // + // Concerns: + //: 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, and replace 'assert' with 'ASSERT'. + //: (C-1) + // + // Testing: + // USAGE EXAMPLE + // -------------------------------------------------------------------- + + if (verbose) cout << endl + << "USAGE EXAMPLE" << endl + << "=============" << endl; + +///Usage +///----- +// This section illustrates intended use of this component. +// +///Example 1: Setting 'baljsn::DecoderOptions' for Strictness +/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Every call to one of the (non-deprecated) 'decode' functions of +// 'baljsn::Decoder' requires the user to provide a 'baljsn::DecoderOptions' +// object that allows the user to fine-tune the rules used when decoding the +// JSON document. The 'setMode' function of this utility provides a convenient +// way to set the option attributes to a combination that is deemed "strict" +// (i.e., strictly complying with the rules of the JSON grammar). +// +// First, create a 'baljsn::DecoderOptions' object: +//.. + baljsn::DecoderOptions options; +//.. +// Now, set the option values for strict compliance: +//.. + baljsn::DecoderOptionsUtil::setMode( + &options, + baljsn::DecoderOptionsUtil::e_STRICT_20240423); +//.. +// Finally, should there be a need, 'options' can be adjusted to a laxer set of +// rules by adjusting individual attributes or, if the original set of default +// attributes is needed, by using 'setMode': +//.. + baljsn::DecoderOptionsUtil::setMode(&options, + baljsn::DecoderOptionsUtil::e_DEFAULT); +//.. + + } break; + case 1: { + // -------------------------------------------------------------------- + // TEST 'setMode' + // + // Concerns: + //: 1 When setting mode 'e_STRICT_20240423' all + //: 'baljsn::DecoderOptions' attributes relevant to strict are set to + //: their expected values *and* no other attributes are changed. + //: + //: 2 When setting mode 'e_DEFAULT' all attributes (relevant to + //: strictness or not) are set to their default values. + //: + //: 3 QoI: Asserted precondition violations are detected when enabled. + // + // Plan: + //: 1 A sequence of ad-hoc tests. (C-1,2) + //: + //: 2 Use 'BSLS_ASSERTTEST_*' macros to confirm pre-condition tests. + //: (C-3) + // + // Testing: + // static void setMode(DecoderOptions *options, Mode mode); + // -------------------------------------------------------------------- + + if (verbose) cout << endl + << "TEST 'setMode'" << endl + << "==============" << endl; + + if (veryVerbose) cout << "Set to Strict Mode" << endl; + + Opts mX; const Opts& X = mX; + + Util::setMode(&mX, Util::e_STRICT_20240423); + + // Set the two non-"strictness" attributes to non-default values. + const int MAX_DEPTH_A = Opts().maxDepth() + 1; + const bool SKIP_UNKNOWN_ELEMENTS_A = !Opts().skipUnknownElements(); + + mX.setMaxDepth(MAX_DEPTH_A); + mX.setSkipUnknownElements(SKIP_UNKNOWN_ELEMENTS_A); + + // Confirm that the "strictness" attributes have the expected value. + ASSERT(X.validateInputIsUtf8() == true ); + ASSERT(X.allowConsecutiveSeparators() == false); + ASSERT(X.allowFormFeedAsWhitespace() == false); + ASSERT(X.allowUnescapedControlCharacters() == false); + + // Confirm that the "strictness" attributes were indeed changed. + ASSERT( X.validateInputIsUtf8() + != Opts().validateInputIsUtf8()); + ASSERT( X.allowConsecutiveSeparators() + != Opts().allowConsecutiveSeparators()); + ASSERT( X.allowFormFeedAsWhitespace() + != Opts().allowFormFeedAsWhitespace()); + ASSERT( X.allowUnescapedControlCharacters() + != Opts().allowUnescapedControlCharacters()); + + // Confirm that the non-"strictness" attributes were *not* changed. + ASSERT(X.maxDepth() == MAX_DEPTH_A); + ASSERT(X.skipUnknownElements() == SKIP_UNKNOWN_ELEMENTS_A); + + if (veryVerbose) cout << "Set to Default" << endl; + + Util::setMode(&mX, Util::e_DEFAULT); + ASSERT(X == Opts()); + + if (veryVerbose) cout << "Negative Testing" << endl; + { + bsls::AssertTestHandlerGuard hG; + + Opts opts; + ASSERT_PASS((Util::setMode(&opts, Util::e_DEFAULT))); + ASSERT_FAIL((Util::setMode( 0, Util::e_DEFAULT))); + } + + } break; + default: { + cerr << "WARNING: CASE `" << test << "' NOT FOUND." << endl; + testStatus = -1; + } + } + + if (testStatus > 0) { + cerr << "Error, non-zero test status = " << testStatus << "." << endl; + } + + return testStatus; +} + +// ---------------------------------------------------------------------------- +// Copyright 2015 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/bal/baljsn/doc/baljsn.txt b/groups/bal/baljsn/doc/baljsn.txt index c6e4fadebd..abb7e7a9dc 100644 --- a/groups/bal/baljsn/doc/baljsn.txt +++ b/groups/bal/baljsn/doc/baljsn.txt @@ -12,7 +12,7 @@ /Hierarchical Synopsis /--------------------- - The 'baljsn' package currently has 14 components having 5 levels of physical + The 'baljsn' package currently has 15 components having 5 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. @@ -28,6 +28,7 @@ 2. baljsn_datumdecoderoptions baljsn_datumencoderoptions baljsn_decoder + baljsn_decoderoptionsutil baljsn_encoderoptions 1. baljsn_decoderoptions @@ -54,6 +55,9 @@ : 'baljsn_decoderoptions': : Provide an attribute class for specifying JSON decoding options. : +: 'baljsn_decoderoptionsutil': +: Provide a utility for configuring 'baljsn::DecoderOptions'. +: : 'baljsn_encoder': : Provide a JSON encoder for 'bdlat'-compatible types. : diff --git a/groups/bal/baljsn/package/baljsn.mem b/groups/bal/baljsn/package/baljsn.mem index df13d4a6a0..e0a866e7b7 100644 --- a/groups/bal/baljsn/package/baljsn.mem +++ b/groups/bal/baljsn/package/baljsn.mem @@ -3,6 +3,7 @@ baljsn_datumencoderoptions baljsn_datumutil baljsn_decoder baljsn_decoderoptions +baljsn_decoderoptionsutil baljsn_encoder baljsn_encoder_testtypes baljsn_encoderoptions