
import os
DBNAME=os.environ.get("ODS_TEST_DB","ods:test")

from Ft.Ods import Database
from Ft.Ods.StorageManager.Adapters import Constants

from Ft.Ods import Collections

from Ft.Ods.MetaData import Module, CollectionKind

import test_collection_util

from Ft.Ods.Collections import ListBase
from Ft.Ods.Collections import CollectionBase


def test_collection_base(tester,db,ck,st,isRel):
    tester.startTest("Collection Base")

    fac = test_collection_util.GetFactory(st)

    tx = db.new()
    tx.begin()

    coll = Collections.CollectionFromTypes(db,ck,st,isRelationship = isRel,subTypeRepositoryId=fac.typeId)
    tester.compare(0,coll.cardinality())
    tester.compare(1,coll.is_empty())

    one = fac.next(db)
    two = fac.next(db)

    coll.insert_element(one)
    coll.insert_element(two)

    tester.compare(2,coll.cardinality())
    tester.compare(0,coll.is_empty())

    tx.commit()

    cid = coll._4ods_getId()

    tx = db.new()
    tx.begin()
    
    coll = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)

    one = fac.recreate(db,one)
    two = fac.recreate(db,two)

    tester.compare(1,coll.contains_element(one))
    tester.compare(1,coll.contains_element(two))

    coll.remove_element(two)

    tester.compare(1,coll.cardinality())
    tester.compare(0,coll.is_empty())
    tx.commit()

    tx = db.new()
    tx.begin()
    
    coll = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)
    one = fac.recreate(db,one)
    two = fac.recreate(db,two)

    tester.compare(1,coll.contains_element(one))
    tester.compare(0,coll.contains_element(two))
    tester.compare(1,coll.cardinality())
    tester.compare(0,coll.is_empty())

    coll2 = coll.copy()
    tester.compare(1,coll2.contains_element(one))
    tester.compare(0,coll2.contains_element(two))


    tx.commit()

    cid2 = coll2._4ods_getId()

    tx = db.new()
    tx.begin()
    
    coll2 = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)
    tester.compare(1,coll2.contains_element(one))
    tester.compare(0,coll2.contains_element(two))

    tx.abort()

    tester.testDone()







def test_list_base(tester,db,ck,st,isRel):

    tester.startGroup("List Base")

    fac = test_collection_util.GetFactory(st)

    tx = db.new()
    tx.begin()

    lb = Collections.CollectionFromTypes(db,ck,st,isRelationship = isRel,subTypeRepositoryId=fac.typeId)

    values = []
    for ctr in range(6):
        values.append(fac.next(db))

    tester.startTest("Test insert_first")
    lb.insert_element_first(values[0])
    tester.compare(1,len(lb))

    tester.compare(values[0],lb[0])
    lb.insert_element_first(values[1])
    tester.compare(2,len(lb))
    tester.compare(values[1],lb[0])

    tx.commit()

    cid = lb._4ods_getId()

    tx = db.new()
    tx.begin()

    values = test_collection_util.recreate(db,fac,values)
    
    lb = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)
    values = test_collection_util.recreate(db,fac,values)
    tester.compare(values[0],lb[1])
    tester.compare(values[1],lb[0])
    tester.testDone()


    tester.startTest("Test insert_element_last")
    lb.insert_element_last(values[2])
    tester.compare(3,len(lb))
    tester.compare(values[2],lb[-1])

    tx.commit()
    tx = db.new()
    tx.begin()

    values = test_collection_util.recreate(db,fac,values)
    lb = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)
    tester.compare(3,len(lb))
    tester.compare(values[2],lb[-1])
    tester.testDone()


    tester.startTest("Test insert_element_after")
    lb.insert_element_after(values[3],1)
    tester.compare(4,len(lb))
    tester.compare(values[3],lb[2])

    tx.commit()
    tx = db.new()
    tx.begin()

    values = test_collection_util.recreate(db,fac,values)
    lb = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)
    tester.compare(4,len(lb))
    tester.compare(values[3],lb[2])
    tester.testDone()


    tester.startTest("test insert_element_before")
    lb.insert_element_before(values[4],1)
    tester.compare(5,len(lb))
    tester.compare(values[4],lb[1])

    tx.commit()
    tx = db.new()
    tx.begin()

    values = test_collection_util.recreate(db,fac,values)
    lb = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)
    tester.compare(5,len(lb))
    tester.compare(values[4],lb[1])
    tester.testDone()


    tester.startTest("Test insert exceptions")


    tester.testException(lb.insert_element_after, (values[5],-1), ListBase.ListBase.InvalidIndex)
    tester.testException(lb.insert_element_after, (values[5],10), ListBase.ListBase.InvalidIndex)
    tester.testException(lb.insert_element_before, (values[5],-1), ListBase.ListBase.InvalidIndex)
    tester.testException(lb.insert_element_before, (values[5],10), ListBase.ListBase.InvalidIndex)

    tester.testDone()


    tester.startTest("Test Retrieve_element_at")

    tester.compare(values[4],lb.retrieve_element_at(1))
    tester.testException(lb.retrieve_element_at, (-1,), ListBase.ListBase.InvalidIndex)
    tester.testException(lb.retrieve_element_at, (100,), ListBase.ListBase.InvalidIndex)
    tester.testDone()


    tester.startTest("TEst retrieve element first")
    tester.compare(values[1],lb.retrieve_first_element())
    tester.testDone()

    tester.startTest("test retrieve element last")
    tester.compare(values[2],lb.retrieve_last_element())
    tester.testDone()


    tester.startTest("Test replace element")
    lb.replace_element_at(values[5],1)
    tester.compare(5,len(lb))
    tester.compare(values[5],lb[1])
    tester.testException(lb.replace_element_at, (values[1],-1), ListBase.ListBase.InvalidIndex)
    tester.testException(lb.replace_element_at, (values[1],10), ListBase.ListBase.InvalidIndex)


    tx.commit()
    tx = db.new()
    tx.begin()

    values = test_collection_util.recreate(db,fac,values)
    lb = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)
    tester.testResults(5,len(lb),done=0,msg='replace element')
    tester.testResults(values[5],lb[1],done=0,msg='replace 1')
    tester.testDone()


    tester.startTest("Test remove_element_at")
    lb.remove_element_at(1)
    tester.testResults(4,len(lb),done=0,msg='remove element')
    tester.testResults(values[0],lb[1],done=0,msg='remove 1')
    tester.testException(lb.remove_element_at, (-1,), ListBase.ListBase.InvalidIndex)
    tester.testException(lb.remove_element_at, (10,), ListBase.ListBase.InvalidIndex)

    tx.commit()
    tx = db.new()
    tx.begin()

    values = test_collection_util.recreate(db,fac,values)
    lb = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)
    tester.testResults(4,len(lb),done=0,msg='remove element')
    tester.testResults(values[0],lb[1],done=0,msg='remove 1')

    tester.testDone()



    tester.startTest("remove_first_element")
    lb.remove_first_element()
    tester.testResults(3,len(lb),done=0,msg='remove first element')
    tester.testResults(values[0],lb[0],done=0,msg='remove first 1')

    tx.commit()
    tx = db.new()
    tx.begin()

    values = test_collection_util.recreate(db,fac,values)
    lb = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)
    tester.testResults(3,len(lb),done=0,msg='remove first element')
    tester.testResults(values[0],lb[0],done=0,msg='remove first 1')

    tester.testDone()


    tester.startTest("Test remove last element")
    lb.remove_last_element()
    tester.testResults(2,len(lb),done=0,msg='remove last element')
    tester.testResults(values[3],lb[-1],done=0,msg='remove last 1')

    tx.commit()
    tx = db.new()
    tx.begin()

    values = test_collection_util.recreate(db,fac,values)
    lb = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)
    tester.testResults(2,len(lb),done=0,msg='remove last element')
    tester.testResults(values[3],lb[-1],done=0,msg='remove last 1')

    tester.testDone()


    tx.commit()
    
    tx = db.new()
    tx.begin()

    lb = Collections.CollectionFromTypes(db,ck,st,isRelationship = isRel,subTypeRepositoryId=fac.typeId)
    values = test_collection_util.recreate(db,fac,values)

    tester.startTest("Test first and last exceptions")

    tester.testException(lb.remove_first_element, (), ListBase.ListBase.InvalidIndex)
    tester.testException(lb.remove_last_element, (), ListBase.ListBase.InvalidIndex)
    tester.testException(lb.retrieve_first_element, (), CollectionBase.CollectionBase.ElementNotFound)
    tester.testException(lb.retrieve_last_element, (), CollectionBase.CollectionBase.ElementNotFound)

    tester.testDone()


    lb2 = lb.copy()

    lb.insert_element(values[0])
    lb2.insert_element(values[1])

    tester.startTest("Test concat")
    rt = lb.concat(lb2)
    tester.testResults(2,len(rt),done=0,msg='concat')
    tester.testResults(1,values[0]in rt,done=0,msg='concat 1')
    tester.testResults(1,values[1]in rt,done=0,msg='concat 1')
    tester.testDone()



    tester.startTest("test append")
    lb.append(lb2)
    tester.testResults(2,len(lb),done=0,msg='append')
    tester.testResults(1,values[0]in lb,done=0,msg='append 1')
    tester.testResults(1,values[1]in lb,done=0,msg='append 1')


    tx.commit()

    cid = lb._4ods_getId()
    cid2 = lb2._4ods_getId()


    tx = db.new()
    tx.begin()

    values = test_collection_util.recreate(db,fac,values)
    lb = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)
    lb2 = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid2)




    tester.testDone()

    tester.startTest("Test is Ordered")
    tester.testResults(1,lb.is_ordered(),done=0,msg='ordered')
    tester.testDone()

    tester.startTest("Test is Allows Duplicates")
    tester.testResults(1,lb.allows_duplicates(),done=0,msg='duplicates')
    tester.testDone()


    tx.commit()

    tester.startTest("Test insert element override")
    tx = db.new()
    tx.begin()

    lb = Collections.CollectionFromTypes(db,ck,st,isRelationship = isRel,subTypeRepositoryId=fac.typeId)
    values = test_collection_util.recreate(db,fac,values)
    lb.insert_element(values[0])
    lb.insert_element(values[1])
    tester.testResults(values[1],lb.retrieve_last_element(),done=0,msg='insert10')

    tx.commit()

    cid = lb._4ods_getId()

    tx = db.new()
    tx.begin()

    values = test_collection_util.recreate(db,fac,values)
    lb = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)
    tester.compare(values[1],lb.retrieve_last_element())
    tester.testDone()

    tester.startTest("Test remove element override")
    lb.remove_element(values[0])
    tester.testResults(1,len(lb),done=0,msg='remove 10')
    tester.testResults(values[1],lb[0],done=0,msg='remove 11')
    tx.commit()

    tx = db.new()
    tx.begin()

    values = test_collection_util.recreate(db,fac,values)
    lb = db._4ods_getPersistentObjectById(Constants.Types.LIST_COLLECTION,cid)
    tester.testResults(values[1],lb[0],done=0,msg='remove 11')
    tester.testDone()
    
    tx.abort()
    tester.groupDone()


def test_set_base(tester,db,ck,st,isRel):

    fac = test_collection_util.GetFactory(st)

    tx = db.new()
    tx.begin()

    sb = Collections.CollectionFromTypes(db,ck,st,isRelationship = isRel,subTypeRepositoryId=fac.typeId)
    sb2 = sb.copy()

    values = []
    for ctr in range(3):
        values.append(fac.next(db))

    sb.insert_element(values[0])
    sb.insert_element(values[1])

    sb2.insert_element(values[1])
    sb2.insert_element(values[2])

    tester.startTest("Test Union")
    rt = sb.create_union(sb2)
    tester.testResults(1,len(rt),done=0,msg='union 1')
    tester.testResults(values[1],rt[0],done=0,msg='union 2')
    tester.testDone()


    tester.startTest("Test Intersection")
    rt = sb.create_intersection(sb2)
    tester.testResults(3,len(rt),done=0,msg='int 1')
    tester.testResults(1,values[0] in rt,done=0,msg='int 2')
    tester.testResults(1,values[1] in rt,done=0,msg='int 3')
    tester.testResults(1,values[2] in rt,done=0,msg='int 4')
    tester.testDone()

    tester.startTest("Difference Works")
    rt = sb.create_difference(sb2)
    tester.testResults(2,len(rt),done=0,msg='diff 1')
    tester.testResults(1,values[0] in rt,done=0,msg='diff 2')
    tester.testResults(1,values[2] in rt,done=0,msg='diff 4')
    tester.testDone()
    tester.testDone()

    tester.startTest("Test Subset")
    union = sb.create_union(sb2)
    inter = sb.create_intersection(sb2)
    diff = sb.create_difference(sb2)
    tester.testResults(0,sb.is_subset_of(union),done=0,msg='subset')
    tester.testResults(1,sb.is_subset_of(inter),done=0,msg='subset2')
    tester.testDone()

    tester.startTest("Test Proper subset")
    tester.testResults(0,sb.is_proper_subset_of(sb),done=0,msg='p subset')
    tester.testResults(1,sb.is_proper_subset_of(inter),done=0,msg='p subset2')
    tester.testDone()


    tester.startTest("Test Superset")
    tester.testResults(1,inter.is_superset_of(sb),done=0,msg='superset')
    tester.testResults(0,union.is_superset_of(sb),done=0,msg='superset2')
    tester.testDone()

    tester.startTest("Test proper superset")    
    tester.testResults(0,sb.is_proper_superset_of(sb),done=0,msg='p superset')
    tester.testResults(1,inter.is_proper_superset_of(sb),done=0,msg='superset2')
    tester.testDone()


    tester.startTest("Test is Ordered")
    tester.testResults(0,sb.is_ordered(),done=0,msg='ordered')
    tester.testDone()

    tester.startTest("Test Allows Duplicates")
    tester.testResults(0,sb.allows_duplicates(),done=0,msg='duplicates')
    tester.testDone()


    tester.startTest("Test insert element override")


    sb = Collections.CollectionFromTypes(db,ck,st,isRelationship = isRel,subTypeRepositoryId=fac.typeId)

    sb.insert_element(values[0])
    sb.insert_element(values[0])
    tester.compare(1,len(sb))
    tester.testDone()
    tx.abort()



def test_bag_base(tester,db,ck,st,isRel):

    fac = test_collection_util.GetFactory(st)

    tx = db.new()
    tx.begin()

    bb = Collections.CollectionFromTypes(db,ck,st,isRelationship = isRel,subTypeRepositoryId=fac.typeId)

    values = []
    for ctr in range(3):
        values.append(fac.next(db))


    tester.startTest("Test Occurrences_of")
    tester.testResults(0,bb.occurrences_of(values[0]),done=0,msg='occ1')
    bb.insert_element(values[0])
    tester.testResults(1,bb.occurrences_of(values[0]),done=0,msg='occ2')
    bb.insert_element(values[0])
    tester.testResults(2,bb.occurrences_of(values[0]),done=0,msg='occ3')
    tester.testDone()

    tester.startTest("Test Union")

    bb = Collections.CollectionFromTypes(db,ck,st,isRelationship = isRel,subTypeRepositoryId=fac.typeId)
    bb2 = bb.copy()
    bb.insert_element(values[0])
    bb.insert_element(values[1])

    bb2.insert_element(values[1])
    bb2.insert_element(values[2])
    rt = bb.create_union(bb2)
    tester.testResults(1,len(rt),done=0,msg='union1')
    tester.testResults(values[1],rt[0],done=0,msg='union2')
    tester.testDone()


    tester.startTest("Test Intersection")
    rt = bb.create_intersection(bb2)
    tester.testResults(3,len(rt),done=0,msg='int1')
    tester.testResults(1,values[0] in rt,done=0,msg='int2')
    tester.testResults(1,values[1] in rt,done=0,msg='int3')
    tester.testResults(1,values[2] in rt,done=0,msg='int4')
    tester.testDone()

    tester.startTest("Test Difference Works")
    rt = bb.create_difference(bb2)
    tester.testResults(2,len(rt),done=0,msg='int1')
    tester.testResults(1,values[0] in rt,done=0,msg='int2')
    tester.testResults(1,values[2] in rt,done=0,msg='int3')
    tester.testDone()


    tester.startTest("Test is Ordered")
    tester.testResults(0,bb.is_ordered(),done=0,msg='ordered')
    tester.testDone()

    tester.startTest("Test is Allows Duplicates")
    tester.testResults(1,bb.allows_duplicates(),done=0,msg='duplicates')
    tester.testDone()




    tester.startTest("Test insert_element and remove_element overrides")

    bb = Collections.CollectionFromTypes(db,ck,st,isRelationship = isRel,subTypeRepositoryId=fac.typeId)
    bb.insert_element(values[0])
    bb.insert_element(values[0])
    bb.remove_element(values[0])
    tester.testResults(1,bb.occurrences_of(values[0]),done=0,msg='insert')
    tester.testDone()

    tx.abort()

def test_modify_pythonic_interface(tester,db,ck,st,isRel):

    tester.startTest("Pythonic Modification interfaces")

    fac = test_collection_util.GetFactory(st)

    tx = db.new()
    tx.begin()

    coll = Collections.CollectionFromTypes(db,ck,st,isRelationship = isRel,subTypeRepositoryId=fac.typeId)

    one = fac.next(db)
    two = fac.next(db)

    coll[0] = one
    tester.compare(1,coll.contains_element(one))
    tester.compare(0,coll.contains_element(two))

    coll[0] = two
    tester.compare(0,coll.contains_element(one))
    tester.compare(1,coll.contains_element(two))

    tx.abort()

    tester.testDone()

    
def test_collection_interface(tester,db,ck,st,isRel):

    tester.startGroup("Collection %s Persistence: %s of %s %s Driver" % (isRel and "(Relationship)" or "",
                                                                         Constants.g_odmgTypeToString[ck],
                                                                         Constants.g_odmgTypeToString[st],
                                                                         tester.test_data['driver']))

    test_collection_base(tester,db,ck,st,isRel)

    if st != Constants.Types.BOOLEAN:
        if ck == Constants.Types.LIST_COLLECTION:
            test_list_base(tester,db,ck,st,isRel)
        elif ck == Constants.Types.SET_COLLECTION:
            test_set_base(tester,db,ck,st,isRel)
        elif ck == Constants.Types.BAG_COLLECTION:
            test_bag_base(tester,db,ck,st,isRel)
        else:
            print ck
            raise "Not SUpported"


    if not isRel:
        test_modify_pythonic_interface(tester,db,ck,st,isRel)

    tester.groupDone()


from Ft.Ods.StorageManager import Adapters

def Test(tester):

    #Test all of the collections in one big test!

    tester.startGroup("Full Collection Test")
    #Can't have a full DB here
    manager = Adapters.GetManager()
    adapter = Adapters.GetAdapter()
    if manager.exists(DBNAME):
        manager.destroy(DBNAME)

    manager.create(DBNAME)
    manager.init(DBNAME)

    db = Database.Database()
    db.open(DBNAME)
    try:

        #Some initialization
        tx = db.new()
        tx.begin()
        test_collection_util.Init(db)

        tx.commit()

        types = Constants.g_allTypes[:]
        types.sort()

        for ck in [Constants.Types.LIST_COLLECTION,
                   Constants.Types.SET_COLLECTION,
                   Constants.Types.BAG_COLLECTION]:


            #for st in types:
            if 1:
                st = Constants.Types.ENUMERATION
                if Constants.g_listTypes[st]:
                    #Tested later
                    continue
                if st in [Constants.Types.VOID,
                          Constants.Types.BLOB,
                          Constants.Types.EXCEPTION]:
                    #Cannot have a collection of voids or blobs
                    continue

                test_collection_interface(tester,db,ck,st,0)

                if st in [Constants.Types.POBJECT,
                          Constants.Types.ROBJECT]:
                    test_collection_interface(tester,db,ck,st,1)

                for f in test_collection_util.factories.values():
                    f.reset()
            
    finally:
        db.close()
    tester.groupDone()


