1 /*
2 *
3 * Copyright (C) 2015-2017, J. Riesmeier, Oldenburg, Germany
4 * All rights reserved. See COPYRIGHT file for details.
5 *
6 * This software and supporting documentation are maintained by
7 *
8 * OFFIS e.V.
9 * R&D Division Health
10 * Escherweg 2
11 * D-26121 Oldenburg, Germany
12 *
13 *
14 * Module: dcmsr
15 *
16 * Author: Joerg Riesmeier
17 *
18 * Purpose:
19 * test program for classes DSRRootTemplate and DSRSubTemplate
20 *
21 */
22
23
24 #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
25
26 #include "dcmtk/ofstd/oftest.h"
27
28 #include "dcmtk/dcmsr/dsrdoc.h"
29 #include "dcmtk/dcmsr/dsrdocst.h"
30 #include "dcmtk/dcmsr/dsrrtpl.h"
31 #include "dcmtk/dcmsr/dsrstpl.h"
32 #include "dcmtk/dcmsr/dsrreftn.h"
33
34
35 /* minimal test class for root template (Basic Diagnostic Imaging Report) */
36 class SRTestTemplate2000
37 : public DSRRootTemplate
38 {
39
40 public:
41
SRTestTemplate2000()42 SRTestTemplate2000()
43 : DSRRootTemplate(DT_BasicTextSR, "2000", "DCMR", UID_DICOMContentMappingResource)
44 {
45 /* make sure that at least the root CONTAINER is there */
46 OFCHECK(addContentItem(RT_isRoot, VT_Container) > 0);
47 }
48 };
49
50 /* minimal test class for sub-template (Person Observer Identifying Attributes) */
51 class SRTestTemplate1003
52 : public DSRSubTemplate
53 {
54
55 public:
56
SRTestTemplate1003()57 SRTestTemplate1003()
58 : DSRSubTemplate("1003", "DCMR")
59 {
60 setExtensible();
61 /* make sure that at least the PNAME content item is there */
62 OFCHECK(addContentItem(RT_unknown, VT_PName, DSRCodedEntryValue("121008", "DCM", "Person Observer Name")).good());
63 }
64 };
65
66 /* minimal test class for sub-template (Planar ROI Measurements) */
67 class SRTestTemplate1410
68 : public DSRSubTemplate
69 {
70
71 public:
72
SRTestTemplate1410()73 SRTestTemplate1410()
74 : DSRSubTemplate("1410", "DCMR")
75 {
76 setExtensible();
77 setOrderSignificant();
78 /* make sure that at least the "root" CONTAINER is there */
79 OFCHECK(addContentItem(RT_unknown, VT_Container, DSRCodedEntryValue("125007", "DCM", "Measurement Group")).good());
80 /* ... and two mandatory child nodes */
81 OFCHECK(addChildContentItem(RT_hasObsContext, VT_Text, DSRCodedEntryValue("112039", "DCM", "Tracking Identifier")).good());
82 OFCHECK(addContentItem(RT_hasObsContext, VT_UIDRef, DSRCodedEntryValue("112040", "DCM", "Tracking Unique Identifier")).good());
83 }
84 };
85
86 /* minimal test class for root template with included templates (Measurement Report) */
87 class SRTestTemplate1500
88 : public DSRRootTemplate
89 {
90
91 public:
92
SRTestTemplate1500()93 SRTestTemplate1500()
94 : DSRRootTemplate(DT_EnhancedSR, "1500", "DCMR", UID_DICOMContentMappingResource)
95 {
96 /* make sure that at least the root CONTAINER is there */
97 OFCHECK(addContentItem(RT_isRoot, VT_Container, DSRCodedEntryValue("126000", "DCM", "Imaging Measurement Report")).good());
98 /* ... and include two sub-templates */
99 OFCHECK(includeTemplate(DSRSharedSubTemplate(new SRTestTemplate1003()), AM_belowCurrent, RT_hasObsContext).good());
100 OFCHECK(includeTemplate(DSRSharedSubTemplate(new SRTestTemplate1410()), AM_afterCurrent, RT_contains).good());
101 }
102 };
103
104 /* minimal test class for template with by-reference relationship (Measurement Group) */
105 class SRTestTemplate1501
106 : public DSRSubTemplate
107 {
108
109 public:
110
SRTestTemplate1501()111 SRTestTemplate1501()
112 : DSRSubTemplate("1501", "DCMR", UID_DICOMContentMappingResource)
113 {
114 setExtensible();
115 /* make sure that at least the top-level CONTAINER is there */
116 OFCHECK(addContentItem(RT_contains, VT_Container, DSRCodedEntryValue("125007,", "DCM", "Measurement Group")).good());
117 /* ... and add two measurements, one referring to the other */
118 OFCHECK(addChildContentItem(RT_contains, VT_Num, DSRCodedEntryValue("12345", "99TEST", "Some Measurement")).good());
119 const size_t nodeID = getNodeID();
120 OFCHECK(addContentItem(RT_contains, VT_Num, DSRCodedEntryValue("09876", "99TEST", "Some other Measurement")).good());
121 OFCHECK(addByReferenceRelationship(RT_inferredFrom, nodeID) > 0);
122 /* update by-reference relationships (prepare for cloning) */
123 OFCHECK(updateByReferenceRelationships().good());
124 }
125 };
126
127
128 /* minimal test class for included sub-template with contained by-reference relationship */
129 class SRTestTemplate1410with1501
130 : public DSRSubTemplate
131 {
132
133 public:
134
SRTestTemplate1410with1501()135 SRTestTemplate1410with1501()
136 : DSRSubTemplate("1410", "DCMR")
137 {
138 setExtensible();
139 /* insert sub-template with some content items */
140 OFCHECK(insertExtraTemplate(SRTestTemplate1410(), AM_belowCurrent, RT_contains).good());
141 /* include sub-template with by-reference relationship */
142 OFCHECK(includeTemplate(DSRSharedSubTemplate(new SRTestTemplate1501()), AM_belowCurrent, RT_contains).good());
143 }
144 };
145
146
147 /* minimal test class for root template with the mandatory CONTAINER */
148 class SRTestRootTemplate
149 : public DSRRootTemplate
150 {
151
152 public:
153
SRTestRootTemplate()154 SRTestRootTemplate()
155 : DSRRootTemplate(DT_ComprehensiveSR, "0815", "99TEST")
156 {
157 setExtensible();
158 /* make sure that at least the root CONTAINER is there */
159 OFCHECK(addContentItem(RT_isRoot, VT_Container, DSRCodedEntryValue("1234", "99TEST", "Some test code")).good());
160 }
161 };
162
163
OFTEST(dcmsr_rootTemplate)164 OFTEST(dcmsr_rootTemplate)
165 {
166 /* first, create an empty SR document */
167 DSRDocument doc(DSRTypes::DT_ComprehensiveSR);
168 /* then, create an almost empty "Basic Diagnostic Imaging Report" (TID 2000) */
169 SRTestTemplate2000 templ;
170 /* perform some basic checks */
171 OFCHECK_EQUAL(doc.getDocumentType(), DSRTypes::DT_ComprehensiveSR);
172 OFCHECK_EQUAL(doc.getTree().countNodes(), 0);
173 OFCHECK_EQUAL(templ.getDocumentType(), DSRTypes::DT_BasicTextSR);
174 OFCHECK_EQUAL(templ.countNodes(), 1);
175 OFCHECK_EQUAL(templ.getTemplateIdentifier(), "2000");
176 OFCHECK_EQUAL(templ.getMappingResource(), "DCMR");
177 OFCHECK_EQUAL(templ.getMappingResourceUID(), UID_DICOMContentMappingResource);
178 OFCHECK(templ.isRootTemplate());
179 OFCHECK(!templ.isExtensible());
180 OFCHECK(!templ.isOrderSignificant());
181 /* replace the document tree with the content of the template */
182 OFCHECK(doc.setTreeFromRootTemplate(templ, OFFalse /*expandTree*/).good());
183 /* and perform some further checks */
184 OFCHECK_EQUAL(doc.getDocumentType(), DSRTypes::DT_BasicTextSR);
185 OFCHECK_EQUAL(doc.getTree().countNodes(), 1);
186 OFCHECK(doc.getTree().compareTemplateIdentification("2000", "DCMR"));
187 OFCHECK(doc.getTree().compareTemplateIdentification("2000", "DCMR", UID_DICOMContentMappingResource));
188 OFCHECK(!doc.getTree().compareTemplateIdentification("200", "DCMR"));
189 OFCHECK(!doc.getTree().compareTemplateIdentification("2000", "DCM"));
190 }
191
192
OFTEST(dcmsr_subTemplate_1)193 OFTEST(dcmsr_subTemplate_1)
194 {
195 /* first, create an empty SR document */
196 DSRDocument doc(DSRTypes::DT_ComprehensiveSR);
197 /* then, create an almost empty "Planar ROI Measurements" (TID 1410) */
198 SRTestTemplate1410 templ;
199 /* and, an empty SR document tree */
200 DSRDocumentTree tree(DSRTypes::DT_EnhancedSR);
201 /* perform some basic checks */
202 OFCHECK_EQUAL(doc.getDocumentType(), DSRTypes::DT_ComprehensiveSR);
203 OFCHECK_EQUAL(doc.getTree().countNodes(), 0);
204 OFCHECK_EQUAL(tree.getDocumentType(), DSRTypes::DT_EnhancedSR);
205 OFCHECK_EQUAL(tree.countNodes(), 0);
206 OFCHECK_EQUAL(templ.countNodes(), 3);
207 OFCHECK_EQUAL(templ.getTemplateIdentifier(), "1410");
208 OFCHECK_EQUAL(templ.getMappingResource(), "DCMR");
209 OFCHECK_EQUAL(templ.getMappingResourceUID(), "");
210 OFCHECK(!templ.isRootTemplate());
211 OFCHECK(templ.isExtensible());
212 OFCHECK(templ.isOrderSignificant());
213 /* insert TID 1410 into the tree ... */
214 OFCHECK(tree.insertSubTree(templ.cloneTree(), DSRTypes::AM_belowCurrent, DSRTypes::RT_isRoot).good());
215 /* and replace the tree of the SR document with the content of the template */
216 OFCHECK(doc.setTree(tree).good());
217 /* finally, perform some further checks */
218 OFCHECK_EQUAL(doc.getDocumentType(), DSRTypes::DT_EnhancedSR);
219 OFCHECK_EQUAL(doc.getTree().countNodes(), 3);
220 OFCHECK(doc.getTree().compareTemplateIdentification("1410", "DCMR"));
221 }
222
223
OFTEST(dcmsr_subTemplate_2)224 OFTEST(dcmsr_subTemplate_2)
225 {
226 /* first, create an empty SR document */
227 DSRDocument doc(DSRTypes::DT_ComprehensiveSR);
228 /* then, create an almost empty "Basic Diagnostic Imaging Report" (TID 2000) */
229 SRTestTemplate2000 templ1;
230 /* and make it extensible (only needed for this test) */
231 templ1.setExtensible();
232 /* also create an almost empty "Person Observer Identifying Attributes" (TID 1003) */
233 SRTestTemplate1003 templ2;
234 /* perform some basic checks */
235 OFCHECK_EQUAL(doc.getDocumentType(), DSRTypes::DT_ComprehensiveSR);
236 OFCHECK_EQUAL(doc.getTree().countNodes(), 0);
237 OFCHECK_EQUAL(templ1.getDocumentType(), DSRTypes::DT_BasicTextSR);
238 OFCHECK_EQUAL(templ1.countNodes(), 1);
239 OFCHECK_EQUAL(templ2.countNodes(), 1);
240 /* insert TID 1003 into TID 2000 */
241 OFCHECK(templ1.insertExtraTemplate(templ2, DSRTypes::AM_belowCurrent, DSRTypes::RT_hasAcqContext).good());
242 OFCHECK_EQUAL(templ1.countNodes(), 2);
243 OFCHECK_EQUAL(templ2.countNodes(), 1);
244 /* replace the document tree with the content of the template */
245 OFCHECK(doc.setTreeFromRootTemplate(templ1, OFFalse /*expandTree*/).good());
246 /* and perform some further checks */
247 OFCHECK_EQUAL(doc.getDocumentType(), DSRTypes::DT_BasicTextSR);
248 OFCHECK_EQUAL(doc.getTree().countNodes(), 2);
249 OFCHECK(doc.getTree().compareTemplateIdentification("2000", "DCMR"));
250 }
251
252
OFTEST(dcmsr_subTemplate_3)253 OFTEST(dcmsr_subTemplate_3)
254 {
255 /* first, create an almost empty "Planar ROI Measurements" (TID 1410) */
256 SRTestTemplate1410 templ;
257 /* then, add additional content items (since the template is extensible) */
258 OFCHECK(templ.isExtensible());
259 OFCHECK(templ.addExtraContentItem(DSRTypes::RT_contains, DSRTypes::VT_Text).good());
260 OFCHECK(templ.getCurrentContentItem().setConceptName(DSRBasicCodedEntry("121106", "DCM", "Comment")).good());
261 OFCHECK(templ.getCurrentContentItem().setStringValue("Some comment").good());
262 OFCHECK(templ.addExtraContentItem(DSRTypes::RT_hasConceptMod, DSRTypes::VT_Text, DSRTypes::AM_belowCurrent).good());
263 OFCHECK(templ.getCurrentContentItem().setConceptName(DSRBasicCodedEntry("121051", "DCM", "Equivalent Meaning of Value")).good());
264 OFCHECK(templ.getCurrentContentItem().setStringValue("blabla").good());
265 OFCHECK(templ.gotoParent() > 0);
266 /* also try to add if template is non-extensible */
267 templ.setExtensible(OFFalse);
268 OFCHECK(templ.addExtraContentItem(DSRTypes::RT_contains, DSRTypes::VT_Container) == SR_EC_NonExtensibleTemplate);
269 /* finally, perform some further checks */
270 OFCHECK_EQUAL(templ.countNodes(), 5);
271 OFCHECK_EQUAL(templ.countChildNodes(), 1);
272 }
273
274
OFTEST(dcmsr_createExpandedTree)275 OFTEST(dcmsr_createExpandedTree)
276 {
277 /* first, create an empty SR document */
278 DSRDocument doc(DSRTypes::DT_ComprehensiveSR);
279 /* then, create an almost empty "Measurement Report" (TID 1500) */
280 SRTestTemplate1500 templ;
281 OFCHECK_EQUAL(templ.countNodes(), 3);
282 /* and set its content as the document tree (with expanded sub-templates) */
283 OFCHECK(doc.getTree().isEmpty());
284 OFCHECK(doc.setTreeFromRootTemplate(templ, OFTrue /*expandTree*/).good());
285 OFCHECK(doc.getTree().isExpandedDocumentTree());
286 OFCHECK_EQUAL(doc.getTree().countNodes(), 5);
287 /* do the same without expanding the (included) sub-templates */
288 OFCHECK(doc.setTreeFromRootTemplate(templ, OFFalse /*expandTree*/).good());
289 OFCHECK(!doc.getTree().isExpandedDocumentTree());
290 OFCHECK_EQUAL(doc.getTree().countNodes(), 3);
291 /* and perform some further checks */
292 OFCHECK_EQUAL(doc.getDocumentType(), DSRTypes::DT_EnhancedSR);
293 OFCHECK(doc.getTree().compareTemplateIdentification("1500", "DCMR"));
294 }
295
296
OFTEST(dcmsr_templateWithByReferenceRelationship_1)297 OFTEST(dcmsr_templateWithByReferenceRelationship_1)
298 {
299 /* first, create an almost empty "Planar ROI Measurements" (TID 1410) */
300 SRTestTemplate1410 templ;
301 /* insert sub-template with by-reference relationship */
302 OFCHECK(templ.isExtensible());
303 OFCHECK(templ.insertExtraTemplate(SRTestTemplate1501(), DSRTypes::AM_afterCurrent, DSRTypes::RT_contains).good());
304 /* then, go to the source content item of the by-reference relationship */
305 OFCHECK(templ.gotoNamedNode(DSRCodedEntryValue("09876", "99TEST", "Some other Measurement")) > 0);
306 /* check whether the correct content item has been found */
307 OFCHECK(templ.getCurrentContentItem().getValueType() == DSRTypes::VT_Num);
308 /* and, finally, check whether the by-reference relationship is still valid */
309 OFCHECK(templ.updateByReferenceRelationships().good());
310 OFCHECK(templ.gotoChild() > 0);
311 OFCHECK(templ.getCurrentContentItem().getValueType() == DSRTypes::VT_byReference);
312 OFCHECK(templ.getCurrentContentItem().getReferencedNodeID() > 0);
313 const DSRDocumentTreeNode *treeNode = templ.getTree().getCurrentNode();
314 if (treeNode != NULL)
315 {
316 if (treeNode->getValueType() == DSRTypes::VT_byReference)
317 {
318 const DSRByReferenceTreeNode *node = OFstatic_cast(const DSRByReferenceTreeNode *, treeNode);
319 OFCHECK_EQUAL(node->getReferencedContentItem(), "1.3.1");
320 }
321 } else
322 OFCHECK_FAIL("could not get read-only access to current node");
323 }
324
325
OFTEST(dcmsr_templateWithByReferenceRelationship_2)326 OFTEST(dcmsr_templateWithByReferenceRelationship_2)
327 {
328 DSRDocument doc;
329 /* first, create a sub-template with included sub-template */
330 SRTestTemplate1410with1501 subTempl;
331 OFCHECK_EQUAL(subTempl.countNodes(), 4);
332 OFCHECK_EQUAL(subTempl.countNodes(OFTrue /*searchIntoSubTemplates*/, OFFalse /*countIncludedTemplateNodes*/), 7);
333 /* then, create a root template with a CONTAINER content item */
334 SRTestRootTemplate rootTempl;
335 OFCHECK_EQUAL(rootTempl.countNodes(), 1);
336 /* insert the sub-template into it */
337 OFCHECK(rootTempl.isExtensible());
338 OFCHECK(rootTempl.insertExtraTemplate(subTempl).good());
339 OFCHECK_EQUAL(rootTempl.countNodes(), 5);
340 OFCHECK_EQUAL(rootTempl.countNodes(OFTrue /*searchIntoSubTemplates*/, OFFalse /*countIncludedTemplateNodes*/), 8);
341 /* check whether the by-reference relationship is still valid */
342 OFCHECK(rootTempl.updateByReferenceRelationships(OFTrue /*includedTemplates*/).good());
343 DSRIncludedTemplateNodeCursor cursor;
344 if (rootTempl.getTree().getCursorToRootNode(cursor))
345 {
346 do {
347 const DSRDocumentTreeNode *treeNode = cursor.getNode();
348 if (treeNode != NULL)
349 {
350 if (treeNode->getValueType() == DSRTypes::VT_byReference)
351 {
352 const DSRByReferenceTreeNode *node = OFstatic_cast(const DSRByReferenceTreeNode *, treeNode);
353 OFCHECK_EQUAL(node->getReferencedContentItem(), "1.1.3.1.1");
354 }
355 }
356 } while (cursor.iterate());
357 }
358 /* and, finally, set its content as the document tree */
359 OFCHECK(doc.setTreeFromRootTemplate(rootTempl, OFTrue /*expandTree*/).good());
360 OFCHECK_EQUAL(doc.getTree().countNodes(), 8);
361 }
362