+ assert math.fabs(aResultVolume - anExpectedResultVolume) <= aTolerance * math.fabs(anExpectedResultVolume), "Area of result[{}]: {:0.27f}. Expected: {:0.27f}. The first {} significant digits not equal.".format(anIndex, aResultVolume, anExpectedResultVolume, theNbSignificantDigits)
+
+
+def testHaveNamingFaces(theFeature, theModel, thePartDoc) :
+ """ Tests if all faces of result have a name
+ :param theFeature: feature to test.
+ """
+ # open transaction since all the checking are performed in tests after model.end() call
+ theModel.begin()
+ # Get feature result/sub-result
+ aResult = theFeature.results()[0].resultSubShapePair()[0]
+ # Get result/sub-result shape
+ shape = aResult.shape()
+ # Create shape explorer with desired shape type
+ shapeExplorer = GeomAPI_ShapeExplorer(shape, GeomAPI_Shape.FACE)
+ # Create list, and store selections in it
+ selectionList = []
+ while shapeExplorer.more():
+ selection = theModel.selection(aResult, shapeExplorer.current()) # First argument should be result/sub-result, second is sub-shape on this result/sub-result
+ selectionList.append(selection)
+ shapeExplorer.next()
+ # Create group with this selection list
+ Group_1 = theModel.addGroup(thePartDoc, selectionList)
+ theModel.end()
+
+ # Now you can check that all selected shapes in group have right shape type and name.
+ groupFeature = Group_1.feature()
+ groupSelectionList = groupFeature.selectionList("group_list")
+ assert(groupSelectionList.size() == len(selectionList))
+ for index in range(0, groupSelectionList.size()):
+ attrSelection = groupSelectionList.value(index)
+ shape = attrSelection.value()
+ name = attrSelection.namingName()
+ assert(shape.isFace())
+ assert(name != ""), "String empty"
+
+def testHaveNamingEdges(theFeature, theModel, thePartDoc) :
+ """ Tests if all edges of result have a name
+ :param theFeature: feature to test.
+ """
+ # Get feature result/sub-result
+ aResult = theFeature.results()[0].resultSubShapePair()[0]
+ # Get result/sub-result shape
+ shape = aResult.shape()
+ # Create shape explorer with desired shape type
+ shapeExplorer = GeomAPI_ShapeExplorer(shape, GeomAPI_Shape.EDGE)
+ # Create list, and store selections in it
+ selectionList = []
+ while shapeExplorer.more():
+ selection = theModel.selection(aResult, shapeExplorer.current()) # First argument should be result/sub-result, second is sub-shape on this result/sub-result
+ selectionList.append(selection)
+ shapeExplorer.next()
+ # Create group with this selection list
+ Group_1 = theModel.addGroup(thePartDoc, selectionList)
+ theModel.do()
+ theModel.end()
+
+ # Now you can check that all selected shapes in group have right shape type and name.
+ groupFeature = Group_1.feature()
+ groupSelectionList = groupFeature.selectionList("group_list")
+ theModel.end()
+ assert(groupSelectionList.size() == len(selectionList))
+ for index in range(0, groupSelectionList.size()):
+ attrSelection = groupSelectionList.value(index)
+ shape = attrSelection.value()
+ name = attrSelection.namingName()
+ assert(shape.isEdge())
+ assert(name != ""), "String empty"
+
+def lowerLevelSubResults(theResult, theList):
+ """ Collects in a list all lover level sub-results (without children).
+ Auxiliary method for context correct definition.
+ """
+ nbSubs = theResult.numberOfSubs()
+ if nbSubs == 0:
+ theList.append(theResult)
+ else:
+ for sub in range(0, nbSubs):
+ lowerLevelSubResults(theResult.subResult(sub), theList)
+
+def testHaveNamingByType(theFeature, theModel, thePartDoc, theSubshapeType) :
+ """ Tests if all sub-shapes of result have a unique name
+ :param theFeature: feature to test.
+ :param theSubshapeType: type of sub-shape
+ """
+ if not theFeature.results():
+ return
+ aFirstRes = theFeature.results()[0]
+ aResList = []
+ lowerLevelSubResults(aFirstRes, aResList)
+
+ selectionList = []
+ shapesList = [] # to append only unique shapes (not isSame)
+ for aR in aResList:
+ # Get feature result/sub-result
+ aResult = aR.resultSubShapePair()[0]
+ # Get result/sub-result shape
+ shape = aResult.shape()
+ # Create shape explorer with desired shape type
+ shapeExplorer = GeomAPI_ShapeExplorer(shape, theSubshapeType)
+ # Create list, and store selections in it
+ while shapeExplorer.more():
+ current = shapeExplorer.current()
+ if current.isEdge() and GeomAPI.GeomAPI_Edge(current).isDegenerated(): # skip degenerative edges because they are not selected
+ shapeExplorer.next()
+ continue
+ aDuplicate = False
+ for alreadyThere in shapesList:
+ if alreadyThere.isSame(current):
+ aDuplicate = True
+ if aDuplicate:
+ shapeExplorer.next()
+ continue
+ shapesList.append(current)
+ selection = theModel.selection(aResult, current) # First argument should be result/sub-result, second is sub-shape on this result/sub-result
+ selectionList.append(selection)
+ shapeExplorer.next()
+ # Create group with this selection list
+ # (do not create group if nothing is selected)
+ if (len(selectionList) == 0):
+ return
+ Group_1 = theModel.addGroup(thePartDoc, selectionList)
+ theModel.do()
+
+ groupSelectionList = Group_1.feature().selectionList("group_list")
+ assert(groupSelectionList.size() == len(selectionList))
+
+ # Check that all selected shapes in group have right shape type and unique name.
+ checkGroup(Group_1, theSubshapeType)
+
+def testHaveNamingSubshapes(theFeature, theModel, thePartDoc) :
+ """ Tests if all vertices/edges/faces of result have a unique name
+ :param theFeature: feature to test.
+ """
+ assert(len(theFeature.results()) > 0)
+ testHaveNamingByType(theFeature, theModel, thePartDoc, GeomAPI_Shape.VERTEX)
+ testHaveNamingByType(theFeature, theModel, thePartDoc, GeomAPI_Shape.EDGE)
+ testHaveNamingByType(theFeature, theModel, thePartDoc, GeomAPI_Shape.FACE)
+
+def testNbSubFeatures(theComposite, theKindOfSub, theExpectedCount):
+ """ Tests number of sub-features of the given type
+ :param theComposite composite feature to check its subs
+ :param theKindOfSub kind of sub-feature to calculate count
+ :param theExpectedCount expected number of sub-features
+ """
+ count = 0
+ for aSub in theComposite.features().list():
+ aFeature = ModelAPI_Feature.feature(aSub)
+ if aFeature is not None and aFeature.getKind() == theKindOfSub:
+ count += 1
+ assert (count == theExpectedCount), "Number of sub-features of type {}: {}, expected {}".format(theKindOfSub, count, theExpectedCount)
+
+def assertSketchArc(theArcFeature):
+ """ Tests whether the arc is correctly defined
+ """
+ aCenterPnt = geomDataAPI_Point2D(theArcFeature.attribute("center_point"))
+ aStartPnt = geomDataAPI_Point2D(theArcFeature.attribute("start_point"))
+ aEndPnt = geomDataAPI_Point2D(theArcFeature.attribute("end_point"))
+ aRadius = theArcFeature.real("radius")
+ aDistCS = sketcher.tools.distancePointPoint(aCenterPnt, aStartPnt)
+ aDistCE = sketcher.tools.distancePointPoint(aCenterPnt, aEndPnt)
+ assert math.fabs(aDistCS - aDistCE) < TOLERANCE, "Wrong arc: center-start distance {}, center-end distance {}".format(aDistCS, aDistCE)
+ assert math.fabs(aRadius.value() -aDistCS) < TOLERANCE, "Wrong arc: radius is {0}, expected {1}".format(aRadius.value(), aDistCS)
+
+def checkResult(theFeature,theModel,NbRes,NbSubRes,NbSolid,NbFace,NbEdge,NbVertex):
+ """ Tests numbers of sub-shapes in results
+ """
+ theModel.testNbResults(theFeature, NbRes)
+ theModel.testNbSubResults(theFeature, NbSubRes)
+ theModel.testNbSubShapes(theFeature, GeomAPI_Shape.SOLID, NbSolid)
+ theModel.testNbSubShapes(theFeature, GeomAPI_Shape.FACE, NbFace)
+ theModel.testNbSubShapes(theFeature, GeomAPI_Shape.EDGE, NbEdge)
+ theModel.testNbSubShapes(theFeature, GeomAPI_Shape.VERTEX, NbVertex)
+
+def checkGroup(theGroup, theShapeType):
+ """ Check that all selected shapes in group have correct shape type and unique name
+ """
+ groupFeature = theGroup.feature()
+ groupSelectionList = groupFeature.selectionList("group_list")
+ presented_names = set()
+ for index in range(0, groupSelectionList.size()):
+ attrSelection = groupSelectionList.value(index)
+ shape = attrSelection.value()
+ name = attrSelection.namingName()
+ if theShapeType == GeomAPI_Shape.VERTEX:
+ assert(shape.isVertex())
+ elif theShapeType == GeomAPI_Shape.EDGE:
+ assert(shape.isEdge())
+ elif theShapeType == GeomAPI_Shape.FACE:
+ assert(shape.isFace())
+ assert(name != ""), "String empty"
+ presented_names.add(name)
+ assert(len(presented_names) == groupSelectionList.size()), "Some names are not unique"
+
+def createSubShape(thePartDoc, theModel, theSelection):
+ """ Create feature according to the type of the given subshape
+ """
+ if theSelection.shapeType() == "VERTEX":
+ return theModel.addVertex(thePartDoc, [theSelection])
+ elif theSelection.shapeType() == "EDGE":
+ return theModel.addEdge(thePartDoc, [theSelection])
+ elif theSelection.shapeType() == "FACE":
+ return theModel.addFace(thePartDoc, [theSelection])
+
+def checkFilter(thePartDoc, theModel, theFilter, theShapesList):
+ """ Check filter's work on specified shape.
+ Shapes given as a dictionary of selection and expected result.
+ """
+ aFiltersFactory = ModelAPI_Session.get().filters()
+ for sel, res in theShapesList.items():
+ needUndo = False
+ shapeName = ""
+ shapeType = "UNKNOWN"
+ if sel.variantType() == ModelHighAPI_Selection.VT_ResultSubShapePair:
+ parent = sel.resultSubShapePair()[0]
+ shape = sel.resultSubShapePair()[1]
+ if shape.isNull():
+ shape = sel.resultSubShapePair()[0].shape()
+ shapeName = sel.name()
+ shapeType = shape.shapeTypeStr()
+ else:
+ needUndo = True
+ theModel.begin()
+ subShapeFeature = createSubShape(thePartDoc, theModel, sel)
+ theModel.end()
+ parent = subShapeFeature.results()[0].resultSubShapePair()[0]
+ shape = subShapeFeature.results()[0].resultSubShapePair()[0].shape()
+ shapeType = sel.typeSubShapeNamePair()[0]
+ shapeName = sel.typeSubShapeNamePair()[1]
+ assert aFiltersFactory.isValid(theFilter.feature(), parent, shape) == res, "Filter result for {} \"{}\" incorrect. Expected {}.".format(shapeType, shapeName, res)
+ if needUndo:
+ theModel.undo()
+
+def checkFeaturesValidity(thePartDoc):
+ """ Check that the features are not in error
+ """
+ aFactory = ModelAPI_Session.get().validators()
+
+ nbFeatures = thePartDoc.size("Features")
+
+ assert nbFeatures>0, "No features found in part doc"
+
+ for i in range(nbFeatures):
+ partObject = thePartDoc.object("Features", i)
+ # Check the data
+ partObjectData = partObject.data()
+ name = partObjectData.name()
+ error = partObjectData.error()
+ # raise the error message if there is one
+ assert error == '', "The feature data {0} is in error: {1}".format(name, error)
+ # raise an error if the the feature is not valid (without error message)
+ assert partObject.data().isValid(), "The feature data {0} is in error.".format(name)
+ # Same checks for the feature itself
+ feature = objectToFeature(partObject)
+ if feature is None:
+ # Folders are not real features
+ continue
+ # raise the error message if there is one
+ assert error == '', "The feature {0} is in error: {1}".format(name, error)
+ # raise an error if the the feature is not valid (without error message)
+ assert aFactory.validate(feature), "The feature {0} is in error.".format(name)