/******************************************************************************* | |
* Copyright (c) 1998, 2013 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) { | |
FileInputStream inputStream = null; | |
try{ | |
inputStream = new FileInputStream(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; | |
} | |
} |