diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 61ca2d7..2076f68 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -7,7 +7,7 @@ The main changes since release 4.0 are: * Convert::copyUnion now always copies between subfields. * CreateRequest prevents a possible SEGFAULT. * New stream operators for Field and PVField are provided. -* New method getAs that is like getSubField except that it throws exception +* New method getSubFieldT that is like getSubField except that it throws exception Convert copy methods and equals operators ----------------------------------------- @@ -73,10 +73,10 @@ Now it can be done as follows: cout << pv << endl; } -New method getAs that is like getSubField except that it throws exception +New method getSubFieldT that is like getSubField except that it throws exception -------------------- -PVStructure has a new template member getAs(const char *name) +PVStructure has a new template member getSubFieldT(std::string const &fieldName) that is like getSubField except that it throws a runtime_error instead of returning null. diff --git a/documentation/pvDataCPP.html b/documentation/pvDataCPP.html index 6ea31bd..53902c0 100644 --- a/documentation/pvDataCPP.html +++ b/documentation/pvDataCPP.html @@ -465,10 +465,10 @@ structure PVStructurePtr doubleValue = getPVDataCreate()->createPVStructure( getStandardField()->scalar(pvDouble,"alarm,timeStamp")); PVDoublePtr pvdouble = - doubleValue->getAs<PVDouble>("value"); + doubleValue->getSubField<PVDouble>("value"); pvdouble->put(1e5); cout << *doubleValue << endl; - double value = doubleValue->getAs<PVDouble>("value")->get(); + double value = doubleValue->getSubField<PVDouble>("value")->get(); cout << "from get " << value << "\n\n"; This produces: @@ -491,7 +491,7 @@ from get 100000 PVStructurePtr doubleArrayValue = pvDataCreate->createPVStructure( standardField->scalarArray(pvDouble,"alarm,timeStamp")); PVDoubleArrayPtr pvDoubleArray = - doubleArrayValue->getAs<PVDoubleArray>("value"); + doubleArrayValue->getSubField<PVDoubleArray>("value"); size_t len = 10; shared_vector<double> xxx(len); for(size_t i=0; i< len; ++i) xxx[i] = i; @@ -605,10 +605,10 @@ structure createUnion(), "alarm,timeStamp")); PVStructurePtr pvTimeStamp = - pvStructure->getAs<PVUnion>("value")->select<PVStructure>(2); - pvTimeStamp->getAs<PVLong>("secondsPastEpoch")->put(1000); + pvStructure->getSubField<PVUnion>("value")->select<PVStructure>(2); + pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000); cout << *pvStructure) << "\n"; - pvStructure->getAs<PVUnion>("value")->select<PVDouble>(0)->put(1e5); + pvStructure->getSubField<PVUnion>("value")->select<PVDouble>(0)->put(1e5); cout << *pvStructure << "\n\n"; This produces: @@ -648,13 +648,13 @@ epics:nt/NTUnion:1.0 standardField->variantUnion("alarm,timeStamp")); PVStructurePtr pvTimeStamp = pvDataCreate->createPVStructure(standardField->timeStamp()); - pvStructure->getAs<PVUnion>("value")->set(pvTimeStamp); - pvTimeStamp->getAs<PVLong>("secondsPastEpoch")->put(1000); + pvStructure->getSubField<PVUnion>("value")->set(pvTimeStamp); + pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000); cout << *pvStructure << "\n"; - pvStructure->getAs<PVUnion>("value")->set( + pvStructure->getSubField<PVUnion>("value")->set( pvDataCreate->createPVScalar(pvDouble)); PVDoublePtr pvValue = static_pointer_cast<PVDouble>( - pvStructure->getAs<PVUnion>("value")->get()); + pvStructure->getSubField<PVUnion>("value")->get()); pvValue->put(1e5); cout << *pvStructure << "\n\n"; @@ -718,7 +718,7 @@ epics:nt/NTUnion:1.0 cout << *pvStructure->getStructure() << endl; cout << "data\n"; cout << *pvStructure << "\n"; - PVUnionPtr pvUnion = pvStructure->getAs<PVUnion>("value");; + PVUnionPtr pvUnion = pvStructure->getSubField<PVUnion>("value");; pvUnion->select("doubleValue"); PVDoublePtr pvDouble = pvUnion->get<PVDouble>(); pvDouble->put(1.55); @@ -726,7 +726,7 @@ epics:nt/NTUnion:1.0 cout << *pvStructure << "\n"; cout << "value = " << pvDouble->get() << "\n"; pvUnion->select("structValue"); - pvDouble = pvUnion->get<PVStructure>()->getAs<PVDouble>("doubleValue"); + pvDouble = pvUnion->get<PVStructure>()->getSubField<PVDouble>("doubleValue"); pvDouble->put(1.65); cout << "select structValue\n"; cout << *pvStructure << "\n"; @@ -2304,14 +2304,21 @@ public: template<typename PVT> std::tr1::shared_ptr<PVT> getSubField(std::string const &fieldName) const - template<typename PVT> - PVT& getAs(const char *name) const; - PVFieldPtr getSubField(std::size_t fieldOffset) const; template<typename PVT> std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const + PVFieldPtr getSubFieldT(std::string const &fieldName) const; + + template<typename PVT> + std::tr1::shared_ptr<PVT> getSubFieldT(std::string const &fieldName) const + + PVFieldPtr getSubFieldT(std::size_t fieldOffset) const; + + template<typename PVT> + std::tr1::shared_ptr<PVT> getSubFieldT(std::size_t fieldOffset) const + virtual void serialize( ByteBuffer *pbuffer,SerializableControl *pflusher) const ; virtual void deserialize( @@ -2332,10 +2339,7 @@ public:
getPVFields
Returns the array of subfields. The set of subfields must all have different field names.
-
getAs(const char *name)
-
Like the getSubField except that it throws std::runtime_error if - the field does not exists or has the wrong type.
-
getSubField(std::string fieldName)
+
getSubField(std::string const &fieldName)
Get a subField of a field.d A non-null result is @@ -2350,9 +2354,13 @@ public:
Get the field located a fieldOffset, where fieldOffset is relative to the top level structure. This returns null if the specified field is not located within this PVStructure. -
- Note The template version replaces getBooleanField, etc.
+
getSubFieldT(std::string const &fieldName)
+
Like getSubField except that it throws std::runtime_error if + the field does not exists or has the wrong type.
+
getSubFieldT(int fieldOffset)
+
Like getSubField except that it throws std::runtime_error if + the field does not exists or has the wrong type.
dumpValue
Method for streams I/O.
@@ -5414,7 +5422,7 @@ public: raiseMonitor = true; if(pvFieldOptions!=NULL) { PVStringPtr pvString = - pvFieldOptions->getAs<PVString>("raiseMonitor"); + pvFieldOptions->getSubField<PVString>("raiseMonitor"); if(pvString!=NULL) { std::string value = pvString->get(); if(value.compare("false")==0) raiseMonitor = false; diff --git a/documentation/pvDataCPP_20150623.html b/documentation/pvDataCPP_20150623.html index 6ea31bd..53902c0 100644 --- a/documentation/pvDataCPP_20150623.html +++ b/documentation/pvDataCPP_20150623.html @@ -465,10 +465,10 @@ structure PVStructurePtr doubleValue = getPVDataCreate()->createPVStructure( getStandardField()->scalar(pvDouble,"alarm,timeStamp")); PVDoublePtr pvdouble = - doubleValue->getAs<PVDouble>("value"); + doubleValue->getSubField<PVDouble>("value"); pvdouble->put(1e5); cout << *doubleValue << endl; - double value = doubleValue->getAs<PVDouble>("value")->get(); + double value = doubleValue->getSubField<PVDouble>("value")->get(); cout << "from get " << value << "\n\n"; This produces: @@ -491,7 +491,7 @@ from get 100000 PVStructurePtr doubleArrayValue = pvDataCreate->createPVStructure( standardField->scalarArray(pvDouble,"alarm,timeStamp")); PVDoubleArrayPtr pvDoubleArray = - doubleArrayValue->getAs<PVDoubleArray>("value"); + doubleArrayValue->getSubField<PVDoubleArray>("value"); size_t len = 10; shared_vector<double> xxx(len); for(size_t i=0; i< len; ++i) xxx[i] = i; @@ -605,10 +605,10 @@ structure createUnion(), "alarm,timeStamp")); PVStructurePtr pvTimeStamp = - pvStructure->getAs<PVUnion>("value")->select<PVStructure>(2); - pvTimeStamp->getAs<PVLong>("secondsPastEpoch")->put(1000); + pvStructure->getSubField<PVUnion>("value")->select<PVStructure>(2); + pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000); cout << *pvStructure) << "\n"; - pvStructure->getAs<PVUnion>("value")->select<PVDouble>(0)->put(1e5); + pvStructure->getSubField<PVUnion>("value")->select<PVDouble>(0)->put(1e5); cout << *pvStructure << "\n\n"; This produces: @@ -648,13 +648,13 @@ epics:nt/NTUnion:1.0 standardField->variantUnion("alarm,timeStamp")); PVStructurePtr pvTimeStamp = pvDataCreate->createPVStructure(standardField->timeStamp()); - pvStructure->getAs<PVUnion>("value")->set(pvTimeStamp); - pvTimeStamp->getAs<PVLong>("secondsPastEpoch")->put(1000); + pvStructure->getSubField<PVUnion>("value")->set(pvTimeStamp); + pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000); cout << *pvStructure << "\n"; - pvStructure->getAs<PVUnion>("value")->set( + pvStructure->getSubField<PVUnion>("value")->set( pvDataCreate->createPVScalar(pvDouble)); PVDoublePtr pvValue = static_pointer_cast<PVDouble>( - pvStructure->getAs<PVUnion>("value")->get()); + pvStructure->getSubField<PVUnion>("value")->get()); pvValue->put(1e5); cout << *pvStructure << "\n\n"; @@ -718,7 +718,7 @@ epics:nt/NTUnion:1.0 cout << *pvStructure->getStructure() << endl; cout << "data\n"; cout << *pvStructure << "\n"; - PVUnionPtr pvUnion = pvStructure->getAs<PVUnion>("value");; + PVUnionPtr pvUnion = pvStructure->getSubField<PVUnion>("value");; pvUnion->select("doubleValue"); PVDoublePtr pvDouble = pvUnion->get<PVDouble>(); pvDouble->put(1.55); @@ -726,7 +726,7 @@ epics:nt/NTUnion:1.0 cout << *pvStructure << "\n"; cout << "value = " << pvDouble->get() << "\n"; pvUnion->select("structValue"); - pvDouble = pvUnion->get<PVStructure>()->getAs<PVDouble>("doubleValue"); + pvDouble = pvUnion->get<PVStructure>()->getSubField<PVDouble>("doubleValue"); pvDouble->put(1.65); cout << "select structValue\n"; cout << *pvStructure << "\n"; @@ -2304,14 +2304,21 @@ public: template<typename PVT> std::tr1::shared_ptr<PVT> getSubField(std::string const &fieldName) const - template<typename PVT> - PVT& getAs(const char *name) const; - PVFieldPtr getSubField(std::size_t fieldOffset) const; template<typename PVT> std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const + PVFieldPtr getSubFieldT(std::string const &fieldName) const; + + template<typename PVT> + std::tr1::shared_ptr<PVT> getSubFieldT(std::string const &fieldName) const + + PVFieldPtr getSubFieldT(std::size_t fieldOffset) const; + + template<typename PVT> + std::tr1::shared_ptr<PVT> getSubFieldT(std::size_t fieldOffset) const + virtual void serialize( ByteBuffer *pbuffer,SerializableControl *pflusher) const ; virtual void deserialize( @@ -2332,10 +2339,7 @@ public:
getPVFields
Returns the array of subfields. The set of subfields must all have different field names.
-
getAs(const char *name)
-
Like the getSubField except that it throws std::runtime_error if - the field does not exists or has the wrong type.
-
getSubField(std::string fieldName)
+
getSubField(std::string const &fieldName)
Get a subField of a field.d A non-null result is @@ -2350,9 +2354,13 @@ public:
Get the field located a fieldOffset, where fieldOffset is relative to the top level structure. This returns null if the specified field is not located within this PVStructure. -
- Note The template version replaces getBooleanField, etc.
+
getSubFieldT(std::string const &fieldName)
+
Like getSubField except that it throws std::runtime_error if + the field does not exists or has the wrong type.
+
getSubFieldT(int fieldOffset)
+
Like getSubField except that it throws std::runtime_error if + the field does not exists or has the wrong type.
dumpValue
Method for streams I/O.
@@ -5414,7 +5422,7 @@ public: raiseMonitor = true; if(pvFieldOptions!=NULL) { PVStringPtr pvString = - pvFieldOptions->getAs<PVString>("raiseMonitor"); + pvFieldOptions->getSubField<PVString>("raiseMonitor"); if(pvString!=NULL) { std::string value = pvString->get(); if(value.compare("false")==0) raiseMonitor = false; diff --git a/src/factory/PVStructure.cpp b/src/factory/PVStructure.cpp index 5d61056..a7996b7 100644 --- a/src/factory/PVStructure.cpp +++ b/src/factory/PVStructure.cpp @@ -107,11 +107,11 @@ const PVFieldPtrArray & PVStructure::getPVFields() const PVFieldPtr PVStructure::getSubField(string const &fieldName) const { - try{ - return GetAsImpl(fieldName.c_str())->shared_from_this(); - }catch(...){ - return PVFieldPtr(); - } + PVField * field = getSubFieldImpl(fieldName.c_str(), false); + if (field) + return field->shared_from_this(); + else + return PVFieldPtr(); } @@ -134,21 +134,59 @@ PVFieldPtr PVStructure::getSubField(size_t fieldOffset) const throw std::logic_error("PVStructure.getSubField: Logic error"); } -PVField* PVStructure::GetAsImpl(const char *name) const +PVFieldPtr PVStructure::getSubFieldT(std::size_t fieldOffset) const +{ + PVFieldPtr pvField = getSubField(fieldOffset); + if (pvField.get()) + return pvField; + else + { + std::stringstream ss; + ss << "Failed to get field with offset " + << fieldOffset << "(Invalid offset)" ; + throw std::runtime_error(ss.str()); + } +} + +PVField* PVStructure::getSubFieldImpl(const char *name, bool throws) const { const PVStructure *parent = this; if(!name) - throw std::invalid_argument("field name is NULL string"); - + { + if (throws) + throw std::invalid_argument("Failed to get field: (Field name is NULL string)"); + else + return NULL; + } + const char *fullName = name; while(true) { const char *sep=name; while(*sep!='\0' && *sep!='.' && *sep!=' ') sep++; if(*sep==' ') - throw std::runtime_error("No spaces allowed in field name"); - + { + if (throws) + { + std::stringstream ss; + ss << "Failed to get field: " << fullName + << " (No spaces allowed in field name)"; + throw std::runtime_error(ss.str()); + } + else + return NULL; + } size_t N = sep-name; if(N==0) - throw std::runtime_error("zero-length field name encountered"); + { + if (throws) + { + std::stringstream ss; + ss << "Failed to get field: " << fullName + << " (Zero-length field name encountered)"; + throw std::runtime_error(ss.str()); + } + else + return NULL; + } const PVFieldPtrArray& pvFields = parent->getPVFields(); @@ -165,13 +203,34 @@ PVField* PVStructure::GetAsImpl(const char *name) const } if(!child) - throw std::runtime_error("field not found"); //TODO: which sub field? + { + if (throws) + { + std::stringstream ss; + ss << "Failed to get field: " << fullName << " (" + << std::string(fullName, sep) << " not found)"; + throw std::runtime_error(ss.str()); + } + else + return NULL; + } if(*sep) { // this is not the requested leaf parent = dynamic_cast(child); if(!parent) - throw std::runtime_error("mid-field is not a PVStructure"); //TODO: which sub field? + { + if (throws) + { + std::stringstream ss; + ss << "Failed to get field: " << fullName + << " (" << std::string(fullName, sep) + << " is not a structure)"; + throw std::runtime_error(ss.str()); + } + else + return NULL; + } child = NULL; name = sep+1; // skip past '.' // loop around to new parent @@ -256,22 +315,13 @@ PVUnionPtr PVStructure::getUnionField(string const &fieldName) PVScalarArrayPtr PVStructure::getScalarArrayField( string const &fieldName,ScalarType elementType) { - try{ - PVFieldPtr pvField = GetAsImpl(fieldName.c_str())->shared_from_this(); - FieldConstPtr field = pvField->getField(); - Type type = field->getType(); - if(type!=scalarArray) { - return nullPVScalarArray; - } - ScalarArrayConstPtr pscalarArray - = static_pointer_cast(pvField->getField()); - if(pscalarArray->getElementType()!=elementType) { - return nullPVScalarArray; - } - return std::tr1::static_pointer_cast(pvField); - }catch(...){ + PVScalarArrayPtr arrayField = getSubField(fieldName); + if (arrayField.get() && + arrayField->getScalarArray()->getElementType()!=elementType) + { return nullPVScalarArray; - } + } + return arrayField; } PVStructureArrayPtr PVStructure::getStructureArrayField( diff --git a/src/pv/pvData.h b/src/pv/pvData.h index 7384cac..e54d636 100644 --- a/src/pv/pvData.h +++ b/src/pv/pvData.h @@ -684,23 +684,42 @@ public: */ PVFieldPtr getSubField(std::string const &fieldName) const; + /** + * Get a subfield with the specified name. + * @param fieldName a '.' separated list of child field names (no whitespace allowed) + * @returns A pointer to the sub-field or null if field does not exist or has a different type + * @code + * PVIntPtr ptr = pvStruct->getSubField("substruct.leaffield"); + * @endcode + */ template - std::tr1::shared_ptr getSubField(std::string const &fieldName) const + FORCE_INLINE std::tr1::shared_ptr getSubField(std::string const &fieldName) const { - PVFieldPtr pvField = getSubField(fieldName); - if (pvField.get()) - return std::tr1::dynamic_pointer_cast(pvField); + return this->getSubField(fieldName.c_str()); + } + + template + std::tr1::shared_ptr getSubField(const char *name) const + { + PVField *raw = getSubFieldImpl(name, false); + if (raw) + return std::tr1::dynamic_pointer_cast(raw->shared_from_this()); else return std::tr1::shared_ptr(); } - + /** * Get the subfield with the specified offset. * @param fieldOffset The offset. * @return Pointer to the field or null if field does not exist. */ PVFieldPtr getSubField(std::size_t fieldOffset) const; - + + /** + * Get the subfield with the specified offset. + * @param fieldOffset The offset. + * @return Pointer to the field or null if field does not exist. + */ template std::tr1::shared_ptr getSubField(std::size_t fieldOffset) const { @@ -711,32 +730,75 @@ public: return std::tr1::shared_ptr(); } -private: - PVField *GetAsImpl(const char *name) const; -public: + /** + * Get a subfield with the specified name. + * @param fieldName a '.' separated list of child field names (no whitespace allowed) + * @returns A reference to the sub-field (never NULL) + * @throws std::runtime_error if the requested sub-field doesn't exist, or has a different type + */ + FORCE_INLINE PVFieldPtr getSubFieldT(std::string const &fieldName) const + { + return getSubFieldImpl(fieldName.c_str())->shared_from_this(); + } /** * Get a subfield with the specified name. - * @param name a '.' separated list of child field names (no whitespace allowed) + * @param fieldName a '.' separated list of child field names (no whitespace allowed) * @returns A reference to the sub-field (never NULL) * @throws std::runtime_error if the requested sub-field doesn't exist, or has a different type * @code - * PVInt& ref = pvStruct->getAs("substruct.leaffield"); + * PVIntPtr ptr = pvStruct->getSubFieldT("substruct.leaffield"); * @endcode */ template - PVT& getAs(const char *name) const + FORCE_INLINE std::tr1::shared_ptr getSubFieldT(std::string const &fieldName) const { - PVT *raw = dynamic_cast(GetAsImpl(name)); - if(!raw) - throw std::runtime_error("Field has wrong type"); - return *raw; + return this->getSubFieldT(fieldName.c_str()); } template - FORCE_INLINE PVT& getAs(std::string const &fieldName) const + std::tr1::shared_ptr getSubFieldT(const char *name) const { - return this->getAs(fieldName.c_str()); + std::tr1::shared_ptr pvField = std::tr1::dynamic_pointer_cast( + getSubFieldImpl(name)->shared_from_this()); + + if (pvField.get()) + return pvField; + else + { + std::stringstream ss; + ss << "Failed to get field: " << name << " (Field has wrong type)"; + throw std::runtime_error(ss.str()); + } + } + /** + * Get the subfield with the specified offset. + * @param fieldOffset The offset. + * @returns A reference to the sub-field (never NULL) + * @throws std::runtime_error if the requested sub-field doesn't exist + */ + PVFieldPtr getSubFieldT(std::size_t fieldOffset) const; + + /** + * Get the subfield with the specified offset. + * @param fieldOffset The offset. + * @returns A reference to the sub-field (never NULL) + * @throws std::runtime_error if the requested sub-field doesn't exist, or has a different type + */ + template + std::tr1::shared_ptr getSubFieldT(std::size_t fieldOffset) const + { + std::tr1::shared_ptr pvField = std::tr1::dynamic_pointer_cast( + getSubFieldT(fieldOffset)); + if (pvField.get()) + return pvField; + else + { + std::stringstream ss; + ss << "Failed to get field with offset " + << fieldOffset << " (Field has wrong type)"; + throw std::runtime_error(ss.str()); + } } /** @@ -911,6 +973,8 @@ public: void copyUnchecked(const PVStructure& from, const BitSet& maskBitSet, bool inverse = false); private: + PVField *getSubFieldImpl(const char *name, bool throws = true) const; + static PVFieldPtr nullPVField; static PVBooleanPtr nullPVBoolean; static PVBytePtr nullPVByte; diff --git a/testApp/pv/testPVData.cpp b/testApp/pv/testPVData.cpp index 327a9c2..ec387f7 100644 --- a/testApp/pv/testPVData.cpp +++ b/testApp/pv/testPVData.cpp @@ -541,16 +541,16 @@ static void testFieldAccess() PVIntPtr a = fld->getSubField("test"); testOk1(a!=NULL); if(a.get()) { - PVInt& b = fld->getAs("test"); - testOk(&b==a.get(), "%p == %p", &b, a.get()); + PVIntPtr b = fld->getSubFieldT("test"); + testOk(b.get()==a.get(), "%p == %p", b.get(), a.get()); } else testSkip(1, "test doesn't exist?"); a = fld->getSubField("hello.world"); testOk1(a!=NULL); if(a.get()) { - PVInt& b = fld->getAs("hello.world"); - testOk(&b==a.get(), "%p == %p", &b, a.get()); + PVIntPtr b = fld->getSubFieldT("hello.world"); + testOk(b.get()==a.get(), "%p == %p", b.get(), a.get()); } else testSkip(1, "hello.world doesn't exist?"); @@ -573,22 +573,67 @@ static void testFieldAccess() // whitespace testOk1(fld->getSubField(" test").get()==NULL); + // intermediate field not structure + testOk1(fld->getSubField("hello.world.invalid").get()==NULL); + + // null string try{ - fld->getAs("invalid"); + char * name = NULL; + fld->getSubFieldT(name); + testFail("missing required exception"); + }catch(std::invalid_argument& e){ + testPass("caught expected exception: %s", e.what()); + } + + // non-existent + try{ + fld->getSubFieldT("invalid"); testFail("missing required exception"); }catch(std::runtime_error& e){ testPass("caught expected exception: %s", e.what()); } + // wrong type try{ - fld->getAs("test"); + fld->getSubFieldT("test"); testFail("missing required exception"); }catch(std::runtime_error& e){ testPass("caught expected exception: %s", e.what()); } + // empty leaf field name try{ - fld->getAs("hello.world.invalid"); + fld->getSubFieldT("hello."); + testFail("missing required exception"); + }catch(std::runtime_error& e){ + testPass("caught expected exception: %s", e.what()); + } + + // empty field name + try{ + fld->getSubFieldT("hello..world"); + testFail("missing required exception"); + }catch(std::runtime_error& e){ + testPass("caught expected exception: %s", e.what()); + } + try{ + fld->getSubFieldT("."); + testFail("missing required exception"); + }catch(std::runtime_error& e){ + testPass("caught expected exception: %s", e.what()); + } + + // whitespace + try{ + fld->getSubFieldT(" test"); + testFail("missing required exception"); + }catch(std::runtime_error& e){ + testPass("caught expected exception: %s", e.what()); + } + + // intermediate field not structure + try{ + fld->getSubFieldT("hello.world.invalid"); testFail("missing required exception"); }catch(std::runtime_error& e){ testPass("caught expected exception: %s", e.what()); @@ -597,7 +642,7 @@ static void testFieldAccess() MAIN(testPVData) { - testPlan(236); + testPlan(242); fieldCreate = getFieldCreate(); pvDataCreate = getPVDataCreate(); standardField = getStandardField();