From 08772a0d243521482396981ddd3737067f30e349 Mon Sep 17 00:00:00 2001 From: azv Date: Thu, 18 Aug 2016 15:32:28 +0300 Subject: [PATCH] Fix unit tests for ParametersPlugin --- src/ModelHighAPI/ModelHighAPI_Dumper.cpp | 28 +++++--- src/ModelHighAPI/ModelHighAPI_Dumper.h | 8 ++- .../ModelHighAPI_FeatureStore.cpp | 32 +++++++-- src/ParametersAPI/ParametersAPI_Parameter.cpp | 5 +- .../Test/TestParameterChangeValue.py | 45 +++++++++++- .../Test/TestParameterCreation.py | 9 ++- .../Test/TestParameterRename.py | 69 ++++++++++++++++--- src/PythonAPI/model/dump/DumpAssistant.py | 8 ++- 8 files changed, 173 insertions(+), 31 deletions(-) diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp index dfc6c389b..28961598f 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp @@ -59,15 +59,20 @@ ModelHighAPI_Dumper* ModelHighAPI_Dumper::getInstance() return mySelf; } +#define CLEAR_STREAM(theStream) { \ + std::ostringstream anOther; \ + swap(theStream, anOther); \ + } + void ModelHighAPI_Dumper::clear(bool bufferOnly) { - myDumpBuffer = std::ostringstream(); + CLEAR_STREAM(myDumpBuffer); myDumpBuffer << std::setprecision(16); clearNotDumped(); if (!bufferOnly) { - myFullDump = std::ostringstream(); + CLEAR_STREAM(myFullDump); myFullDump << std::setprecision(16); myNames.clear(); @@ -82,7 +87,7 @@ void ModelHighAPI_Dumper::clearNotDumped() myNotDumpedEntities.clear(); } -const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity) +const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity, bool theSaveNotDumped) { EntityNameMap::const_iterator aFound = myNames.find(theEntity); if (aFound != myNames.end()) @@ -116,7 +121,8 @@ const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity) } myNames[theEntity] = std::pair(aName, isUserDefined); - myNotDumpedEntities.insert(theEntity); + if (theSaveNotDumped) + myNotDumpedEntities.insert(theEntity); return myNames[theEntity].first; } @@ -150,10 +156,13 @@ bool ModelHighAPI_Dumper::process(const std::shared_ptr& theD bool ModelHighAPI_Dumper::process(const std::shared_ptr& theDoc) { bool isOk = true; - // dump all features std::list aFeatures = theDoc->allFeatures(); std::list::const_iterator aFeatIt = aFeatures.begin(); - for (; aFeatIt != aFeatures.end(); ++aFeatIt) { + // firstly, dump all parameters + for (; aFeatIt != aFeatures.end(); ++ aFeatIt) + dumpParameter(*aFeatIt); + // dump all other features + for (aFeatIt = aFeatures.begin(); aFeatIt != aFeatures.end(); ++aFeatIt) { CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast(*aFeatIt); if (aCompFeat) // iteratively process composite features isOk = process(aCompFeat) && isOk; @@ -206,6 +215,9 @@ bool ModelHighAPI_Dumper::processSubs(const std::shared_ptrnumberOfSubs(); +////////////////////////////////////// + std::list aList = theComposite->reflist("Features")->list(); +////////////////////////////////////// for (int anIndex = 0; anIndex < aNbSubs; ++anIndex) { FeaturePtr aFeature = theComposite->subFeature(anIndex); if (isDumped(aFeature)) @@ -533,11 +545,11 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( myDumpBuffer << "]"; } else { // clear buffer and store list "as is" - myDumpBuffer = std::ostringstream(); + CLEAR_STREAM(myDumpBuffer); *this << theRefList; // save buffer and clear it again std::string aDumpedList = myDumpBuffer.str(); - myDumpBuffer = std::ostringstream(); + CLEAR_STREAM(myDumpBuffer); // obtain name of list FeaturePtr anOwner = ModelAPI_Feature::feature(theRefList->owner()); std::string aListName = name(anOwner) + "_objects"; diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.h b/src/ModelHighAPI/ModelHighAPI_Dumper.h index f7f0dcc3e..61ed60703 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.h +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.h @@ -9,6 +9,7 @@ #include "ModelHighAPI.h" +#include #include #include #include @@ -80,13 +81,18 @@ public: const std::string& theObject = std::string()); /// Returns name of specified entity + /// \param theEntity [in] named entity + /// \param theSaveNotDumped [in] if \c true, the entity should be stored as not dumped (will be dumped automatically) + /// \return name of the entity MODELHIGHAPI_EXPORT - const std::string& name(const EntityPtr& theEntity); + const std::string& name(const EntityPtr& theEntity, bool theSaveNotDumped = true); /// Returns name of parent composite feature for specified entity MODELHIGHAPI_EXPORT const std::string& parentName(const FeaturePtr& theFeature); + /// Dump parameter feature only + virtual void dumpParameter(const FeaturePtr& theFeature) = 0; /// Dump given feature virtual void dumpFeature(const FeaturePtr& theFeature, const bool theForce = false) = 0; diff --git a/src/ModelHighAPI/ModelHighAPI_FeatureStore.cpp b/src/ModelHighAPI/ModelHighAPI_FeatureStore.cpp index 326f4a16b..ac702d968 100644 --- a/src/ModelHighAPI/ModelHighAPI_FeatureStore.cpp +++ b/src/ModelHighAPI/ModelHighAPI_FeatureStore.cpp @@ -34,6 +34,10 @@ #include #include +#include + +#define PRECISION 7 +#define TOLERANCE (1.e-7) ModelHighAPI_FeatureStore::ModelHighAPI_FeatureStore(FeaturePtr theFeature) { storeData(theFeature->data(), myAttrs); @@ -112,6 +116,16 @@ std::string ModelHighAPI_FeatureStore::compareData(std::shared_ptr 0) + theOutput << " "; + theOutput << std::fixed << setprecision(PRECISION) + << (fabs(theArray[i]) < TOLERANCE ? 0.0 : theArray[i]); + } +} + std::string ModelHighAPI_FeatureStore::dumpAttr(const AttributePtr& theAttr) { static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators(); FeaturePtr aFeatOwner = std::dynamic_pointer_cast(theAttr->owner()); @@ -153,9 +167,10 @@ std::string ModelHighAPI_FeatureStore::dumpAttr(const AttributePtr& theAttr) { aResult<text(); } else if (aType == ModelAPI_AttributeDouble::typeId()) { AttributeDoublePtr anAttr = std::dynamic_pointer_cast(theAttr); - if (anAttr->text().empty()) - aResult<value(); - else + if (anAttr->text().empty()) { + double aVal = anAttr->value(); + dumpArray(aResult, &aVal, 1); + } else aResult<text(); } else if (aType == ModelAPI_AttributeBoolean::typeId()) { AttributeBooleanPtr anAttr = std::dynamic_pointer_cast(theAttr); @@ -245,13 +260,16 @@ std::string ModelHighAPI_FeatureStore::dumpAttr(const AttributePtr& theAttr) { aResult<value(a)<<" "; } else if (aType == GeomDataAPI_Point::typeId()) { AttributePointPtr anAttr = std::dynamic_pointer_cast(theAttr); - aResult<x()<<" "<y()<<" "<z(); + double aValues[3] = {anAttr->x(), anAttr->y(), anAttr->z()}; + dumpArray(aResult, aValues, 3); } else if (aType == GeomDataAPI_Dir::typeId()) { AttributeDirPtr anAttr = std::dynamic_pointer_cast(theAttr); - aResult<x()<<" "<y()<<" "<z(); + double aValues[3] = {anAttr->x(), anAttr->y(), anAttr->z()}; + dumpArray(aResult, aValues, 3); } else if (aType == GeomDataAPI_Point2D::typeId()) { AttributePoint2DPtr anAttr = std::dynamic_pointer_cast(theAttr); - aResult<x()<<" "<y()<<" "; + double aValues[2] = {anAttr->x(), anAttr->y()}; + dumpArray(aResult, aValues, 2); } else { aResult<<"__unknownattribute__"; } @@ -276,7 +294,7 @@ std::string ModelHighAPI_FeatureStore::dumpShape(std::shared_ptr& // output the main characteristics aResult<<"Volume: "< aCenter = GeomAlgoAPI_ShapeTools::centreOfMass(theShape); - aResult<<"Center of mass: "<x()<<" "<y()<<" "<z()<document()); - const std::string& aParamName = theDumper.name(aBase); + const std::string& aParamName = theDumper.name(aBase, false); AttributeStringPtr anExpr = aBase->string(ParametersPlugin_Parameter::EXPRESSION_ID()); AttributeStringPtr aComment = aBase->string(ParametersPlugin_Parameter::COMMENT_ID()); diff --git a/src/ParametersPlugin/Test/TestParameterChangeValue.py b/src/ParametersPlugin/Test/TestParameterChangeValue.py index 46b076db2..c78775aee 100644 --- a/src/ParametersPlugin/Test/TestParameterChangeValue.py +++ b/src/ParametersPlugin/Test/TestParameterChangeValue.py @@ -81,13 +81,54 @@ class TestParameterRename(unittest.TestCase): aSketchCircle = aSketchFeature.addFeature("SketchCircle") anCircleCentr = geomDataAPI_Point2D(aSketchCircle.attribute("CircleCenter")) aRadiusAttr = aSketchCircle.real("CircleRadius") - anCircleCentr.setText("x1 + 10.0", "x1 + 20.0") - aRadiusAttr.setText("x1") + anCircleCentr.setValue(10., 20.) + aRadiusAttr.setValue(10.) self.aSession.finishOperation() self.anCircleCentr = anCircleCentr self.aRadiusAttr = aRadiusAttr + # constraints to fix circle position and radius + self.aSession.startOperation() + # fix X coordinate + aDistanceConstraint1 = aSketchFeature.addFeature("SketchConstraintDistance") + refattrA = aDistanceConstraint1.refattr("ConstraintEntityA") + refattrA.setAttr(anCircleCentr) + refattrB = aDistanceConstraint1.refattr("ConstraintEntityB") + anOY = aSketchFeature.addFeature("SketchLine") + aStartPoint = geomDataAPI_Point2D(anOY.attribute("StartPoint")) + anEndPoint = geomDataAPI_Point2D(anOY.attribute("EndPoint")) + aStartPoint.setValue(0., 0.) + anEndPoint.SetValue(0., 100.) + anOY.selection("External").selectSubShape("EDGE", "OY") + refattrB.setObject(modelAPI_ResultConstruction(anOY.firstResult())) + value = aDistanceConstraint1.real("ConstraintValue") + value.setText("x1 + 10.0") + aDistanceConstraint1.execute(); + # fix Y coordinate + aDistanceConstraint2 = aSketchFeature.addFeature("SketchConstraintDistance") + refattrA = aDistanceConstraint2.refattr("ConstraintEntityA") + refattrA.setAttr(anCircleCentr) + refattrB = aDistanceConstraint2.refattr("ConstraintEntityB") + anOX = aSketchFeature.addFeature("SketchLine") + aStartPoint = geomDataAPI_Point2D(anOX.attribute("StartPoint")) + anEndPoint = geomDataAPI_Point2D(anOX.attribute("EndPoint")) + aStartPoint.setValue(0., 0.) + anEndPoint.SetValue(100., 0.) + anOX.selection("External").selectSubShape("EDGE", "OX") + refattrB.setObject(modelAPI_ResultConstruction(anOX.firstResult())) + value = aDistanceConstraint2.real("ConstraintValue") + value.setText("x1 + 20.0") + aDistanceConstraint2.execute(); + # fix radius + aRadiusConstraint = aSketchFeature.addFeature("SketchConstraintRadius") + refattrA = aRadiusConstraint.refattr("ConstraintEntityA") + refattrA.setObject(modelAPI_ResultConstruction(aSketchCircle.lastResult())) + aRadiusConstrAttr = aRadiusConstraint.real("ConstraintValue") + aRadiusConstrAttr.setText("x1") + aRadiusConstraint.execute() + self.aSession.finishOperation() + self.assertEqual(self.anCircleCentr.x(), 160.) self.assertEqual(self.anCircleCentr.y(), 170.) self.assertEqual(aRadiusAttr.value(), 150.) diff --git a/src/ParametersPlugin/Test/TestParameterCreation.py b/src/ParametersPlugin/Test/TestParameterCreation.py index a791a54e9..e4ac3fee0 100644 --- a/src/ParametersPlugin/Test/TestParameterCreation.py +++ b/src/ParametersPlugin/Test/TestParameterCreation.py @@ -114,7 +114,7 @@ assert (aTmValue == round(2 * math.pi, 6)) #========================================================================= # Use parameters to set radius of a circle : # 1. Create a circle (250., 250), r = 25. -# 2. Set a 'cr1' as text value of radius attribute +# 2. Create a radius constraint and set 'cr1' as text value of constraint #========================================================================= aSession.startOperation() aSketchCircle = aSketchFeature.addFeature("SketchCircle") @@ -125,7 +125,12 @@ aRadiusAttr.setValue(25.) aSession.finishOperation() # Apply parameter aSession.startOperation() -aRadiusAttr.setText("cr1") +aRadiusConstraint = aSketchFeature.addFeature("SketchConstraintRadius") +refattrA = aRadiusConstraint.refattr("ConstraintEntityA") +refattrA.setObject(modelAPI_ResultConstruction(aSketchCircle.lastResult())) +aRadiusConstrAttr = aRadiusConstraint.real("ConstraintValue") +aRadiusConstrAttr.setText("cr1") +aRadiusConstraint.execute() aSession.finishOperation() assert(aRadiusAttr.value() == 100.) #========================================================================= diff --git a/src/ParametersPlugin/Test/TestParameterRename.py b/src/ParametersPlugin/Test/TestParameterRename.py index 0605fac1a..795ce9fe7 100644 --- a/src/ParametersPlugin/Test/TestParameterRename.py +++ b/src/ParametersPlugin/Test/TestParameterRename.py @@ -83,13 +83,58 @@ class TestParameterRename(unittest.TestCase): aSketchCircle = aSketchFeature.addFeature("SketchCircle") anCircleCentr = geomDataAPI_Point2D(aSketchCircle.attribute("CircleCenter")) aRadiusAttr = aSketchCircle.real("CircleRadius") - anCircleCentr.setText("x1 + 10.0", "x1 + 20.0") - aRadiusAttr.setText("x1") + anCircleCentr.setValue(10., 20.) + aRadiusAttr.setValue(10.) self.aSession.finishOperation() self.anCircleCentr = anCircleCentr self.aRadiusAttr = aRadiusAttr + # constraints to fix circle position and radius + self.aSession.startOperation() + # fix X coordinate + aDistanceConstraint1 = aSketchFeature.addFeature("SketchConstraintDistance") + refattrA = aDistanceConstraint1.refattr("ConstraintEntityA") + refattrA.setAttr(anCircleCentr) + refattrB = aDistanceConstraint1.refattr("ConstraintEntityB") + anOY = aSketchFeature.addFeature("SketchLine") + aStartPoint = geomDataAPI_Point2D(anOY.attribute("StartPoint")) + anEndPoint = geomDataAPI_Point2D(anOY.attribute("EndPoint")) + aStartPoint.setValue(0., 0.) + anEndPoint.SetValue(0., 100.) + anOY.selection("External").selectSubShape("EDGE", "OY") + refattrB.setObject(modelAPI_ResultConstruction(anOY.firstResult())) + valueX = aDistanceConstraint1.real("ConstraintValue") + valueX.setText("x1 + 10.0") + aDistanceConstraint1.execute(); + # fix Y coordinate + aDistanceConstraint2 = aSketchFeature.addFeature("SketchConstraintDistance") + refattrA = aDistanceConstraint2.refattr("ConstraintEntityA") + refattrA.setAttr(anCircleCentr) + refattrB = aDistanceConstraint2.refattr("ConstraintEntityB") + anOX = aSketchFeature.addFeature("SketchLine") + aStartPoint = geomDataAPI_Point2D(anOX.attribute("StartPoint")) + anEndPoint = geomDataAPI_Point2D(anOX.attribute("EndPoint")) + aStartPoint.setValue(0., 0.) + anEndPoint.SetValue(100., 0.) + anOX.selection("External").selectSubShape("EDGE", "OX") + refattrB.setObject(modelAPI_ResultConstruction(anOX.firstResult())) + valueY = aDistanceConstraint2.real("ConstraintValue") + valueY.setText("x1 + 20.0") + aDistanceConstraint2.execute(); + # fix radius + aRadiusConstraint = aSketchFeature.addFeature("SketchConstraintRadius") + refattrA = aRadiusConstraint.refattr("ConstraintEntityA") + refattrA.setObject(modelAPI_ResultConstruction(aSketchCircle.lastResult())) + aRadiusConstrAttr = aRadiusConstraint.real("ConstraintValue") + aRadiusConstrAttr.setText("x1") + aRadiusConstraint.execute() + self.aSession.finishOperation() + + self.aCircleCenterX = valueX + self.aCircleCenterY = valueY + sel.aCircleRadius = aRadiusConstraintAttr + self.assertEqual(self.anCircleCentr.x(), 160.) self.assertEqual(self.anCircleCentr.y(), 170.) self.assertEqual(aRadiusAttr.value(), 150.) @@ -110,9 +155,13 @@ class TestParameterRename(unittest.TestCase): aParam = self.dtParams["x2"] self.assertEqual(aParam.string("expression").value(), "a1 + y1 + 100.0") # Check rename in the feature - self.assertEqual(self.anCircleCentr.textX(), "a1 + 10.0") - self.assertEqual(self.anCircleCentr.textY(), "a1 + 20.0") - self.assertEqual(self.aRadiusAttr.text(), "a1") + self.assertEqual(self.aCircleCenterX.text(), "a1 + 10.0") + self.assertEqual(self.aCircleCenterY.text(), "a1 + 20.0") + self.assertEqual(self.aCircleRadius.text(), "a1") + # Check values + self.assertEqual(self.anCircleCentr.x(), 160.) + self.assertEqual(self.anCircleCentr.y(), 170.) + self.assertEqual(self.aRadiusAttr.value(), 150.) def test_rename_not_unique(self): # Rename to not unique name @@ -129,9 +178,13 @@ class TestParameterRename(unittest.TestCase): aParam = self.dtParams["x2"] self.assertEqual(aParam.string("expression").value(), "x1 + y1 + 100.0") # Check rename in the feature (Expected: not renamed) - self.assertEqual(self.anCircleCentr.textX(), "x1 + 10.0") - self.assertEqual(self.anCircleCentr.textY(), "x1 + 20.0") - self.assertEqual(self.aRadiusAttr.text(), "x1") + self.assertEqual(self.aCircleCenterX.text(), "x1 + 10.0") + self.assertEqual(self.aCircleCenterY.text(), "x1 + 20.0") + self.assertEqual(self.aCircleRadius.text(), "x1") + # Check values + self.assertEqual(self.anCircleCentr.x(), 160.) + self.assertEqual(self.anCircleCentr.y(), 170.) + self.assertEqual(self.aRadiusAttr.value(), 150.) if __name__ == '__main__': unittest.main() diff --git a/src/PythonAPI/model/dump/DumpAssistant.py b/src/PythonAPI/model/dump/DumpAssistant.py index dc4c87384..b4a27add1 100644 --- a/src/PythonAPI/model/dump/DumpAssistant.py +++ b/src/PythonAPI/model/dump/DumpAssistant.py @@ -40,7 +40,7 @@ class DumpAssistant(ModelHighAPI.ModelHighAPI_Dumper): if aFeatureKind in self.myFeatures: # Dump only feature created by user (in history). # For all other features, just keep their name. - if theForce or aFeatureKind == "Parameter" or theFeature.isInHistory(): + if theForce or theFeature.isInHistory(): self.myFeatures[aFeatureKind](theFeature).dump(self) else: self.name(theFeature) @@ -50,6 +50,12 @@ class DumpAssistant(ModelHighAPI.ModelHighAPI_Dumper): # In case of theFeature is not a constraint, it will not be dumped. self.myFeatures[SketchAPI.SketchAPI_Constraint.ID()](theFeature).dump(self) + ## Dump all parameters + def dumpParameter(self, theFeature): + aFeatureKind = theFeature.getKind() + if aFeatureKind == "Parameter" and aFeatureKind in self.myFeatures: + self.myFeatures[aFeatureKind](theFeature).dump(self) + ## Return getter for specified attribute def attributeGetter(self, theFeature, theAttrName): aFeatureKind = theFeature.getKind() -- 2.39.2