Skip to content

Commit 547414e

Browse files
committed
Updates to testcase.py to fix a problem with testcases
1 parent 387afae commit 547414e

File tree

2 files changed

+52
-51
lines changed

2 files changed

+52
-51
lines changed

elmclient/examples/dn_simple_createfolderandartifact.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
rmcontext = 'rm'
5757

5858
# the project+compontent+config that will be updated
59-
proj = "rm_optout_p1"
59+
proj = "rm_optin_p2"
6060
comp = proj
6161
conf = f"{comp} Initial Stream"
6262

@@ -68,6 +68,7 @@
6868

6969
##################################################################################
7070
if __name__=="__main__":
71+
print( f"You provided {len(sys.argv)} arguments" )
7172
if len(sys.argv) != 5:
7273
print( 'A typical commandline might be: dn_simple_createfolderandartifact.py "Stakeholder Requirement" "My first stakefilder requirement" / newfoldername' )
7374
raise Exception( 'You must provide: The artifact type, the artifact text, and the folder path to create the artifact in - each surrounded by " if including spaces' )

elmclient/testcase.py

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,6 @@ class TestCaseLink:
1414
class TestCase:
1515
@classmethod
1616
def create_minimal(cls, title: str) -> 'TestCase':
17-
"""
18-
Create a new minimal TestCase instance with just a title.
19-
The generated XML will include only the required namespaces, type, and title.
20-
:param title: Title of the new Test Case
21-
:return: A minimal TestCase object
22-
"""
2317
namespaces = {
2418
'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
2519
'dcterms': 'http://purl.org/dc/terms/',
@@ -55,7 +49,6 @@ def create_minimal(cls, title: str) -> 'TestCase':
5549
namespaces=namespaces
5650
)
5751

58-
# Add to elements for proper serialization
5952
tc.elements.append((
6053
'{http://purl.org/dc/terms/}title',
6154
{'{http://www.w3.org/2001/XMLSchema#}datatype': 'http://www.w3.org/2001/XMLSchema#string'},
@@ -87,49 +80,28 @@ def create_minimal(cls, title: str) -> 'TestCase':
8780
links: List[TestCaseLink] = field(default_factory=list)
8881
namespaces: Dict[str, str] = field(default_factory=dict)
8982
elements: List[Tuple[str, Dict[str, str], Optional[str]]] = field(default_factory=list)
90-
91-
83+
extra_descriptions: Dict[str, List[Tuple[str, Dict[str, str], Optional[str]]]] = field(default_factory=dict)
9284

9385
def add_link(self, predicate: str, target: str, title: Optional[str] = None):
94-
"""
95-
Add a generic link to the test case.
96-
:param predicate: Predicate URI of the link
97-
:param target: Target URI of the linked resource
98-
:param title: Optional title describing the link
99-
"""
10086
self.links.append(TestCaseLink(predicate=predicate, target=target, title=title))
10187

10288
def add_validatesRequirementLink(self, target: str, title: Optional[str] = None):
103-
"""
104-
Add a validatesRequirement link to the test case and include a corresponding RDF property.
105-
:param target: The target requirement URI
106-
:param title: Optional title for the link
107-
"""
10889
self.links.append(TestCaseLink(
10990
subject=self.uri,
11091
predicate="http://open-services.net/ns/qm#validatesRequirement",
11192
target=target,
11293
title=title
11394
))
114-
# Add corresponding property to the TestCase element list
11595
tag = '{' + self.namespaces.get('oslc_qm', 'http://open-services.net/ns/qm#') + '}validatesRequirement'
11696
attrib = {'{' + self.namespaces['rdf'] + '}resource': target}
11797
self.elements.append((tag, attrib, None))
11898

11999
def delete_link(self, target: str) -> bool:
120-
"""
121-
Delete a generic link based on its target URI.
122-
:param target: The target URI to remove
123-
:return: True if a link was removed, False otherwise
124-
"""
125100
initial_length = len(self.links)
126101
self.links = [link for link in self.links if link.target != target]
127102
return len(self.links) < initial_length
128103

129104
def delete_validatesRequirementLink(self, target: str) -> bool:
130-
"""
131-
Delete validatesRequirement links matching the target URL from both the links list and the elements list.
132-
"""
133105
initial_links = len(self.links)
134106
self.links = [link for link in self.links if not (
135107
link.predicate == "http://open-services.net/ns/qm#validatesRequirement" and link.target == target)
@@ -146,22 +118,42 @@ def delete_validatesRequirementLink(self, target: str) -> bool:
146118

147119
@staticmethod
148120
def from_etree(etree: ET._ElementTree) -> 'TestCase':
149-
"""
150-
Parse a TestCase instance from an RDF XML ElementTree.
151-
:param etree: lxml.etree ElementTree representing the RDF
152-
:return: TestCase instance with parsed data
153-
"""
154121
root = etree.getroot()
155122
namespaces = {k if k is not None else '': v for k, v in root.nsmap.items()}
156123
ns = namespaces.copy()
157124

158-
main_elem = root.find(".//rdf:Description[@rdf:about]", ns)
125+
# Find all rdf:Description elements with rdf:about
126+
about_elements = root.findall(".//rdf:Description[@rdf:about]", ns)
127+
128+
# Identify the main test case element (without '#' in rdf:about)
129+
main_elem = None
130+
for elem in about_elements:
131+
uri = elem.attrib.get(f'{{{ns["rdf"]}}}about')
132+
#print(uri)
133+
if uri and 'TestCase' in uri and '#' not in uri:
134+
main_elem = elem
135+
break
136+
159137
if main_elem is None:
160-
raise ValueError("No rdf:Description with rdf:about found")
138+
raise ValueError("No main rdf:Description with rdf:about (without '#') found")
161139

162140
uri = main_elem.attrib[f'{{{ns["rdf"]}}}about']
163141
testcase = TestCase(uri=uri, namespaces=namespaces)
164142

143+
144+
145+
# def from_etree(etree: ET._ElementTree) -> 'TestCase':
146+
# root = etree.getroot()
147+
# namespaces = {k if k is not None else '': v for k, v in root.nsmap.items()}
148+
# ns = namespaces.copy()
149+
150+
# main_elem = root.find(".//rdf:Description[@rdf:about]", ns)
151+
# if main_elem is None:
152+
# raise ValueError("No rdf:Description with rdf:about found")
153+
154+
# uri = main_elem.attrib[f'{{{ns["rdf"]}}}about']
155+
# testcase = TestCase(uri=uri, namespaces=namespaces)
156+
165157
for elem in main_elem:
166158
tag = elem.tag
167159
text = elem.text.strip() if elem.text else ""
@@ -214,13 +206,21 @@ def from_etree(etree: ET._ElementTree) -> 'TestCase':
214206
title=title_elem.text if title_elem is not None else None
215207
))
216208

209+
for desc in root.findall(".//rdf:Description[@rdf:about]", ns):
210+
about = desc.attrib.get(f'{{{ns["rdf"]}}}about')
211+
if about == testcase.uri:
212+
continue
213+
elems = []
214+
for elem in desc:
215+
tag = elem.tag
216+
text = elem.text.strip() if elem.text else ""
217+
attrib = dict(elem.attrib)
218+
elems.append((tag, attrib, text))
219+
testcase.extra_descriptions[about] = elems
220+
217221
return testcase
218222

219223
def to_etree(self) -> ET._ElementTree:
220-
"""
221-
Serialize the TestCase instance to an RDF XML ElementTree.
222-
:return: lxml.etree ElementTree
223-
"""
224224
NSMAP = self.namespaces or {'rdf': "http://www.w3.org/1999/02/22-rdf-syntax-ns#"}
225225
rdf = ET.Element(ET.QName(NSMAP['rdf'], 'RDF'), nsmap=NSMAP)
226226
if self.uri!="":
@@ -230,7 +230,6 @@ def to_etree(self) -> ET._ElementTree:
230230
else:
231231
desc = ET.SubElement(rdf, ET.QName(NSMAP['rdf'], 'Description'))
232232

233-
# Emit known fields first
234233
def add(tag_ns: str, tag: str, text=None, attrib=None):
235234
el = ET.SubElement(desc, ET.QName(NSMAP[tag_ns], tag), attrib or {})
236235
if text:
@@ -273,7 +272,7 @@ def add(tag_ns: str, tag: str, text=None, attrib=None):
273272
for tag, attrib, text in self.elements:
274273
short_tag = ET.QName(tag).localname
275274
if short_tag in known_tags:
276-
continue # already added from field values
275+
continue
277276
el = ET.SubElement(desc, ET.QName(tag), {
278277
ET.QName(k) if isinstance(k, str) and ':' in k else k: v for k, v in attrib.items()
279278
})
@@ -300,17 +299,18 @@ def add(tag_ns: str, tag: str, text=None, attrib=None):
300299
if link.title:
301300
ET.SubElement(stmt, ET.QName(NSMAP['dcterms'], 'title')).text = link.title
302301

302+
for about, elems in self.extra_descriptions.items():
303+
desc = ET.SubElement(rdf, ET.QName(NSMAP['rdf'], 'Description'), {
304+
ET.QName(NSMAP['rdf'], 'about'): about
305+
})
306+
for tag, attrib, text in elems:
307+
el = ET.SubElement(desc, ET.QName(tag), attrib)
308+
if text:
309+
el.text = text
310+
303311
return ET.ElementTree(rdf)
304312

305313
def is_xml_equal(self, other: 'TestCase') -> bool:
306-
"""
307-
Compare two TestCase instances for XML structural equality.
308-
:param other: Another TestCase instance
309-
:return: True if both XML trees are semantically identical
310-
"""
311-
"""
312-
Compare two TestCase instances for XML structural equality.
313-
"""
314314
def clean(xml: ET._ElementTree) -> bytes:
315315
return ET.tostring(xml.getroot(), encoding='utf-8', method='c14n')
316316

0 commit comments

Comments
 (0)