/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.testing.sdo; import commonj.sdo.ChangeSummary; import commonj.sdo.DataObject; import commonj.sdo.Property; import commonj.sdo.Sequence; import commonj.sdo.helper.CopyHelper; import commonj.sdo.helper.DataFactory; import commonj.sdo.helper.EqualityHelper; import commonj.sdo.helper.HelperContext; import commonj.sdo.helper.TypeHelper; import commonj.sdo.helper.XMLDocument; import commonj.sdo.helper.XMLHelper; import commonj.sdo.helper.XSDHelper; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.eclipse.persistence.sdo.SDOChangeSummary; import org.eclipse.persistence.sdo.SDOConstants; import org.eclipse.persistence.sdo.SDODataObject; import org.eclipse.persistence.sdo.SDOProperty; import org.eclipse.persistence.sdo.SDOSequence; import org.eclipse.persistence.sdo.SDOSetting; import org.eclipse.persistence.sdo.SDOType; import org.eclipse.persistence.sdo.ValueStore; import org.eclipse.persistence.sdo.helper.SDOClassLoader; import org.eclipse.persistence.sdo.helper.SDODataHelper; import org.eclipse.persistence.sdo.helper.SDOHelperContext; import org.eclipse.persistence.sdo.helper.SDOTypeHelper; import org.eclipse.persistence.sdo.helper.SDOXMLHelper; import org.eclipse.persistence.sdo.helper.SDOXSDHelper; import commonj.sdo.Type; import commonj.sdo.impl.HelperProvider; import org.eclipse.persistence.Version; import org.eclipse.persistence.logging.AbstractSessionLog; import org.eclipse.persistence.platform.xml.XMLComparer; import static org.eclipse.persistence.sdo.SDOConstants.*; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class SDOTestCase extends junit.framework.TestCase { static { System.setProperty("user.timezone", "Canada/Eastern"); } public boolean useLogging = false; public boolean ignoreCRLF = false; public boolean customContext = false; public boolean loggingLevelFinest = false; public HelperContext aHelperContext; public TypeHelper typeHelper; public XMLHelper xmlHelper; public XSDHelper xsdHelper; public EqualityHelper equalityHelper; public CopyHelper copyHelper; public DataFactory dataFactory; public SDODataHelper dataHelper; public DocumentBuilder parser; public String classgenCompilePath; public String tempFileDir; public SDOXMLComparer xmlComparer; protected static final String USER_DIR = System.getProperty("user.dir").replace('\\', '/'); protected static final String FILE_PROTOCOL = USER_DIR.startsWith("/")? "file:" : "file:/"; protected static final String HTTP_PROTOCOL = "http://"; protected static final String NON_DEFAULT_JAVA_PACKAGE_DIR = "org/example"; protected static final String NON_DEFAULT_JAVA_PACKAGE_NAME = "org.example"; protected static final String NON_DEFAULT_URI = "http://www.example.org"; public SDOTestCase(String name) { super(name); useLogging = Boolean.getBoolean("useLogging"); ignoreCRLF = Boolean.getBoolean("ignoreCRLF"); customContext = Boolean.getBoolean("customContext"); loggingLevelFinest = Boolean.getBoolean("loggingLevelFinest"); classgenCompilePath = System.getProperty("sdo.classgen.compile.path"); tempFileDir = System.getProperty("tempFileDir"); if(null == tempFileDir || tempFileDir.length() < 1) { tempFileDir = "."; } if (loggingLevelFinest && AbstractSessionLog.getLog().getLevel() != AbstractSessionLog.FINEST) { // override default INFO logging level for static logs AbstractSessionLog.getLog().setLevel(AbstractSessionLog.FINEST); AbstractSessionLog.getLog().log(AbstractSessionLog.FINEST, "{0} {1}", // new Object[] {Version.getProduct(), Version.getVersionString()}, false); } // reverse the flags so that a false(from the flag not found) will not // default to a static context } public void setUp() { xmlComparer = new SDOXMLComparer(); if (customContext) { // default to instance of a HelperContext aHelperContext = new SDOHelperContext(); } else { // default to static context (Global) aHelperContext = HelperProvider.getDefaultContext(); } typeHelper = aHelperContext.getTypeHelper(); xmlHelper = aHelperContext.getXMLHelper(); xsdHelper = aHelperContext.getXSDHelper(); equalityHelper = aHelperContext.getEqualityHelper(); copyHelper = aHelperContext.getCopyHelper(); dataFactory = aHelperContext.getDataFactory(); // TODO: we should be using the DataHelper interface dataHelper = (SDODataHelper)aHelperContext.getDataHelper(); DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); builderFactory.setNamespaceAware(true); builderFactory.setIgnoringElementContentWhitespace(true); try { parser = builderFactory.newDocumentBuilder(); } catch (Exception e) { fail("Could not create parser."); e.printStackTrace(); } ((SDOTypeHelper) typeHelper).reset(); ((SDOXMLHelper) xmlHelper).reset(); ((SDOXSDHelper) xsdHelper).reset(); } public void tearDown() throws Exception { ((SDOTypeHelper) typeHelper).reset(); ((SDOXMLHelper) xmlHelper).reset(); ((SDOXSDHelper) xsdHelper).reset(); typeHelper = null; xmlHelper = null; xsdHelper = null; equalityHelper = null; copyHelper = null; dataFactory = null; parser = null; aHelperContext = null; } public void assertXMLIdentical(Document control, Document test) { boolean isEqual = xmlComparer.isNodeEqual(control, test); String controlString = ""; String testString = ""; if (!isEqual) { org.eclipse.persistence.platform.xml.XMLTransformer t = org.eclipse.persistence.platform.xml.XMLPlatformFactory.getInstance().getXMLPlatform().newXMLTransformer(); java.io.StringWriter controlWriter = new java.io.StringWriter(); t.transform(control, controlWriter); t = org.eclipse.persistence.platform.xml.XMLPlatformFactory.getInstance().getXMLPlatform().newXMLTransformer(); java.io.StringWriter testWriter = new java.io.StringWriter(); t.transform(test, testWriter); controlString = controlWriter.toString(); testString = testWriter.toString(); } assertTrue("Documents are not equal.\nCONTROL:\n" + controlString + "\nTEST:\n" + testString, isEqual); } public void assertSchemaIdentical(Document control, Document test) { assertTrue("Node " + control + " is not equal to node " + test, xmlComparer.isSchemaEqual(control, test)); } public String getName() { String longClassName = getClass().getName(); String shortClassName = longClassName.substring(longClassName.lastIndexOf(".") + 1, longClassName.length() - 1); return shortClassName + SDO_XPATH_NS_SEPARATOR_FRAGMENT + super.getName(); } protected void log(String string) { if (useLogging) { System.out.println(string); } } protected void log(List items) { if (useLogging) { for (int i = 0; i < items.size(); i++) { log(items.get(i)); } } } protected void log(Object object) { if (useLogging) { if (object instanceof Type) { log((Type) object); } else { System.out.println(object.toString()); } } } protected void log(Type type) { if (useLogging) { System.out.println(type.getURI()); System.out.println(type.getName()); } } public String getSchema(String fileName) { String xsdSchema = EMPTY_STRING; FileInputStream is = null; try { is = new FileInputStream(fileName); return getSchema(is, fileName); } catch (Exception e) { log(getClass().toString() + ": Reading error for : " + fileName + " message: " + e.getClass() + " " + e.getMessage()); } finally { try { if (null != is) { is.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return xsdSchema; } public String getSchema(InputStream is, String fileName) { String xsdSchema = EMPTY_STRING; try { byte[] bytes = new byte[is.available()]; is.read(bytes); xsdSchema = new String(bytes); log(xsdSchema); return xsdSchema; } catch (Exception e) { log(getClass().toString() + ": Reading error for : " + fileName + " message: " + e.getClass() + " " + e.getMessage()); } finally { try { if (null != is) { is.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return xsdSchema; } /* Tree specific algorithms to aide in testing */ /** * Return the depth of this dataObject from it's root * * @return int */ public int depth(DataObject aChild) { if (null == aChild.getContainer()) { // base case return 0; } else { // recursive case return 1 + depth(aChild.getContainer()); } } // diff function required /** * Return an ArrayList of all the DataObjects in the tree in a preOrder * fashion */ public List<DataObject> preOrderTraversalDataObjectList(SDODataObject currentDO) { return preOrderTraversalDataObjectList(currentDO, new ArrayList<DataObject>(), false, true); } public List<DataObject> preOrderTraversalDataObjectList(DataObject currentDO) { return preOrderTraversalDataObjectList((SDODataObject) currentDO, new ArrayList<DataObject>(), false, true); } /** * Return an ArrayList of all the DataObjects (including unset ones) in the * tree in a preOrder fashion */ public List<DataObject> preOrderTraversalDataObjectList(SDODataObject currentDO, boolean countNullObjects) { return preOrderTraversalDataObjectList(currentDO, new ArrayList<DataObject>(), countNullObjects, true); } private List<DataObject> preOrderTraversalDataObjectList(SDODataObject currentDO, ArrayList<DataObject> currentList, boolean countNullObjects, boolean recurse) { if (currentDO != null) { // add yourself currentList.add(currentDO); // check DO's recursively List instanceProperties = currentDO.getInstanceProperties(); SDOProperty nextProperty = null; Object value = null; if (recurse) { for (int i = 0; i < instanceProperties.size(); i++) { nextProperty = (SDOProperty) instanceProperties.get(i); value = currentDO.get(nextProperty); boolean recurseHopefullyNotToInfinityPlease = true; if (!nextProperty.getType().isChangeSummaryType() && !nextProperty.getType().isDataType()) { // don't traverse into opposite properties to avoid an // infinite loop if (null != nextProperty.getOpposite()) { recurseHopefullyNotToInfinityPlease = false; } if (nextProperty.isMany()) { // iterate list Object manyItem; // use of delete while using an iterator will // generate a ConcurrentModificationException for (int index = 0; index < ((List) value).size(); index++) { manyItem = ((List) value).get(index); if (manyItem != null && manyItem instanceof SDODataObject) { preOrderTraversalDataObjectList((SDODataObject) manyItem, currentList, countNullObjects, recurseHopefullyNotToInfinityPlease); } } } else { if (value != null) { preOrderTraversalDataObjectList((SDODataObject) value, currentList, countNullObjects, recurseHopefullyNotToInfinityPlease); } } } } } } else { if (countNullObjects) { currentList.add(currentDO); } } return currentList; } protected void assertCreated(DataObject dataObject, ChangeSummary changeSummary) { assertTrue(changeSummary.isCreated(dataObject)); assertFalse(changeSummary.isModified(dataObject)); assertFalse(changeSummary.isDeleted(dataObject)); // if we are at the root then there is no parent to track if (null != dataObject.getContainer()) { // check that parent (if not the root) sequence has been saved in // originalSequences (if dataObject is not an attribute - which it // is not) if (dataObject.getContainer().getSequence() != null) { assertNotNull(changeSummary.getOldSequence(dataObject.getContainer())); } else { assertNull(changeSummary.getOldSequence(dataObject.getContainer())); } } assertEquals(0, changeSummary.getOldValues(dataObject).size()); } protected void assertModified(DataObject dataObject, ChangeSummary changeSummary) { assertFalse(changeSummary.isCreated(dataObject)); assertTrue(changeSummary.isModified(dataObject)); assertFalse(changeSummary.isDeleted(dataObject)); } protected void assertChildrenUnset(DataObject dataobject) { // verify all properties are unset and all many properties are size 0 Iterator anIterator = dataobject.getType().getProperties().iterator(); while (anIterator.hasNext()) { Property aProperty = (Property) anIterator.next(); Object aPropertyValue = dataobject.get(aProperty); assertFalse(dataobject.isSet(aProperty)); // all properties must be unset if (aProperty.isMany()) { assertSame(((List) aPropertyValue).size(), 0); } else { if(!aProperty.getType().isDataType()) { assertEquals(aProperty.getDefault(),aPropertyValue); // assertSame(aProperty.getDefault(), dataobject.get(aProperty)); } else { // JIRA-253: we return a wrapped numeric primitive when it has no default Type aType = aProperty.getType(); if (aType.equals(SDO_BOOLEAN)) { assertEquals(false, ((Boolean)aPropertyValue).booleanValue()); } else if (aType.equals(SDO_BYTE)) { assertEquals(0, ((Byte)aPropertyValue).byteValue()); } else if (aType.equals(SDO_CHARACTER)) { assertEquals(0, ((Character)aPropertyValue).charValue()); } else if (aType.equals(SDO_DOUBLE)) { assertEquals(0, ((Double)aPropertyValue).doubleValue()); } else if (aType.equals(SDO_FLOAT)) { assertEquals(0, ((Float)aPropertyValue).floatValue()); } else if (aType.equals(SDO_INT)) { assertEquals(0, ((Integer)aPropertyValue).intValue()); } else if (aType.equals(SDO_SHORT)) { assertEquals(0, ((Short)aPropertyValue).shortValue()); } else if (aType.equals(SDO_LONG)) { assertEquals(0, ((Long)aPropertyValue).longValue()); } } } } } protected void assertDeleted(DataObject dataobject, ChangeSummary changeSummary) { assertDeleted(dataobject, changeSummary, true, false, false); } protected void assertDeleted(DataObject dataobject, ChangeSummary changeSummary, boolean nullContainer) { assertDeleted(dataobject, changeSummary, nullContainer, false, false); } // for objects that were detached and then (re)set - their container and cs // will not be null but they will have oldSettings/deletedList items protected void assertDeleted(DataObject dataObject, ChangeSummary changeSummary, boolean nullContainer, boolean testLoadSave) { assertDeleted(dataObject, changeSummary, nullContainer, false, testLoadSave); assertChildrenUnset(dataObject); } protected void assertDeleted(DataObject dataObject, ChangeSummary changeSummary, boolean nullContainer, boolean isReAttached, boolean testLoadSave) { assertFalse(changeSummary.isCreated(dataObject)); assertFalse(changeSummary.isModified(dataObject)); if (!isReAttached) { assertTrue(((SDOChangeSummary) changeSummary).isDeleted(dataObject)); if (dataObject.getSequence() != null) { assertNotNull(changeSummary.getOldSequence(dataObject)); } else { assertNull(changeSummary.getOldSequence(dataObject)); } } else { assertFalse(((SDOChangeSummary) changeSummary).isDeleted(dataObject)); } int propertySize = dataObject.getType().getProperties().size(); int oldValuesSize = changeSummary.getOldValues(dataObject).size(); assertEquals(propertySize, oldValuesSize); // for objects that were detached and then (re)set - their container and // cs will not be null but they will have oldSettings/deletedList items if (nullContainer) { assertNull(dataObject.getContainer()); // verify that the cs is not set on deleted/detached objects assertNull(dataObject.getChangeSummary()); } assertChildrenUnset(dataObject); } // detached objects' properties are intact and not unset protected void assertDetached(DataObject dataobject, ChangeSummary changeSummary) { assertDetached(dataobject, changeSummary, true, false, false); } // we delete/detach and then (Re)set - deletedSet is cleared but oldSettings // remain (for now until we have smart undo code) protected void assertDetachedAndReset(DataObject dataobject, ChangeSummary changeSummary, boolean nullContainment) { assertDetached(dataobject, changeSummary, nullContainment, true, false); } protected void assertDetached(DataObject dataobject, ChangeSummary changeSummary, boolean nullContainment) { assertDetached(dataobject, changeSummary, nullContainment, false, false); } protected void assertDetached(DataObject dataobject, ChangeSummary changeSummary, boolean nullContainment, boolean isReAttached) { assertDetached(dataobject, changeSummary, nullContainment, isReAttached, false); } // isReAttached means that the property was detached and then (re)set - no // deletedSet entry but oldSettings remain protected void assertDetached(DataObject dataobject, ChangeSummary changeSummary, boolean nullContainment, boolean isReAttached, boolean testLoadSave) { assertFalse(changeSummary.isCreated(dataobject)); assertFalse(changeSummary.isModified(dataobject)); if (!isReAttached) { assertTrue(((SDOChangeSummary) changeSummary).isDeleted(dataobject)); } else { assertFalse(((SDOChangeSummary) changeSummary).isDeleted(dataobject)); } int propertySize = dataobject.getType().getProperties().size(); int oldValuesSize = changeSummary.getOldValues(dataobject).size(); assertEquals(propertySize, oldValuesSize); // for objects that were detached and then (re)set - their container and // cs will not be null but they will have oldSettings/deletedList items if (nullContainment) { assertNull(dataobject.getContainer()); // verify that the cs is not set on deleted/detached objects assertNull(dataobject.getChangeSummary()); } } protected void assertUnchanged(DataObject dataobject, ChangeSummary changeSummary) { assertFalse(changeSummary.isCreated(dataobject)); assertFalse(changeSummary.isModified(dataobject)); assertFalse(changeSummary.isDeleted(dataobject)); assertEquals(0, changeSummary.getOldValues(dataobject).size()); } // inOrderNodeList, preOrderNodeList, postOrderNodeList // function to monitor actual values inside the oldSetting HashMap protected void checkOldSettingsValues(String values, SDOChangeSummary aCS, List dataObjectList) { SDODataObject aDataObject = null; for (int i = 0; i < dataObjectList.size(); i++) { aDataObject = (SDODataObject) dataObjectList.get(i); assertEquals(Integer.parseInt(values.substring(i, i + 1)), aCS.getOldValues(aDataObject).size()); } } protected void checkOldContainers(SDOChangeSummary aCS,// List dataObjectChildList, List dataObjectContainerList) {// we need // generics here SDODataObject aChildDataObject = null; SDODataObject aContainerDataObject = null; for (int i = 0; i < dataObjectChildList.size(); i++) { aChildDataObject = (SDODataObject) dataObjectChildList.get(i); aContainerDataObject = (SDODataObject) dataObjectContainerList.get(i); assertEquals(aChildDataObject, aCS.getOldContainer(aContainerDataObject)); } } /* * ChangeSummary specific functions for undoChanges */ /** * * @param currentDO * @param isCSonAncestor */ public void assertChangeSummaryStatusIfClearedIfCSIsAncestor(DataObject currentDO, boolean isCSonAncestor) { if (currentDO != null) { // check current DO if (isCSonAncestor) { assertNull(((SDODataObject) currentDO).getChangeSummary()); } else { assertNotNull(((SDODataObject) currentDO).getChangeSummary()); } // check DO's recursively List instanceProperties = currentDO.getInstanceProperties(); for (int i = 0; i < instanceProperties.size(); i++) { SDOProperty nextProperty = (SDOProperty) instanceProperties.get(i); Object value = currentDO.get(nextProperty); if (!nextProperty.getType().isChangeSummaryType() && !nextProperty.getType().isDataType() && value != null) { if (nextProperty.isMany()) { // iterate list Object manyItem; // use of delete while using an iterator will generate a // ConcurrentModificationException for (int index = 0; index < ((List) value).size(); index++) { manyItem = ((List) value).get(index); if (manyItem != null) { assertChangeSummaryStatusIfClearedIfCSIsAncestor((SDODataObject) manyItem, isCSonAncestor); } } } else { assertChangeSummaryStatusIfClearedIfCSIsAncestor((SDODataObject) value, isCSonAncestor); } } } } } /** * * @param aChangeSummary * @param undoneDO * @param originalDO */ protected void assertUndoChangesEqualToOriginal(ChangeSummary aChangeSummary,// DataObject undoneDO, DataObject originalDO) { // get logging flag before boolean loggingStateBefore = aChangeSummary.isLogging(); aChangeSummary.undoChanges(); assertTrue(loggingStateBefore == aChangeSummary.isLogging()); // verify that the model has been returned to its original base state assertTrue(equalityHelper.equal(undoneDO, originalDO)); // the objects are deep copies of each other but not the actual same // purchase order assertFalse(undoneDO == originalDO); // verify that CS is cleared but logging is unchanged assertTrue(aChangeSummary.getChangedDataObjects().size() == 0); assertTrue(aChangeSummary.getOldValues(undoneDO).size() == 0); assertTrue(aChangeSummary.getOldValues(originalDO).size() == 0); } /** * * @param aRootObject */ // test undo when logging is off (with previous changes) protected void assertValueStoresInitializedAfterLoggingOn(DataObject aRootObject) { // verify logging is on assertTrue(aRootObject.getChangeSummary().isLogging()); // verify original VS is null and save a copy of current VS for object // identity testing after undo ValueStore aCurrentValueStore = ((SDODataObject) aRootObject)._getCurrentValueStore(); assertNotNull(aCurrentValueStore); ValueStore anOriginalValueStore = (ValueStore) ((SDOChangeSummary) aRootObject.getChangeSummary()).getOriginalValueStores().get(aRootObject); assertNull(anOriginalValueStore); } /** * * @param aRootObject * @param aCurrentValueStoreAfterLoggingFirstOnParam */ protected void assertValueStoresCopiedAndSwappedAfterFirstModifyOperation(DataObject aRootObject, ValueStore aCurrentValueStoreAfterLoggingFirstOnParam) { // verify logging is on assertTrue(aRootObject.getChangeSummary().isLogging()); assertNotNull(aCurrentValueStoreAfterLoggingFirstOnParam); ValueStore anOriginalValueStoreAfterOperation = (ValueStore) ((SDOChangeSummary) aRootObject.getChangeSummary()).getOriginalValueStores().get(aRootObject); ValueStore aCurrentValueStoreAfterOperation = ((SDODataObject) aRootObject)._getCurrentValueStore(); assertNotNull(anOriginalValueStoreAfterOperation); assertNotNull(aCurrentValueStoreAfterOperation); assertTrue(anOriginalValueStoreAfterOperation == aCurrentValueStoreAfterLoggingFirstOnParam); } protected void assertSequencesCopiedAndSwappedAfterFirstModifyOperation(DataObject aRootObject, Sequence aCurrentSequenceAfterLoggingFirstOnParam) { // verify logging is on assertTrue(aRootObject.getChangeSummary().isLogging()); assertNotNull(aCurrentSequenceAfterLoggingFirstOnParam); Sequence anOriginalSequenceAfterOperation = (Sequence) ((SDOChangeSummary) aRootObject.getChangeSummary()).getOriginalSequences().get(aRootObject); Sequence aCurrentSequenceAfterOperation = ((SDODataObject) aRootObject).getSequence(); assertNotNull(anOriginalSequenceAfterOperation); assertNotNull(aCurrentSequenceAfterOperation); assertTrue(anOriginalSequenceAfterOperation == aCurrentSequenceAfterLoggingFirstOnParam); } /** * * @param aRootObject * @param aCurrentValueStoreAfterLoggingFirstOnParam */ protected void assertValueStoresReturnedToStartStateAfterUndoChanges(DataObject aRootObject, ValueStore aCurrentValueStoreAfterLoggingFirstOnParam) { // verify logging is on assertTrue(aRootObject.getChangeSummary().isLogging()); ValueStore anOriginalValueStoreAfterUndo = (ValueStore) ((SDOChangeSummary) aRootObject.getChangeSummary()).getOriginalValueStores().get(aRootObject); ValueStore aCurrentValueStoreAfterUndo = ((SDODataObject) aRootObject)._getCurrentValueStore(); assertNull(anOriginalValueStoreAfterUndo); assertNotNull(aCurrentValueStoreAfterUndo); // we return the original value store back to the current VS assertTrue(aCurrentValueStoreAfterUndo == aCurrentValueStoreAfterLoggingFirstOnParam); } /** * * @param aRootObject * @param aCurrentSequenceAfterLoggingFirstOnParam */ protected void assertSequencesReturnedToStartStateAfterUndoChanges(DataObject aRootObject, Sequence aCurrentSequenceAfterLoggingFirstOnParam) { // verify logging is on assertTrue(aRootObject.getChangeSummary().isLogging()); SDOSequence anOriginalSequenceAfterUndo = (SDOSequence) ((SDOChangeSummary) aRootObject.getChangeSummary()).getOriginalSequences().get(aRootObject); SDOSequence aCurrentSequenceAfterUndo = (SDOSequence) ((SDODataObject) aRootObject).getSequence(); assertNull(anOriginalSequenceAfterUndo); assertNotNull(aCurrentSequenceAfterUndo); // we return the sequence back to the current VS assertEquals(aCurrentSequenceAfterUndo.size(), aCurrentSequenceAfterLoggingFirstOnParam.size()); assertTrue(compareSequences(aCurrentSequenceAfterUndo, (SDOSequence) aCurrentSequenceAfterLoggingFirstOnParam, true)); } /** * INTERNAL: Return whether the 2 sequences are equal. Element properties * and unstructured text will be compared - attributes are out of scope. * <p> * For shallow equal - only dataType=true objects are compared, DataObject * values are ignored but should be defaults. Note: A setting object should * handle its own isEqual() behavior * * @param aSequence * @param aSequenceCopy * @param isDeep * @return */ public boolean compareSequences(SDOSequence aSequence, SDOSequence aSequenceCopy, boolean isDeep) { // corner case: isSequenced set to true after type definition had not // sequence if (null == aSequence && null == aSequenceCopy) { return true; } // both sequences must be null if (null == aSequence || null == aSequenceCopy) { return false; } // for shallow equal - match whether we skipped creating settings or set // value=null for shallow copies if (aSequence.size() != aSequenceCopy.size()) { return false; } // the settings inside the sequence must be new objects SDOSetting originalSetting = null; SDOSetting copySetting = null; List originalSettingsList = aSequence.getSettings(); List copySettingsList = aSequenceCopy.getSettings(); if (null == originalSettingsList || null == copySettingsList) { return false; } Property originalProperty = null; Property copyProperty = null; /** * For shallow equal when dataType is false we do not check this * setting, the value will be unset (default value) in the shallow copy. * orig v1=String v2=DataObject v3=String shallowcopy v1=String * v2=null(default) v3=String deepcopy v1=String v2=DataObject v3=String */ for (int index = 0, size = aSequence.size(); index < size; index++) { originalSetting = (SDOSetting) originalSettingsList.get(index); copySetting = (SDOSetting) copySettingsList.get(index); originalProperty = originalSetting.getProperty(); copyProperty = copySetting.getProperty(); // we must handle null properties that represent unstructured text // both null = unstructured // one null = invalid state (return not equal) // both !null = valid state (check equality) if ((null == originalProperty && null != copyProperty) || (null != originalProperty && null == copyProperty)) { return false; } // the property field on the setting must point to the same property // instance as the original // handle both properties == null if (originalProperty != copyProperty) { return false; } Object originalValue = originalSetting.getValue(); Object copyValue = copySetting.getValue(); // for unstructuredText (null property) and simple dataTypes we // check equality directly if (null == originalProperty || originalProperty.getType().isDataType()) { // if one of the values is null return false if (((null == originalValue) && (null != copyValue)) || // ((null != originalValue) && (null == copyValue))) { return false; } // if both values are null - they are equal // we can also use !.equals if ((null != originalValue) && !originalValue.equals(copyValue)) { return false; } } else { // For complex types // we do not need to check deep equality on dataObjects twice // here, just check instances // because the dataObject compare will iterate all the // properties of each dataObject // only compare DataObjects when in a deep equal if (isDeep) { if (null != originalValue && null != copyValue) { // setting.isSet is ignored for sequences // perform a deep equal on the single item // the values may not match their types - return false // instead of a CCE if (originalValue instanceof DataObject && copyValue instanceof DataObject) { if (!equalityHelper.equal((DataObject) originalValue, (DataObject) copyValue)) { return false; } } else { return false; } } else { // both values must be null to be equal if ((null == originalValue && null != copyValue) || (null == copyValue && null != originalValue)) { return false; } } } else { /** * For DataObjects in general anything that is deep equal is * also shallow equal - but not the reverse. In the case of * shallow equal on sequences. We can ignore the state of * the 2 complex objects. UC1: if aSequenceCopy setting was * from a shallowCopy then it will be unset. UC2: if * aSequenceCopy setting was from a deepCopy or a reversed * argument shallowCopy then it may be unset or set. We will * not check for a default value on either sequence setting. */ } } } return true; } /** * Remove CR\LF=13\10 from source and target strings so that we can run the * suite on windows without assertEquals() failing. Use the system property * -DignoreCRLF=true * * @param control * @param test * @param removeCRLF * void * */ protected DataObject addProperty(DataObject parentType, String name, Type propType) { DataObject newProperty = parentType.createDataObject("property"); SDOProperty prop = (SDOProperty) newProperty.getType().getProperty("name"); newProperty.set(prop, name); prop = (SDOProperty) newProperty.getType().getProperty("type"); newProperty.set(prop, propType); return newProperty; } /** * * @param parentType * @param name * @param propType * @param isContainment * @return */ protected DataObject addProperty(DataObject parentType, String name, Type propType, boolean isContainment) { DataObject newProperty = addProperty(parentType, name, propType); newProperty.setBoolean(CONTAINMENT, isContainment); return newProperty; } /** * * @param parentType * @param name * @param propType * @param isContainment * @param isMany * @return */ protected DataObject addProperty(DataObject parentType, String name, Type propType, boolean isContainment, boolean isMany) { DataObject newProperty = addProperty(parentType, name, propType, isContainment); newProperty.setBoolean(SDOXML_MANY, isMany); return newProperty; } protected DataObject addProperty(DataObject parentType, String name, Type propType, boolean isContainment, boolean isMany, boolean isElement) { DataObject newProperty = addProperty(parentType, name, propType, isContainment, isMany); if (isElement) { newProperty.set(XMLELEMENT_PROPERTY, true); } return newProperty; } protected DataObject addProperty(DataObject parentType, String name, DataObject propTypeDO, boolean isContainment, boolean isMany, boolean isElement) { DataObject newProperty = parentType.createDataObject("property"); SDOProperty prop = (SDOProperty) newProperty.getType().getProperty("name"); newProperty.set(prop, name); prop = (SDOProperty) newProperty.getType().getProperty("type"); newProperty.set(prop, propTypeDO); newProperty.setBoolean(CONTAINMENT, isContainment); if (isElement) { newProperty.set(XMLELEMENT_PROPERTY, true); } return newProperty; } /** * Set the oc prop containing the idProp property - for unidirectional/bidirectional relationships */ public void setIDPropForReferenceProperties(DataObject doType, Object idProp) { // get the global property referencing the idProp property doType.set(ID_PROPERTY, idProp); } /** * INTERNAL: * Get the reference ID open content Property if it exists for this Type. * @return id Property or null */ public SDOProperty getIDProp(Type aType) { return (SDOProperty)aType.getProperty((String)aType.get(SDOConstants.ID_PROPERTY)); } /** * * @param uri * @param name * @return */ protected DataObject defineType(String uri, String name) { DataObject newType = aHelperContext.getDataFactory().create(SDO_URL, TYPE); newType.set("uri", uri); newType.set("name", name); return newType; } public HelperContext getHelperContext() { return aHelperContext; } public void setHelperContext(HelperContext helperContext) { aHelperContext = helperContext; } protected void assertEqualsBytes(byte[] controlBytes, byte[] bytes) { if (controlBytes.length != bytes.length) { fail("Expected:" + log(controlBytes) + " but was:" + log(bytes)); } for (int i = 0; i < controlBytes.length; i++) { if (controlBytes[i] != bytes[i]) { fail("Expected:" + log(controlBytes) + " but was:" + log(bytes)); } } } protected String log(byte[] bytes) { String s = new String(); for (int i = 0; i < bytes.length; i++) { s += bytes[i]; } return s; } protected Document getDocument(String fileName) { InputStream inputStream = null; try{ inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName); return getDocument(inputStream); } catch (Exception e) { e.printStackTrace(); fail("An error occurred loading the control document:" + fileName); return null; } finally { try { if (null != inputStream) { inputStream.close(); } } catch (Exception e2) { e2.printStackTrace(); } } } protected Document getDocument(InputStream inputStream) { try { Document document = parser.parse(inputStream); inputStream.close(); return document; } catch (Exception e) { e.printStackTrace(); fail("An error occurred loading the control document:"); // + inputStream.); return null; } finally { try { if (null != inputStream) { inputStream.close(); } } catch (Exception e2) { e2.printStackTrace(); } } } public void assertStringsEqual(String controlString, String generatedString) { String controlString2 = removeCRLFfromString(controlString); String generatedString2 = removeCRLFfromString(generatedString); // Allow Windows generated java code to pass comparison as well as Linux generated ones // if (ignoreCRLF) { assertEquals(controlString2, generatedString2); // } else { // assertEquals(controlString, generatedString); // } } protected void removeEmptyTextNodes(Node node) { NodeList nodeList = node.getChildNodes(); Node childNode; for (int x = nodeList.getLength() - 1; x >= 0; x--) { childNode = nodeList.item(x); if (childNode.getNodeType() == Node.TEXT_NODE) { if (childNode.getNodeValue().trim().equals("")) { node.removeChild(childNode); } } else if (childNode.getNodeType() == Node.ELEMENT_NODE) { removeEmptyTextNodes(childNode); } } } protected String removeWhiteSpaceFromString(String s) { String returnString = s.replaceAll(" ", ""); returnString = returnString.replaceAll("\n", ""); returnString = returnString.replaceAll("\t", ""); returnString = returnString.replaceAll("\r", ""); return returnString; } protected String removeCRLFfromString(String s) { String returnString = s.replaceAll("\n", ""); returnString = returnString.replaceAll("\t", ""); returnString = returnString.replaceAll("\r", ""); return returnString; } /** * Write to the output stream and return a success flag if no exceptions * thrown * * @param anObject * @param uri * @param typename * @param aStream * @return success flag */ public boolean writeXML(DataObject anObject, String uri, String typename, OutputStream aStream) { boolean success = true; // verify save if (useLogging) { try { xmlHelper.save(anObject, uri, typename, aStream); } catch (Exception e) { System.out.println("Exception: " + e.getMessage()); e.printStackTrace(); success = false; } } return success; } public DataObject loadXML(String filename, boolean resetChangeSummary) { DataObject anObject = null; try { XMLDocument document = xmlHelper.load(new FileInputStream(filename)); anObject = document.getRootObject(); // leave the cs alone? if (resetChangeSummary) { ChangeSummary aCS = anObject.getChangeSummary(); if (aCS != null) { aCS.endLogging(); } } } catch (Exception e) { e.printStackTrace(); fail("_Error: SDOTestSuite.loadXML(): An error occurred loading the xml file " + filename); } return anObject; } protected void emptyAndDeleteDirectory(File f) { if (f.isDirectory()) { File[] files = f.listFiles(); for (int i = 0; i < files.length; i++) { File next = files[i]; if (next.isDirectory()) { emptyAndDeleteDirectory(next); } else { next.delete(); } } f.delete(); } } protected void deleteDirsOnExit(File f) { if (f.isDirectory()) { File[] files = f.listFiles(); for (int i = 0; i < files.length; i++) { File next = files[i]; if (next.isDirectory()) { deleteDirsOnExit(next); } else { next.deleteOnExit(); } } f.deleteOnExit(); } } protected String getClassPathForCompile(){ return classgenCompilePath; } }