def __drawEllipseForDiagonalInheritanceLines(self, diagram: ImageDiagram):

        # imgDraw: ImageDraw = diagram._imgDraw

        eDef: EllipseDefinition = EllipseDefinition()
        pos: Position = Position(ELLIPSE_X, ELLIPSE_Y)
        size: Size = Size(width=ELLIPSE_WIDTH, height=ELLIPSE_HEIGHT)

        eDef.position = pos
        eDef.size = size
        diagram.drawEllipse(eDef)
        diagram.drawRectangle(eDef)
    def testBasicMethod(self):

        baseName: str = f'{TestConstants.TEST_FILE_NAME}-BasicMethod'
        fileName: str = f'{baseName}.{ImageFormat.PNG.value}'

        diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}')

        position: Position = Position(107, 30)
        size: Size = Size(width=266, height=100)

        car: ClassDefinition = ClassDefinition(name='Car',
                                               position=position,
                                               size=size)

        initMethodDef: MethodDefinition = MethodDefinition(
            name='__init__', visibility=DefinitionType.Public)

        initParam: ParameterDefinition = ParameterDefinition(
            name='make', parameterType='str', defaultValue='')
        initMethodDef.parameters = [initParam]
        car.methods = [initMethodDef]

        diagram.drawClass(car)
        diagram.write()

        self._assertIdenticalFiles(
            baseName=baseName,
            generatedFileName=fileName,
            failMessage='Basic Method image file should be identical')
    def testMethodParametersDisplay(self):

        toClassDefinition: ToClassDefinition = self._buildDisplayMethodParametersTest(
        )

        baseName: str = f'{TestConstants.TEST_FILE_NAME}-MethodParametersDisplay'
        fileName: str = f'{baseName}.{ImageFormat.PNG.value}'

        diagram: ImageDiagram = ImageDiagram(fileName=fileName)

        classDefinitions: ClassDefinitions = toClassDefinition.classDefinitions
        for testClass in classDefinitions:
            diagram.drawClass(classDefinition=testClass)

        testLineDefinitions: UmlLineDefinitions = toClassDefinition.umlLineDefinitions

        for testLine in testLineDefinitions:
            diagram.drawUmlLine(testLine)

        diagram.write()

        self._assertIdenticalFiles(
            baseName=baseName,
            generatedFileName=fileName,
            failMessage='MethodParametersDisplay image file should be identical'
        )
    def testBasicFields(self):

        baseName: str = f'{TestConstants.TEST_FILE_NAME}-BasicFields'
        fileName: str = f'{baseName}.{ImageFormat.PNG.value}'

        diagram: ImageDiagram = ImageDiagram(fileName=fileName)
        fieldsTestClass: ClassDefinition = ClassDefinition(
            name='FieldsTestClass',
            position=Position(226, 102),
            size=Size(height=156, width=230))

        fieldsTestClass.fields = self._buildFields()

        initMethodDef: MethodDefinition = MethodDefinition(
            name='__init__', visibility=DefinitionType.Public)

        fieldsTestClass.methods = [initMethodDef]

        diagram.drawClass(classDefinition=fieldsTestClass)
        diagram.write()

        self._assertIdenticalFiles(
            baseName=baseName,
            generatedFileName=fileName,
            failMessage='Basic Fields image file should be identical')
    def __init__(self, imageOptions: ImageOptions, dpi: int = 0, pyutVersion: str = '', pluginVersion: str = ''):
        """

        Args:
            imageOptions: Lots of information on how to draw the diagram

            dpi:  Dots per inch;  Only used in PDF generation;  Image generation is in pixels

            pyutVersion:  Information for header

            pluginVersion:  Information for header
        """

        self.logger:              Logger             = getLogger(__name__)
        self._classDefinitions:   ClassDefinitions   = []
        self._umlLineDefinitions: UmlLineDefinitions = []

        today: str = strftime("%d %b %Y %H:%M:%S", localtime())
        headerText: str = f'Pyut Version {pyutVersion} Plugin Version {pluginVersion} - {today}'

        fqFileName:  str         = imageOptions.outputFileName
        imageFormat: ImageFormat = imageOptions.imageFormat
        if imageFormat == ImageFormat.PDF:
            self._diagram: PdfDiagram = PdfDiagram(fileName=fqFileName, dpi=dpi, headerText=headerText)
        else:
            self._diagram: ImageDiagram = ImageDiagram(fileName=fqFileName,
                                                       headerText=headerText   # TODO use image size from new method signature
                                                       )
    def testSophisticatedLayout(self):

        baseName: str = f'{TestConstants.TEST_FILE_NAME}-SophisticatedLayout'
        fileName: str = f'{baseName}.{ImageFormat.PNG.value}'

        diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}')

        classDefinitions: ClassDefinitions = [
            self._buildCar(),
            self._buildCat(),
            self._buildOpie(),
            self._buildNameTestCase(),
            self._buildElectricCar()
        ]
        for classDefinition in classDefinitions:
            classDefinition = cast(ClassDefinition, classDefinition)
            diagram.drawClass(classDefinition=classDefinition)

        lineDefinitions: UmlLineDefinitions = self._buildSophisticatedLineDefinitions(
        )
        for lineDefinition in lineDefinitions:
            diagram.drawUmlLine(lineDefinition=lineDefinition)

        diagram.write()

        self._assertIdenticalFiles(
            baseName=baseName,
            generatedFileName=fileName,
            failMessage='Sophisticated Layout image file should be identical')
    def testFillPage(self):

        baseName: str = f'{TestConstants.TEST_FILE_NAME}-FillPage'
        fileName: str = f'{baseName}.{ImageFormat.PNG.value}'

        diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}')

        widthInterval: int = TestImageDiagram.CELL_WIDTH // 10
        heightInterval: int = TestImageDiagram.CELL_HEIGHT // 10

        for x in range(0, TestImageDiagram.TEST_LAST_X_POSITION):
            scrX: int = (x * TestImageDiagram.CELL_WIDTH) + (widthInterval * x)

            for y in range(0, TestImageDiagram.TEST_LAST_Y_POSITION):

                scrY: int = (y * TestImageDiagram.CELL_HEIGHT) + (
                    y * heightInterval)
                classDef: ClassDefinition = ClassDefinition(
                    name=f'{TestImageDiagram.BASE_TEST_CLASS_NAME}{x}{y}',
                    position=Position(scrX, scrY),
                    size=Size(width=TestImageDiagram.CELL_WIDTH,
                              height=TestImageDiagram.CELL_HEIGHT))
                diagram.drawClass(classDef)

        diagram.write()

        self._assertIdenticalFiles(
            baseName=baseName,
            generatedFileName=fileName,
            failMessage='Fill Page image file should be identical')
    def testMinimalInheritance(self):

        baseName: str = f'{TestConstants.TEST_FILE_NAME}-MinimalInheritance'
        fileName: str = f'{baseName}.{ImageFormat.PNG.value}'

        diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}')

        cat: ClassDefinition = ClassDefinition(name='Gato',
                                               position=Position(536, 19),
                                               size=Size(height=74, width=113))
        opie: ClassDefinition = ClassDefinition(name='Opie',
                                                position=Position(495, 208),
                                                size=Size(width=216,
                                                          height=87))

        diagram.drawClass(classDefinition=cat)
        diagram.drawClass(classDefinition=opie)

        startPosition: Position = Position(600, 208)
        endPosition: Position = Position(600, 93)
        linePositions: LinePositions = [startPosition, endPosition]

        opieToCat: UmlLineDefinition = UmlLineDefinition(
            lineType=LineType.Inheritance, linePositions=linePositions)

        diagram.drawUmlLine(lineDefinition=opieToCat)
        diagram.write()

        self._assertIdenticalFiles(
            baseName=baseName,
            generatedFileName=fileName,
            failMessage='Minimal Inheritance image file should be identical')
    def testBends(self):

        baseName: str = f'{TestConstants.TEST_FILE_NAME}-Bends'
        fileName: str = f'{baseName}.{ImageFormat.PNG.value}'

        diagram: ImageDiagram = ImageDiagram(fileName=fileName)

        top: ClassDefinition = self._buildTopClass()
        left: ClassDefinition = self._buildLeftClass()
        right: ClassDefinition = self._buildRightClass()

        bentClasses: List[ClassDefinition] = [top, left, right]
        for bentClass in bentClasses:
            diagram.drawClass(classDefinition=bentClass)

        bentLineDefinitions: UmlLineDefinitions = self._buildBendTest()

        for bentLine in bentLineDefinitions:
            diagram.drawUmlLine(bentLine)

        diagram.write()

        self._assertIdenticalFiles(
            baseName=baseName,
            generatedFileName=fileName,
            failMessage='Bends image file should be identical')
    def testAddSuffixEmbeddedDotsNot(self):
        diagram: ImageDiagram = ImageDiagram(
            fileName=TestImageDiagram.DOTTED_EXPECTED_NAME)

        adjustedName: str = diagram._addSuffix(
            fileName=TestImageDiagram.DOTTED_EXPECTED_NAME,
            suffix=TestImageDiagram.EXPECTED_SUFFIX)

        self.assertEqual(TestImageDiagram.DOTTED_EXPECTED_NAME, adjustedName,
                         'Suffix incorrectly added for embedded periods')
    def testAddSuffix(self):

        diagram: ImageDiagram = ImageDiagram(fileName='/user/hasii/bogus')

        adjustedName: str = diagram._addSuffix(
            fileName=TestImageDiagram.UNADJUSTED_NAME,
            suffix=TestImageDiagram.EXPECTED_SUFFIX)

        self.assertEqual(TestImageDiagram.EXPECTED_NAME, adjustedName,
                         'Suffix not added correctly')
    def testAddSuffixEmbeddedDots(self):

        diagram: ImageDiagram = ImageDiagram(
            fileName=TestImageDiagram.DOTTED_UNADJUSTED_NAME)

        adjustedName: str = diagram._addSuffix(
            fileName=TestImageDiagram.DOTTED_UNADJUSTED_NAME,
            suffix=TestImageDiagram.EXPECTED_SUFFIX)

        self.assertEqual(TestImageDiagram.DOTTED_EXPECTED_NAME, adjustedName,
                         'Suffix with embedded periods not added correctly')
    def testAddSuffixNot(self):

        diagram: ImageDiagram = ImageDiagram(
            fileName=TestImageDiagram.EXPECTED_NAME)

        adjustedName: str = diagram._addSuffix(
            fileName=TestImageDiagram.EXPECTED_NAME,
            suffix=TestImageDiagram.EXPECTED_SUFFIX)

        self.assertEqual(TestImageDiagram.EXPECTED_NAME, adjustedName,
                         'Suffix incorrectly added')
    def testBasicMethods(self):

        baseName: str = f'{TestConstants.TEST_FILE_NAME}-BasicMethods'
        fileName: str = f'{baseName}.{ImageFormat.PNG.value}'

        diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}')

        classDef: ClassDefinition = self._buildCar()

        diagram.drawClass(classDef)
        diagram.write()

        self._assertIdenticalFiles(
            baseName=baseName,
            generatedFileName=fileName,
            failMessage='Basic Methods image file should be identical')
    def testBasicHeader(self):

        baseName: str = f'{TestConstants.TEST_FILE_NAME}-BasicHeader'
        fileName: str = f'{baseName}.{ImageFormat.PNG.value}'

        diagram: ImageDiagram = ImageDiagram(
            fileName=f'{fileName}',
            headerText=TestDiagramParent.UNIT_TEST_HEADER)
        classDef: ClassDefinition = self._buildCar()

        diagram.drawClass(classDef)
        diagram.write()

        self._assertIdenticalFiles(
            baseName=baseName,
            generatedFileName=fileName,
            failMessage='Basic Header image file should be identical')
    def testBasic(self):

        baseName: str = f'{TestConstants.TEST_FILE_NAME}-Basic'
        fileName: str = f'{baseName}.{ImageFormat.PNG.value}'

        diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}')
        classDef: ClassDefinition = ClassDefinition(
            name=TestDiagramParent.BASE_TEST_CLASS_NAME,
            size=Size(width=266, height=100),
            position=Position(x=107, y=30))

        diagram.drawClass(classDef)
        diagram.write()

        self._assertIdenticalFiles(
            baseName=baseName,
            generatedFileName=fileName,
            failMessage='Basic image file should be identical')
    def testBigClass(self):

        toClassDefinition: ToClassDefinition = self._buildBigClassFromXml()

        baseName: str = f'{TestConstants.TEST_FILE_NAME}-BigClass'
        fileName: str = f'{baseName}.{ImageFormat.PNG.value}'

        diagram: ImageDiagram = ImageDiagram(fileName=fileName)
        classDefinitions: ClassDefinitions = toClassDefinition.classDefinitions
        for bigClass in classDefinitions:
            diagram.drawClass(classDefinition=bigClass)

        diagram.write()

        self._assertIdenticalFiles(
            baseName=baseName,
            generatedFileName=fileName,
            failMessage='Big Class image file should be identical')
    def testOrthogonalInheritanceLines(self):
        diagram: ImageDiagram = ImageDiagram(
            fileName=
            f'{TestConstants.TEST_FILE_NAME}-OrthogonalInheritanceLines.{ImageFormat.PNG.value}'
        )

        self._drawHorizontalBoundaries(diagram)
        self._drawVerticalBoundaries(diagram)

        lineDrawer: ImageLine = ImageLine(
            docWriter=diagram._imgDraw, diagramPadding=diagram._diagramPadding)

        north, south, east, west = self._createOrthogonalLines(
            LineType.Inheritance)
        lineDefinitions: UmlLineDefinitions = [north, south, east, west]
        for lineDefinition in lineDefinitions:
            lineDrawer.draw(lineDefinition)

        diagram.write()
    def testDiagonalAggregationLines(self):

        diagram: ImageDiagram = ImageDiagram(
            fileName=
            f'{TestConstants.TEST_FILE_NAME}-DiagonalAggregationLines.{ImageFormat.PNG.value}'
        )
        self.__drawEllipseForDiagonalInheritanceLines(diagram)

        lineDrawer: ImageLine = ImageLine(
            docWriter=diagram._imgDraw, diagramPadding=diagram._diagramPadding)

        northEast, northWest, southEast, southWest = self.__createDiagonalLines(
            LineType.Aggregation)
        definitions: UmlLineDefinitions = [
            northEast, northWest, southEast, southWest
        ]
        for definition in definitions:
            lineDrawer.draw(definition)
        diagram.write()
    def testSophisticatedHeader(self):

        today: str = strftime("%d %b %Y %H:%M:%S",
                              self.unitTestTimeStamp.timetuple())
        headerText: str = f'{TestDiagramParent.UNIT_TEST_SOPHISTICATED_HEADER} - {today}'

        baseName: str = f'{TestConstants.TEST_FILE_NAME}-SophisticatedHeader'
        fileName: str = f'{baseName}.{ImageFormat.PNG.value}'

        diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}',
                                             headerText=headerText)
        classDef: ClassDefinition = self._buildCar()

        diagram.drawClass(classDef)

        diagram.write()

        self._assertIdenticalFiles(
            baseName=baseName,
            generatedFileName=fileName,
            failMessage='Sophisticated Header image file should be identical')
    def testBendsFromXmlInput(self):

        toClassDefinition: ToClassDefinition = self._buildBendTestFromXml()

        baseName: str = f'{TestConstants.TEST_FILE_NAME}-BendsFromXmlInput'
        fileName: str = f'{baseName}.{ImageFormat.PNG.value}'

        diagram: ImageDiagram = ImageDiagram(fileName=fileName)

        classDefinitions: ClassDefinitions = toClassDefinition.classDefinitions
        for bentClass in classDefinitions:
            diagram.drawClass(classDefinition=bentClass)

        bentLineDefinitions: UmlLineDefinitions = toClassDefinition.umlLineDefinitions

        for bentLine in bentLineDefinitions:
            diagram.drawUmlLine(bentLine)

        diagram.write()

        self._assertIdenticalFiles(
            baseName=baseName,
            generatedFileName=fileName,
            failMessage='BendsFromXmlInput image file should be identical')
Exemple #22
0
class OglToPyUmlDefinition:

    INHERITANCE_DESTINATION_POSITION_NUDGE_FACTOR: int = 1

    def __init__(self,
                 imageOptions: ImageOptions,
                 dpi: int = 0,
                 pyutVersion: str = '',
                 pluginVersion: str = ''):
        """

        Args:
            imageOptions: Lots of information on how to draw the diagram

            dpi:  Dots per inch;  Only used in PDF generation;  Image generation is in pixels

            pyutVersion:  Information for header

            pluginVersion:  Information for header
        """

        self.logger: Logger = getLogger(__name__)
        self._classDefinitions: ClassDefinitions = []
        self._umlLineDefinitions: UmlLineDefinitions = []
        self._prefs: PyutPreferences = PyutPreferences()

        today: str = strftime("%d %b %Y %H:%M:%S", localtime())
        headerText: str = f'Pyut Version {pyutVersion} Plugin Version {pluginVersion} - {today}'

        fqFileName: str = imageOptions.outputFileName
        imageFormat: ImageFormat = imageOptions.imageFormat
        imageLibShowParameters: DisplayMethodParameters = self.__toImageLibraryEnum(
            self._prefs.showParameters)
        if imageFormat == ImageFormat.PDF:
            self._diagram: BaseDiagram = PdfDiagram(
                fileName=fqFileName,
                dpi=dpi,
                headerText=headerText,
                docDisplayMethodParameters=imageLibShowParameters)
        else:
            self._diagram = ImageDiagram(
                fileName=fqFileName, headerText=headerText
            )  # TODO use image size from new method signature)

    def toClassDefinitions(self, oglObjects: List[OglClass]):

        classDefinitions: ClassDefinitions = []

        for oglObject in oglObjects:

            umlObject: OglClass = cast(OglClass, oglObject)
            if not isinstance(umlObject, OglClass):
                continue

            pyutClass: PyutClass = cast(PyutClass, umlObject.pyutObject)

            x, y = umlObject.GetPosition()
            w, h = umlObject.GetSize()
            position: Position = Position(x=x, y=y)
            size: Size = Size(width=int(w), height=int(h))

            classDefinition: ClassDefinition = ClassDefinition(
                name=pyutClass.name, position=position, size=size)

            if pyutClass.displayParameters is True:
                classDefinition.displayMethodParameters = DisplayMethodParameters.DISPLAY
            else:
                classDefinition.displayMethodParameters = DisplayMethodParameters.DO_NOT_DISPLAY

            classDefinition = self.__addClassDiagramDisplayPreferences(
                pyutClass=pyutClass, classDefinition=classDefinition)

            self._addMethods(classDefinition=classDefinition,
                             pyutClass=pyutClass)
            self._diagram.drawClass(classDefinition=classDefinition)
            classDefinitions.append(classDefinition)

        self._classDefinitions = classDefinitions

    def layoutLines(self, oglObjects: List[OglClass]):

        umlLineDefinitions: UmlLineDefinitions = []

        for umlObject in oglObjects:

            if not isinstance(umlObject, OglLink):
                continue
            oglLink: OglLink = cast(OglLink, umlObject)

            pyutLink: PyutLink = oglLink.getPyutObject()
            umlLinkType: LinkType = pyutLink.linkType
            lineType: LineType = self._toPyUmlLineType(umlLinkType)

            linePositions: LinePositions = self._toPyUmlPositions(
                oglLink, umlLinkType)
            self.logger.debug(f'{lineType=} {linePositions=}')

            line: UmlLineDefinition = UmlLineDefinition(
                lineType=lineType, linePositions=linePositions)

            self._diagram.drawUmlLine(lineDefinition=line)
            umlLineDefinitions.append(line)

        self._umlLineDefinitions = umlLineDefinitions

    def write(self):
        self._diagram.write()

    def _toPyUmlLineType(self, umlLinkType) -> LineType:

        if umlLinkType == LinkType.INHERITANCE:
            lineType: LineType = LineType.Inheritance
        elif umlLinkType == LinkType.COMPOSITION:
            lineType = LineType.Composition
        elif umlLinkType == LinkType.AGGREGATION:
            lineType = LineType.Aggregation
        else:
            lineType = LineType.Association  # This won't happen yet

        return lineType

    def _toPyUmlPositions(self, oglLink,
                          pyutLinkType: LinkType) -> LinePositions:

        if pyutLinkType == LinkType.INHERITANCE:
            srcAnchor: AnchorPoint = oglLink.sourceAnchor
            destAnchor: AnchorPoint = oglLink.destinationAnchor
        else:
            srcAnchor = oglLink.destinationAnchor
            destAnchor = oglLink.sourceAnchor

        srcX, srcY = srcAnchor.GetPosition()
        destX, destY = destAnchor.GetPosition()

        sourcePosition: Position = Position(x=srcX, y=srcY)
        destinationPosition: Position = Position(x=destX, y=destY)

        bends: List[ControlPoint] = oglLink.GetControlPoints()
        if bends is None or len(bends) == 0:
            linePositions: LinePositions = [
                sourcePosition, destinationPosition
            ]
        else:
            linePositions = [sourcePosition]
            for cp in bends:
                bend: ControlPoint = cast(ControlPoint, cp)
                self.logger.debug(f'{bend:}')

                bendX, bendY = bend.GetPosition()
                bendPosition: Position = Position(x=bendX, y=bendY)
                linePositions.append(bendPosition)

            linePositions.append(destinationPosition)

        return linePositions

    def _addMethods(self, classDefinition: ClassDefinition,
                    pyutClass: PyutClass) -> ClassDefinition:

        methods: Methods = []
        for method in pyutClass.methods:

            pyutMethod: PyutMethod = cast(PyutMethod, method)

            methodDef: MethodDefinition = MethodDefinition(
                name=pyutMethod.name)

            methodDef.visibility = self.__toDefinitionType(
                pyutMethod.visibility)
            methodDef.returnType = pyutMethod.returnType.value

            self.__addParameters(methodDefinition=methodDef,
                                 pyutMethod=pyutMethod)
            methods.append(methodDef)

        classDefinition.methods = methods
        return classDefinition

    def __addParameters(self, methodDefinition: MethodDefinition,
                        pyutMethod: PyutMethod) -> MethodDefinition:

        parameters: Parameters = []
        for parameter in pyutMethod.parameters:

            paramDef: ParameterDefinition = ParameterDefinition(
                name=parameter.name)
            paramDef.parameterType = parameter.type.value
            paramDef.defaultValue = parameter.defaultValue

            parameters.append(paramDef)

        methodDefinition.parameters = parameters
        self.logger.debug(f'{methodDefinition.name=}  {parameters=}')
        return methodDefinition

    def __toDefinitionType(self,
                           visibility: PyutVisibilityEnum) -> DefinitionType:

        if visibility == PyutVisibilityEnum.PUBLIC:
            return DefinitionType.Public

    def __addClassDiagramDisplayPreferences(
            self, pyutClass: PyutClass,
            classDefinition: ClassDefinition) -> ClassDefinition:

        classDefinition.displayMethods = pyutClass.showMethods
        classDefinition.displayFields = pyutClass.showFields

        return classDefinition

    def __toImageLibraryEnum(self,
                             showParameters: bool) -> DisplayMethodParameters:

        if showParameters is True:
            return DisplayMethodParameters.DISPLAY
        else:
            return DisplayMethodParameters.DO_NOT_DISPLAY