/*
 * Copyright (c) 1998, 2021 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 v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.testing.sdo.model.sequence;

import commonj.sdo.ChangeSummary;
import commonj.sdo.DataObject;
import commonj.sdo.Property;
import commonj.sdo.Sequence;
import commonj.sdo.Type;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import junit.textui.TestRunner;
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.SDOType;
import org.eclipse.persistence.sdo.helper.DefaultSchemaLocationResolver;
import org.eclipse.persistence.sdo.helper.ListWrapper;
import org.eclipse.persistence.sdo.helper.SDOXSDHelper;
import org.eclipse.persistence.exceptions.SDOException;

public class SDOSequenceTestCS extends SDOSequenceTestCases {

    public static final String URINAME = "http://www.example.org";
    public static final String COMPANY_TYPENAME = "Company";
    public static final String PO_TYPENAME = "PurchaseOrder";
    public static final String PO_SEQUENCE_PATH = "porder[1]";
    public static final int PO_SEQUENCE_SIZE = 7;
    public static final int PO_SEQUENCE_TREE_SIZE = 7;
    public static final int PO_COMMENT_LIST_SIZE = 2;
    public static final int PO_TREE_SIZE = 5;
    public static final String PO_PATH = "porder";
    public static final String CUSTOMER_PATH = "cust";
    public static final String ITEM_PATH = "item";
    public static final String CUSTOMER_TYPENAME = "Customer";
    public static final String ADDRESS_TYPENAME = "USAddress";
    public static final String ITEM_TYPENAME = "Item";
    public static final String PO_COMMENT_VALUE1 = "comment 1";

    public static final String XML_PATH = "org/eclipse/persistence/testing/sdo/model/sequence/CompanyWithSequenceCS.xml";
    public static final String XSD_PATH = "org/eclipse/persistence/testing/sdo/schemas/CompanyWithSequenceCS.xsd";

    public static final int NO_MATCH_INDEX = -1;

    protected DataObject root;
    protected ChangeSummary cs;
    protected Type stringType;
    protected Type dateType;
    protected Type yearMonthDayType;
    protected Type decimalType;
    protected Type idType;


    public SDOSequenceTestCS(String name) {
        super(name);
    }

    @Override
    public void setUp() {
        super.setUp();
        stringType = typeHelper.getType(SDOConstants.SDO_URL, SDOConstants.STRING);
        dateType = typeHelper.getType(SDOConstants.SDO_URL, SDOConstants.DATE);
        yearMonthDayType = typeHelper.getType(SDOConstants.SDO_URL, SDOConstants.YEARMONTHDAY);
        decimalType = SDOConstants.SDO_DECIMAL;
        idType = typeHelper.getType(SDOConstants.SDO_URL, SDOConstants.ID);
    }

    public static void main(String[] args) {
        String[] arguments = { "-c", "org.eclipse.persistence.testing.sdo.model.sequence.SDOSequenceTestCS" };
        TestRunner.main(arguments);
    }

    protected String getControlRootURI() {
        return URINAME;
    }

    protected String getControlRootName() {
        return "company";
    }

    @Override
    public String getSchemaToDefine() {
        return XSD_PATH;
    }

    @Override
    public String getControlGeneratedFileName() {
        return XSD_PATH;
    }

    @Override
    protected List<Type> getTypesToGenerateFrom() {
        return getControlTypes();
    }

    public static String getXSDString(String filename) {
        try {
            FileInputStream inStream = new FileInputStream(filename);
            byte[] bytes = new byte[inStream.available()];
            inStream.read(bytes);
            return new String(bytes);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * This function will define control types programmatically to compare to XSD definition
     * by using the standard spec SDODataObject generation method on page
     *
     * The existing getControlTypes() uses non-public Property constructors
     */
    public DataObject createRootObject(boolean viaXML, List types) {
        DataObject aRoot = null;
        if(viaXML) {
            aRoot = loadXML(XML_PATH, false);
        } else {
            DataObject cust1 = dataFactory.create(typeHelper.getType(URINAME, CUSTOMER_TYPENAME));
            cust1.set("custID", 5);
            List emails = new ArrayList();
            emails.add("email1-DF@myCompany.com");
            emails.add("email2-DF@myCompany.com");
            cust1.set("email", emails);
            List phones = new ArrayList();
            phones.add("6135550001");
            cust1.set("phone", phones);

            DataObject item1 = dataFactory.create(typeHelper.getType(URINAME, ITEM_TYPENAME));
            item1.set("itemID", 3);
            item1.set("name", "item1-DF");
            DataObject item2 = dataFactory.create(typeHelper.getType(URINAME, ITEM_TYPENAME));
            item2.set("itemID", 6);
            item2.set("name", "item2-DF");
            DataObject item3 = dataFactory.create(typeHelper.getType(URINAME, ITEM_TYPENAME));
            item3.set("itemID", 7);
            item3.set("name", "item3-DF");

            DataObject billTo = dataFactory.create(typeHelper.getType(URINAME, ADDRESS_TYPENAME));
            billTo.set("name", "bill");
            DataObject shipTo = dataFactory.create(typeHelper.getType(URINAME, ADDRESS_TYPENAME));
            shipTo.set("name", "ship");

            DataObject po1 = dataFactory.create(typeHelper.getType(URINAME, PO_TYPENAME));
            po1.set("poID", 10);
            po1.set("shipTo", shipTo);
            po1.set("billTo", billTo);

            // set comments list
            List<String> comments = new ArrayList<String>();
            comments.add(PO_COMMENT_VALUE1);
            comments.add("comment 2");
            po1.set("comment", comments);

            po1.set("orderDate", "1999-10-20");

            // references to company/item
            List<DataObject> itemsRef = new ArrayList<DataObject>();
            itemsRef.add(item2);//6);
            itemsRef.add(item3);//7);
            po1.set("item", itemsRef); // unwrapping exception

            aRoot = dataFactory.create(typeHelper.getType(URINAME, COMPANY_TYPENAME));
            aRoot.set(CUSTOMER_PATH, cust1);
            //aRoot.set(propertyIndex, value)
            // add purchaseOrders
            List<DataObject> pos = new ArrayList<DataObject>();
            pos.add(po1);
            aRoot.set(PO_PATH, pos);

            // add items (containment)
            List<DataObject> items = new ArrayList<DataObject>();
            items.add(item1);
            items.add(item2);
            items.add(item3);
            aRoot.set(ITEM_PATH, items);

            aRoot.set("name", "mycomp-DF");

            SDOChangeSummary aChangeSummary = new SDOChangeSummary();
            // add changeSummary
            aRoot.set("myChangeSummary", aChangeSummary);
        }
        return aRoot;
    }


    private Type defineAndPostProcessUnidirectional(String containingPropertyLocalName, DataObject typeToDefine, //
            String idPropertyName, String containingPropertyName) {
        // define the current type
        Type aType = typeHelper.define(typeToDefine);
        // get the
        Property containingProperty = aType.getProperty(containingPropertyName);
        ((SDOProperty)containingProperty).setXsd(true);
        ((SDOProperty)containingProperty).setXsdLocalName(containingProperty.getContainingType().getName());//containingPropertyLocalName);
//        ((SDOType)aType).setIDProp(aType.getProperty(idPropertyName));
        // set unidirection reference id
        setIDPropForReferenceProperties(typeToDefine, containingPropertyLocalName);

        return aType;
    }

    private Type defineAndPostProcessBidirectional(DataObject typeToDefine, String idPropertyName) {
        Type aType = typeHelper.define(typeToDefine);
        //SDOProperty itemProperty = (SDOProperty)aType.getProperty("item");
        //itemProperty.setXsd(true);
        //((SDOType)aType).setIDProp(aType.getProperty(idPropertyName));
        return aType;
    }

    private Type registerAddressType(boolean sequencedFlag) {
        DataObject addressType = dataFactory.create(SDOConstants.SDO_URL, SDOConstants.TYPE);
        SDOProperty prop = (SDOProperty)addressType.getType().getProperty("uri");
        addressType.set(prop, getControlRootURI());
        prop = (SDOProperty)addressType.getType().getProperty(SDOConstants.SDOXML_NAME);
        addressType.set(prop,  ADDRESS_TYPENAME);

        addProperty(addressType, "name", stringType);
        addProperty(addressType, "street", stringType);
        addProperty(addressType, "city", stringType);
        addProperty(addressType, "state", stringType);
        addProperty(addressType, "zip", decimalType);

        DataObject newProperty = addProperty(addressType, "country", stringType);
        prop = (SDOProperty)newProperty.getType().getProperty("default");
        newProperty.set(prop, "US");
        return typeHelper.define(addressType);
    }

    private Type registerItemType(boolean sequencedFlag) {
        DataObject itemType = dataFactory.create(SDOConstants.SDO_URL, SDOConstants.TYPE);
        SDOProperty prop = (SDOProperty)itemType.getType().getProperty("uri");
        itemType.set(prop, getControlRootURI());
        prop = (SDOProperty)itemType.getType().getProperty(SDOConstants.SDOXML_NAME);
        String typeName = ITEM_TYPENAME;
        String idPropName = "itemID";
        // set unidirection reference id
        setIDPropForReferenceProperties(itemType, "itemID");

        itemType.set(prop, typeName);

        DataObject newProperty = itemType.createDataObject("property");
        SDOProperty aProp = (SDOProperty)newProperty.getType().getProperty(SDOConstants.SDOXML_NAME);
        newProperty.set(aProp, idPropName);
        aProp = (SDOProperty)newProperty.getType().getProperty("type");
        Type idType = typeHelper.getType(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI, "ID");
        newProperty.set(aProp, stringType);     // no ID type to set - use string type
        aProp.setXsd(true);

        addProperty(itemType, "name", stringType);

        Type aType = typeHelper.define(itemType);
        //itemProperty.setXsd(true);
//        ((SDOType)aType).setIDProp(aType.getProperty(idPropName));
        return aType;
    }

    // sequenced
    private Type registerPurchaseOrderType(boolean sequencedFlag, Type addressType, Type itemType, Type customerType) {
         // instance properties available
         // aliasName, name, many, containment, default, readOnly, type, opposite, nullable
        DataObject purchaseOrderTypeDO = dataFactory.create(SDOConstants.SDO_URL, SDOConstants.TYPE);
        SDOProperty prop = (SDOProperty)purchaseOrderTypeDO.getType().getProperty("uri");
        purchaseOrderTypeDO.set(prop, getControlRootURI());
        purchaseOrderTypeDO.set("sequenced", sequencedFlag);
        prop = (SDOProperty)purchaseOrderTypeDO.getType().getProperty(SDOConstants.SDOXML_NAME);
        String typeName = PO_TYPENAME;
        String idPropName = "poID";
        purchaseOrderTypeDO.set(prop, typeName);
        // set unidirection reference id
        setIDPropForReferenceProperties(purchaseOrderTypeDO, "poID");

        // add properties in sequence
        DataObject shipToProp = addProperty(purchaseOrderTypeDO, "shipTo", addressType, true);
        DataObject billToProp = addProperty(purchaseOrderTypeDO, "billTo", addressType, true);
        DataObject commentProp = addProperty(purchaseOrderTypeDO, "comment", stringType, false, true);

        // unidirectional IDREFS
        DataObject itemProp = addProperty(purchaseOrderTypeDO, "item", itemType, false, true);

        DataObject poidProperty = addProperty(purchaseOrderTypeDO, idPropName, stringType, false);
        // !many, !containment and !nullable - we must set one of these so poID can be an element and exist in the sequence
        poidProperty.set("nullable", true); // this statement goes along with the false containment flag above
        addProperty(purchaseOrderTypeDO, "orderDate", yearMonthDayType);

        String containingPropertyName = ITEM_PATH;
        Type aType = defineAndPostProcessUnidirectional(typeName, purchaseOrderTypeDO, idPropName, containingPropertyName);
        return aType;
    }

    // not sequenced
    private Type registerCompanyType(boolean sequencedFlag, Type purchaseOrderType, Type customerType, Type itemType, Type csType) {
        SDOType changeSummaryType = (SDOType) typeHelper.getType(SDOConstants.SDO_URL, SDOConstants.CHANGESUMMARY);

        DataObject companyType = dataFactory.create(SDOConstants.SDO_URL, SDOConstants.TYPE);
        SDOProperty prop = (SDOProperty)companyType.getType().getProperty("uri");
        companyType.set(prop, getControlRootURI());
        companyType.set("sequenced", true);//false);//sequencedFlag); // sequenced is false by default
        //companyType.set("sequenced", true);
        prop = (SDOProperty)companyType.getType().getProperty(SDOConstants.SDOXML_NAME);
        companyType.set(prop,  COMPANY_TYPENAME);

        DataObject name = addProperty(companyType, "name", stringType);
        //name.setInstanceProperty(SDOConstants.XMLELEMENT_PROPERTY, Boolean.TRUE);
        SDOProperty nameProp = (SDOProperty)companyType.getType().getProperty(SDOConstants.XMLELEMENT_PROPERTY_NAME);
        //name.set(SDOConstants.XMLELEMENT_PROPERTY_NAME, false);
        //nameProp.setInstanceProperty(SDOConstants.XMLELEMENT_PROPERTY, Boolean.FALSE);
        DataObject custProp =  addProperty(companyType, CUSTOMER_PATH, customerType, true, false);
        DataObject poProp = addProperty(companyType, PO_PATH, purchaseOrderType, true, true);
        DataObject itemProp = addProperty(companyType, ITEM_PATH, itemType, true, true);

        // changeSummary property
        DataObject changeSumPropertyDO = addProperty(companyType, "myChangeSummary", changeSummaryType);
        changeSumPropertyDO.set("containment", false);

        Type aType = typeHelper.define(companyType);
        return aType;
    }

    @Override
    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;
    }

    private Type registerChangeSummary() {
        DataObject csTypeDO = dataFactory.create(SDOConstants.SDO_URL, SDOConstants.TYPE);
        SDOProperty csProp = (SDOProperty)csTypeDO.getType().getProperty("uri");
        //SDOProperty csProperty = new SDOProperty(aHelperContext);
        //csProperty.setName(name);
        csTypeDO.set(csProp, getControlRootURI());
        //csTypeDO.set("name", "myChangeSummary");
        SDOProperty prop = (SDOProperty)csTypeDO.getType().getProperty(SDOConstants.SDOXML_NAME);
        csTypeDO.set(prop, "myChangeSummary");
        //csTypeDO.set("containment", false);
        SDOProperty typeProp = (SDOProperty)csTypeDO.getType().getProperty("type");//SDOConstants.SDOXML_PROPERTYTYPE);
        Type aType = typeHelper.define(csTypeDO);
        return aType;
    }

    private Type registerCustomerType(boolean sequencedFlag, Type purchaseOrderType) {
        DataObject customerType = dataFactory.create(SDOConstants.SDO_URL, SDOConstants.TYPE);
        SDOProperty prop = (SDOProperty)customerType.getType().getProperty("uri");
        customerType.set("sequenced", true);//sequencedFlag); // sequenced is true by default
        customerType.set(prop, getControlRootURI());
        prop = (SDOProperty)customerType.getType().getProperty(SDOConstants.SDOXML_NAME);
        String typeName = CUSTOMER_TYPENAME;
        String idPropName = "custID";
        String emailPropName = "email";
        String phonePropName = "phone";
        customerType.set(prop, typeName);
        setIDPropForReferenceProperties(customerType, "custID");

        DataObject custEmailProperty = addProperty(customerType, emailPropName, stringType);
        DataObject custPhoneProperty = addProperty(customerType, phonePropName, stringType);

        DataObject custidProperty = addProperty(customerType, idPropName, stringType);
//        DataObject poProp = addProperty(customerType, "purchaseOrder", purchaseOrderType, false, false);
        // post define processing
        String containingPropertyName = "purchaseOrder";
        //Type aType = defineAndPostProcessUnidirectional(typeName, customerType, idPropName, containingPropertyName);
        Type aType = typeHelper.define(customerType);
        return aType;
    }


     // See section 3.8.4 p.41
     // We would like to create at least one test framework that uses the standard createDataObject spec
     // instead of creating Property objects - which uses a non-public public api
    public void registerTypes(boolean sequencedFlag) {
        // pass the sequenced flag to the typeHelper.define() calls so we can create without a sequence
        Type addressType = registerAddressType(sequencedFlag);
        Type itemType = registerItemType(sequencedFlag);
        Type customerType = null;
        Type poType = registerPurchaseOrderType(sequencedFlag, addressType, itemType, customerType);
        customerType = registerCustomerType(sequencedFlag, poType);
        Type csType = registerChangeSummary();
        Type companyType = registerCompanyType(sequencedFlag, poType, customerType, itemType, csType);
    }

    public void registerTypes() {
        registerTypes(true);
    }
    @Override
    public List<Type> getControlTypes() {
        List<Type> types = new ArrayList<Type>();
        if(typeHelper.getType(URINAME, COMPANY_TYPENAME) != null) {
            types.add(typeHelper.getType(URINAME, COMPANY_TYPENAME));
        }
        if(typeHelper.getType(URINAME, PO_TYPENAME) != null) {
            types.add(typeHelper.getType(URINAME, PO_TYPENAME));
        }
        if(typeHelper.getType(URINAME, CUSTOMER_TYPENAME) != null) {
            types.add(typeHelper.getType(URINAME, CUSTOMER_TYPENAME));
        }
        if(typeHelper.getType(URINAME, ADDRESS_TYPENAME) != null) {
            types.add(typeHelper.getType(URINAME, ADDRESS_TYPENAME));
        }
        if(typeHelper.getType(URINAME, ITEM_TYPENAME) != null) {
            types.add(typeHelper.getType(URINAME, ITEM_TYPENAME));
        }
        return types;
    }

    public void setTypeSequenced(String typeName, boolean sequenced) {
        SDOType aType = (SDOType)typeHelper.getType(URINAME, typeName);
        aType.setSequenced(sequenced);
    }

    // use XSD to define and XML to load - sequenced Flag has affect only when defining via typeHelper
    public void defineAndLoadRoot(boolean defineViaXSD, boolean loadViaXML, boolean sequencedFlag) {
            DefaultSchemaLocationResolver resolver = new DefaultSchemaLocationResolver(getMap());
            List<Type> types = null;
            if(defineViaXSD) {
                types = xsdHelper.define(getXSDString(XSD_PATH));
            } else {
                registerTypes(sequencedFlag);
                types = getControlTypes();
            }

            String generatedSchema = ((SDOXSDHelper)xsdHelper).generate(types, resolver);
            //log(generatedSchema);
            root = createRootObject(loadViaXML, types);
            int aRootsize = preOrderTraversalDataObjectList((SDODataObject)root).size();
//            if(!loadViaXML)  {
//                assertTrue(writeXML(root, URINAME, COMPANY_TYPENAME, System.out));
//            }
            assertEquals(10, aRootsize);
        }

    public void defineAndLoadRoot(boolean defineViaXSD, boolean loadViaXML) {
        defineAndLoadRoot(defineViaXSD, loadViaXML, true);
    }
    public void defineAndLoadRoot() {
        defineAndLoadRoot(true, true);
    }


    private SDOSequence getSequence(DataObject aRoot, String sequencePath, int sequenceSize) {
        // get sequence DO
        DataObject dataObject = (DataObject)aRoot.get(sequencePath);
        assertNotNull(dataObject);
        assertTrue(dataObject.getType().isSequenced());
        // get sequence
        SDOSequence aSequence = (SDOSequence)dataObject.getSequence();
        // check sequence
        assertNotNull(aSequence);
        //assertEquals(sequenceSize, aSequence.size());
        return aSequence;
    }

    public int getNthSequenceIndexFor(SDOSequence aSequence, String propertyName) {
        return getNthSequenceIndexFor(aSequence, propertyName, 1);
    }

    public int getNthSequenceIndexFor(SDOSequence aSequence, String propertyName, int matchNumber) {
        // search for the indexed position in the sequence that corresponds to propertyName
        int matchIndex = -1;
        int numberMatches = matchNumber;
        Property aProperty = null;
        // TODO: linear performance hit
        for(int i = 0, size = aSequence.size(); i < size; i++) {
            aProperty = aSequence.getProperty(i);
            // TODO: handle null property for unstructured text
            if(aProperty != null && aProperty.getName().equals(propertyName)) {
                // breakout of loop with this property
                matchIndex = i;
                if(--numberMatches < 1) {
                    i = aSequence.size();
                }
            }
        }
        return matchIndex;
    }

    /**
     * Invoke a get() call to finish the lazy initialization of this map
     */
    public Map verifyOldSequences(SDOChangeSummary aCS) {
        return aCS.getOldSequences();
    }

    /**
     * Invoke a get() call to finish the lazy initialization of this map
     */
    public Map verifyOriginalSequences(SDOChangeSummary aCS) {
        return aCS.getOriginalSequences();
    }

    /**
     * ChangeSummary tests
     */


    public void turnCSon(SDOChangeSummary aCS) {
        assertNotNull(aCS);
        aCS.endLogging();
        aCS.beginLogging();
    }

    public void testAddTextUndoChanges() {
        // make a source object
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        int sequenceSize = aSequence.size();
        DataObject poDO = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(poDO);
        DataObject shipToDO = (DataObject)poDO.get("shipTo");
        assertNotNull(shipToDO);
        List items = (List)poDO.get("item");
        assertNotNull(poDO);
        int listSize = items.size();
        assertEquals(2, listSize);

        // turn on change summary
        SDOChangeSummary aCS = (SDOChangeSummary)root.getChangeSummary();
        turnCSon(aCS);

        // change a sequence that is not tracked by the cs
        aSequence.addText("random text2");

        // verify change
       int newSequenceSize = aSequence.size();
       assertEquals(sequenceSize + 1, newSequenceSize);

        // verify changeSummary not changed
       Map oldSequences = aCS.getOldSequences();
       Map originalSequences = aCS.getOriginalSequences();
       assertEquals(0, oldSequences.size());
       assertEquals(1, originalSequences.size());

        // undo change (nop for untracked items)
       aCS.undoChanges();

        // verify unchange (nop for untracked items)
       assertEquals(sequenceSize + 1, newSequenceSize);

        // verify unChangeSummary (still no changes)
       assertEquals(0, oldSequences.size());
       assertEquals(0, originalSequences.size());
    }

    /**
     * Purpose:
     * Test that the sequence on a move is updated on both the source and target objects
     */
    public void testMoveToCopyAlsoRemovesSequenceSettingOnOriginal() {
        // make a source object
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject poDO = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(poDO);
        DataObject shipToDO = (DataObject)poDO.get("shipTo");
        assertNotNull(shipToDO);

        // make a copy so that we can move between trees
        DataObject rootCopy = copyHelper.copy(root);
        // check sequence was copied
        SDOSequence aPOSequenceCopy = getSequence(rootCopy, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        assertNotNull(aPOSequenceCopy);
        int sequenceCopySizeBeforeDelete = aPOSequenceCopy.size();

        // delete shipTo on target
        DataObject poDOCopy = (DataObject)rootCopy.get(PO_SEQUENCE_PATH);
        assertNotNull(poDO);
        SDODataObject shipToCopy = (SDODataObject)poDOCopy.get("shipTo");
        assertNotNull(shipToCopy);
        shipToCopy.delete();

        // verify that the sequence on the copy has been adjusted
        int sequenceCopySizeAfterDelete = aPOSequenceCopy.size();
        assertEquals(sequenceCopySizeBeforeDelete - 1, sequenceCopySizeAfterDelete);
        // verify that the object was deleted on the copy in prep for a move from the root to this copy
        assertNull(rootCopy.get(PO_SEQUENCE_PATH + "/shipTo"));

        // get shipTo sequence
        int shipToSequenceIndex = getNthSequenceIndexFor(aSequence, "shipTo");
        assertTrue(shipToSequenceIndex > -1);
        DataObject shipToObjectFromSetting = (DataObject)aSequence.getValue(shipToSequenceIndex);
        assertNotNull(shipToObjectFromSetting);
        assertTrue(shipToObjectFromSetting == shipToDO);

        // turn on change summary
        SDOChangeSummary aCSroot = (SDOChangeSummary)root.getChangeSummary();
        turnCSon(aCSroot);
        SDOChangeSummary aCScopy = (SDOChangeSummary)rootCopy.getChangeSummary();
        turnCSon(aCScopy);

        // move shipTo from root to copyRoot
        int sequenceSizeBeforeMove = aSequence.size();
        int sequenceCopySizeBeforeMove = aPOSequenceCopy.size();
        poDOCopy.set("shipTo", shipToDO);

        // verify that the sequence on the copy has been increased and on the original has been decreased
        int sequenceCopySizeAfterMove = aPOSequenceCopy.size();
        int sequenceSizeAfterMove = aSequence.size();
        assertEquals(sequenceCopySizeBeforeMove + 1, sequenceCopySizeAfterMove);
        assertEquals(sequenceSizeBeforeMove - 1, sequenceSizeAfterMove);
        // verify that the object was deleted on the copy in prep for a move from the root to this copy
        assertNull(root.get(PO_SEQUENCE_PATH + "/shipTo"));

        // undoChanges
       // aCS.undoChanges();

        // verify unchange
        // shipTo has moved back to the root from copyRoot
        //assertNull()

        // verify unChangeSummary

    }

    public void testRemoveAllEmptyComplexManyReferenceViaListWrapper() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        int sequenceSizeBefore = aSequence.size();
        DataObject itemDO1 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // after removal the items list indexes on the dataObject will shift down, get item[2] for later comparison
        DataObject itemDO2 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[2]");
        assertNotNull(itemDO1);
        assertNotNull(itemDO2);
        assertFalse(itemDO1 == itemDO2);

        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        // get item from sequence
        int item2SequenceIndex = getNthSequenceIndexFor(aSequence, "item", 2);
        assertTrue(item2SequenceIndex > -1);
        DataObject itemObjectFromSetting = (DataObject)aSequence.getValue(item2SequenceIndex);
        assertNotNull(itemObjectFromSetting);
        assertTrue(itemObjectFromSetting == itemDO2);

        // create a list of items to remove
        List<DataObject> listToRemove = new ArrayList<DataObject>();
        //for(Iterator<DataObject> i = existingList.iterator(); i.hasNext();) {
            //listToRemove.add(i.next());
        //}

        int sizeListToRemove = listToRemove.size();

        // remove entire list
        existingList.removeAll(listToRemove);
        assertEquals(sequenceSizeBefore - sizeListToRemove, aSequence.size());
        assertEquals(listSizeBefore - sizeListToRemove, existingList.size());

        // are we removed on the DataObject?
        //DataObject item1ObjectFromAfterRemove = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // TODO: verify delete or dont delete after a sequence.remove
        //assertTrue(item1ObjectFromAfterRemove == itemDO1);
        //assertFalse(item1ObjectFromAfterRemove == itemDO2);
    }

    public void verifyAddAllAtIndexComplexManyByListWrapperAddPropertyOnExistingList(int addIndex) {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item3 = (DataObject)root.get("item[1]");
        assertNotNull(item3);

        Property itemProperty = po.getInstanceProperty("item");

        // add list of items to existing list
        List<DataObject> aListToAdd = new ArrayList<DataObject>();
        aListToAdd.add(item3);
        // add to the end of the list
        existingList.addAll(addIndex,aListToAdd);

        // verify that the list has increased on the do
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);

        // verify that the sequence size has increased
        assertEquals(indexToPlaceAtEnd + aListToAdd.size(), aSequence.size());

        // get back new Setting value
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd + aListToAdd.size() - 1);
        assertNotNull(item2Value);
        assertEquals(item2Value, aListToAdd.get(0));
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + aListToAdd.size(), aSequence.size());

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + aListToAdd.size(), treeSizeAfterAdd);
    }

    public void testAddAllAtIndex0ComplexManyByListWrapperAddPropertyOnExistingList() {
        verifyAddAllAtIndexComplexManyByListWrapperAddPropertyOnExistingList(0);
    }

    public void testAddAllAtIndex1ComplexManyByListWrapperAddPropertyOnExistingList() {
        verifyAddAllAtIndexComplexManyByListWrapperAddPropertyOnExistingList(1);
    }
    /*
    public void testRemoveSimpleManyBySequence() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        ListWrapper existingList = (ListWrapper)po.get("comment");
        int listSizeBefore = existingList.size();
        assertEquals(PO_COMMENT_LIST_SIZE, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();

        Property aProperty = po.getInstanceProperty("comment");

        // add list of items to existing list
        //List<String> aListToAdd = new ArrayList<String>();
        //aListToAdd.add("comment 2");
        //aListToAdd.add("comment 3");

        // remove entire list of comments
        for(int i=0; i<listSizeBefore; i++) {
            //int indexOfSetting = aSequence.getIndex(aProperty, existingList.get(i));
            int indexOfSetting = getNthSequenceIndexFor(aSequence, aProperty.getName());
            // get original setting
            SDOSetting aSetting = (SDOSetting)aSequence.getSettings().get(indexOfSetting);

            aSequence.remove(indexOfSetting);

            assertFalse(aSetting == aSequence.getSettings().get(indexOfSetting));
        }

        // verify that the list has decreased on the do
        int listSizeAfter = ((ListWrapper)po.get("comment")).size();
        assertEquals(0, listSizeAfter);

        // verify that the sequence size has decreased
        assertEquals(indexToPlaceAtEnd - listSizeBefore, aSequence.size());

        // verify that the sequence hash corresponding to the index to be removed is gone
        // check decreased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE - listSizeBefore, aSequence.size());

        // verify that DataObject has not changed for simple types
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd, treeSizeAfterAdd);
    }
    */
    public void testClearSimpleManyByListWrapper() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        ListWrapper existingList = (ListWrapper)po.get("comment");
        int listSizeBefore = existingList.size();
        assertEquals(PO_COMMENT_LIST_SIZE, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();

        Property itemProperty = po.getInstanceProperty("comment");

        // add list of items to existing list
        List<String> aListToAdd = new ArrayList<String>();
        aListToAdd.add("comment 2");
        aListToAdd.add("comment 3");

        existingList.clear();

        // verify that the list has decreased on the do
        int listSizeAfter = ((ListWrapper)po.get("comment")).size();
        assertEquals(0, listSizeAfter);

        // verify that the sequence size has decreased
        assertEquals(indexToPlaceAtEnd - listSizeBefore, aSequence.size());

        // check decreased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE - listSizeBefore, aSequence.size());

        // verify that DataObject has not changed for simple types
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd, treeSizeAfterAdd);
    }

    public void testClearComplexManyReferenceByListWrapper() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item3 = (DataObject)root.get("item[1]");
        assertNotNull(item3);

        Property itemProperty = po.getInstanceProperty("item");

        // add list of items to existing list
        List<DataObject> aListToAdd = new ArrayList<DataObject>();
        aListToAdd.add(item3);
        aListToAdd.add(item3);

        existingList.clear();

        // verify that the list has decreased on the do
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore - aListToAdd.size(), listSizeAfter);

        // verify that the sequence size has decreased
        assertEquals(indexToPlaceAtEnd - aListToAdd.size(), aSequence.size());

        // check decreased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE - aListToAdd.size(), aSequence.size());

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd - aListToAdd.size(), treeSizeAfterAdd);
    }

    // SDOSequence and SDODataObject bidirectional testing
    public void testDeleteAlsoRemovesSequenceSetting() {
        defineAndLoadRoot(false, false);
        // get sequence po
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());
        DataObject shipToDO = (DataObject)po.get("shipTo");
        assertNotNull(shipToDO);
        SDOSequence aSequence = (SDOSequence)po.getSequence();
        assertNotNull(aSequence);
        // 4 instead of 5 because the one attribute property cannot be sequenced
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        // get shipTo sequence
        int shipToSequenceIndex = getNthSequenceIndexFor(aSequence, "shipTo");
        assertTrue(shipToSequenceIndex > -1);
        DataObject shipToObjectFromSetting = (DataObject)aSequence.getValue(shipToSequenceIndex);
        assertNotNull(shipToObjectFromSetting);
        assertTrue(shipToObjectFromSetting == shipToDO);

        // delete po[1]/shipTo
        shipToDO.delete();

        // are we removed on the sequence?
        int shipToSequenceIndexAfterDelete = getNthSequenceIndexFor(aSequence, "shipTo");
        assertEquals(NO_MATCH_INDEX, shipToSequenceIndexAfterDelete);
        //DataObject shipToObjectFromSettingAfterDelete = (DataObject)aSequence.getValue(getSequenceIndexFor(aSequence, "shipTo"));
        //assertNull(shipToObjectFromSettingAfterDelete);
    }

    public void testUnsetAlsoRemovesSequenceSetting() {
        defineAndLoadRoot(false, false);
        // get sequence po
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());
        DataObject shipToDO = (DataObject)po.get("shipTo");
        assertNotNull(shipToDO);
        SDOSequence aSequence = (SDOSequence)po.getSequence();
        assertNotNull(aSequence);
        // 4 instead of 5 because the one attribute property cannot be sequenced
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        // get shipTo sequence
        int shipToSequenceIndex = getNthSequenceIndexFor(aSequence, "shipTo");
        assertTrue(shipToSequenceIndex > -1);
        DataObject shipToObjectFromSetting = (DataObject)aSequence.getValue(shipToSequenceIndex);
        assertNotNull(shipToObjectFromSetting);
        assertTrue(shipToObjectFromSetting == shipToDO);

        // delete po[1]/shipTo
        po.unset("shipTo");

        // are we removed on the sequence?
        int shipToSequenceIndexAfterDelete = getNthSequenceIndexFor(aSequence, "shipTo");
        assertEquals(NO_MATCH_INDEX, shipToSequenceIndexAfterDelete);
    }

    public void testDetachAlsoRemovesSequenceSetting() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject shipToDO = (DataObject)root.get(PO_SEQUENCE_PATH + "/shipTo");
        assertNotNull(shipToDO);

        // get shipTo sequence
        int shipToSequenceIndex = getNthSequenceIndexFor(aSequence, "shipTo");
        assertTrue(shipToSequenceIndex > -1);
        DataObject shipToObjectFromSetting = (DataObject)aSequence.getValue(shipToSequenceIndex);
        assertNotNull(shipToObjectFromSetting);
        assertTrue(shipToObjectFromSetting == shipToDO);

        // delete po[1]/shipTo
        shipToDO.detach();

        // are we removed on the sequence?
        int shipToSequenceIndexAfterDelete = getNthSequenceIndexFor(aSequence, "shipTo");
        assertEquals(NO_MATCH_INDEX, shipToSequenceIndexAfterDelete);
    }

    public void testSetNullAlsoSetsSequenceSetting() {

    }

    // TODO: Issue resolution 20070403-1: is remove local to Sequence - no
    public void testRemoveDoesDeleteDataObjectPropertyValue() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject shipToDO = (DataObject)root.get(PO_SEQUENCE_PATH + "/shipTo");
        assertNotNull(shipToDO);

        // get shipTo sequence
        int shipToSequenceIndex = getNthSequenceIndexFor(aSequence, "shipTo");
        assertTrue(shipToSequenceIndex > -1);
        DataObject shipToObjectFromSetting = (DataObject)aSequence.getValue(shipToSequenceIndex);
        assertNotNull(shipToObjectFromSetting);
        assertTrue(shipToObjectFromSetting == shipToDO);

        // delete po[1]/shipTo from setting
        aSequence.remove(shipToSequenceIndex);

        // are we removed on the DataObject?
        DataObject shipToObjectFromAfterRemove = (DataObject)root.get(PO_SEQUENCE_PATH + "/shipTo");
        assertNull(shipToObjectFromAfterRemove);
    }
/*
    // TODO: tltest cannot pickup now SDOSequence function defs
    public void testRemoveIndexDoesDeleteDataObjectPropertyValue() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject shipToDO = (DataObject)root.get(PO_SEQUENCE_PATH + "/shipTo");
        assertNotNull(shipToDO);

        // get shipTo sequence
        int shipToSequenceIndex = getNthSequenceIndexFor(aSequence, "shipTo");
        assertTrue(shipToSequenceIndex > -1);
        DataObject shipToObjectFromSetting = (DataObject)aSequence.getValue(shipToSequenceIndex);
        assertNotNull(shipToObjectFromSetting);
        assertTrue(shipToObjectFromSetting == shipToDO);

        // delete po[0] from setting
        aSequence.remove(aSequence.getProperty(0).getName(), aSequence.getProperty(0).getType().getURI(),  true);

        // are we removed on the DataObject?
        Object shipToObjectFromAfterRemove = root.get(PO_SEQUENCE_PATH + "/poID");
        // TODO: verify delete or dont delete after a sequence.remove
        assertNull(shipToObjectFromAfterRemove);
    }
    */

    public void testRemoveIndex0ContainingSimpleSingleType() {

    }
    public void testRemoveIndex0ContainingComplexSingleType() {

    }
    public void testRemoveIndex0ContainingComplexManyType() {

    }
    public void testRemoveIndex0ContainingMultipleComplexManyType() {

    }
    public void testRemoveIndex0ContainingSimpleManyType() {

    }
    /**
     * SDOSequence specific unit tests
     */

    public void testSequenceConstructorWithNullDataObjectThrowsException() {
        // create a non-standard sequence - a null DataObject is invalid
        boolean exceptionThrown = false;
        SDOSequence aSequence = null;
        int errorCode = -1;
        try {
            aSequence = new SDOSequence(null);
        } catch (SDOException e) {
            exceptionThrown = true;
            errorCode = e.getErrorCode();
        } finally {
            assertTrue(exceptionThrown);
            assertNull(aSequence);
            assertEquals(45021, errorCode);
        }
    }

    /**
     * Returns the <code>Sequence</code> for this DataObject.
     * When getType().isSequencedType() == true,
     * the Sequence of a DataObject corresponds to the
     * XML elements representing the values of its Properties.
     * Updates through DataObject and the Lists or Sequences returned
     * from DataObject operate on the same data.
     * When getType().isSequencedType() == false, null is returned.
     */
    public void testSequenceReturnFrom_SDODataObject_getSequence() {
        defineAndLoadRoot(false, false);
        getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
    }

    /**
     * Returns the value of a <code>Sequence</code> property identified by the specified path.
     * @param path the path to a valid object and property.
     * @see #get(String)
     * @deprecated in 2.1.0.
     */
    @Deprecated
    public void test_SequenceReturnFrom_SDODataObject_getSequence_StringFails() {
        defineAndLoadRoot(false, false);
        assertNotNull(root);
        boolean exceptionThrown = false;
        SDOSequence aSequence = null;
        int errorCode = -1;
        try {
            aSequence = (SDOSequence)root.getSequence(PO_PATH);
        } catch (SDOException e) {
            exceptionThrown = true;
            errorCode = e.getErrorCode();
        } finally {
            assertTrue(exceptionThrown);
            assertNull(aSequence);
            assertEquals(45020, errorCode);
        }
    }

    public void test_SequenceReturnFrom_SDODataObject_getSequence_StringPasses() {
        defineAndLoadRoot(false, false);
        assertNotNull(root);
        SDOSequence aSequence = (SDOSequence)root.getSequence(PO_SEQUENCE_PATH);
        // check sequence
        assertNotNull(aSequence);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());
    }

    /**
     * Returns the value of a <code>Sequence</code> property identified by the specified property index.
     * @param propertyIndex the index of the property.
     * @see #get(int)
     * @deprecated in 2.1.0.
     */
    @Deprecated
    public void test_SequenceReturnFrom_SDODataObject_getSequence_index_type_complex_many() {
        defineAndLoadRoot(false, false);
        assertNotNull(root);
        // get property index of porder
        int propertyIndex = ((SDOProperty)root.getInstanceProperty(PO_PATH)).getIndexInType();
        // Expect a failure for a complex many property
        boolean exceptionThrown = false;
        int errorCode = -1;
        SDOSequence aSequence = null;
        try {
            aSequence = (SDOSequence)root.getSequence(propertyIndex);
        } catch (SDOException e) {
            exceptionThrown = true;
            errorCode = e.getErrorCode();
        } finally {
            assertTrue(exceptionThrown);
            assertNull(aSequence);
            assertEquals(45022, errorCode);
        }
    }

    public void test_SequenceReturnFrom_SDODataObject_getSequence_index_type_simple_many() {
        defineAndLoadRoot(false, false);
        assertNotNull(root);
        // get property index of porder
        int propertyIndex = ((SDOProperty)root.getInstanceProperty(PO_PATH)).getIndexInType();
        assertEquals(2, propertyIndex);
        // Expect a failure for a many property
        boolean exceptionThrown = false;
        SDOSequence aSequence = null;
        int errorCode = -1;
        try {
            aSequence = (SDOSequence)root.getSequence(propertyIndex);
        } catch (SDOException e) {
            exceptionThrown = true;
            errorCode = e.getErrorCode();
        } finally {
            assertTrue(exceptionThrown);
            assertNull(aSequence);
            assertEquals(45022, errorCode);
        }
        //verifySequenceIntegrity(aSequence, root.getInstanceProperty(PO_PATH));
    }

    public void test_SequenceReturnFrom_SDODataObject_getSequence_index_type_simple_single() {
        defineAndLoadRoot(false, false);
        assertNotNull(root);
        // get property index of porder
        int propertyIndex = ((SDOProperty)root.getInstanceProperty(PO_PATH)).getIndexInType();
        // Expect a failure for a many property
        boolean exceptionThrown = false;
        SDOSequence aSequence = null;
        int errorCode = -1;
        try {
            aSequence = (SDOSequence)root.getSequence(propertyIndex);
        } catch (SDOException e) {
            exceptionThrown = true;
            errorCode = e.getErrorCode();
        } finally {
            assertTrue(exceptionThrown);
            assertNull(aSequence);
            assertEquals(45022, errorCode);
        }
        //verifySequenceIntegrity(aSequence, root.getInstanceProperty(PO_PATH));
    }

    // TODO: NEED SINGLE COMPLEX WITH COMPLEX CHILDREN
    public void test_SequenceReturnFrom_SDODataObject_getSequence_index_type_complex_single() {
        defineAndLoadRoot(false, false);
        assertNotNull(root);
        // get property index of porder
        int propertyIndex = ((SDOProperty)root.getInstanceProperty(CUSTOMER_PATH)).getIndexInType();
        SDOSequence aSequence = (SDOSequence)root.getSequence(propertyIndex);
//        verifySequenceIntegrity(aSequence, root.getInstanceProperty(CUSTOMER_PATH));
    }

    /**
     * Returns the value of the specified <code>Sequence</code> property.
     * @param property the property to get.
     * @see #get(Property)
     * @deprecated in 2.1.0.
     */
    @Deprecated
    public void test_SequenceReturnFrom_SDODataObject_getSequence_Property_type_single_many() {
        defineAndLoadRoot(false, false);
        assertNotNull(root);
        // get property index of porder
        Property aPOProperty = root.getInstanceProperty(PO_PATH);
        // Expect a failure for a single many property
        SDOSequence aSequence = null;
        boolean exceptionThrown = false;
        int errorCode = -1;
        try {
            aSequence = (SDOSequence)root.getSequence(aPOProperty);
        } catch (SDOException e) {
            exceptionThrown = true;
            errorCode = e.getErrorCode();
        } finally {
            assertTrue(exceptionThrown);
            assertNull(aSequence);
            assertEquals(45022, errorCode);
        }
    }

    public void test_SequenceReturnFrom_SDODataObject_getSequence_Property_type_complex_many() {
        defineAndLoadRoot(false, false);
        assertNotNull(root);
        // get property index of porder
        Property aPOProperty = root.getInstanceProperty(PO_PATH);
        // Expect a failure for a complex many property
        SDOSequence aSequence = null;
        boolean exceptionThrown = false;
        int errorCode = -1;
        try {
            aSequence = (SDOSequence)root.getSequence(aPOProperty);
        } catch (SDOException e) {
            exceptionThrown = true;
            errorCode = e.getErrorCode();
        } finally {
            assertTrue(exceptionThrown);
            assertNull(aSequence);
            assertEquals(45022, errorCode);
        }
    }

    public void test_SequenceReturnFrom_SDODataObject_getSequence_Property_type_simple_single() {
        defineAndLoadRoot(false, false);
        assertNotNull(root);
        // get property index of porder
        Property aPOProperty = root.getInstanceProperty(PO_PATH);
        // Expect a failure for a simple single property
        SDOSequence aSequence = null;
        boolean exceptionThrown = false;
        int errorCode = -1;
        try {
            aSequence = (SDOSequence)root.getSequence(aPOProperty);
        } catch (SDOException e) {
            exceptionThrown = true;
            errorCode = e.getErrorCode();
        } finally {
            assertTrue(exceptionThrown);
            assertNull(aSequence);
            assertEquals(45022, errorCode);
        }
    }

    public void test_SequenceReturnFrom_SDODataObject_getSequence_Property_type_complex_single() {
        defineAndLoadRoot(false, false);
        //setTypeSequenced(CUSTOMER_TYPENAME, true);
        assertNotNull(root);
        // get property index of porder
        Property aCustomerProperty = root.getInstanceProperty(CUSTOMER_PATH);
        // Expect no failure for a complex single property
        SDOSequence aSequence = null;
        boolean exceptionThrown = false;
        int errorCode = -1;
        try {
            aSequence = (SDOSequence)root.getSequence(aCustomerProperty);
        } catch (SDOException e) {
            exceptionThrown = true;
            errorCode = e.getErrorCode();
        } finally {
            assertFalse(exceptionThrown);
            assertNotNull(aSequence);
            //assertEquals(45022, errorCode);
        }
       }

    private boolean verifySequenceIntegrity(SDOSequence aSequence, Property aProperty) {
        assertNotNull(aSequence);
        // verify that the # element properties (not attributes) are the same as in aProperty

        List<Property> sequencedProperties = new ArrayList<Property>();//InProperty;//aProperty.getInstanceProperties()
        for(Iterator i = aProperty.getInstanceProperties().iterator(); i.hasNext();) {
            Property currentProperty = (Property)i.next();
            if(currentProperty.getType().isSequenced()) {
                sequencedProperties.add(currentProperty);
            }
        }
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());
        return true;
    }

    public void testSDOSequence_constructor() {
        // DataObject aDataObject) {
        // get po
        defineAndLoadRoot(false, false);
        // get sequence po
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());

        SDOSequence aSequence = new SDOSequence((SDODataObject)po);
        // verify size
        assertEquals(0, aSequence.size());
    }

    /**
     * Returns the number of entries in the sequence.
     */
    public void test_intReturnFrom_size() {
    }

    // create an open content property
    public void test_booleanReturnFrom_add_String_Object_createOpenContentProperty() {
    }

    /**
     * Adds a new entry with the specified property name and value
     * to the end of the entries.
     * @param propertyName the name of the entry's property.
     * @param value the value for the entry.
     */
    public void test_booleanReturnFrom_add_String_Object() {
        // String propertyName, Object value) {
    }

    /**
     * Adds a new entry with the specified property index and value
     * to the end of the entries.
     * @param propertyIndex the index of the entry's property.
     * @param value the value for the entry.
     */
    public void test_booleanReturnFrom_add_int_Object() {
        // int propertyIndex, Object value) {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item2 = (DataObject)root.get("item[2]");
        assertNotNull(item2);

        // get "item" property index
        int propIndex = 0;
        for(Iterator i=po.getInstanceProperties().iterator(); i.hasNext();) {
            Property aProperty = (Property)i.next();
            if(aProperty != null && aProperty.getName().equals("item")) {
                break;
            } else {
                propIndex++;
            }
        }
        // add to sequence
        aSequence.add(propIndex, item2);
        // get back new Setting value
        //ListWrapper item2Value = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(item2Value);
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_SIZE + 1, aSequence.size());

        // verify that the list has increased
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + 1, listSizeAfter);

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + 1, treeSizeAfterAdd);
    }

    public void testAddListToSequence() {
        // a do.set(List) should populate the sequence

    }

    /**
     * Adds a new entry with the specified property and value
     * to the end of the entries.
     * @param property the property of the entry.
     * @param value the value for the entry.
     */
    public void test_booleanReturnFrom_add_Property_Object() {
        // Property property, Object value) {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item2 = (DataObject)root.get("item[2]");
        assertNotNull(item2);

        Property itemProperty = po.getInstanceProperty("item");

        // add to sequence
        aSequence.add(itemProperty, item2);
        // get back new Setting value
        //ListWrapper item2Value = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(item2Value);
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + 1, aSequence.size());

        // verify that the list has increased
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + 1, listSizeAfter);

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + 1, treeSizeAfterAdd);
    }

    /**
     * Test setting a many property using a single item of a list instead of passing a
     * ListWrapper as usual.
     * The existing list will need to be null (not an empty ListWrapper)
     */
    public void test_booleanReturnFrom_add_Property_Object_WhereValuePassedIsSingleItemInEmptyList() {
        // Property property, Object value) {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item2 = (DataObject)root.get("item[2]");
        assertNotNull(item2);

        Property itemProperty = po.getInstanceProperty("item");

        // add to sequence
        aSequence.add(itemProperty, item2);




        // get back new Setting value
        //ListWrapper item2Value = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(item2Value);
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + 1, aSequence.size());

        // verify that the list has increased
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + 1, listSizeAfter);

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + 1, treeSizeAfterAdd);
    }

    public void testAddMultipleValuesIntoSequence() {
    }
/*
    public List<SDOSetting> reflectiveGetList(Object receiver, String fieldName) {
        List<SDOSetting> instanceField = null;
        try {
            Class cls = receiver.getClass();
            //Field field = cls.getField(fieldName);
            Field field = cls.getDeclaredField(fieldName);
            // override default security settings for private field access from another class
            field.setAccessible(true);
            instanceField = (List<SDOSetting>)field.get(receiver);
          } catch (Throwable e) {
             System.err.println(e);
          }
          return instanceField;
    }

    public DataObject reflectiveGetDataObject(Object receiver, String fieldName) {
        DataObject instanceField = null;
        try {
            Class cls = receiver.getClass();
            //Field field = cls.getField(fieldName);
            Field field = cls.getDeclaredField(fieldName);
            // override default security settings for private field access from another class
            field.setAccessible(true);
            instanceField = (DataObject)field.get(receiver);
          } catch (Throwable e) {
             System.err.println(e);
          }
          return instanceField;
    }
*/
/*    public boolean compareSequences(SDOSequence aSequence, SDOSequence aSequenceCopy, int size, boolean isDeep) {
        // the sequence may be a new object but may be the same if we compare a sequence to itself
        int sequenceSize = aSequence.size();
        assertEquals(size, sequenceSize);
        assertEquals(aSequence.size(), aSequenceCopy.size());
        // the settings inside the sequence must be new objects
        SDOSetting originalSetting = null;
        SDOSetting copySetting = null;
        List<SDOSetting> originalSettingsList = aSequence.getSettings();
        assertNotNull(originalSettingsList);
        assertEquals(sequenceSize, originalSettingsList.size());
        List copySettingsList = aSequenceCopy.getSettings();
        assertNotNull(copySettingsList);
        assertEquals(sequenceSize, copySettingsList.size());

        Property originalProperty = null;
        Property copyProperty = null;

        for(int index = 0, size2 = aSequence.size(); index <  size2; index++) {
            originalSetting = originalSettingsList.get(index);
            copySetting = (SDOSetting)copySettingsList.get(index);

            // dataObject back pointer may be distinct
//            DataObject originalDO = reflectiveGetDataObject(aSequence, "dataObject");
//            DataObject copyDO = reflectiveGetDataObject(aSequenceCopy, "dataObject");

            // each setting may be a new object
            //assertFalse(originalSetting == copySetting);
            // the property field on the setting must point to the same property instance as the original
            // check names before instances
            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)) {
                   assertTrue(false);
            }

               if(null != originalProperty) {
                   assertEquals(originalProperty.getName(), copyProperty.getName());
                   assertEquals(originalProperty.hashCode(), copyProperty.hashCode());
                   // the value field on the setting must point the the deep copy value instance
                   // the property field on the setting must point to the same property instance as the original
                   if(originalProperty != copyProperty) {
                       assertTrue(false);
                   }
               }
            // for unstructuredText (null property) and simple dataTypes we check equality directly
/*            if(null != originalProperty && originalProperty.getType().isDataType()) {
                if(!originalSetting.getValue().equals(copySetting.getValue())) { // we can also use !.equals()
                    assertTrue(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) {
                    // there are no lists in settings
                    Object originalValue = originalSetting.getValue();
                    Object copyValue = copySetting.getValue();

                    if(null != originalValue && null != copyValue) {
                        if(originalProperty.isMany()) {
                            List aList = (List)originalValue;
                            List aListCopy = (List)copyValue;
                            for(int i = 0, lsize = aList.size(); i< lsize; i++) {
                                if(!equal((DataObject)aList.get(i), (DataObject)aListCopy.get(i))) {
                                    return false;
                                }
                            }
                        } else {
                            if(!equal((DataObject)originalValue, (DataObject)copyValue)) {
                                return false;
                            }
                        }
                    }
                }
            }
*//*        }
        return true;
    }
*/
    public void testCopyDeepWithNoSequence() {

    }

    public void testCopyShallowWithNoSequence() {
    }

    public void testCopyShallowWithDiffSequenceSimpleValue() {
    }

    public void testCopyDeepComplexManySequence() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        // copy po
        DataObject rootCopy = copyHelper.copy(root);
        // check sequence was copied
        SDOSequence aSequenceCopy = getSequence(rootCopy, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        assertNotNull(aSequenceCopy);
        assertEquals(aSequence.size(), aSequenceCopy.size());
        //compareSequences(aSequence, aSequenceCopy, PO_SEQUENCE_SIZE, true);
    }

    public void testCopyDeepComplexSingleSequence() {

    }

    public void testCopyDeepSimpleManySequence() {

    }

    public void testCopyDeepSimpleSingleSequence() {

    }

    public void testEqualShallowSimpleSingleSequence() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        //aSequence.setValue(0, 5);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        // copy po
        DataObject poCopy = copyHelper.copyShallow(po);
        // check sequence was copied
        SDOSequence aSequenceCopy = (SDOSequence)poCopy.getSequence();
        assertNotNull(aSequenceCopy);
        //compareSequences(aSequence, aSequenceCopy, PO_SEQUENCE_SIZE, false);

        // test equalityHelper
        //DataObject poCopy = (DataObject)rootCopy.get(PO_SEQUENCE_PATH);
        boolean bEqual = equalityHelper.equalShallow(po, poCopy);
        assertTrue(bEqual);
    }

    public void testEqualShallowSimpleSingleSequenceDifferentValue() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        //aSequence.setValue(0, 5);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        // copy po
        DataObject poCopy = copyHelper.copyShallow(po);
        // check sequence was copied
        SDOSequence aSequenceCopy = (SDOSequence)poCopy.getSequence();
        assertNotNull(aSequenceCopy);
        //compareSequences(aSequence, aSequenceCopy, PO_SEQUENCE_SIZE, false);

        boolean bEqual = equalityHelper.equalShallow(po, poCopy);
        assertTrue(bEqual);

        // modify copy sequence
        aSequenceCopy.setValue(0, 5);

        // test equalityHelper
        //DataObject poCopy = (DataObject)rootCopy.get(PO_SEQUENCE_PATH);
        bEqual = equalityHelper.equalShallow(po, poCopy);
        assertFalse(bEqual);
    }

    public void testEqualShallowFailsSimpleSingleSequenceDifferentValueViaXSD() {
        //defineAndLoadRoot(true, false);
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        //aSequence.setValue(0, 5);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        // copy po
        DataObject poCopy = copyHelper.copyShallow(po);
        // check sequence was copied
        SDOSequence aSequenceCopy = (SDOSequence)poCopy.getSequence();
        assertNotNull(aSequenceCopy);
        //compareSequences(aSequence, aSequenceCopy, PO_SEQUENCE_SIZE, false);

        // modify copy sequence
        aSequenceCopy.setValue(0, 5);
        // test equalityHelper
        //DataObject poCopy = (DataObject)rootCopy.get(PO_SEQUENCE_PATH);
        boolean bEqual = equalityHelper.equalShallow(po, poCopy);
        assertFalse(bEqual);
    }

    public void testEqualShallowSimpleSingleSequenceDifferentUnstructuredTextValue() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        aSequence.addText("text1");
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        // copy po
        DataObject poCopy = copyHelper.copyShallow(po);
        // check sequence was copied
        SDOSequence aSequenceCopy = (SDOSequence)poCopy.getSequence();
        assertNotNull(aSequenceCopy);
        //compareSequences(aSequence, aSequenceCopy, PO_TREE_SIZE + 1, false);

        // modify copy sequence
        aSequenceCopy.setValue(aSequenceCopy.size() -1, "text2");
        // test equalityHelper
        //DataObject poCopy = (DataObject)rootCopy.get(PO_SEQUENCE_PATH);
        boolean bEqual = equalityHelper.equalShallow(po, poCopy);
        assertFalse(bEqual);
    }


    public void testDeepEqualWithNoSequence() {

    }

    public void testEqualShallowWithNoSequence() {

    }

    public void testEqualDeepComplexManySequence() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        // copy po
        DataObject rootCopy = copyHelper.copy(root);
        // check sequence was copied
        SDOSequence aSequenceCopy = getSequence(rootCopy, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        assertNotNull(aSequenceCopy);
        //compareSequences(aSequence, aSequenceCopy, PO_SEQUENCE_SIZE, true);

        // test equalityHelper
        DataObject poCopy = (DataObject)rootCopy.get(PO_SEQUENCE_PATH);
        boolean bEqual = equalityHelper.equal(po, poCopy);
        assertTrue(bEqual);
    }

    public void testEqualDeepComplexManySequenceWithDifferentSequence2() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        // copy po
        DataObject rootCopy = copyHelper.copy(root);
        // check sequence was copied
        SDOSequence aSequenceCopy = getSequence(rootCopy, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        assertNotNull(aSequenceCopy);
        //compareSequences(aSequence, aSequenceCopy, PO_SEQUENCE_SIZE, true);

        // modify copy sequence
        aSequenceCopy.setValue(0, null);
        // test equalityHelper
        DataObject poCopy = (DataObject)rootCopy.get(PO_SEQUENCE_PATH);
        boolean bEqual = equalityHelper.equal(po, poCopy);
        assertFalse(bEqual);
    }

    /*
//  variant test cases that should cause equality failure
    testSequenceOnCopyHasDifferentOrder
    testSequenceOnCopyIsEmpty
    testSequenceOnCopyIsLarger
    testSequenceOnCopyIsSmaller
    testSequenceOnCopyHasDifferentPropertyAtIndex
    testSequenceOnCopyHasDifferentValueAtIndex
    testSequenceOnOriginalHasDifferentOrder
    testSequenceOnOriginalIsEmpty
    testSequenceOnOriginalIsLarger
    testSequenceOnOriginalIsSmaller
    testSequenceOnOriginalHasDifferentPropertyAtIndex
    testSequenceOnOriginalHasDifferentValueAtIndex
*/

    public void testEqualDeepTrueAfterIsSequencedSetToFalseAfterDefineViaNonSpecMethod() {
        defineAndLoadRoot(false, false);
        Sequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        // copy po
        DataObject rootCopy = copyHelper.copy(root);
        // check sequence was copied
        Sequence aSequenceCopy = getSequence(rootCopy, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        assertNotNull(aSequenceCopy);
        //compareSequences((SDOSequence)aSequence, (SDOSequence)aSequenceCopy, PO_SEQUENCE_SIZE, true);

        // test equalityHelper
        DataObject poCopy = (DataObject)rootCopy.get(PO_SEQUENCE_PATH);
        boolean bEqual = equalityHelper.equal(po, poCopy);
        assertTrue(bEqual);

        // modify copy sequence state - non public method - both po and poCopy will have their state changed because they share an SDOType
        assertTrue(po.getType().isSequenced());
        assertTrue(poCopy.getType().isSequenced());
        // WARNING: Users should not be doing this - however it is supported
        ((SDOType)poCopy.getType()).setSequenced(false);
        assertFalse(po.getType().isSequenced());
        assertFalse(poCopy.getType().isSequenced());
        bEqual = equalityHelper.equal(po, poCopy);
        // sequences will not be compared
        assertTrue(bEqual);
    }

    public void testSequencesStillNullAfterIsSequencedSetToTrueOutOfSpec() {
        // create a dataObject with no sequence - the root
        defineAndLoadRoot(false, false);
        Sequence aSequence = root.getSequence();
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        // copy po
        DataObject rootCopy = copyHelper.copy(root);
        // verify we are using the same context
        //assertEquals(helperContext, ((SDOCopyHelper)copyHelper).getHelperContext())
        // check sequence was copied
        SDOSequence aSequenceCopy = getSequence(rootCopy, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        assertNotNull(aSequenceCopy);
        //compareSequences(aSequence, aSequenceCopy, PO_SEQUENCE_SIZE, true);

        // test equalityHelper
        DataObject poCopy = (DataObject)rootCopy.get(PO_SEQUENCE_PATH);
        boolean bEqual = equalityHelper.equal(po, poCopy);
        assertTrue(bEqual);

        // modify copy sequence state - non public method - both po and poCopy will have their state changed because they share an SDOType
        assertTrue(po.getType().isSequenced());
        assertTrue(poCopy.getType().isSequenced());
        // WARNING: Users should not be doing this - however it is supported
        ((SDOType)poCopy.getType()).setSequenced(false);
        assertFalse(po.getType().isSequenced());
        assertFalse(poCopy.getType().isSequenced());
        bEqual = equalityHelper.equal(po, poCopy);
        // sequences will not be compared
        assertTrue(bEqual);

        // turn on isSequenced - not available via spec interface - do not use
        // copy

        // check equality

    }

    public void testEqualDeepComplexSingleSequence() {

    }

    public void testEqualDeepSimpleManySequence() {

    }

    public void testEqualDeepSimpleSingleSequence() {

    }


//  remove via sequence
    public void testRemoveSimpleSingleByIndex() {

    }
    public void testRemoveSimpleManyByIndex() {

    }
    public void testRemoveComplexSingleByIndex() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject shipToDO = (DataObject)root.get(PO_SEQUENCE_PATH + "/shipTo");
        assertNotNull(shipToDO);

        // get shipTo sequence
        int shipToSequenceIndex = getNthSequenceIndexFor(aSequence, "shipTo");
        assertTrue(shipToSequenceIndex > -1);
        DataObject shipToObjectFromSetting = (DataObject)aSequence.getValue(shipToSequenceIndex);
        assertNotNull(shipToObjectFromSetting);
        assertTrue(shipToObjectFromSetting == shipToDO);

        // delete po[1]/shipTo from setting
        aSequence.remove(shipToSequenceIndex);

        // are we removed on the DataObject?
        DataObject shipToObjectFromAfterRemove = (DataObject)root.get(PO_SEQUENCE_PATH + "/shipTo");
        // TODO: verify delete or dont delete after a sequence.remove
        assertNull(shipToObjectFromAfterRemove);
    }

    public void testRemoveComplexManyByIndex() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        int sequenceSizeBefore = aSequence.size();
        DataObject itemDO1 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // after removal the items list indexes on the dataObject will shift down, get item[2] for later comparison
        DataObject itemDO2 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[2]");
        assertNotNull(itemDO1);
        assertNotNull(itemDO2);
        assertFalse(itemDO1 == itemDO2);

        // get item from sequence
        int item2SequenceIndex = getNthSequenceIndexFor(aSequence, "item", 2);
        assertTrue(item2SequenceIndex > -1);
        DataObject itemObjectFromSetting = (DataObject)aSequence.getValue(item2SequenceIndex);
        assertNotNull(itemObjectFromSetting);
        assertTrue(itemObjectFromSetting == itemDO2);

        // delete po[1]/item[2] from setting
        aSequence.remove(item2SequenceIndex);
        assertEquals(sequenceSizeBefore - 1, aSequence.size());

        // are we removed on the DataObject?
        DataObject item1ObjectFromAfterRemove = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // TODO: verify delete or dont delete after a sequence.remove
        assertTrue(item1ObjectFromAfterRemove == itemDO1);
        assertFalse(item1ObjectFromAfterRemove == itemDO2);
    }

    public void testRemoveIndexComplexManyReferenceViaListWrapper() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        int sequenceSizeBefore = aSequence.size();
        DataObject itemDO1 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // after removal the items list indexes on the dataObject will shift down, get item[2] for later comparison
        DataObject itemDO2 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[2]");
        assertNotNull(itemDO1);
        assertNotNull(itemDO2);
        assertFalse(itemDO1 == itemDO2);

        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        // get item from sequence
        int item2SequenceIndex = getNthSequenceIndexFor(aSequence, "item", 2);
        assertTrue(item2SequenceIndex > -1);
        DataObject itemObjectFromSetting = (DataObject)aSequence.getValue(item2SequenceIndex);
        assertNotNull(itemObjectFromSetting);
        assertTrue(itemObjectFromSetting == itemDO2);

        // create a list of items to remove
        List<DataObject> listToRemove = new ArrayList<DataObject>();
        for(Iterator<DataObject> i = existingList.iterator(); i.hasNext();) {
            listToRemove.add(i.next());
        }

        int sizeListToRemove = listToRemove.size();

        // remove entire list
        for(int i=0; i<listSizeBefore; i++) {
            existingList.remove(0);
        }
        assertEquals(sequenceSizeBefore - sizeListToRemove, aSequence.size());
        assertEquals(listSizeBefore - sizeListToRemove, existingList.size());

        // are we removed on the DataObject?
        //DataObject item1ObjectFromAfterRemove = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // TODO: verify delete or dont delete after a sequence.remove
        //assertTrue(item1ObjectFromAfterRemove == itemDO1);
        //assertFalse(item1ObjectFromAfterRemove == itemDO2);
    }

    public void testRemoveIndexFirstDuplicateComplexManyReferenceViaListWrapper() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        int sequenceSizeBefore = aSequence.size();
        DataObject itemDO1 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // after removal the items list indexes on the dataObject will shift down, get item[2] for later comparison
        DataObject itemDO2 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[2]");
        assertNotNull(itemDO1);
        assertNotNull(itemDO2);
        assertFalse(itemDO1 == itemDO2);

        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        // get item from sequence
        int item2SequenceIndex = getNthSequenceIndexFor(aSequence, "item", 2);
        assertTrue(item2SequenceIndex > -1);
        DataObject itemObjectFromSetting = (DataObject)aSequence.getValue(item2SequenceIndex);
        assertNotNull(itemObjectFromSetting);
        assertTrue(itemObjectFromSetting == itemDO2);

        // create a list of items to remove
        List<DataObject> listToRemove = new ArrayList<DataObject>();
        for(Iterator<DataObject> i = existingList.iterator(); i.hasNext();) {
            listToRemove.add(i.next());
        }

        int sizeListToRemove = listToRemove.size();

        // remove entire list
        for(int i=0; i<listSizeBefore; i++) {
            existingList.remove(0);
        }
        assertEquals(sequenceSizeBefore - sizeListToRemove, aSequence.size());
        assertEquals(listSizeBefore - sizeListToRemove, existingList.size());

        // are we removed on the DataObject?
        //DataObject item1ObjectFromAfterRemove = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // TODO: verify delete or dont delete after a sequence.remove
        //assertTrue(item1ObjectFromAfterRemove == itemDO1);
        //assertFalse(item1ObjectFromAfterRemove == itemDO2);
    }

    /**
     * Unable to test removal of an index of a duplicated list because the updateContainment code now does not allow duplicate
     * containment dataobjects
     */
    public void testRemoveIndexFirstDuplicateComplexManyReferenceViaSequence() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        int sequenceSizeBefore = aSequence.size();
        DataObject itemDO1 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // after removal the items list indexes on the dataObject will shift down, get item[2] for later comparison
        DataObject itemDO2 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[2]");
        assertNotNull(itemDO1);
        assertNotNull(itemDO2);
        assertFalse(itemDO1 == itemDO2);

        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        // get item from sequence
        int item2SequenceIndex = getNthSequenceIndexFor(aSequence, "item", 2);
        assertTrue(item2SequenceIndex > -1);
        DataObject itemObjectFromSetting = (DataObject)aSequence.getValue(item2SequenceIndex);
        assertNotNull(itemObjectFromSetting);
        assertTrue(itemObjectFromSetting == itemDO2);

        // create a list of items to remove
        List<DataObject> listToRemove = new ArrayList<DataObject>();
        for(Iterator<DataObject> i = existingList.iterator(); i.hasNext();) {
            listToRemove.add(i.next());
        }

        int sizeListToRemove = listToRemove.size();

        // q2: remove(itemDO@123 = index 2) from seq(itemDO@123, shipToDO@234, itemDO@123, itemDO@123) = seq(itemDO@123, shipToDO@234, itemDO@123) - 3rd item removed
        // invalid state - cannot reproduce

        // remove entire list
        for(int i=0; i<listSizeBefore; i++) {
            aSequence.remove(5);
        }
        assertEquals(sequenceSizeBefore - sizeListToRemove, aSequence.size());
        assertEquals(listSizeBefore - sizeListToRemove, existingList.size());

        // are we removed on the DataObject?
        //DataObject item1ObjectFromAfterRemove = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // TODO: verify delete or dont delete after a sequence.remove
        //assertTrue(item1ObjectFromAfterRemove == itemDO1);
        //assertFalse(item1ObjectFromAfterRemove == itemDO2);
    }

    public void testRemoveAllComplexManyReferenceViaListWrapper() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        int sequenceSizeBefore = aSequence.size();
        DataObject itemDO1 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // after removal the items list indexes on the dataObject will shift down, get item[2] for later comparison
        DataObject itemDO2 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[2]");
        assertNotNull(itemDO1);
        assertNotNull(itemDO2);
        assertFalse(itemDO1 == itemDO2);

        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        // get item from sequence
        int item2SequenceIndex = getNthSequenceIndexFor(aSequence, "item", 2);
        assertTrue(item2SequenceIndex > -1);
        DataObject itemObjectFromSetting = (DataObject)aSequence.getValue(item2SequenceIndex);
        assertNotNull(itemObjectFromSetting);
        assertTrue(itemObjectFromSetting == itemDO2);

        // create a list of items to remove
        List<DataObject> listToRemove = new ArrayList<DataObject>();
        for(Iterator<DataObject> i = existingList.iterator(); i.hasNext();) {
            listToRemove.add(i.next());
        }

        int sizeListToRemove = listToRemove.size();

        // remove entire list
        existingList.removeAll(listToRemove);
        assertEquals(sequenceSizeBefore - sizeListToRemove, aSequence.size());
        assertEquals(listSizeBefore - sizeListToRemove, existingList.size());

        // are we removed on the DataObject?
        //DataObject item1ObjectFromAfterRemove = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // TODO: verify delete or dont delete after a sequence.remove
        //assertTrue(item1ObjectFromAfterRemove == itemDO1);
        //assertFalse(item1ObjectFromAfterRemove == itemDO2);
    }

    public void testRemoveAllComplexManyViaListWrapper() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, "/", 5);
        int sequenceSizeBefore = aSequence.size();
        DataObject itemDO1 = (DataObject)root.get("item[1]");
        // after removal the items list indexes on the dataObject will shift down, get item[2] for later comparison
        DataObject itemDO2 = (DataObject)root.get("item[2]");
        assertNotNull(itemDO1);
        assertNotNull(itemDO2);
        assertFalse(itemDO1 == itemDO2);

        //DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        ListWrapper existingList = (ListWrapper)root.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(3, listSizeBefore);

        // get item from sequence
        int item2SequenceIndex = getNthSequenceIndexFor(aSequence, "item", 2);
        assertTrue(item2SequenceIndex > -1);
        DataObject itemObjectFromSetting = (DataObject)aSequence.getValue(item2SequenceIndex);
        assertNotNull(itemObjectFromSetting);
        assertTrue(itemObjectFromSetting == itemDO2);

        // create a list of items to remove
        List<DataObject> listToRemove = new ArrayList<DataObject>();
        for(Iterator<DataObject> i = existingList.iterator(); i.hasNext();) {
            listToRemove.add(i.next());
        }

        int sizeListToRemove = listToRemove.size();

        // remove entire list
        existingList.removeAll(listToRemove);
        assertEquals(sequenceSizeBefore - sizeListToRemove, aSequence.size());
        assertEquals(listSizeBefore - sizeListToRemove, existingList.size());

        // are we removed on the DataObject?
        //DataObject item1ObjectFromAfterRemove = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // TODO: verify delete or dont delete after a sequence.remove
        //assertTrue(item1ObjectFromAfterRemove == itemDO1);
        //assertFalse(item1ObjectFromAfterRemove == itemDO2);
        assertEquals(0, existingList.size());
    }

    public void testRemoveComplexManyReferenceViaListWrapperIndex() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        int sequenceSizeBefore = aSequence.size();
        DataObject itemDO1 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // after removal the items list indexes on the dataObject will shift down, get item[2] for later comparison
        DataObject itemDO2 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[2]");
        assertNotNull(itemDO1);
        assertNotNull(itemDO2);
        assertFalse(itemDO1 == itemDO2);

        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        // get item from sequence
        int item2SequenceIndex = getNthSequenceIndexFor(aSequence, "item", 2);
        assertTrue(item2SequenceIndex > -1);
        DataObject itemObjectFromSetting = (DataObject)aSequence.getValue(item2SequenceIndex);
        assertNotNull(itemObjectFromSetting);
        assertTrue(itemObjectFromSetting == itemDO2);

        // delete po[1]/item[2] from setting
        existingList.remove(1);
        assertEquals(sequenceSizeBefore - 1, aSequence.size());

        // are we removed on the DataObject?
        DataObject item1ObjectFromAfterRemove = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // TODO: verify delete or dont delete after a sequence.remove
        assertTrue(item1ObjectFromAfterRemove == itemDO1);
        assertFalse(item1ObjectFromAfterRemove == itemDO2);
    }

    public void testRemoveComplexManyReferenceViaListWrapperReference() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        int sequenceSizeBefore = aSequence.size();
        DataObject itemDO1 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // after removal the items list indexes on the dataObject will shift down, get item[2] for later comparison
        DataObject itemDO2 = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[2]");
        assertNotNull(itemDO1);
        assertNotNull(itemDO2);
        assertFalse(itemDO1 == itemDO2);

        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        // get item from sequence
        int item2SequenceIndex = getNthSequenceIndexFor(aSequence, "item", 2);
        assertTrue(item2SequenceIndex > -1);
        DataObject itemObjectFromSetting = (DataObject)aSequence.getValue(item2SequenceIndex);
        assertNotNull(itemObjectFromSetting);
        assertTrue(itemObjectFromSetting == itemDO2);

        // delete po[1]/item[2] from setting
        existingList.remove(itemDO2);
        assertEquals(sequenceSizeBefore - 1, aSequence.size());

        // are we removed on the DataObject?
        DataObject item1ObjectFromAfterRemove = (DataObject)root.get(PO_SEQUENCE_PATH + "/item[1]");
        // TODO: verify delete or dont delete after a sequence.remove
        assertTrue(item1ObjectFromAfterRemove == itemDO1);
        assertFalse(item1ObjectFromAfterRemove == itemDO2);
    }

    public void testRemoveComplexManyViaListWrapperReference() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, "/", 5);
        int sequenceSizeBefore = aSequence.size();
        DataObject itemDO1 = (DataObject)root.get("item[1]");
        // after removal the items list indexes on the dataObject will shift down, get item[2] for later comparison
        DataObject itemDO2 = (DataObject)root.get("item[2]");
        assertNotNull(itemDO1);
        assertNotNull(itemDO2);
        assertFalse(itemDO1 == itemDO2);

        ListWrapper existingList = (ListWrapper)root.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(3, listSizeBefore);

        // get item from sequence
        int item2SequenceIndex = getNthSequenceIndexFor(aSequence, "item", 2);
        assertTrue(item2SequenceIndex > -1);
        DataObject itemObjectFromSetting = (DataObject)aSequence.getValue(item2SequenceIndex);
        assertNotNull(itemObjectFromSetting);
        assertTrue(itemObjectFromSetting == itemDO2);

        // delete po[1]/item[2] from setting
        existingList.remove(itemDO2);
        assertEquals(sequenceSizeBefore - 1, aSequence.size());

        // are we removed on the DataObject?
        DataObject item1ObjectFromAfterRemove = (DataObject)root.get("item[1]");
        // TODO: verify delete or dont delete after a sequence.remove
        assertTrue(item1ObjectFromAfterRemove == itemDO1);
        assertFalse(item1ObjectFromAfterRemove == itemDO2);
    }


    /**
     * Test operations involving deep complex types that contain complex children
     *
     */
    public void testRemoveNullComplexManyWithComplexChildrenViaListWrapperReference() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, "/", 5);
        int sequenceSizeBefore = aSequence.size();
        ListWrapper existingList = (ListWrapper)root.get("porder");
        int listSizeBefore = existingList.size();
        assertEquals(1, listSizeBefore);
        existingList.remove(null);
        assertEquals(sequenceSizeBefore, aSequence.size());
    }

    public void testRemoveComplexManyWithComplexChildreViaListWrapperReference() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, "/", 5);
        int sequenceSizeBefore = aSequence.size();
        DataObject po1 = (DataObject)root.get("porder[1]");
        assertNotNull(po1);

        ListWrapper existingList = (ListWrapper)root.get("porder");
        int listSizeBefore = existingList.size();
        assertEquals(1, listSizeBefore);

        existingList.remove(po1);
        assertEquals(sequenceSizeBefore - 1, aSequence.size());

        // are we removed on the DataObject?
        ListWrapper existingList2 = (ListWrapper)root.get("porder");  // same instance of existingList
        int listSizeAfter = existingList2.size();
        assertEquals(0, listSizeAfter);
    }

//     remove via dataobject (same as detach)
    public void testUnsetSimpleSingleByIndex() {

    }
    public void testUnsetSimpleManyByIndex() {

    }
    public void testUnsetComplexSingleByIndex() {

    }
    public void testUnsetComplexManyByIndex() {

    }

    public void testDeleteSimpleSingleByProperty() {

    }
    public void testDeleteSimpleManyByProperty() {

    }
    public void testDeleteComplexSingleByProperty() {

    }
    public void testDeleteComplexManyByProperty() {

    }

    public void testDetachSimpleSingleByProperty() {

    }
    public void testDetachSimpleManyByProperty() {

    }
    public void testDetachComplexSingleByProperty() {

    }
    public void testDetachComplexManyByProperty() {

    }

//     add via sequence

//     add via dataobject
    public void testAddSimpleSingleByDataObjectSetProperty() {

    }
    public void testAddSimpleManyByDataObjectSetPropertyWithListOnEmptyList() {

    }
    public void testAddSimpleManyByDataObjectSetPropertyWithListOnExistingList() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("comment")).size();
        assertEquals(PO_COMMENT_LIST_SIZE, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();

        Property commentProperty = po.getInstanceProperty("comment");

        // add list of items to sequence
        List<String> aListToAdd = new ArrayList<String>();
        aListToAdd.add("comment 2");
        aListToAdd.add("comment 3");
        aSequence.add(indexToPlaceAtEnd, commentProperty, aListToAdd);

        // get back new Setting value
        String comment2Value = (String)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(comment2Value);
        assertEquals(comment2Value, aListToAdd.get(0));
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence for simple type
        assertEquals(PO_SEQUENCE_TREE_SIZE + aListToAdd.size(), aSequence.size());

        // verify that the list has increased
        int listSizeAfter = ((ListWrapper)po.get("comment")).size();
        assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);

        // verify that DataObject has changed but not the # of dataObjects
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + 0, treeSizeAfterAdd);
    }

    public void testAddComplexSingleByDataObjectSetProperty() {
    }
    public void testAddComplexManyByDataObjectSetPropertyWithListOnEmptyList() {

    }

    public void testAddComplexManyByDataObjectSetPropertyWithListOnExistingList() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item3 = (DataObject)root.get("item[1]");
        assertNotNull(item3);

        Property itemProperty = po.getInstanceProperty("item");

        // add list of items to sequence
        List<DataObject> aListToAdd = new ArrayList<DataObject>();
        aListToAdd.add(item3);
        aSequence.add(indexToPlaceAtEnd, itemProperty, aListToAdd);

        // get back new Setting value
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(item2Value);
        assertEquals(item2Value, aListToAdd.get(0));
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + 1, aSequence.size());

        // verify that the list has increased
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + 1, treeSizeAfterAdd);
    }

    public void testAddComplexManyByDataObjectSetPropertyWithSingleItemOnEmptyList() {
    }

    public void testAddComplexManyByDataObjectSetPropertyWithSingleItemOnExistingList() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item3 = (DataObject)root.get("item[3]");
        assertNotNull(item3);

        Property itemProperty = po.getInstanceProperty("item");

        // add to sequence
        aSequence.add(indexToPlaceAtEnd, itemProperty, item3);
        // get back new Setting value
        //ListWrapper item2Value = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(item2Value);
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + 1, aSequence.size());

        // verify that the list has increased
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + 1, listSizeAfter);

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + 1, treeSizeAfterAdd);
    }

//  add via ListWrapper
    public void testAddSimpleSingleByListWrapperAddProperty() {

    }
    public void testAddSimpleManyByListWrapperAddProperty() {

    }
    public void testAddComplexSingleByListWrapperAddProperty() {

    }
    public void testAddComplexManyByListWrapperAddPropertyOnEmptyList() {

    }

    public void testAddComplexManyByListWrapperAddPropertyOnExistingList() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item3 = (DataObject)root.get("item[1]");
        assertNotNull(item3);

        Property itemProperty = po.getInstanceProperty("item");

        // add list of items to existing list
        List<DataObject> aListToAdd = new ArrayList<DataObject>();
        aListToAdd.add(item3);
        aListToAdd.add(item3);
        for(Iterator<DataObject> i = aListToAdd.iterator(); i.hasNext();) {
            // add to the end of the list
            existingList.add(i.next());
        }

        // verify that the list has increased on the do
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);

        // verify that the sequence size has increased
        assertEquals(indexToPlaceAtEnd + aListToAdd.size(), aSequence.size());

        // get back new Setting value
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd + aListToAdd.size() - 1);
        assertNotNull(item2Value);
        assertEquals(item2Value, aListToAdd.get(0));
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + aListToAdd.size(), aSequence.size());

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + aListToAdd.size(), treeSizeAfterAdd);
    }

    public void testAddComplexManyByListWrapperAddAllPropertyOnExistingList() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item3 = (DataObject)root.get("item[1]");
        assertNotNull(item3);

        Property itemProperty = po.getInstanceProperty("item");

        // add list of items to existing list
        List<DataObject> aListToAdd = new ArrayList<DataObject>();
        aListToAdd.add(item3);
        aListToAdd.add(item3);
        // add to the end of the list
        existingList.addAll(aListToAdd);

        // verify that the list has increased on the do
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);

        // verify that the sequence size has increased
        assertEquals(indexToPlaceAtEnd + aListToAdd.size(), aSequence.size());

        // get back new Setting value
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd + aListToAdd.size() - 1);
        assertNotNull(item2Value);
        assertEquals(item2Value, aListToAdd.get(0));
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + aListToAdd.size(), aSequence.size());

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + aListToAdd.size(), treeSizeAfterAdd);
    }

    public void testAddAllComplexManyNonContainmentByListWrapperAddAllPropertyOnExistingList() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item3 = (DataObject)root.get("item[3]");
        assertNotNull(item3);

        Property itemProperty = po.getInstanceProperty("item");

        // add list of items to existing list
        List<DataObject> aListToAdd = new ArrayList<DataObject>();
        aListToAdd.add(item3);
        // add to the end of the list
        existingList.addAll(aListToAdd);

        // verify that the list has increased on the do
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);

        // verify that the sequence size has increased
        assertEquals(indexToPlaceAtEnd + aListToAdd.size(), aSequence.size());

        // get back new Setting value
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd + aListToAdd.size() - 1);
        assertNotNull(item2Value);
        assertEquals(item2Value, aListToAdd.get(0));
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + aListToAdd.size(), aSequence.size());

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + aListToAdd.size(), treeSizeAfterAdd);
    }
/*
    public void testRemove1StOccurrenceComplexManyNonContainmentByListWrapperAddAllPropertyOnExistingList() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item3 = (DataObject)root.get("item[3]");
        assertNotNull(item3);

        Property itemProperty = po.getInstanceProperty("item");

        // add list of items to existing list
        List<DataObject> aListToAdd = new ArrayList<DataObject>();
        aListToAdd.add(item3);
        // add to the end of the list
        existingList.addAll(aListToAdd);

        // verify that the list has increased on the do
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);

        // verify that the sequence size has increased
        assertEquals(indexToPlaceAtEnd + aListToAdd.size(), aSequence.size());

        // get back new Setting value
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd + aListToAdd.size() - 1);
        assertNotNull(item2Value);
        assertEquals(item2Value, aListToAdd.get(0));
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + aListToAdd.size(), aSequence.size());

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + aListToAdd.size(), treeSizeAfterAdd);

        // get sequence object that will be removed
        SDOSetting aSetting5 = (SDOSetting)aSequence.getSettings().get(5);
        SDOSetting aSetting6 = (SDOSetting)aSequence.getSettings().get(6);
        // remove the first occurrence of the duplicated items in the sequence
        existingList.remove(1);

        // check size
        assertEquals(indexToPlaceAtEnd, aSequence.size());

        // verify that the correct index in the sequence was removed based on the listWrapper index
        //assertEquals(aSetting6, aSequence.getSettings().get(5)); // 6 shifted into 5's place
        //assertFalse(aSetting5 == aSequence.getSettings().get(5)); // 5 is gone
        assertTrue(aSetting5 == aSequence.getSettings().get(5)); // 5 is still there
    }

    public void testRemove2ndOccurrenceComplexManyNonContainmentByListWrapperAddAllPropertyOnExistingList() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item3 = (DataObject)root.get("item[3]");
        assertNotNull(item3);

        Property itemProperty = po.getInstanceProperty("item");

        // add list of items to existing list
        List<DataObject> aListToAdd = new ArrayList<DataObject>();
        aListToAdd.add(item3);
        // add to the end of the list
        existingList.addAll(aListToAdd);

        // verify that the list has increased on the do
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);

        // verify that the sequence size has increased
        assertEquals(indexToPlaceAtEnd + aListToAdd.size(), aSequence.size());

        // get back new Setting value
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd + aListToAdd.size() - 1);
        assertNotNull(item2Value);
        assertEquals(item2Value, aListToAdd.get(0));
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + aListToAdd.size(), aSequence.size());

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + aListToAdd.size(), treeSizeAfterAdd);

        // get sequence object that will be removed
        SDOSetting aSetting5 = (SDOSetting)aSequence.getSettings().get(5);
        SDOSetting aSetting6 = (SDOSetting)aSequence.getSettings().get(6);
        // remove the first occurrence of the duplicated items in the sequence
        existingList.remove(2);

        // check size
        assertEquals(indexToPlaceAtEnd, aSequence.size());

        // verify that the correct index in the sequence was removed based on the listWrapper index
        assertEquals(aSetting5, aSequence.getSettings().get(5)); // 6 shifted into 5's place
        assertFalse(aSetting6 == aSequence.getSettings().get(5)); // 5 is gone
    }*/

    // TODO: Verify that existing duplicates will be removed before the new list is added - addAll same as set
    public void testAddAllDuplicatesComplexManyByListWrapperAddAllPropertyOnExistingList() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, "/", 5);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(root).size();
        assertEquals(10, treeSizeBeforeAdd);
        assertEquals(5, aSequence.size());

        ListWrapper existingList = (ListWrapper)root.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(3, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item3 = (DataObject)root.get("item[3]");
        assertNotNull(item3);

        Property itemProperty = root.getInstanceProperty("item");

        // add list of items to existing list
        List<DataObject> aListToAdd = new ArrayList<DataObject>();
        aListToAdd.add(item3);
        aListToAdd.add(item3);
        aListToAdd.add(item3);
        // add to the end of the list
        existingList.addAll(aListToAdd);

        // verify that the list has increased on the do
        int listSizeAfter = ((ListWrapper)root.get("item")).size();


        // TODO: We should not be removing the existing item?
        int newItems = aListToAdd.size() - 3;
        //assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);
        assertEquals(listSizeBefore + newItems, listSizeAfter);

        // verify that the sequence size has increased
        assertEquals(indexToPlaceAtEnd + newItems, aSequence.size());

        // get back new Setting value
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd + newItems - 1);
        assertNotNull(item2Value);
        assertEquals(item2Value, aListToAdd.get(0));
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd - 1));
        // check increased size of sequence
        assertEquals(indexToPlaceAtEnd + newItems, aSequence.size());

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(root).size();
        assertEquals(treeSizeBeforeAdd + newItems, treeSizeAfterAdd);

    }
/*
    // TODO: Verify that existing duplicates will be removed before the new list is added - addAll same as set
    public void testRemove2ndOccurrenceSimpleManyByListWrapperAddAllPropertyOnExistingList() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        ListWrapper existingList = (ListWrapper)po.get("comment");
        int listSizeBefore = existingList.size();
        assertEquals(PO_COMMENT_LIST_SIZE, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        Property commentProperty = po.getInstanceProperty("comment");

        // add list of items to existing list
        List<String> aListToAdd = new ArrayList<String>();
        aListToAdd.add(PO_COMMENT_VALUE1);
        aListToAdd.add(PO_COMMENT_VALUE1);
        aListToAdd.add(PO_COMMENT_VALUE1);
        // add to the end of the list
        existingList.addAll(aListToAdd);

        // verify that the list has increased on the do
        int listSizeAfter = ((ListWrapper)po.get("comment")).size();

        // TODO: We should not be removing the existing item?
        int newItems = aListToAdd.size();
        //assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);
        assertEquals(listSizeBefore + newItems, listSizeAfter);

        // verify that the sequence size has increased
        assertEquals(indexToPlaceAtEnd + newItems, aSequence.size());

        // get back new Setting value
        String comment2Value = (String)aSequence.getValue(indexToPlaceAtEnd + newItems - 1);
        assertNotNull(comment2Value);
        assertEquals(comment2Value, aListToAdd.get(0));
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd - 1));
        // check increased size of sequence
        assertEquals(indexToPlaceAtEnd + newItems, aSequence.size());

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        // but dataObject node list is the same
        assertEquals(treeSizeBeforeAdd, treeSizeAfterAdd);

        // get sequence object that will be removed
        SDOSetting aSetting7 = (SDOSetting)aSequence.getSettings().get(7);
        SDOSetting aSetting8 = (SDOSetting)aSequence.getSettings().get(8);
        SDOSetting aSetting9 = (SDOSetting)aSequence.getSettings().get(9);
        // remove the first occurrence of the duplicated items in the sequence
        int aSequenceSizeBeforeRemove = aSequence.size();
        existingList.remove(2);

        // check size
        assertEquals(aSequenceSizeBeforeRemove - 1, aSequence.size());

        // verify that the correct index in the sequence was removed based on the listWrapper index
        assertEquals(aSetting8, aSequence.getSettings().get(7)); // 6 shifted into 5's place
        assertEquals(aSetting9, aSequence.getSettings().get(8)); // 6 shifted into 5's place
        assertFalse(aSetting7 == aSequence.getSettings().get(7)); // 5 is gone
        assertFalse(aSetting7 == aSequence.getSettings().get(8)); // 5 is gone
        //assertFalse(aSetting7 == aSequence.getSettings().get(9)); // 5 is gone
    }
        */
    // TODO: Verify that existing duplicates will be removed before the new list is added - addAll same as set
    public void testRemoveLastOccurrenceComplexManyByListWrapperAddAllPropertyOnExistingList() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, "/", 5);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(root).size();
        assertEquals(10, treeSizeBeforeAdd);
        assertEquals(5, aSequence.size());

        ListWrapper existingList = (ListWrapper)root.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(3, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item3 = (DataObject)root.get("item[3]");
        assertNotNull(item3);

        Property itemProperty = root.getInstanceProperty("item");

        // add list of items to existing list
        List<DataObject> aListToAdd = new ArrayList<DataObject>();
        aListToAdd.add(item3);
        aListToAdd.add(item3);
        aListToAdd.add(item3);
        // add to the end of the list
        existingList.addAll(aListToAdd);

        // verify that the list has increased on the do
        int listSizeAfter = ((ListWrapper)root.get("item")).size();


        // TODO: We should not be removing the existing item
        int newItems = aListToAdd.size() - 3;
        //assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);
        assertEquals(listSizeBefore + newItems, listSizeAfter);

        // verify that the sequence size has increased by 1
        assertEquals(indexToPlaceAtEnd + newItems, aSequence.size());

        // get back new Setting value
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd + newItems - 1);
        assertNotNull(item2Value);
        assertEquals(item2Value, aListToAdd.get(0));
        // the following is no longer valid after we refactored addAll(do list) to not add duplicates
/*        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(indexToPlaceAtEnd + newItems, aSequence.size());

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(root).size();
        assertEquals(treeSizeBeforeAdd + newItems, treeSizeAfterAdd);

        // get sequence object that will be removed
        SDOSetting aSetting4 = (SDOSetting)aSequence.getSettings().get(4);
        SDOSetting aSetting5 = (SDOSetting)aSequence.getSettings().get(5);
        SDOSetting aSetting6 = (SDOSetting)aSequence.getSettings().get(6);
        // remove the first occurrence of the duplicated items in the sequence
        int aSequenceSizeBeforeRemove = aSequence.size();
        existingList.remove(existingList.size() - 1);

        // check size
        assertEquals(aSequenceSizeBeforeRemove -1, aSequence.size());

        // verify that the correct index in the sequence was removed based on the listWrapper index
        assertEquals(aSetting4, aSequence.getSettings().get(4));
        assertEquals(aSetting5, aSequence.getSettings().get(5));
        assertFalse(aSetting6 == aSequence.getSettings().get(5));
*/    }

    // Purpose is to verify that a remove(item) for duplicates removes the first occurrence of that item.
    /*
    public void testRemove1stOccurrenceSimpleManyByListWrapperAddAllPropertyOnExistingList() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        ListWrapper existingList = (ListWrapper)po.get("comment");
        int listSizeBefore = existingList.size();
        assertEquals(PO_COMMENT_LIST_SIZE, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        Property commentProperty = po.getInstanceProperty("comment");

        // add list of items to existing list
        List<String> aListToAdd = new ArrayList<String>();
        aListToAdd.add(PO_COMMENT_VALUE1);
        aListToAdd.add(PO_COMMENT_VALUE1);
        aListToAdd.add(PO_COMMENT_VALUE1);
        // add to the end of the list
        existingList.addAll(aListToAdd);

        // verify that the list has increased on the do
        int listSizeAfter = ((ListWrapper)po.get("comment")).size();

        // TODO: We should not be removing the existing item?
        int newItems = aListToAdd.size();
        //assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);
        assertEquals(listSizeBefore + newItems, listSizeAfter);

        // verify that the sequence size has increased
        assertEquals(indexToPlaceAtEnd + newItems, aSequence.size());

        // get back new Setting value
        String comment2Value = (String)aSequence.getValue(indexToPlaceAtEnd + newItems - 1);
        assertNotNull(comment2Value);
        assertEquals(comment2Value, aListToAdd.get(0));
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd - 1));
        // check increased size of sequence
        assertEquals(indexToPlaceAtEnd + newItems, aSequence.size());

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        // but dataObject node list is the same
        assertEquals(treeSizeBeforeAdd, treeSizeAfterAdd);

        // get sequence object that will be removed
        SDOSetting aSetting7 = (SDOSetting)aSequence.getSettings().get(7);
        SDOSetting aSetting8 = (SDOSetting)aSequence.getSettings().get(8);
        SDOSetting aSetting9 = (SDOSetting)aSequence.getSettings().get(9);
        // remove the first occurrence of the duplicated items in the sequence
        int aSequenceSizeBeforeRemove = aSequence.size();
        existingList.remove("comment 1");

        // check size
        assertEquals(aSequenceSizeBeforeRemove - 1, aSequence.size());

        // verify that the correct index in the sequence was removed based on the listWrapper index
        assertEquals(aSetting8, aSequence.getSettings().get(7)); // 6 shifted into 5's place
        assertEquals(aSetting9, aSequence.getSettings().get(8)); // 6 shifted into 5's place
        assertFalse(aSetting7 == aSequence.getSettings().get(7)); // 5 is gone
        assertFalse(aSetting7 == aSequence.getSettings().get(8)); // 5 is gone
        //assertFalse(aSetting7 == aSequence.getSettings().get(9)); // 5 is gone
    }
    */
    public void testAddAllComplexManyByListWrapperAddAllPropertyOnExistingList() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, "/", 5);
        //DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(root).size();
        assertEquals(10, treeSizeBeforeAdd);
        assertEquals(5, aSequence.size());

        ListWrapper existingList = (ListWrapper)root.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(3, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item3 = (DataObject)root.get("item[1]");
        assertNotNull(item3);

        Property itemProperty = root.getInstanceProperty("item");

        // add list of items to existing list
        List<DataObject> aListToAdd = new ArrayList<DataObject>();

        DataObject item4 = dataFactory.create(typeHelper.getType(URINAME, ITEM_TYPENAME));
        item4.set("itemID", 4);
        item4.set("name", "item4-DF");
        DataObject item5 = dataFactory.create(typeHelper.getType(URINAME, ITEM_TYPENAME));
        item5.set("itemID", 5);
        item5.set("name", "item5-DF");
        aListToAdd.add(item4);
        aListToAdd.add(item5);
        // add to the end of the list
        existingList.addAll(aListToAdd);

        // verify that the list has increased on the do
        int listSizeAfter = ((ListWrapper)root.get("item")).size();
        assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);

        // verify that the sequence size has increased
        assertEquals(indexToPlaceAtEnd + aListToAdd.size(), aSequence.size());

        // get back new Setting value
        for(int i=0; i< aListToAdd.size(); i++) {
            SDODataObject itemValue = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd + i);
            assertNotNull(itemValue);
            assertEquals(itemValue, aListToAdd.get(i));
            assertNotNull(aSequence.getProperty(indexToPlaceAtEnd + i));
        }
        // check increased size of sequence
        assertEquals(5 + aListToAdd.size(), aSequence.size());

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(root).size();
        assertEquals(treeSizeBeforeAdd + aListToAdd.size(), treeSizeAfterAdd);
    }

    /**
     * Adds a new entry with the specified property name and value
     * at the specified entry index.
     * @param index the index at which to add the entry.
     * @param propertyName the name of the entry's property.
     * @param value the value for the entry.
     * TODO: single and many versions required
     */
    public void test_voidReturnFrom_add_int_String_Object() {
        // int index, String propertyName, Object value) {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item2 = (DataObject)root.get("item[2]");
        assertNotNull(item2);
        // add to sequence
        aSequence.add(indexToPlaceAtEnd, "item", item2);
        // get back new Setting value
        //ListWrapper item2Value = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(item2Value);
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + 1, aSequence.size());

        // verify that the list has increased
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + 1, listSizeAfter);

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + 1, treeSizeAfterAdd);
    }

    /**
     * Adds a new entry with the specified property index and value
     * at the specified entry index.
     * @param index the index at which to add the entry.
     * @param propertyIndex the index of the entry's property.
     * @param value the value for the entry.
     * TODO: single and many versions required
     */
    public void test_voidReturnFrom_add_int_int_Object() {
        // int index, int propertyIndex, Object value) {
        // int index, String propertyName, Object value) {
        defineAndLoadRoot(false, false);
        // detach shipTo
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item2 = (DataObject)root.get("item[2]");
        assertNotNull(item2);

        // get "item" property index
        int propIndex = 0;
        for(Iterator i=po.getInstanceProperties().iterator(); i.hasNext();) {
            Property aProperty = (Property)i.next();
            if(aProperty != null && aProperty.getName().equals("item")) {
                break;
            } else {
                propIndex++;
            }
        }
        // add to sequence
        aSequence.add(indexToPlaceAtEnd, propIndex, item2);
        // get back new Setting value
        //ListWrapper item2Value = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(item2Value);
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + 1, aSequence.size());

        // verify that the list has increased
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + 1, listSizeAfter);

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + 1, treeSizeAfterAdd);
    }

    /**
     * Adds a new entry with the specified property and value
     * at the specified entry index.
     * @param index the index at which to add the entry.
     * @param property the property of the entry.
     * @param value the value for the entry.
     */
    public void test_voidReturnFrom_add_int_Property_Object() {
        // int index, Property property, Object value) {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item2 = (DataObject)root.get("item[2]");
        assertNotNull(item2);

        Property itemProperty = po.getInstanceProperty("item");

        // add to sequence
        aSequence.add(indexToPlaceAtEnd, itemProperty, item2);
        // get back new Setting value
        //ListWrapper item2Value = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(item2Value);
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + 1, aSequence.size());

        // verify that the list has increased
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + 1, listSizeAfter);

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + 1, treeSizeAfterAdd);
    }

    public void test_voidReturnFrom_add_int_Property_Object_outofbounds() {
        // int index, Property property, Object value) {
        defineAndLoadRoot(false, false);
        // detach shipTo
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item2 = (DataObject)root.get("item[2]");
        assertNotNull(item2);

        Property itemProperty = po.getInstanceProperty("item");

        // add to sequence
        try {
            aSequence.add(-1, itemProperty, item2);
        } catch (Exception e) {

        }

      boolean exceptionThrown =false;
        // get back new Setting value
        ListWrapper item2Value = null;
        try {
            item2Value = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        } catch (SDOException e) {
            assertEquals(SDOException.INVALID_INDEX ,e.getErrorCode());
        exceptionThrown = true;
        }
        assertNull(item2Value);
      assertTrue(exceptionThrown);

/*        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence didnt happen
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        // verify that the list has not increased
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore, listSizeAfter);

        // verify that DataObject has not changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd, treeSizeAfterAdd);
*/    }

    public void test_voidReturnFrom_add_int_Property_Object_propertyIsAttribute() {
        // int index, Property property, Object value) {
        defineAndLoadRoot(false, false);
        // detach shipTo
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size();
        // object to add
        DataObject item2 = (DataObject)root.get("item[2]");
        assertNotNull(item2);

        Property orderDateProperty = po.getInstanceProperty("orderDate");

        // add to sequence
        try {
            aSequence.add(indexToPlaceAtEnd, orderDateProperty, "1999-10-19");
        } catch (Exception e) {

        }

        // get back new Setting value
        ListWrapper item2Value = null;

        try {
            item2Value = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        } catch (SDOException e) {
            assertEquals(SDOException.INVALID_INDEX ,e.getErrorCode());
        }
        assertNull(item2Value);
   }


    /**
     * Removes the entry at the given entry index.
     * @param index the index of the entry.
     */
    public void test_voidReturnFrom_remove_int() {
        // int index) {
    }

    /**
     * Moves the entry at <code>fromIndex</code> to <code>toIndex</code>.
     * @param toIndex the index of the entry destination.
     * @param fromIndex the index of the entry to move.
     */
    public void test_voidReturnFrom_move_int_int() {
        // int toIndex, int fromIndex) {
    }

    /**
    * @deprecated replaced by {@link #addText(String)} in 2.1.0
    */
    @Deprecated
    public void test_voidReturnFrom_add_String() {
        // String text) {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        int textIndexToPlaceAtEnd = aSequence.size();

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);

        aSequence.add("random text");
        Object addText = aSequence.getValue(textIndexToPlaceAtEnd);
        assertNotNull(addText);
        assertNull(aSequence.getProperty(textIndexToPlaceAtEnd));
        assertEquals(PO_SEQUENCE_TREE_SIZE + 1, aSequence.size());

        // verify that DataObject has not changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd, treeSizeAfterAdd);
    }

    /**
     * @deprecated replaced by {@link #addText(int, String)} in 2.1.0
     */
    @Deprecated
    public void test_voidReturnFrom_add_int_String() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        int textIndexToPlaceAtEnd = aSequence.size();

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);

        aSequence.add(textIndexToPlaceAtEnd, "random text");
        Object addText = aSequence.getValue(textIndexToPlaceAtEnd);
        assertNotNull(addText);
        assertNull(aSequence.getProperty(textIndexToPlaceAtEnd));
        assertEquals(PO_SEQUENCE_TREE_SIZE + 1, aSequence.size());

        // verify that DataObject has not changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd, treeSizeAfterAdd);
    }

    /**
     * Adds a new text entry to the end of the Sequence.
     * @param text value of the entry.
     */
    public void test_voidReturnFrom_addText_String() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        int textIndexToPlaceAtEnd = aSequence.size();

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);

        aSequence.addText("random text");
        Object addText = aSequence.getValue(textIndexToPlaceAtEnd);
        assertNotNull(addText);
        assertNull(aSequence.getProperty(textIndexToPlaceAtEnd));
        assertEquals(PO_SEQUENCE_TREE_SIZE + 1, aSequence.size());

        // verify that DataObject has not changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd, treeSizeAfterAdd);
    }

    /**
     * Adds a new text entry at the given index.
     * @param index the index at which to add the entry.
     * @param text value of the entry.
     */
    public void test_voidReturnFromAddText_int_String() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        int textIndexToPlaceAtEnd = aSequence.size();

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);

        aSequence.addText(textIndexToPlaceAtEnd, "random text");
        Object addText = aSequence.getValue(textIndexToPlaceAtEnd);
        assertNotNull(addText);
        assertNull(aSequence.getProperty(textIndexToPlaceAtEnd));
        assertEquals(PO_SEQUENCE_TREE_SIZE + 1, aSequence.size());

        // verify that DataObject has not changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd, treeSizeAfterAdd);
    }

    /**
     * Sets the entry at a specified index to the new value.
     * @param index the index of the entry.
     * @param value the new value for the entry.
     */
    public void test_addAll_complexMany() {
        // int index, Object value) {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        ListWrapper existingList = (ListWrapper)po.get("item");
        int listSizeBefore = existingList.size();
        assertEquals(2, listSizeBefore);

        int sequenceSizeBefore = aSequence.size();
        int indexToPlaceAtEnd = aSequence.size() - 1;
        // object to replace
        DataObject item2 = (DataObject)root.get("item[2]");
        assertNotNull(item2);

        // object to add
        DataObject item3 = (DataObject)root.get("item[1]");
        assertNotNull(item3);

        // add to sequence

        // TODO: TEST setting a many property using an item instead of a List of items

        // add the item to the current list
        // add list of items to existing list
        List<DataObject> aListToAdd = new ArrayList<DataObject>();
        aListToAdd.add(item3);
        // add to the end of the list
        existingList.addAll(aListToAdd);

        // verify that the list has increased on the do
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + aListToAdd.size(), listSizeAfter);

        // verify that the sequence size has increased
        assertEquals(sequenceSizeBefore + aListToAdd.size(), aSequence.size());

        // get back new Setting value
        SDODataObject item2Value = (SDODataObject)aSequence.getValue(aSequence.size() -1);
        assertNotNull(item2Value);
        assertEquals(item2Value, aListToAdd.get(0));
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check increased size of sequence
        assertEquals(PO_SEQUENCE_TREE_SIZE + 1, aSequence.size());

        // verify that DataObject has changed
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + 1, treeSizeAfterAdd);
    }

    public void test_setValue_singleComplex() {

    }
    public void test_setValue_manySimple() {

    }
    public void test_setValue_manyComplex() {

    }

    public void test_setValue_manyComplex_toNull_ThrowsUnsupportedOperationException() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        int indexToPlaceAtEnd = aSequence.size() - 1;
        boolean exceptionOccurred = false;
        // null value on non-nillable many property will throw exception
        try {
            aSequence.setValue(indexToPlaceAtEnd, null);
        } catch (UnsupportedOperationException iex) {
            exceptionOccurred = true;
        }
        assertTrue("An UnsupportedOperationException did not occur as expected", exceptionOccurred);
    }

    public void test_setValue_manyComplex_invalidIndexThrowsException() {
        // int index, String propertyName, Object value) {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size() - 1;
        // object to replace
        DataObject item2 = (DataObject)root.get("item[2]");

        assertNotNull(item2);
/*
        // add the item to the current list
        ListWrapper existingList = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(existingList);
        existingList.add(item2);

        boolean exceptionThrown = false;
        try {
            aSequence.setValue(indexToPlaceAtEnd + 1, existingList);
        } catch (IndexOutOfBoundsException e) {
            exceptionThrown = true;
        } finally {
            assertTrue(exceptionThrown);
        }

        // get back modified Setting value
        ListWrapper item2Value = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(item2Value);
        assertNotNull(aSequence.getProperty(indexToPlaceAtEnd));
        // check no increase in size of sequence
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        // verify that the list has increased
        int listSizeAfter = ((ListWrapper)po.get("item")).size();
        assertEquals(listSizeBefore + 1, listSizeAfter);

        // verify that DataObject has changed in size
        int treeSizeAfterAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(treeSizeBeforeAdd + 1, treeSizeAfterAdd);
*/    }

    public void test_getValue_whereSettingIsNull() {
        registerCustomerType(true, null);
        DataObject cust1 = dataFactory.create(typeHelper.getType(URINAME, CUSTOMER_TYPENAME));
        cust1.set("custID", 5);
        List emails = new ArrayList();
        emails.add("email1-DF@myCompany.com");
        emails.add("email2-DF@myCompany.com");
        cust1.set("email", emails);
        List phones = new ArrayList();
        phones.add("6135550001");
        cust1.set("phone", phones);

        // create a non-standard sequence
        SDOSequence aSequence = new SDOSequence((SDODataObject)cust1);
        // TODO: there is no way to get a null setting from a sequence
    }

    public void test_getValue_whereIndexIsOutOfBounds() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size() - 1;
        // object to replace
        DataObject item2 = (DataObject)root.get("item[2]");

        assertNotNull(item2);
/*
        // add the item to the current list
        ListWrapper existingList = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(existingList);
        existingList.add(item2);

        boolean exceptionThrown = false;
        try {
            aSequence.getValue(-1);
        } catch (IndexOutOfBoundsException e) {
            exceptionThrown = true;
        } finally {
            assertTrue(exceptionThrown);
        }
*/    }

    /**
     * Returns the property for the given entry index.
     * Returns <code>null</code> for mixed text entries.
     * @param index the index of the entry.
     */
    public void test_PropertyReturnFrom_getProperty() {
        // int index) {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size() - 1;
        // object to replace
        DataObject item2 = (DataObject)root.get("item[2]");

        assertNotNull(item2);

/*        // add the item to the current list
        ListWrapper existingList = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(existingList);
        existingList.add(item2);

        boolean exceptionThrown = false;
        Property property1 = po.getInstanceProperty("item");
        Object property1Return = null;
        try {
            property1Return = aSequence.getProperty(indexToPlaceAtEnd);
        } catch (IndexOutOfBoundsException e) {
            exceptionThrown = true;
        } finally {
            assertFalse(exceptionThrown);
        }

        // verify property
        assertNotNull(property1Return);
        assertEquals(property1, property1Return);
*/    }

    /**
     * Returns the property value for the given entry index.
     * @param index the index of the entry.
     */
    public void test_ObjectReturnFrom_getValue() {
        // int index) {
    }

    public void test_getProperty_whereIndexIsOutOfBounds() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);

        int treeSizeBeforeAdd = preOrderTraversalDataObjectList(po).size();
        assertEquals(PO_TREE_SIZE, treeSizeBeforeAdd);
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());

        int listSizeBefore = ((ListWrapper)po.get("item")).size();
        assertEquals(2, listSizeBefore);

        int indexToPlaceAtEnd = aSequence.size() - 1;
        // object to replace
        DataObject item2 = (DataObject)root.get("item[2]");

        assertNotNull(item2);

/*        // add the item to the current list
        ListWrapper existingList = (ListWrapper)aSequence.getValue(indexToPlaceAtEnd);
        assertNotNull(existingList);
        existingList.add(item2);

        boolean exceptionThrown = false;
        try {
            aSequence.getProperty(-1);
        } catch (IndexOutOfBoundsException e) {
            exceptionThrown = true;
        } finally {
            assertTrue(exceptionThrown);
        }
*/    }

    // get id
    public void test_getSequenceViaPropertyIndexFromSingleSimpleType() {

    }

    // get comment[1]
    public void test_getSequenceViaPropertyIndexFromManySimpleType() {

    }

    // get
    public void test_getSequenceViaPropertyIndexFromSingleComplexType() {

    }

    // get porder[1]
    public void test_getSequenceViaPropertyIndexFromManyComplexType() {

    }

    public void testMoveSameIndex() {
        defineAndLoadRoot(false, false);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());
        SDOSequence aSequence = (SDOSequence)po.getSequence();

        // move 2 sequenced objects
        Property beforeMoveProp1 = aSequence.getProperty(1);
        assertNotNull(beforeMoveProp1);

        aSequence.move(1, 1);

        Property afterMoveProp1 = aSequence.getProperty(1);
        assertTrue(beforeMoveProp1 == afterMoveProp1);
    }


    public void testMoveSameIndexOutOfBoundsHigh() {
        defineAndLoadRoot(false, false);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());
        SDOSequence aSequence = (SDOSequence)po.getSequence();

        // move 2 sequenced objects
        Property beforeMoveProp1 = aSequence.getProperty(1);
        assertNotNull(beforeMoveProp1);

            aSequence.move(99, 99);

        Property afterMoveProp1 = aSequence.getProperty(1);
        // verify the move did not take place
        assertTrue(beforeMoveProp1 == afterMoveProp1);

    }

    public void testMoveIndexFromOutOfBoundsHigh() {
        defineAndLoadRoot(false, false);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());
        SDOSequence aSequence = (SDOSequence)po.getSequence();

        // move 2 sequenced objects
        Property beforeMoveProp1 = aSequence.getProperty(1);
        assertNotNull(beforeMoveProp1);
        boolean exceptionThrown = false;
        try {
            aSequence.move(99, 1);
        } catch (SDOException e) {
        assertEquals(SDOException.INVALID_INDEX ,e.getErrorCode());

            // catch error
          exceptionThrown = true;
        }

        Property afterMoveProp1 = aSequence.getProperty(1);
        // verify the move did not take place
        assertTrue(beforeMoveProp1 == afterMoveProp1);
        assertTrue(exceptionThrown);
    }

    public void testMoveIndexToOutOfBoundsHigh() {
        defineAndLoadRoot(false, false);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());
        SDOSequence aSequence = (SDOSequence)po.getSequence();

        // move 2 sequenced objects
        Property beforeMoveProp1 = aSequence.getProperty(1);
        assertNotNull(beforeMoveProp1);
        boolean exceptionThrown = false;
        try {
            aSequence.move(1, 99);
        } catch (SDOException e) {
            // catch error
          assertEquals(SDOException.INVALID_INDEX ,e.getErrorCode());
          exceptionThrown = true;
        }

        Property afterMoveProp1 = aSequence.getProperty(1);
        // verify the move did not take place
        assertTrue(beforeMoveProp1 == afterMoveProp1);
        assertTrue(exceptionThrown);
    }

    public void testMoveIndexBothOutOfBoundsHigh() {
        defineAndLoadRoot(false, false);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());
        SDOSequence aSequence = (SDOSequence)po.getSequence();

        // move 2 sequenced objects
        Property beforeMoveProp1 = aSequence.getProperty(1);
        assertNotNull(beforeMoveProp1);
        boolean exceptionThrown = false;
        try {
            aSequence.move(101, 99);
        } catch (SDOException e) {
            // catch error
          assertEquals(SDOException.INVALID_INDEX ,e.getErrorCode());
            exceptionThrown = true;

        }

        Property afterMoveProp1 = aSequence.getProperty(1);
        // verify the move did not take place
        assertTrue(beforeMoveProp1 == afterMoveProp1);
        assertTrue(exceptionThrown);
    }

    public void testMoveSameIndexOutOfBoundsLow() {
        defineAndLoadRoot(false, false);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());
        SDOSequence aSequence = (SDOSequence)po.getSequence();

        // move 2 sequenced objects
        Property beforeMoveProp1 = aSequence.getProperty(1);
        assertNotNull(beforeMoveProp1);
            aSequence.move(-1, -1);

        Property afterMoveProp1 = aSequence.getProperty(1);
        // verify the move did not take place
        assertTrue(beforeMoveProp1 == afterMoveProp1);

    }

    public void testMoveIndexFromOutOfBoundsLow() {
        defineAndLoadRoot(false, false);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());
        SDOSequence aSequence = (SDOSequence)po.getSequence();

        // move 2 sequenced objects
        Property beforeMoveProp1 = aSequence.getProperty(1);
        assertNotNull(beforeMoveProp1);
        boolean exceptionThrown = false;
        try {
            aSequence.move(-1, 1);
        } catch (SDOException e) {
            assertEquals(SDOException.INVALID_INDEX ,e.getErrorCode());
          // catch error
            exceptionThrown = true;
        }

        Property afterMoveProp1 = aSequence.getProperty(1);
        // verify the move did not take place
        assertTrue(beforeMoveProp1 == afterMoveProp1);
        assertTrue(exceptionThrown);
    }

    public void testMoveIndexToOutOfBoundsLow() {
        defineAndLoadRoot(false, false);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());
        SDOSequence aSequence = (SDOSequence)po.getSequence();

        // move 2 sequenced objects
        Property beforeMoveProp1 = aSequence.getProperty(1);
        assertNotNull(beforeMoveProp1);
        boolean exceptionThrown = false;
        try {
            aSequence.move(1, -1);
        } catch (SDOException e) {
            // catch error
            exceptionThrown = true;
        assertEquals(SDOException.INVALID_INDEX ,e.getErrorCode());
        }

        Property afterMoveProp1 = aSequence.getProperty(1);
        // verify the move did not take place
        assertTrue(beforeMoveProp1 == afterMoveProp1);
        assertTrue(exceptionThrown);
    }

    public void testMoveIndexBothOutOfBoundsLow() {
        defineAndLoadRoot(false, false);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());
        SDOSequence aSequence = (SDOSequence)po.getSequence();

        // move 2 sequenced objects
        Property beforeMoveProp1 = aSequence.getProperty(1);
        assertNotNull(beforeMoveProp1);
        boolean exceptionThrown = false;
        try {
            aSequence.move(-1, -2);
        } catch (SDOException e) {
            // catch error
          assertEquals(SDOException.INVALID_INDEX ,e.getErrorCode());
          exceptionThrown = true;
        }

        Property afterMoveProp1 = aSequence.getProperty(1);
        // verify the move did not take place
        assertTrue(beforeMoveProp1 == afterMoveProp1);
        assertTrue(exceptionThrown);
    }

    public void testMoveIndex0toEnd() {
        defineAndLoadRoot(false, false);
        //SDOSequence aSequence = getSequence();
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());
        SDOSequence aSequence = (SDOSequence)po.getSequence();

        // move 2 sequenced objects
        Property beforeMoveProp0 = aSequence.getProperty(0);
        Property beforeMoveProp1 = aSequence.getProperty(1);
        Property beforeMoveProp3 = aSequence.getProperty(3);
        assertNotNull(beforeMoveProp0);
        assertNotNull(beforeMoveProp1);
        assertNotNull(beforeMoveProp3);

        // 0,1,2,3 -> 1,2,3,0
        aSequence.move(3, 0);

        Property afterMoveProp0 = aSequence.getProperty(0);
        //Property afterMoveProp0 = aSequence.getProperty(0);
        Property afterMoveProp3 = aSequence.getProperty(3);
        assertTrue(beforeMoveProp1 == afterMoveProp0);
        assertTrue(beforeMoveProp0 == afterMoveProp3);
    }

    public void testMoveIndexEndto0() {

    }
    public void testMoveIndexAdjacent1to2() {

    }
    public void testMoveIndexAdjacent2to1() {

    }

    public void testToString() {
        // exercise the toString() method for code coverage
        defineAndLoadRoot(false, false);
        // get sequence po
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());
        SDOSequence aSequence = (SDOSequence)po.getSequence();
        assertNotNull(aSequence);
        // 4 instead of 5 because the one attribute property cannot be sequenced
        assertEquals(PO_SEQUENCE_SIZE, aSequence.size());
        String aString = aSequence.toString();
        assertNotNull(aString);
        // we could do some minimal string comparison

    }

    public void testEqualDeepSameSequence() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        //compareSequences(aSequence, aSequence, PO_SEQUENCE_SIZE, true);
        // get sequence po
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());

        // test equalityHelper
        boolean bEqual = equalityHelper.equal(po, po);
        assertTrue(bEqual);
    }

    public void testEqualShallowSameSequence() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        //compareSequences(aSequence, aSequence, PO_SEQUENCE_SIZE, true);
        // get sequence po
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());

        // test equalityHelper
        boolean bEqual = equalityHelper.equalShallow(po, po);
        assertTrue(bEqual);
    }

    // Via a non-interface method the user is able to set sequenced=true after type definition - not supported
    public void testEqualShallowSameSequenceFlagTrueButSequenceIsNull() {
        defineAndLoadRoot(false, false);
        SDOSequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        //compareSequences(aSequence, aSequence, PO_SEQUENCE_SIZE, true);
        // get sequence po
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        assertNotNull(po);
        assertTrue(po.getType().isSequenced());

        // test equalityHelper
        boolean bEqual = equalityHelper.equalShallow(po, po);
        assertTrue(bEqual);

/*
        defineAndLoadRoot(false, false);
        Sequence aSequence = getSequence(root, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        DataObject po = (DataObject)root.get(PO_SEQUENCE_PATH);
        // copy po
        DataObject rootCopy = (DataObject)copyHelper.copy(root);
        // check sequence was copied
        Sequence aSequenceCopy = getSequence(rootCopy, PO_SEQUENCE_PATH, PO_SEQUENCE_SIZE);
        assertNotNull(aSequenceCopy);
        //compareSequences((SDOSequence)aSequence, (SDOSequence)aSequenceCopy, PO_SEQUENCE_SIZE, true);

        // test equalityHelper
        DataObject poCopy = (DataObject)rootCopy.get(PO_SEQUENCE_PATH);
        boolean bEqual = equalityHelper.equal(po, poCopy);
        assertTrue(bEqual);

        // modify copy sequence state - non public method - both po and poCopy will have their state changed because they share an SDOType
        assertTrue(po.getType().isSequenced());
        assertTrue(poCopy.getType().isSequenced());
        // WARNING: Users should not be doing this - however it is supported
        ((SDOType)poCopy.getType()).setSequenced(false);
        assertFalse(po.getType().isSequenced());
        assertFalse(poCopy.getType().isSequenced());
        bEqual = equalityHelper.equal(po, poCopy);
        // sequences will not be compared
        assertTrue(bEqual);
*/    }


/*
    // use XSD to define and XML to load - working
    public void testDefineViaXSDandLoadViaXML() throws Exception {
        DefaultSchemaLocationResolver resolver = new DefaultSchemaLocationResolver(getMap());
           List<Type> types = xsdHelper.define(getXSDString(XSD_PATH));

        String generatedSchema = ((SDOXSDHelper)xsdHelper).generate(types, resolver);
        log(generatedSchema);
        root = createRootObject(true, types);
        int aRootsize = preOrderTraversalDataObjectList((SDODataObject)root).size();
        assertTrue(writeXML(root, URINAME, COMPANY_TYPENAME, System.out));
        //assertXMLIdentical(getDocument(getControlGeneratedFileName()), generatedSchemaDoc);
    }


    // use XSD to define and programmatic DataFactory to load -  not working
    public void testDefineViaXSDandLoadViaDataFactory() throws Exception {
        DefaultSchemaLocationResolver resolver = new DefaultSchemaLocationResolver(getMap());
           List<Type> types = xsdHelper.define(getXSDString(XSD_PATH));
        String generatedSchema = ((SDOXSDHelper)xsdHelper).generate(types, resolver);
        log(generatedSchema);
        root = createRootObject(false, types);
        int aRootsize = preOrderTraversalDataObjectList((SDODataObject)root).size();
        assertEquals(9, aRootsize);
        assertTrue(writeXML(root, URINAME, COMPANY_TYPENAME, System.out));
    }
*/
/*
    // use programmatic define(DataObject) to define and XML to load - not working
    public void testDefineViaDataObjectandLoadViaXML() throws Exception {
        DefaultSchemaLocationResolver resolver = new DefaultSchemaLocationResolver(getMap());
        registerTypes();
        List<Type> types = getTypesToGenerateFrom();
        String generatedSchema = ((SDOXSDHelper)xsdHelper).generate(types, resolver);
        log(generatedSchema);
        root = createRootObject(true, types);
        int aRootsize = preOrderTraversalDataObjectList((SDODataObject)root).size();
        assertTrue(writeXML(root, URINAME, COMPANY_TYPENAME, System.out));
    }
*/
/*
    // use programmatic define(DataObject) and programmatic DataFactory to load
    public void testDefineViaDataObjectandLoadViaDataFactory() throws Exception {
        DefaultSchemaLocationResolver resolver = new DefaultSchemaLocationResolver(getMap());
        registerTypes();
        List<Type> types = getTypesToGenerateFrom();

        String generatedSchema = ((SDOXSDHelper)xsdHelper).generate(types, resolver);
        log(generatedSchema);
        root = createRootObject(false, types);
        int aRootsize = preOrderTraversalDataObjectList((SDODataObject)root).size();
        assertEquals(9, aRootsize);
        assertTrue(writeXML(root, URINAME, COMPANY_TYPENAME, System.out));
    }
*/
}
