import os


odl_string = '''
module Test {
class Foo {

  attribute boolean b;
  attribute char c;
  attribute short s;
  attribute string s2;
  attribute unsigned short us;
  attribute long l;
  attribute unsigned long ul;
  attribute long long ll;
  attribute float f;
  attribute double d;
  attribute octet o;
};
};
'''

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

import sys, test_util, time
from Ft.Ods import Database
from Ft.Ods.StorageManager.Adapters import Constants


def test_type(tester,db,name,attr,vals):


    tester.startTest("Test %s" % name)


    for val in vals:

        tx = db.new()
        tx.begin()
        foo = db.lookup("Foo")
        setattr(foo, attr, val)
        tx.commit()

        # Allow disk caching to catch up (damned gdbm is too fast)
	time.sleep(.05)

        tx = db.new()
        tx.begin()
        foo = db.lookup("Foo")
        actual = getattr(foo, attr)
        tester.compare(val, actual, msg="Wrong value")
        tx.abort()
        
        # Allow disk caching to catch up (damned gdbm is too fast)
        time.sleep(.05)

    tester.testDone()

def test_type_exception(tester,db,name,attr,vals):


    tester.startTest("Test Exception %s" % name)

    for val in vals:

        tx = db.new()
        tx.begin()
        foo = db.lookup("Foo")
        tester.testException(setattr,(foo, attr, val),TypeError)
        tx.abort()

    tester.testDone()

from Ft.Lib import Uuid


def Test(tester):
    try:
        _Test(tester)
    finally:
        if os.path.exists('Test'):
            from distutils import dir_util
            dir_util.remove_tree('Test')

def _Test(tester):

    tester.startGroup("Types %s Driver" % tester.test_data['driver'])

    test_util.DbInit(DBNAME,odl_string)

    tester.startTest('Testing Generated syntax')
    try:
        from Test import Foo
        reload(Foo)
    except:
        tester.error('Error in syntax', 1)


    tester.testDone()

    db = Database.Database()
    db.open(DBNAME)
    try:
        tx = db.new()
        tx.begin()

        #Create an instance of Foo to play with

        f = Foo.new(db)

        db.bind(f,"Foo")

        tx.commit()


        #Test booleans
        test_type(tester,db,"Boolean",'b',[1,0])
        #Test booleans
        test_type_exception(tester,db,"Boolean",'b',['f',0.342,13])

        # XXX maximum int in python is 2147483647 (2**31-1)
        # NB Python Library Reference 2.1.4:
        #    Plain integers (also just called integers) are implemented
        #    using long in C, which gives them at least 32 bits of precision.
        test_type(tester,db,"Short",'s',[1-2**30,-20000,-1000,0,1000,20000,2**30-1])
        test_type_exception(tester,db,"Short",'s',['f',0.342])
        test_type(tester,db,"String",'s2',["TEST1","","A really big string"*100])
        test_type_exception(tester,db,"String",'s2',[1,0.342])
        # XXX 4ODS represents unsigned short by python integers (signed short)
        test_type(tester,db,"Unsigned Short",'us',[0,1000,20000,2**30-1])
        test_type_exception(tester,db,"Unsigned Short",'us',['f',0.342])
        test_type(tester,db,"Long",'l',[-100000,-10000, -1000, 0,1000,10000,100000])
        test_type_exception(tester,db,"Long",'l',['f',0.342])
        test_type(tester,db,"Unsigned Long",'ul',[0,1000,10000,100000])
        test_type_exception(tester,db,"Unsigned Long",'ul',['f',0.342])
        test_type(tester,db,"Long Long",'ll',[0,1000,10000,100000,Uuid.GenerateUuid()])
        test_type_exception(tester,db,"Long Long",'ll',['f',0.342])
        test_type(tester,db,"Float",'f',[ -1000.4, 0.234,1000.5])
        test_type_exception(tester,db,"Float",'f',['f'])
        test_type(tester,db,"Double",'d',[-100000.123,-10000.234, -1000.432, 0,1000.567,10000.765,100000.423])
        test_type_exception(tester,db,"Double",'d',['f'])

        test_type(tester,db,"Char",'c',['a','z', 'A', '0','7','@'])
        test_type_exception(tester,db,"Char",'c',[1,"hi"])

        test_type(tester,db,"Octet",'o',[32,55, 100, 128,200,255])
        test_type_exception(tester,db,"Octet",'o',[-1,256,1000])

    finally:
        db.close()
    tester.groupDone()



