Skip to content

Commit

Permalink
ADD writer_tests.py: unit tests for writer.py
Browse files Browse the repository at this point in the history
Currently 11 tests are present.
  • Loading branch information
podestplatz committed Jun 12, 2019
1 parent 4de5078 commit 72a63ff
Show file tree
Hide file tree
Showing 21 changed files with 932 additions and 26 deletions.
16 changes: 13 additions & 3 deletions src/bcf/markup.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,9 @@ def file(self, newVal):
raise ValueError("File only supports the types 'str' and 'Uri'."\
" Erroneous type is: {}".format(type(newVal)))


@property
def snapshot(self):
return self._snapshot
return self._snapshot.value

@snapshot.setter
def snapshot(self, newVal):
Expand All @@ -250,6 +249,8 @@ def viewpoint(self):
def viewpoint(self, newVal):
if isinstance(newVal, Viewpoint):
self._viewpoint = newVal
elif newVal is None:
self._viewpoint = None
else:
raise ValueError("The new value has to be of type `Viewpoint`."\
" Erroneous type: {}".format(type(newVal)))
Expand Down Expand Up @@ -352,7 +353,7 @@ def __init__(self,
self.creation = creation
self._comment = SimpleElement(comment, "Comment", self)
self.viewpoint = viewpoint
self.lastModification = lastModification
self._lastModification = lastModification


@property
Expand All @@ -363,6 +364,15 @@ def comment(self):
def comment(self, newVal):
self._comment.value = newVal

@property
def lastModification(self):
return self._lastModification

@lastModification.setter
def lastModification(self, newVal):
self._lastModification = newVal
self._lastModification.containingObject = self


def __eq__(self, other):

Expand Down
67 changes: 63 additions & 4 deletions src/bcf/modification.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,70 @@
from enum import Enum
from datetime import datetime
from interfaces.hierarchy import Hierarchy
from interfaces.state import State

import bcf.project as p


class ModificationType(Enum):
CREATION = 1
MODIFICATION = 2

class Modification(Hierarchy, State):

"""
This class is used by Topic and Comment to for one denote the author
and date of the last change and the creator and the creation date of an
object of one of the respective classes
object of one of the respective classes.
If it shall be written by the writer module then just supply it with
self._author or self._date, not the object of Modification itself
"""

def __init__(self,
author: str,
date: datetime,
containingElement = None,
state: State.States = State.States.ORIGINAL):
state: State.States = State.States.ORIGINAL,
modType: ModificationType = ModificationType.CREATION):

""" Initialisation function for Modification """

State.__init__(self, state)
Hierarchy.__init__(self, containingElement)
self.author = author
self.date = date
if modType == ModificationType.CREATION:
self._author = p.SimpleElement(author, "Author", self)
self._date = p.SimpleElement(date, "Date", self)
else:
self._author = p.SimpleElement(author, "ModifiedAuthor", self)
self._date = p.SimpleElement(date, "ModifiedDate", self)

# hacky way of pretending that author and date inherit XMLName
# completely.
self._author.getEtElement = self.getEtElementAuthor
self._date.getEtElement = self.getEtElementDate


@property
def author(self):
return self._author.value

@author.setter
def author(self, newVal):
if not isinstance(newVal, str):
raise ValueError("The value of author must be a string!")
else:
self._author.value = newVal

@property
def date(self):
return self._date.value

@date.setter
def date(self, newValue):
if not isinstance(newValue, datetime):
raise ValueError("The value of date has to be datetime!")
else:
self._date.value = newVal


def __eq__(self, other):
Expand All @@ -38,3 +81,19 @@ def __str__(self):
ret_str = "Modification(author='{}', datetime='{}')".format(self.author,
self.date)
return ret_str


def getEtElementDate(self, elem):

elem.tag = self._date.xmlName
elem.text = self.date.isoformat("T", "seconds")

return elem


def getEtElementAuthor(self, elem):

elem.tag = self._author.xmlName
elem.text = self.author

return elem
4 changes: 4 additions & 0 deletions src/bcf/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
from interfaces.identifiable import Identifiable

DEBUG = True
def debug(msg):
if DEBUG:
print(msg)


class SimpleElement(XMLName, Hierarchy, State):

Expand Down
5 changes: 3 additions & 2 deletions src/bcf/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ def buildProject(projectFilePath: str, projectSchema: str):

def buildComment(commentDict: Dict):

id = commentDict["@Guid"]
id = UUID(commentDict["@Guid"])
commentDate = dateutil.parser.parse(commentDict["Date"]) # parse ISO 8601 datetime
commentAuthor = commentDict["Author"]
creationData = Modification(commentAuthor, commentDate)
Expand Down Expand Up @@ -397,7 +397,8 @@ def buildViewpointReference(viewpointDict):
if snapshotFile:
snapshotFile = Uri(snapshotFile)

index = getOptionalFromDict(viewpointDict, "Index", 0)
# -1 denotes a missing index value
index = getOptionalFromDict(viewpointDict, "Index", -1)

vpReference = ViewpointReference(id, viewpointFile, snapshotFile, index)

Expand Down
8 changes: 4 additions & 4 deletions src/bcf/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ def getSystemTmp():

global tempDir
if tempDir is None:
#tempDir = tempfile.TemporaryDirectory()
tempDir = tempfile.mkdtemp()
tempDir = tempfile.TemporaryDirectory()
#tempDir = tempfile.mkdtemp()

#return tempDir.name
return tempDir
return tempDir.name
#return tempDir


def retrieveWebFile(schema: Schema, storePath: str):
Expand Down
33 changes: 23 additions & 10 deletions src/bcf/writer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import io # used for writing files in utf8
import sys
from uuid import UUID

if __name__ == "__main__":
sys.path.insert(0, "/home/patrick/projects/freecad/plugin/src")
Expand Down Expand Up @@ -114,8 +115,15 @@ def getUniqueIdOfListElementInHierarchy(element):
for item in elementHierarchy[1:]:
if item.__class__.__name__ in listElements:
listElement = item
p.debug("writer.{}(): {} is a list element!".format(
getUniqueIdOfListElementInHierarchy.__name__,
item))
break

if isinstance(listElement, iI.Identifiable):
p.debug("writer.{}(): its id = {} element!".format(
getUniqueIdOfListElementInHierarchy.__name__,
item.id))
return item.id
return None

Expand Down Expand Up @@ -173,9 +181,9 @@ def getTopicOfElement(element):
def getIdAttrName(elementId):

idAttrName = ""
if isinstance(listElemId, UUID):
if isinstance(elementId, UUID):
idAttrName = "Guid"
elif isinstance(listElemId, str):
elif isinstance(elementId, str):
idAttrName = "IfcGuid"

return idAttrName
Expand All @@ -197,12 +205,16 @@ def getParentElement(element, etRoot):

etParent = None
listElemId = getUniqueIdOfListElementInHierarchy(element)
p.debug("writer.{}(): got id {} for {}".format(getParentElement.__name__,
listElemId, element.__class__.__name__))
if not listElemId: # parent can be found easily by tag
etParent = etRoot.find(strHierarchy[1])
if not etParent and etRoot.tag == strHierarchy[1]:
etParent = etRoot
else:
idAttrName = getIdAttrName(listElementId)
idAttrName = getIdAttrName(listElemId)
p.debug("writer.{}(): searching elementtree for .//*[@{}='{}']".format(
getParentElement.__name__, idAttrName, listElemId))
etParent = etRoot.find(".//*[@{}='{}']".format(idAttrName,
str(listElemId)))

Expand All @@ -215,9 +227,11 @@ def getInsertionIndex(element, etParent):
etChildren = [ elem.tag for elem in list(etParent) ]
revEtChildren = list(reversed(etChildren))
highestIndex = 0
if reader.DEBUG:
print("writer.getInsertionIndex()\ndefined sequence: {}\nactual"\
" sequence: {}".format(parentSequence, etChildren))
p.debug("writer.{}()\n\tdefined sequence: {}\n\tactual"\
" sequence: {}".format(getInsertionIndex.__name__,
parentSequence, etChildren))
p.debug("writer.{}(): element is of type {}".format(
getInsertionIndex.__name__, type(element)))
for seqElem in parentSequence:
if seqElem == element.xmlName:
break
Expand Down Expand Up @@ -294,7 +308,7 @@ def xmlPrettify(element: ET.Element):

unformatted = ET.tostring(element, encoding="utf8")
domParsed = MD.parseString(unformatted)
formatted = domParsed.toprettyxml(indent="\t")
formatted = domParsed.toprettyxml(encoding="UTF-8", indent="\t").decode("utf-8")
# remove possible blank lines
prettyXML = "\n".join([ line for line in formatted.split("\n")
if line.strip() ])
Expand Down Expand Up @@ -383,9 +397,8 @@ def addElement(element):
visinfoRootEtElem = ET.Element("", {})
vp.getEtElement(visinfoRootEtElem)

if reader.DEBUG:
print("writer.addElement(): Writing new viewpoint to"\
" {}".format(element.file))
p.debug("writer.{}(): Writing new viewpoint to"\
" {}".format(addElement.__name__, element.file))

vpFilePath = os.path.join(bcfDir, str(topicDir), str(element.file))
vpXmlPrettyText = xmlPrettify(visinfoRootEtElem)
Expand Down
22 changes: 20 additions & 2 deletions src/interfaces/identifiable.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
from uuid import UUID

class Identifiable:

def __init__(self, uId = None):
self.id = uId
self._id = uId
if not id:
self.id = id(self)
self._id = id(self)

@property
def id(self):
return self._id

@id.setter
def id(self, newVal):
if isinstance(newVal, UUID):
self._id = newVal
elif isinstance(newVal, str):
try:
self._id = UUID(newVal)
except:
self._id = newVal
else:
raise ValueError("Id has to be of type UUID or string!")
2 changes: 1 addition & 1 deletion src/tests/reader-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def test_complete_topic(self):
dateutil.parser.parse("2017-10-10T14:24:31+00:00"))
expectedReferences = [
topic.DocumentReference(
id=UUID("0a36e3d6-97e9-47d6-ab4f-227990429f52"),
guid=UUID("0a36e3d6-97e9-47d6-ab4f-227990429f52"),
external=True,
reference=uri.Uri("/url/to/document"),
description="This is a description of the document") ]
Expand Down
Loading

0 comments on commit 72a63ff

Please sign in to comment.