View Javadoc
1   package emissary.core;
2   
3   import emissary.core.IBaseDataObjectXmlCodecs.ElementEncoders;
4   import emissary.core.channels.InMemoryChannelFactory;
5   import emissary.core.channels.SeekableByteChannelFactory;
6   import emissary.core.constants.IbdoXmlElementNames;
7   import emissary.kff.KffDataObjectHandler;
8   import emissary.test.core.junit5.UnitTest;
9   import emissary.util.ByteUtil;
10  import emissary.util.PlaceComparisonHelper;
11  
12  import jakarta.annotation.Nullable;
13  import org.jdom2.Document;
14  import org.jdom2.Element;
15  import org.jdom2.input.SAXBuilder;
16  import org.jdom2.input.sax.XMLReaders;
17  import org.junit.jupiter.api.Test;
18  
19  import java.io.IOException;
20  import java.io.StringReader;
21  import java.nio.ByteBuffer;
22  import java.nio.channels.SeekableByteChannel;
23  import java.nio.charset.StandardCharsets;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.List;
27  import java.util.Map.Entry;
28  import java.util.Random;
29  import java.util.TreeMap;
30  
31  import static emissary.core.IBaseDataObjectXmlCodecs.ALWAYS_SHA256_ELEMENT_ENCODERS;
32  import static emissary.core.IBaseDataObjectXmlCodecs.DEFAULT_ELEMENT_DECODERS;
33  import static emissary.core.IBaseDataObjectXmlCodecs.DEFAULT_ELEMENT_ENCODERS;
34  import static emissary.core.IBaseDataObjectXmlCodecs.SHA256_ELEMENT_ENCODERS;
35  import static emissary.core.IBaseDataObjectXmlCodecs.extractBytes;
36  import static org.junit.jupiter.api.Assertions.assertEquals;
37  import static org.junit.jupiter.api.Assertions.assertNull;
38  
39  class IBaseDataObjectXmlHelperTest extends UnitTest {
40      @Test
41      void testParentIbdoNoFieldsChanged() throws Exception {
42          final IBaseDataObject initialIbdo = new BaseDataObject();
43          final IBaseDataObject expectedIbdo = new BaseDataObject();
44          final List<IBaseDataObject> expectedChildren = new ArrayList<>();
45          final List<IBaseDataObject> actualChildren = new ArrayList<>();
46  
47          final IBaseDataObject actualIbdo = ibdoFromXmlFromIbdo(expectedIbdo, expectedChildren, initialIbdo,
48                  actualChildren, DEFAULT_ELEMENT_ENCODERS);
49          final String diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, actualIbdo, expectedChildren,
50                  actualChildren, "testParentIbdoNoFieldsChanged", DiffCheckConfiguration.onlyCheckData());
51  
52          assertNull(diff);
53  
54          final IBaseDataObject sha256ActualIbdo = ibdoFromXmlFromIbdo(expectedIbdo, expectedChildren, initialIbdo,
55                  actualChildren, SHA256_ELEMENT_ENCODERS);
56          final String sha256Diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, sha256ActualIbdo, expectedChildren,
57                  actualChildren, "testParentIbdoNoFieldsChangedSha256", DiffCheckConfiguration.onlyCheckData());
58  
59          assertNull(sha256Diff);
60  
61          final IBaseDataObject alwaysSha256ActualIbdo = ibdoFromXmlFromIbdo(expectedIbdo, expectedChildren, initialIbdo,
62                  actualChildren, ALWAYS_SHA256_ELEMENT_ENCODERS);
63          final String alwaysSha256Diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, alwaysSha256ActualIbdo, expectedChildren,
64                  actualChildren, "testParentIbdoNoFieldsChangedAlwaysSha256", DiffCheckConfiguration.onlyCheckData());
65  
66          assertNull(alwaysSha256Diff);
67      }
68  
69      private static void setAllFieldsPrintable(final IBaseDataObject ibdo, final byte[] bytes) {
70          ibdo.setData(bytes);
71          ibdo.setBirthOrder(5);
72          ibdo.setBroken("Broken1");
73          ibdo.setBroken("Broken2");
74          ibdo.setClassification("Classification");
75          ibdo.pushCurrentForm("Form1");
76          ibdo.pushCurrentForm("Form2");
77          ibdo.setFilename("Filename");
78          ibdo.setFileType("FileType");
79          ibdo.setFontEncoding("FontEncoding");
80          ibdo.setFooter("Footer".getBytes(StandardCharsets.UTF_8));
81          ibdo.setHeader("Header".getBytes(StandardCharsets.UTF_8));
82          ibdo.setHeaderEncoding("HeaderEncoding");
83          ibdo.setId("Id");
84          ibdo.setNumChildren(9);
85          ibdo.setNumSiblings(10);
86          ibdo.setOutputable(false);
87          ibdo.setPriority(1);
88          ibdo.addProcessingError("ProcessingError1");
89          ibdo.addProcessingError("ProcessingError2");
90          ibdo.setTransactionId("TransactionId");
91          ibdo.setWorkBundleId("WorkBundleId");
92          ibdo.putParameter("Parameter1Key", "Parameter1Value");
93          ibdo.putParameter("Parameter2Key", Arrays.asList("Parameter2Value1", "Parameter2Value2"));
94          ibdo.putParameter("Parameter3Key", Arrays.asList(10L, 20L));
95          ibdo.addAlternateView("AlternateView1Key", "AlternateView1Value".getBytes(StandardCharsets.UTF_8));
96          ibdo.addAlternateView("AlternateView11Key", "AlternateView11Value".getBytes(StandardCharsets.UTF_8));
97      }
98  
99      private static void setAllFieldsNonPrintable(final IBaseDataObject ibdo, final byte[] bytes) {
100         ibdo.setData(bytes);
101         ibdo.setBirthOrder(5);
102         ibdo.setBroken("\001Broken1");
103         ibdo.setBroken("\001Broken2");
104         ibdo.setClassification("\001Classification");
105         ibdo.pushCurrentForm("Form1");
106         ibdo.pushCurrentForm("Form2");
107         ibdo.setFilename("\001Filename");
108         ibdo.setFileType("\001FileType");
109         ibdo.setFontEncoding("\001FontEncoding");
110         ibdo.setFooter("\001Footer".getBytes(StandardCharsets.UTF_8));
111         ibdo.setHeader("\001Header".getBytes(StandardCharsets.UTF_8));
112         ibdo.setHeaderEncoding("\001HeaderEncoding");
113         ibdo.setId("\001Id");
114         ibdo.setNumChildren(9);
115         ibdo.setNumSiblings(10);
116         ibdo.setOutputable(false);
117         ibdo.setPriority(1);
118         ibdo.addProcessingError("\001ProcessingError1");
119         ibdo.addProcessingError("\001ProcessingError2");
120         ibdo.setTransactionId("\001TransactionId");
121         ibdo.setWorkBundleId("\001WorkBundleId");
122         ibdo.putParameter("\020Parameter1Key", "\020Parameter1Value");
123         ibdo.putParameter("\020Parameter2Key", "\020Parameter2Value");
124         ibdo.addAlternateView("\200AlternateView1Key",
125                 "\200AlternateView1Value".getBytes(StandardCharsets.UTF_8));
126         ibdo.addAlternateView("\200AlternateView11Key",
127                 "\200AlternateView11Value".getBytes(StandardCharsets.UTF_8));
128     }
129 
130     private static void hashData(final IBaseDataObject ibdo) {
131         final String sha256String = ByteUtil.sha256Bytes(ibdo.data());
132         final byte[] sha256Bytes = sha256String == null ? new byte[0] : sha256String.getBytes(StandardCharsets.UTF_8);
133 
134         ibdo.setData(sha256Bytes);
135     }
136 
137     private static void hashAlternateViews(final IBaseDataObject ibdo) {
138         for (Entry<String, byte[]> entry : new TreeMap<>(ibdo.getAlternateViews()).entrySet()) {
139             final String sha256String = ByteUtil.sha256Bytes(entry.getValue());
140             final byte[] sha256Bytes = sha256String == null ? new byte[0] : sha256String.getBytes(StandardCharsets.UTF_8);
141 
142             ibdo.addAlternateView(entry.getKey(), sha256Bytes);
143         }
144     }
145 
146     @Test
147     void testParentIbdoAllFieldsChanged() throws Exception {
148         final IBaseDataObject initialIbdo = new BaseDataObject();
149         final IBaseDataObject expectedIbdo = new BaseDataObject();
150         final List<IBaseDataObject> expectedChildren = new ArrayList<>();
151         final List<IBaseDataObject> actualChildren = new ArrayList<>();
152         final byte[] bytes = "Data".getBytes(StandardCharsets.UTF_8);
153 
154         setAllFieldsPrintable(expectedIbdo, bytes);
155 
156         final IBaseDataObject actualIbdo = ibdoFromXmlFromIbdo(expectedIbdo, expectedChildren, initialIbdo,
157                 actualChildren, DEFAULT_ELEMENT_ENCODERS);
158         final String diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, actualIbdo, expectedChildren,
159                 actualChildren, "testParentIbdoAllFieldsChanged", DiffCheckConfiguration.onlyCheckData());
160 
161         assertNull(diff);
162 
163         final IBaseDataObject sha256ActualIbdo = ibdoFromXmlFromIbdo(expectedIbdo, expectedChildren, initialIbdo,
164                 actualChildren, SHA256_ELEMENT_ENCODERS);
165         final String sha256Diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, sha256ActualIbdo, expectedChildren,
166                 actualChildren, "testParentIbdoAllFieldsChangedSha256", DiffCheckConfiguration.onlyCheckData());
167 
168         assertNull(sha256Diff);
169 
170         final IBaseDataObject alwaysSha256ActualIbdo = ibdoFromXmlFromIbdo(expectedIbdo, expectedChildren, initialIbdo,
171                 actualChildren, ALWAYS_SHA256_ELEMENT_ENCODERS);
172 
173         hashData(expectedIbdo);
174         hashAlternateViews(expectedIbdo);
175 
176         final String alwaysSha256Diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, alwaysSha256ActualIbdo, expectedChildren,
177                 actualChildren, "testParentIbdoAllFieldsChangedAlwaysSha256", DiffCheckConfiguration.onlyCheckData());
178 
179         assertNull(alwaysSha256Diff);
180     }
181 
182     @Test
183     void testBase64Conversion() throws Exception {
184         final IBaseDataObject initialIbdo = new BaseDataObject();
185         final IBaseDataObject expectedIbdo = new BaseDataObject();
186         final List<IBaseDataObject> expectedChildren = new ArrayList<>();
187         final List<IBaseDataObject> actualChildren = new ArrayList<>();
188         final byte[] bytes = "\001Data".getBytes(StandardCharsets.UTF_8);
189 
190         setAllFieldsNonPrintable(expectedIbdo, bytes);
191 
192         final IBaseDataObject actualIbdo = ibdoFromXmlFromIbdo(expectedIbdo, expectedChildren, initialIbdo,
193                 actualChildren, DEFAULT_ELEMENT_ENCODERS);
194         final String diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, actualIbdo, expectedChildren,
195                 actualChildren, "testBase64Conversion", DiffCheckConfiguration.onlyCheckData());
196 
197         assertNull(diff);
198 
199         final IBaseDataObject sha256ActualIbdo = ibdoFromXmlFromIbdo(expectedIbdo, expectedChildren, initialIbdo,
200                 actualChildren, SHA256_ELEMENT_ENCODERS);
201 
202         hashData(expectedIbdo);
203         hashAlternateViews(expectedIbdo);
204 
205         final String sha256Diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, sha256ActualIbdo, expectedChildren,
206                 actualChildren, "testSha256Conversion", DiffCheckConfiguration.onlyCheckData());
207 
208         assertNull(sha256Diff);
209 
210         final IBaseDataObject expectedIbdo2 = new BaseDataObject();
211 
212         setAllFieldsNonPrintable(expectedIbdo2, bytes);
213 
214         final IBaseDataObject alwaysSha256ActualIbdo = ibdoFromXmlFromIbdo(expectedIbdo, expectedChildren, initialIbdo,
215                 actualChildren, ALWAYS_SHA256_ELEMENT_ENCODERS);
216 
217         hashData(expectedIbdo);
218         hashAlternateViews(expectedIbdo);
219 
220         final String alwaysSha256Diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, alwaysSha256ActualIbdo, expectedChildren,
221                 actualChildren, "testParentIbdoAllFieldsChangedAlwaysSha256", DiffCheckConfiguration.onlyCheckData());
222 
223         assertNull(alwaysSha256Diff);
224     }
225 
226     @Test
227     void testLengthAttributeDefault() throws Exception {
228         final IBaseDataObject ibdo = new BaseDataObject();
229         final List<IBaseDataObject> children = new ArrayList<>();
230         final byte[] bytes = "Data".getBytes(StandardCharsets.UTF_8);
231 
232         setAllFieldsPrintable(ibdo, bytes);
233 
234         final String xmlString = IBaseDataObjectXmlHelper.xmlFromIbdo(ibdo, children, ibdo, DEFAULT_ELEMENT_ENCODERS);
235 
236         final SAXBuilder builder = new SAXBuilder(XMLReaders.NONVALIDATING);
237         final Document document = builder.build(new StringReader(xmlString));
238         final Element root = document.getRootElement();
239 
240         assertNull(checkLengthElement(root, (int) ibdo.getChannelSize(), "answers", "data"));
241         assertNull(checkLengthElement(root, ibdo.footer().length, "answers", "footer"));
242         assertNull(checkLengthElement(root, ibdo.header().length, "answers", "header"));
243         assertNull(checkLengthKeyValue(root, ibdo.getAlternateView("AlternateView1Key").length, "AlternateView1Key", "answers", "view"));
244         assertNull(checkLengthKeyValue(root, ibdo.getAlternateView("AlternateView11Key").length, "AlternateView11Key", "answers", "view"));
245     }
246 
247     @Test
248     void testLengthAttributeHash() throws Exception {
249         final IBaseDataObject ibdo = new BaseDataObject();
250         final List<IBaseDataObject> children = new ArrayList<>();
251         final byte[] bytes = "Data".getBytes(StandardCharsets.UTF_8);
252 
253         setAllFieldsNonPrintable(ibdo, bytes);
254 
255         final String xmlString = IBaseDataObjectXmlHelper.xmlFromIbdo(ibdo, children, ibdo, DEFAULT_ELEMENT_ENCODERS);
256 
257         final SAXBuilder builder = new SAXBuilder(XMLReaders.NONVALIDATING);
258         final Document document = builder.build(new StringReader(xmlString));
259         final Element root = document.getRootElement();
260 
261         assertNull(checkLengthElement(root, (int) ibdo.getChannelSize(), "answers", "data"));
262         assertNull(checkLengthElement(root, ibdo.footer().length, "answers", "footer"));
263         assertNull(checkLengthElement(root, ibdo.header().length, "answers", "header"));
264         assertNull(checkLengthKeyValue(root, ibdo.getAlternateView("\200AlternateView1Key").length, "\200AlternateView1Key", "answers", "view"));
265         assertNull(checkLengthKeyValue(root, ibdo.getAlternateView("\200AlternateView11Key").length, "\200AlternateView11Key", "answers", "view"));
266     }
267 
268     @Nullable
269     private static String checkLengthElement(Element rootElement, int lengthToCheck, String... xmlPathElementNames) {
270         Element element = rootElement;
271 
272         for (int i = 0; i < xmlPathElementNames.length; i++) {
273             final String xmlPathElementName = xmlPathElementNames[i];
274             final List<Element> elements = element.getChildren(xmlPathElementName);
275 
276             if (elements == null || elements.size() != 1) {
277                 return "Cound not find element " + xmlPathElementName;
278             }
279 
280             element = elements.get(0);
281         }
282 
283         String lengthElement = element.getAttributeValue(IBaseDataObjectXmlCodecs.LENGTH_ATTRIBUTE_NAME);
284 
285         if (lengthElement == null) {
286             return "Could not find length element";
287         }
288 
289         try {
290             long length = Long.parseLong(lengthElement);
291 
292             if (length == lengthToCheck) {
293                 return null;
294             } else {
295                 return "Looking for length " + lengthToCheck + ", but found " + length;
296             }
297         } catch (NumberFormatException e) {
298             return "NumberFormatException: " + lengthElement;
299         }
300     }
301 
302     @Nullable
303     private static String checkLengthKeyValue(Element rootElement, int lengthToCheck, String key, String... xmlPathElementNames) {
304         Element element = rootElement;
305 
306         for (int i = 0; i < xmlPathElementNames.length - 1; i++) {
307             final String xmlPathElementName = xmlPathElementNames[i];
308             final List<Element> elements = element.getChildren(xmlPathElementName);
309 
310             if (elements == null || elements.isEmpty()) {
311                 return "Cound not find element " + xmlPathElementName;
312             }
313 
314             element = elements.get(0);
315         }
316 
317         List<Element> keyValueElements = element.getChildren(xmlPathElementNames[xmlPathElementNames.length - 1]);
318 
319         for (int j = 0; j < keyValueElements.size(); j++) {
320             final Element e = keyValueElements.get(j);
321             final Element nameElement = e.getChild(IbdoXmlElementNames.NAME);
322             final String name = nameElement.getValue();
323             final String nameEncoding = nameElement.getAttributeValue(IBaseDataObjectXmlCodecs.ENCODING_ATTRIBUTE_NAME);
324             final String nameDecoded = new String(extractBytes(nameEncoding, name), StandardCharsets.UTF_8);
325 
326             if (nameDecoded.equals(key)) {
327                 element = e.getChild(IbdoXmlElementNames.VALUE);
328             }
329         }
330 
331         String lengthElement = element.getAttributeValue(IBaseDataObjectXmlCodecs.LENGTH_ATTRIBUTE_NAME);
332 
333         if (lengthElement == null) {
334             return "Could not find length element";
335         }
336 
337         try {
338             long length = Long.parseLong(lengthElement);
339 
340             if (length == lengthToCheck) {
341                 return null;
342             } else {
343                 return "Looking for length " + lengthToCheck + ", but found " + length;
344             }
345         } catch (NumberFormatException e) {
346             return "NumberFormatException: " + lengthElement;
347         }
348     }
349 
350     @Test
351     void testAttachmentsAndExtractedRecords() throws Exception {
352         final IBaseDataObject initialIbdo = new BaseDataObject();
353         final IBaseDataObject expectedIbdo = new BaseDataObject();
354         final IBaseDataObject childIbdo1 = new BaseDataObject();
355         final IBaseDataObject childIbdo2 = new BaseDataObject();
356         final IBaseDataObject extractedIbdo1 = new BaseDataObject();
357         final IBaseDataObject extractedIbdo2 = new BaseDataObject();
358         final List<IBaseDataObject> expectedChildren = new ArrayList<>();
359         final List<IBaseDataObject> actualChildren = new ArrayList<>();
360 
361         childIbdo1.setFilename("Child1");
362         childIbdo2.setFilename("Child2");
363         extractedIbdo1.setFilename("ExtractedRecord1");
364         extractedIbdo2.setFilename("ExtractedRecord2");
365 
366         expectedIbdo.setFilename("Parent");
367         expectedIbdo.addExtractedRecord(extractedIbdo1);
368         expectedIbdo.addExtractedRecord(extractedIbdo2);
369 
370         expectedChildren.add(childIbdo1);
371         expectedChildren.add(childIbdo2);
372 
373         final IBaseDataObject actualIbdo = ibdoFromXmlFromIbdo(expectedIbdo, expectedChildren, initialIbdo,
374                 actualChildren, DEFAULT_ELEMENT_ENCODERS);
375         final String diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, actualIbdo, expectedChildren,
376                 actualChildren, "testAttachmentsAndExtractedRecords", DiffCheckConfiguration.onlyCheckData());
377 
378         assertNull(diff);
379     }
380 
381     @Test
382     void testBadChannelFactory() throws Exception {
383         final IBaseDataObject initialIbdo = new BaseDataObject();
384         final IBaseDataObject expectedIbdo = new BaseDataObject();
385         final IBaseDataObject dataExceptionIbdo = new BaseDataObject();
386         final List<IBaseDataObject> expectedChildren = new ArrayList<>();
387         final List<IBaseDataObject> actualChildren = new ArrayList<>();
388 
389         dataExceptionIbdo.setChannelFactory(new ExceptionChannelFactory());
390 
391         final IBaseDataObject actualIbdo = ibdoFromXmlFromIbdo(dataExceptionIbdo, expectedChildren, initialIbdo,
392                 actualChildren, DEFAULT_ELEMENT_ENCODERS);
393         final String diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, actualIbdo, expectedChildren,
394                 actualChildren, "testBadChannelFactory", DiffCheckConfiguration.onlyCheckData());
395 
396         assertNull(diff);
397 
398         final IBaseDataObject sha256ActualIbdo = ibdoFromXmlFromIbdo(dataExceptionIbdo, expectedChildren, initialIbdo,
399                 actualChildren, SHA256_ELEMENT_ENCODERS);
400         final String sha256Diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, sha256ActualIbdo, expectedChildren,
401                 actualChildren, "testBadChannelFactory", DiffCheckConfiguration.onlyCheckData());
402 
403         assertNull(sha256Diff);
404 
405         final IBaseDataObject alwaysSha256ActualIbdo = ibdoFromXmlFromIbdo(dataExceptionIbdo, expectedChildren, initialIbdo,
406                 actualChildren, ALWAYS_SHA256_ELEMENT_ENCODERS);
407         final String alwaysSha256Diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, alwaysSha256ActualIbdo, expectedChildren,
408                 actualChildren, "testBadChannelFactory", DiffCheckConfiguration.onlyCheckData());
409 
410         assertNull(alwaysSha256Diff);
411     }
412 
413     @Test
414     void testBadIntegerDecoding() throws Exception {
415         final IBaseDataObject initialIbdo = new BaseDataObject();
416         final IBaseDataObject expectedIbdo = new BaseDataObject();
417         final IBaseDataObject priorityIbdo = new BaseDataObject();
418         final List<IBaseDataObject> expectedChildren = new ArrayList<>();
419         final List<IBaseDataObject> actualChildren = new ArrayList<>();
420 
421         priorityIbdo.setPriority(100);
422 
423         final String xmlString = IBaseDataObjectXmlHelper.xmlFromIbdo(priorityIbdo, expectedChildren, initialIbdo, DEFAULT_ELEMENT_ENCODERS);
424         final String newXmlString = xmlString.replace("100", "100A");
425 
426         final SAXBuilder builder = new SAXBuilder(XMLReaders.NONVALIDATING);
427         final Document document = builder.build(new StringReader(newXmlString));
428         final IBaseDataObject actualIbdo = IBaseDataObjectXmlHelper.ibdoFromXml(document, actualChildren, DEFAULT_ELEMENT_DECODERS);
429 
430         final String diff = PlaceComparisonHelper.checkDifferences(expectedIbdo, actualIbdo, expectedChildren,
431                 actualChildren, "testBadChannelFactory", DiffCheckConfiguration.onlyCheckData());
432 
433         assertNull(diff);
434     }
435 
436     @Test
437     void testCreateStandardInitialIbdo() {
438         final byte[] bytes = new byte[20];
439 
440         new Random().nextBytes(bytes);
441 
442         final SeekableByteChannelFactory sbcf = InMemoryChannelFactory.create(bytes);
443         final String classification = "Classification";
444         final String formAndFileType = "FormAndFiletype";
445         final KffDataObjectHandler kff = new KffDataObjectHandler(KffDataObjectHandler.TRUNCATE_KNOWN_DATA,
446                 KffDataObjectHandler.SET_FORM_WHEN_KNOWN, KffDataObjectHandler.SET_FILE_TYPE);
447         final List<String> differences = new ArrayList<>();
448         final IBaseDataObject expectedIbdo = new BaseDataObject();
449         final IBaseDataObject tempIbdo = new BaseDataObject();
450 
451         tempIbdo.setChannelFactory(sbcf);
452         kff.hash(tempIbdo);
453         expectedIbdo.setParameters(tempIbdo.getParameters());
454 
455         expectedIbdo.setCurrentForm(formAndFileType);
456         expectedIbdo.setFileType(formAndFileType);
457         expectedIbdo.setClassification(classification);
458 
459         final IBaseDataObject actualIbdo = IBaseDataObjectXmlHelper.createStandardInitialIbdo(new BaseDataObject(), sbcf, classification,
460                 formAndFileType, kff);
461 
462         IBaseDataObjectDiffHelper.diff(expectedIbdo, actualIbdo, differences, DiffCheckConfiguration.onlyCheckData());
463 
464         assertEquals(0, differences.size());
465     }
466 
467     private static IBaseDataObject ibdoFromXmlFromIbdo(final IBaseDataObject ibdo, final List<IBaseDataObject> children,
468             final IBaseDataObject initialIbdo, final List<IBaseDataObject> outputChildren, final ElementEncoders elementEncoders) throws Exception {
469         final String xmlString = IBaseDataObjectXmlHelper.xmlFromIbdo(ibdo, children, initialIbdo, elementEncoders);
470 
471         final SAXBuilder builder = new SAXBuilder(XMLReaders.NONVALIDATING);
472         final Document document = builder.build(new StringReader(xmlString));
473 
474         return IBaseDataObjectXmlHelper.ibdoFromXml(document, outputChildren, DEFAULT_ELEMENT_DECODERS);
475     }
476 
477     private static class ExceptionChannelFactory implements SeekableByteChannelFactory {
478         @Override
479         public SeekableByteChannel create() {
480             return new SeekableByteChannel() {
481                 @Override
482                 public boolean isOpen() {
483                     return true;
484                 }
485 
486                 @Override
487                 public void close() throws IOException {
488                     throw new IOException("This SBC only throws Exceptions");
489                 }
490 
491                 @Override
492                 public int read(final ByteBuffer dst) throws IOException {
493                     throw new IOException("This SBC only throws Exceptions");
494                 }
495 
496                 @Override
497                 public int write(final ByteBuffer src) throws IOException {
498                     throw new IOException("This SBC only throws Exceptions");
499                 }
500 
501                 @Override
502                 public long position() throws IOException {
503                     throw new IOException("This SBC only throws Exceptions");
504                 }
505 
506                 @Override
507                 public SeekableByteChannel position(final long newPosition) throws IOException {
508                     throw new IOException("This SBC only throws Exceptions");
509                 }
510 
511                 @Override
512                 public long size() throws IOException {
513                     throw new IOException("This SBC only throws Exceptions");
514                 }
515 
516                 @Override
517                 public SeekableByteChannel truncate(final long size) throws IOException {
518                     throw new IOException("This SBC only throws Exceptions");
519                 }
520             };
521         }
522     }
523 }