Kano001's picture
Upload 919 files
375a1cf verified
""" Unit tests version 2.6.1.0 for adodbapi"""
"""
adodbapi - A python DB API 2.0 interface to Microsoft ADO
Copyright (C) 2002 Henrik Ekelund
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Updates by Vernon Cole
"""
import copy
import datetime
import decimal
import random
import string
import sys
import unittest
try:
import win32com.client
win32 = True
except ImportError:
win32 = False
# run the configuration module.
import adodbapitestconfig as config # will set sys.path to find correct version of adodbapi
# in our code below, all our switches are from config.whatever
import tryconnection
import adodbapi
import adodbapi.apibase as api
try:
import adodbapi.ado_consts as ado_consts
except ImportError: # we are doing a shortcut import as a module -- so
try:
import ado_consts
except ImportError:
from adodbapi import ado_consts
def str2bytes(sval):
return sval.encode("latin1")
long = int
def randomstring(length):
return "".join([random.choice(string.ascii_letters) for n in range(32)])
class CommonDBTests(unittest.TestCase):
"Self contained super-simple tests in easy syntax, should work on everything between mySQL and Oracle"
def setUp(self):
self.engine = "unknown"
def getEngine(self):
return self.engine
def getConnection(self):
raise NotImplementedError # "This method must be overriden by a subclass"
def getCursor(self):
return self.getConnection().cursor()
def testConnection(self):
crsr = self.getCursor()
assert crsr.__class__.__name__ == "Cursor"
def testErrorHandlerInherits(self):
if not self.remote:
conn = self.getConnection()
mycallable = lambda connection, cursor, errorclass, errorvalue: 1
conn.errorhandler = mycallable
crsr = conn.cursor()
assert (
crsr.errorhandler == mycallable
), "Error handler on crsr should be same as on connection"
def testDefaultErrorHandlerConnection(self):
if not self.remote:
conn = self.getConnection()
del conn.messages[:]
try:
conn.close()
conn.commit() # Should not be able to use connection after it is closed
except:
assert len(conn.messages) == 1
assert len(conn.messages[0]) == 2
assert conn.messages[0][0] == api.ProgrammingError
def testOwnErrorHandlerConnection(self):
if self.remote: # ToDo: use "skip"
return
mycallable = (
lambda connection, cursor, errorclass, errorvalue: 1
) # does not raise anything
conn = self.getConnection()
conn.errorhandler = mycallable
conn.close()
conn.commit() # Should not be able to use connection after it is closed
assert len(conn.messages) == 0
conn.errorhandler = None # This should bring back the standard error handler
try:
conn.close()
conn.commit() # Should not be able to use connection after it is closed
except:
pass
# The Standard errorhandler appends error to messages attribute
assert (
len(conn.messages) > 0
), "Setting errorhandler to none should bring back the standard error handler"
def testDefaultErrorHandlerCursor(self):
crsr = self.getConnection().cursor()
if not self.remote:
del crsr.messages[:]
try:
crsr.execute("SELECT abbtytddrf FROM dasdasd")
except:
assert len(crsr.messages) == 1
assert len(crsr.messages[0]) == 2
assert crsr.messages[0][0] == api.DatabaseError
def testOwnErrorHandlerCursor(self):
if self.remote: # ToDo: should be a "skip"
return
mycallable = (
lambda connection, cursor, errorclass, errorvalue: 1
) # does not raise anything
crsr = self.getConnection().cursor()
crsr.errorhandler = mycallable
crsr.execute("SELECT abbtytddrf FROM dasdasd")
assert len(crsr.messages) == 0
crsr.errorhandler = None # This should bring back the standard error handler
try:
crsr.execute("SELECT abbtytddrf FROM dasdasd")
except:
pass
# The Standard errorhandler appends error to messages attribute
assert (
len(crsr.messages) > 0
), "Setting errorhandler to none should bring back the standard error handler"
def testUserDefinedConversions(self):
if self.remote: ## Todo: should be a "skip"
return
try:
duplicatingConverter = lambda aStringField: aStringField * 2
assert duplicatingConverter("gabba") == "gabbagabba"
self.helpForceDropOnTblTemp()
conn = self.getConnection()
# the variantConversions attribute should not exist on a normal connection object
self.assertRaises(AttributeError, lambda x: conn.variantConversions[x], [2])
if not self.remote:
# create a variantConversions attribute on the connection
conn.variantConversions = copy.copy(api.variantConversions)
crsr = conn.cursor()
tabdef = (
"CREATE TABLE xx_%s (fldData VARCHAR(100) NOT NULL, fld2 VARCHAR(20))"
% config.tmp
)
crsr.execute(tabdef)
crsr.execute(
"INSERT INTO xx_%s(fldData,fld2) VALUES('gabba','booga')"
% config.tmp
)
crsr.execute(
"INSERT INTO xx_%s(fldData,fld2) VALUES('hey','yo')" % config.tmp
)
# change converter for ALL adoStringTypes columns
conn.variantConversions[api.adoStringTypes] = duplicatingConverter
crsr.execute(
"SELECT fldData,fld2 FROM xx_%s ORDER BY fldData" % config.tmp
)
rows = crsr.fetchall()
row = rows[0]
self.assertEqual(row[0], "gabbagabba")
row = rows[1]
self.assertEqual(row[0], "heyhey")
self.assertEqual(row[1], "yoyo")
upcaseConverter = lambda aStringField: aStringField.upper()
assert upcaseConverter("upThis") == "UPTHIS"
# now use a single column converter
rows.converters[1] = upcaseConverter # convert second column
self.assertEqual(row[0], "heyhey") # first will be unchanged
self.assertEqual(row[1], "YO") # second will convert to upper case
finally:
try:
del conn.variantConversions # Restore the default
except:
pass
self.helpRollbackTblTemp()
def testUserDefinedConversionForExactNumericTypes(self):
# variantConversions is a dictionary of conversion functions
# held internally in adodbapi.apibase
#
# !!! this test intentionally alters the value of what should be constant in the module
# !!! no new code should use this example, to is only a test to see that the
# !!! deprecated way of doing this still works. (use connection.variantConversions)
#
if not self.remote and sys.version_info < (3, 0): ### Py3 need different test
oldconverter = adodbapi.variantConversions[
ado_consts.adNumeric
] # keep old function to restore later
# By default decimal and "numbers" are returned as decimals.
# Instead, make numbers return as floats
try:
adodbapi.variantConversions[ado_consts.adNumeric] = adodbapi.cvtFloat
self.helpTestDataType(
"decimal(18,2)", "NUMBER", 3.45, compareAlmostEqual=1
)
self.helpTestDataType(
"numeric(18,2)", "NUMBER", 3.45, compareAlmostEqual=1
)
# now return strings
adodbapi.variantConversions[ado_consts.adNumeric] = adodbapi.cvtString
self.helpTestDataType("numeric(18,2)", "NUMBER", "3.45")
# now a completly weird user defined convertion
adodbapi.variantConversions[ado_consts.adNumeric] = (
lambda x: "!!This function returns a funny unicode string %s!!" % x
)
self.helpTestDataType(
"numeric(18,2)",
"NUMBER",
"3.45",
allowedReturnValues=[
"!!This function returns a funny unicode string 3.45!!"
],
)
finally:
# now reset the converter to its original function
adodbapi.variantConversions[
ado_consts.adNumeric
] = oldconverter # Restore the original convertion function
def helpTestDataType(
self,
sqlDataTypeString,
DBAPIDataTypeString,
pyData,
pyDataInputAlternatives=None,
compareAlmostEqual=None,
allowedReturnValues=None,
):
self.helpForceDropOnTblTemp()
conn = self.getConnection()
crsr = conn.cursor()
tabdef = (
"""
CREATE TABLE xx_%s (
fldId integer NOT NULL,
fldData """
% config.tmp
+ sqlDataTypeString
+ ")\n"
)
crsr.execute(tabdef)
# Test Null values mapped to None
crsr.execute("INSERT INTO xx_%s (fldId) VALUES (1)" % config.tmp)
crsr.execute("SELECT fldId,fldData FROM xx_%s" % config.tmp)
rs = crsr.fetchone()
self.assertEqual(rs[1], None) # Null should be mapped to None
assert rs[0] == 1
# Test description related
descTuple = crsr.description[1]
assert descTuple[0] in ["fldData", "flddata"], 'was "%s" expected "%s"' % (
descTuple[0],
"fldData",
)
if DBAPIDataTypeString == "STRING":
assert descTuple[1] == api.STRING, 'was "%s" expected "%s"' % (
descTuple[1],
api.STRING.values,
)
elif DBAPIDataTypeString == "NUMBER":
assert descTuple[1] == api.NUMBER, 'was "%s" expected "%s"' % (
descTuple[1],
api.NUMBER.values,
)
elif DBAPIDataTypeString == "BINARY":
assert descTuple[1] == api.BINARY, 'was "%s" expected "%s"' % (
descTuple[1],
api.BINARY.values,
)
elif DBAPIDataTypeString == "DATETIME":
assert descTuple[1] == api.DATETIME, 'was "%s" expected "%s"' % (
descTuple[1],
api.DATETIME.values,
)
elif DBAPIDataTypeString == "ROWID":
assert descTuple[1] == api.ROWID, 'was "%s" expected "%s"' % (
descTuple[1],
api.ROWID.values,
)
elif DBAPIDataTypeString == "UUID":
assert descTuple[1] == api.OTHER, 'was "%s" expected "%s"' % (
descTuple[1],
api.OTHER.values,
)
else:
raise NotImplementedError # "DBAPIDataTypeString not provided"
# Test data binding
inputs = [pyData]
if pyDataInputAlternatives:
inputs.extend(pyDataInputAlternatives)
inputs = set(inputs) # removes redundant string==unicode tests
fldId = 1
for inParam in inputs:
fldId += 1
try:
crsr.execute(
"INSERT INTO xx_%s (fldId,fldData) VALUES (?,?)" % config.tmp,
(fldId, inParam),
)
except:
if self.remote:
for message in crsr.messages:
print(message)
else:
conn.printADOerrors()
raise
crsr.execute(
"SELECT fldData FROM xx_%s WHERE ?=fldID" % config.tmp, [fldId]
)
rs = crsr.fetchone()
if allowedReturnValues:
allowedTypes = tuple([type(aRV) for aRV in allowedReturnValues])
assert isinstance(
rs[0], allowedTypes
), 'result type "%s" must be one of %s' % (type(rs[0]), allowedTypes)
else:
assert isinstance(
rs[0], type(pyData)
), 'result type "%s" must be instance of %s' % (
type(rs[0]),
type(pyData),
)
if compareAlmostEqual and DBAPIDataTypeString == "DATETIME":
iso1 = adodbapi.dateconverter.DateObjectToIsoFormatString(rs[0])
iso2 = adodbapi.dateconverter.DateObjectToIsoFormatString(pyData)
self.assertEqual(iso1, iso2)
elif compareAlmostEqual:
s = float(pyData)
v = float(rs[0])
assert (
abs(v - s) / s < 0.00001
), "Values not almost equal recvd=%s, expected=%f" % (rs[0], s)
else:
if allowedReturnValues:
ok = False
self.assertTrue(
rs[0] in allowedReturnValues,
'Value "%s" not in %s' % (repr(rs[0]), allowedReturnValues),
)
else:
self.assertEqual(
rs[0],
pyData,
'Values are not equal recvd="%s", expected="%s"'
% (rs[0], pyData),
)
def testDataTypeFloat(self):
self.helpTestDataType("real", "NUMBER", 3.45, compareAlmostEqual=True)
self.helpTestDataType("float", "NUMBER", 1.79e37, compareAlmostEqual=True)
def testDataTypeDecmal(self):
self.helpTestDataType(
"decimal(18,2)",
"NUMBER",
3.45,
allowedReturnValues=["3.45", "3,45", decimal.Decimal("3.45")],
)
self.helpTestDataType(
"numeric(18,2)",
"NUMBER",
3.45,
allowedReturnValues=["3.45", "3,45", decimal.Decimal("3.45")],
)
self.helpTestDataType(
"decimal(20,2)",
"NUMBER",
444444444444444444,
allowedReturnValues=[
"444444444444444444.00",
"444444444444444444,00",
decimal.Decimal("444444444444444444"),
],
)
if self.getEngine() == "MSSQL":
self.helpTestDataType(
"uniqueidentifier",
"UUID",
"{71A4F49E-39F3-42B1-A41E-48FF154996E6}",
allowedReturnValues=["{71A4F49E-39F3-42B1-A41E-48FF154996E6}"],
)
def testDataTypeMoney(self): # v2.1 Cole -- use decimal for money
if self.getEngine() == "MySQL":
self.helpTestDataType(
"DECIMAL(20,4)", "NUMBER", decimal.Decimal("-922337203685477.5808")
)
elif self.getEngine() == "PostgreSQL":
self.helpTestDataType(
"money",
"NUMBER",
decimal.Decimal("-922337203685477.5808"),
compareAlmostEqual=True,
allowedReturnValues=[
-922337203685477.5808,
decimal.Decimal("-922337203685477.5808"),
],
)
else:
self.helpTestDataType("smallmoney", "NUMBER", decimal.Decimal("214748.02"))
self.helpTestDataType(
"money", "NUMBER", decimal.Decimal("-922337203685477.5808")
)
def testDataTypeInt(self):
if self.getEngine() != "PostgreSQL":
self.helpTestDataType("tinyint", "NUMBER", 115)
self.helpTestDataType("smallint", "NUMBER", -32768)
if self.getEngine() not in ["ACCESS", "PostgreSQL"]:
self.helpTestDataType(
"bit", "NUMBER", 1
) # Does not work correctly with access
if self.getEngine() in ["MSSQL", "PostgreSQL"]:
self.helpTestDataType(
"bigint",
"NUMBER",
3000000000,
allowedReturnValues=[3000000000, int(3000000000)],
)
self.helpTestDataType("int", "NUMBER", 2147483647)
def testDataTypeChar(self):
for sqlDataType in ("char(6)", "nchar(6)"):
self.helpTestDataType(
sqlDataType,
"STRING",
"spam ",
allowedReturnValues=["spam", "spam", "spam ", "spam "],
)
def testDataTypeVarChar(self):
if self.getEngine() == "MySQL":
stringKinds = ["varchar(10)", "text"]
elif self.getEngine() == "PostgreSQL":
stringKinds = ["varchar(10)", "text", "character varying"]
else:
stringKinds = [
"varchar(10)",
"nvarchar(10)",
"text",
"ntext",
] # ,"varchar(max)"]
for sqlDataType in stringKinds:
self.helpTestDataType(sqlDataType, "STRING", "spam", ["spam"])
def testDataTypeDate(self):
if self.getEngine() == "PostgreSQL":
dt = "timestamp"
else:
dt = "datetime"
self.helpTestDataType(
dt, "DATETIME", adodbapi.Date(2002, 10, 28), compareAlmostEqual=True
)
if self.getEngine() not in ["MySQL", "PostgreSQL"]:
self.helpTestDataType(
"smalldatetime",
"DATETIME",
adodbapi.Date(2002, 10, 28),
compareAlmostEqual=True,
)
if tag != "pythontime" and self.getEngine() not in [
"MySQL",
"PostgreSQL",
]: # fails when using pythonTime
self.helpTestDataType(
dt,
"DATETIME",
adodbapi.Timestamp(2002, 10, 28, 12, 15, 1),
compareAlmostEqual=True,
)
def testDataTypeBinary(self):
binfld = str2bytes("\x07\x00\xE2\x40*")
arv = [binfld, adodbapi.Binary(binfld), bytes(binfld)]
if self.getEngine() == "PostgreSQL":
self.helpTestDataType(
"bytea", "BINARY", adodbapi.Binary(binfld), allowedReturnValues=arv
)
else:
self.helpTestDataType(
"binary(5)", "BINARY", adodbapi.Binary(binfld), allowedReturnValues=arv
)
self.helpTestDataType(
"varbinary(100)",
"BINARY",
adodbapi.Binary(binfld),
allowedReturnValues=arv,
)
if self.getEngine() != "MySQL":
self.helpTestDataType(
"image", "BINARY", adodbapi.Binary(binfld), allowedReturnValues=arv
)
def helpRollbackTblTemp(self):
self.helpForceDropOnTblTemp()
def helpForceDropOnTblTemp(self):
conn = self.getConnection()
with conn.cursor() as crsr:
try:
crsr.execute("DROP TABLE xx_%s" % config.tmp)
if not conn.autocommit:
conn.commit()
except:
pass
def helpCreateAndPopulateTableTemp(self, crsr):
tabdef = (
"""
CREATE TABLE xx_%s (
fldData INTEGER
)
"""
% config.tmp
)
try: # EAFP
crsr.execute(tabdef)
except api.DatabaseError: # was not dropped before
self.helpForceDropOnTblTemp() # so drop it now
crsr.execute(tabdef)
for i in range(9): # note: this poor SQL code, but a valid test
crsr.execute("INSERT INTO xx_%s (fldData) VALUES (%i)" % (config.tmp, i))
# NOTE: building the test table without using parameter substitution
def testFetchAll(self):
crsr = self.getCursor()
self.helpCreateAndPopulateTableTemp(crsr)
crsr.execute("SELECT fldData FROM xx_%s" % config.tmp)
rs = crsr.fetchall()
assert len(rs) == 9
# test slice of rows
i = 3
for row in rs[3:-2]: # should have rowid 3..6
assert row[0] == i
i += 1
self.helpRollbackTblTemp()
def testPreparedStatement(self):
crsr = self.getCursor()
self.helpCreateAndPopulateTableTemp(crsr)
crsr.prepare("SELECT fldData FROM xx_%s" % config.tmp)
crsr.execute(crsr.command) # remember the one that was prepared
rs = crsr.fetchall()
assert len(rs) == 9
assert rs[2][0] == 2
self.helpRollbackTblTemp()
def testWrongPreparedStatement(self):
crsr = self.getCursor()
self.helpCreateAndPopulateTableTemp(crsr)
crsr.prepare("SELECT * FROM nowhere")
crsr.execute(
"SELECT fldData FROM xx_%s" % config.tmp
) # should execute this one, not the prepared one
rs = crsr.fetchall()
assert len(rs) == 9
assert rs[2][0] == 2
self.helpRollbackTblTemp()
def testIterator(self):
crsr = self.getCursor()
self.helpCreateAndPopulateTableTemp(crsr)
crsr.execute("SELECT fldData FROM xx_%s" % config.tmp)
for i, row in enumerate(
crsr
): # using cursor as an iterator, rather than fetchxxx
assert row[0] == i
self.helpRollbackTblTemp()
def testExecuteMany(self):
crsr = self.getCursor()
self.helpCreateAndPopulateTableTemp(crsr)
seq_of_values = [(111,), (222,)]
crsr.executemany(
"INSERT INTO xx_%s (fldData) VALUES (?)" % config.tmp, seq_of_values
)
if crsr.rowcount == -1:
print(
self.getEngine()
+ " Provider does not support rowcount (on .executemany())"
)
else:
self.assertEqual(crsr.rowcount, 2)
crsr.execute("SELECT fldData FROM xx_%s" % config.tmp)
rs = crsr.fetchall()
assert len(rs) == 11
self.helpRollbackTblTemp()
def testRowCount(self):
crsr = self.getCursor()
self.helpCreateAndPopulateTableTemp(crsr)
crsr.execute("SELECT fldData FROM xx_%s" % config.tmp)
if crsr.rowcount == -1:
# print("provider does not support rowcount on select")
pass
else:
self.assertEqual(crsr.rowcount, 9)
self.helpRollbackTblTemp()
def testRowCountNoRecordset(self):
crsr = self.getCursor()
self.helpCreateAndPopulateTableTemp(crsr)
crsr.execute("DELETE FROM xx_%s WHERE fldData >= 5" % config.tmp)
if crsr.rowcount == -1:
print(self.getEngine() + " Provider does not support rowcount (on DELETE)")
else:
self.assertEqual(crsr.rowcount, 4)
self.helpRollbackTblTemp()
def testFetchMany(self):
crsr = self.getCursor()
self.helpCreateAndPopulateTableTemp(crsr)
crsr.execute("SELECT fldData FROM xx_%s" % config.tmp)
rs = crsr.fetchmany(3)
assert len(rs) == 3
rs = crsr.fetchmany(5)
assert len(rs) == 5
rs = crsr.fetchmany(5)
assert len(rs) == 1 # Asked for five, but there is only one left
self.helpRollbackTblTemp()
def testFetchManyWithArraySize(self):
crsr = self.getCursor()
self.helpCreateAndPopulateTableTemp(crsr)
crsr.execute("SELECT fldData FROM xx_%s" % config.tmp)
rs = crsr.fetchmany()
assert len(rs) == 1 # arraysize Defaults to one
crsr.arraysize = 4
rs = crsr.fetchmany()
assert len(rs) == 4
rs = crsr.fetchmany()
assert len(rs) == 4
rs = crsr.fetchmany()
assert len(rs) == 0
self.helpRollbackTblTemp()
def testErrorConnect(self):
conn = self.getConnection()
kw = {}
if "proxy_host" in conn.kwargs:
kw["proxy_host"] = conn.kwargs["proxy_host"]
conn.close()
self.assertRaises(api.DatabaseError, self.db, "not a valid connect string", kw)
def testRowIterator(self):
self.helpForceDropOnTblTemp()
conn = self.getConnection()
crsr = conn.cursor()
tabdef = (
"""
CREATE TABLE xx_%s (
fldId integer NOT NULL,
fldTwo integer,
fldThree integer,
fldFour integer)
"""
% config.tmp
)
crsr.execute(tabdef)
inputs = [(2, 3, 4), (102, 103, 104)]
fldId = 1
for inParam in inputs:
fldId += 1
try:
crsr.execute(
"INSERT INTO xx_%s (fldId,fldTwo,fldThree,fldFour) VALUES (?,?,?,?)"
% config.tmp,
(fldId, inParam[0], inParam[1], inParam[2]),
)
except:
if self.remote:
for message in crsr.messages:
print(message)
else:
conn.printADOerrors()
raise
crsr.execute(
"SELECT fldTwo,fldThree,fldFour FROM xx_%s WHERE ?=fldID" % config.tmp,
[fldId],
)
rec = crsr.fetchone()
# check that stepping through an emulated row works
for j in range(len(inParam)):
assert (
rec[j] == inParam[j]
), 'returned value:"%s" != test value:"%s"' % (rec[j], inParam[j])
# check that we can get a complete tuple from a row
assert tuple(rec) == inParam, 'returned value:"%s" != test value:"%s"' % (
repr(rec),
repr(inParam),
)
# test that slices of rows work
slice1 = tuple(rec[:-1])
slice2 = tuple(inParam[0:2])
assert slice1 == slice2, 'returned value:"%s" != test value:"%s"' % (
repr(slice1),
repr(slice2),
)
# now test named column retrieval
assert rec["fldTwo"] == inParam[0]
assert rec.fldThree == inParam[1]
assert rec.fldFour == inParam[2]
# test array operation
# note that the fields vv vv vv are out of order
crsr.execute("select fldThree,fldFour,fldTwo from xx_%s" % config.tmp)
recs = crsr.fetchall()
assert recs[1][0] == 103
assert recs[0][1] == 4
assert recs[1]["fldFour"] == 104
assert recs[0, 0] == 3
assert recs[0, "fldTwo"] == 2
assert recs[1, 2] == 102
for i in range(1):
for j in range(2):
assert recs[i][j] == recs[i, j]
def testFormatParamstyle(self):
self.helpForceDropOnTblTemp()
conn = self.getConnection()
conn.paramstyle = "format" # test nonstandard use of paramstyle
crsr = conn.cursor()
tabdef = (
"""
CREATE TABLE xx_%s (
fldId integer NOT NULL,
fldData varchar(10),
fldConst varchar(30))
"""
% config.tmp
)
crsr.execute(tabdef)
inputs = ["one", "two", "three"]
fldId = 2
for inParam in inputs:
fldId += 1
sql = (
"INSERT INTO xx_"
+ config.tmp
+ " (fldId,fldConst,fldData) VALUES (%s,'thi%s :may cause? trouble', %s)"
)
try:
crsr.execute(sql, (fldId, inParam))
except:
if self.remote:
for message in crsr.messages:
print(message)
else:
conn.printADOerrors()
raise
crsr.execute(
"SELECT fldData, fldConst FROM xx_" + config.tmp + " WHERE %s=fldID",
[fldId],
)
rec = crsr.fetchone()
self.assertEqual(
rec[0],
inParam,
'returned value:"%s" != test value:"%s"' % (rec[0], inParam),
)
self.assertEqual(rec[1], "thi%s :may cause? trouble")
# now try an operation with a "%s" as part of a literal
sel = (
"insert into xx_" + config.tmp + " (fldId,fldData) VALUES (%s,'four%sfive')"
)
params = (20,)
crsr.execute(sel, params)
# test the .query implementation
assert "(?," in crsr.query, 'expected:"%s" in "%s"' % ("(?,", crsr.query)
# test the .command attribute
assert crsr.command == sel, 'expected:"%s" but found "%s"' % (sel, crsr.command)
# test the .parameters attribute
if not self.remote: # parameter list will be altered in transit
self.assertEqual(crsr.parameters, params)
# now make sure the data made it
crsr.execute("SELECT fldData FROM xx_%s WHERE fldID=20" % config.tmp)
rec = crsr.fetchone()
self.assertEqual(rec[0], "four%sfive")
def testNamedParamstyle(self):
self.helpForceDropOnTblTemp()
conn = self.getConnection()
crsr = conn.cursor()
crsr.paramstyle = "named" # test nonstandard use of paramstyle
tabdef = (
"""
CREATE TABLE xx_%s (
fldId integer NOT NULL,
fldData varchar(10))
"""
% config.tmp
)
crsr.execute(tabdef)
inputs = ["four", "five", "six"]
fldId = 10
for inParam in inputs:
fldId += 1
try:
crsr.execute(
"INSERT INTO xx_%s (fldId,fldData) VALUES (:Id,:f_Val)"
% config.tmp,
{"f_Val": inParam, "Id": fldId},
)
except:
if self.remote:
for message in crsr.messages:
print(message)
else:
conn.printADOerrors()
raise
crsr.execute(
"SELECT fldData FROM xx_%s WHERE fldID=:Id" % config.tmp, {"Id": fldId}
)
rec = crsr.fetchone()
self.assertEqual(
rec[0],
inParam,
'returned value:"%s" != test value:"%s"' % (rec[0], inParam),
)
# now a test with a ":" as part of a literal
crsr.execute(
"insert into xx_%s (fldId,fldData) VALUES (:xyz,'six:five')" % config.tmp,
{"xyz": 30},
)
crsr.execute("SELECT fldData FROM xx_%s WHERE fldID=30" % config.tmp)
rec = crsr.fetchone()
self.assertEqual(rec[0], "six:five")
def testPyformatParamstyle(self):
self.helpForceDropOnTblTemp()
conn = self.getConnection()
crsr = conn.cursor()
crsr.paramstyle = "pyformat" # test nonstandard use of paramstyle
tabdef = (
"""
CREATE TABLE xx_%s (
fldId integer NOT NULL,
fldData varchar(10))
"""
% config.tmp
)
crsr.execute(tabdef)
inputs = ["four", "five", "six"]
fldId = 10
for inParam in inputs:
fldId += 1
try:
crsr.execute(
"INSERT INTO xx_%s (fldId,fldData) VALUES (%%(Id)s,%%(f_Val)s)"
% config.tmp,
{"f_Val": inParam, "Id": fldId},
)
except:
if self.remote:
for message in crsr.messages:
print(message)
else:
conn.printADOerrors()
raise
crsr.execute(
"SELECT fldData FROM xx_%s WHERE fldID=%%(Id)s" % config.tmp,
{"Id": fldId},
)
rec = crsr.fetchone()
self.assertEqual(
rec[0],
inParam,
'returned value:"%s" != test value:"%s"' % (rec[0], inParam),
)
# now a test with a "%" as part of a literal
crsr.execute(
"insert into xx_%s (fldId,fldData) VALUES (%%(xyz)s,'six%%five')"
% config.tmp,
{"xyz": 30},
)
crsr.execute("SELECT fldData FROM xx_%s WHERE fldID=30" % config.tmp)
rec = crsr.fetchone()
self.assertEqual(rec[0], "six%five")
def testAutomaticParamstyle(self):
self.helpForceDropOnTblTemp()
conn = self.getConnection()
conn.paramstyle = "dynamic" # test nonstandard use of paramstyle
crsr = conn.cursor()
tabdef = (
"""
CREATE TABLE xx_%s (
fldId integer NOT NULL,
fldData varchar(10),
fldConst varchar(30))
"""
% config.tmp
)
crsr.execute(tabdef)
inputs = ["one", "two", "three"]
fldId = 2
for inParam in inputs:
fldId += 1
try:
crsr.execute(
"INSERT INTO xx_"
+ config.tmp
+ " (fldId,fldConst,fldData) VALUES (?,'thi%s :may cause? troub:1e', ?)",
(fldId, inParam),
)
except:
if self.remote:
for message in crsr.messages:
print(message)
else:
conn.printADOerrors()
raise
trouble = "thi%s :may cause? troub:1e"
crsr.execute(
"SELECT fldData, fldConst FROM xx_" + config.tmp + " WHERE ?=fldID",
[fldId],
)
rec = crsr.fetchone()
self.assertEqual(
rec[0],
inParam,
'returned value:"%s" != test value:"%s"' % (rec[0], inParam),
)
self.assertEqual(rec[1], trouble)
# inputs = [u'four',u'five',u'six']
fldId = 10
for inParam in inputs:
fldId += 1
try:
crsr.execute(
"INSERT INTO xx_%s (fldId,fldData) VALUES (:Id,:f_Val)"
% config.tmp,
{"f_Val": inParam, "Id": fldId},
)
except:
if self.remote:
for message in crsr.messages:
print(message)
else:
conn.printADOerrors()
raise
crsr.execute(
"SELECT fldData FROM xx_%s WHERE :Id=fldID" % config.tmp, {"Id": fldId}
)
rec = crsr.fetchone()
self.assertEqual(
rec[0],
inParam,
'returned value:"%s" != test value:"%s"' % (rec[0], inParam),
)
# now a test with a ":" as part of a literal -- and use a prepared query
ppdcmd = (
"insert into xx_%s (fldId,fldData) VALUES (:xyz,'six:five')" % config.tmp
)
crsr.prepare(ppdcmd)
crsr.execute(ppdcmd, {"xyz": 30})
crsr.execute("SELECT fldData FROM xx_%s WHERE fldID=30" % config.tmp)
rec = crsr.fetchone()
self.assertEqual(rec[0], "six:five")
def testRollBack(self):
conn = self.getConnection()
crsr = conn.cursor()
assert not crsr.connection.autocommit, "Unexpected beginning condition"
self.helpCreateAndPopulateTableTemp(crsr)
crsr.connection.commit() # commit the first bunch
crsr.execute("INSERT INTO xx_%s (fldData) VALUES(100)" % config.tmp)
selectSql = "SELECT fldData FROM xx_%s WHERE fldData=100" % config.tmp
crsr.execute(selectSql)
rs = crsr.fetchall()
assert len(rs) == 1
self.conn.rollback()
crsr.execute(selectSql)
assert (
crsr.fetchone() == None
), "cursor.fetchone should return None if a query retrieves no rows"
crsr.execute("SELECT fldData from xx_%s" % config.tmp)
rs = crsr.fetchall()
assert len(rs) == 9, "the original records should still be present"
self.helpRollbackTblTemp()
def testCommit(self):
try:
con2 = self.getAnotherConnection()
except NotImplementedError:
return # should be "SKIP" for ACCESS
assert not con2.autocommit, "default should be manual commit"
crsr = con2.cursor()
self.helpCreateAndPopulateTableTemp(crsr)
crsr.execute("INSERT INTO xx_%s (fldData) VALUES(100)" % config.tmp)
con2.commit()
selectSql = "SELECT fldData FROM xx_%s WHERE fldData=100" % config.tmp
crsr.execute(selectSql)
rs = crsr.fetchall()
assert len(rs) == 1
crsr.close()
con2.close()
conn = self.getConnection()
crsr = self.getCursor()
with conn.cursor() as crsr:
crsr.execute(selectSql)
rs = crsr.fetchall()
assert len(rs) == 1
assert rs[0][0] == 100
self.helpRollbackTblTemp()
def testAutoRollback(self):
try:
con2 = self.getAnotherConnection()
except NotImplementedError:
return # should be "SKIP" for ACCESS
assert not con2.autocommit, "unexpected beginning condition"
crsr = con2.cursor()
self.helpCreateAndPopulateTableTemp(crsr)
crsr.execute("INSERT INTO xx_%s (fldData) VALUES(100)" % config.tmp)
selectSql = "SELECT fldData FROM xx_%s WHERE fldData=100" % config.tmp
crsr.execute(selectSql)
rs = crsr.fetchall()
assert len(rs) == 1
crsr.close()
con2.close()
crsr = self.getCursor()
try:
crsr.execute(
selectSql
) # closing the connection should have forced rollback
row = crsr.fetchone()
except api.DatabaseError:
row = None # if the entire table disappeared the rollback was perfect and the test passed
assert row == None, (
"cursor.fetchone should return None if a query retrieves no rows. Got %s"
% repr(row)
)
self.helpRollbackTblTemp()
def testAutoCommit(self):
try:
ac_conn = self.getAnotherConnection({"autocommit": True})
except NotImplementedError:
return # should be "SKIP" for ACCESS
crsr = ac_conn.cursor()
self.helpCreateAndPopulateTableTemp(crsr)
crsr.execute("INSERT INTO xx_%s (fldData) VALUES(100)" % config.tmp)
crsr.close()
with self.getCursor() as crsr:
selectSql = "SELECT fldData from xx_%s" % config.tmp
crsr.execute(
selectSql
) # closing the connection should _not_ have forced rollback
rs = crsr.fetchall()
assert len(rs) == 10, "all records should still be present"
ac_conn.close()
self.helpRollbackTblTemp()
def testSwitchedAutoCommit(self):
try:
ac_conn = self.getAnotherConnection()
except NotImplementedError:
return # should be "SKIP" for ACCESS
ac_conn.autocommit = True
crsr = ac_conn.cursor()
self.helpCreateAndPopulateTableTemp(crsr)
crsr.execute("INSERT INTO xx_%s (fldData) VALUES(100)" % config.tmp)
crsr.close()
conn = self.getConnection()
ac_conn.close()
with self.getCursor() as crsr:
selectSql = "SELECT fldData from xx_%s" % config.tmp
crsr.execute(
selectSql
) # closing the connection should _not_ have forced rollback
rs = crsr.fetchall()
assert len(rs) == 10, "all records should still be present"
self.helpRollbackTblTemp()
def testExtendedTypeHandling(self):
class XtendString(str):
pass
class XtendInt(int):
pass
class XtendFloat(float):
pass
xs = XtendString(randomstring(30))
xi = XtendInt(random.randint(-100, 500))
xf = XtendFloat(random.random())
self.helpForceDropOnTblTemp()
conn = self.getConnection()
crsr = conn.cursor()
tabdef = (
"""
CREATE TABLE xx_%s (
s VARCHAR(40) NOT NULL,
i INTEGER NOT NULL,
f REAL NOT NULL)"""
% config.tmp
)
crsr.execute(tabdef)
crsr.execute(
"INSERT INTO xx_%s (s, i, f) VALUES (?, ?, ?)" % config.tmp, (xs, xi, xf)
)
crsr.close()
conn = self.getConnection()
with self.getCursor() as crsr:
selectSql = "SELECT s, i, f from xx_%s" % config.tmp
crsr.execute(
selectSql
) # closing the connection should _not_ have forced rollback
row = crsr.fetchone()
self.assertEqual(row.s, xs)
self.assertEqual(row.i, xi)
self.assertAlmostEqual(row.f, xf)
self.helpRollbackTblTemp()
class TestADOwithSQLServer(CommonDBTests):
def setUp(self):
self.conn = config.dbSqlServerconnect(
*config.connStrSQLServer[0], **config.connStrSQLServer[1]
)
self.conn.timeout = 30 # turn timeout back up
self.engine = "MSSQL"
self.db = config.dbSqlServerconnect
self.remote = config.connStrSQLServer[2]
def tearDown(self):
try:
self.conn.rollback()
except:
pass
try:
self.conn.close()
except:
pass
self.conn = None
def getConnection(self):
return self.conn
def getAnotherConnection(self, addkeys=None):
keys = dict(config.connStrSQLServer[1])
if addkeys:
keys.update(addkeys)
return config.dbSqlServerconnect(*config.connStrSQLServer[0], **keys)
def testVariableReturningStoredProcedure(self):
crsr = self.conn.cursor()
spdef = """
CREATE PROCEDURE sp_DeleteMeOnlyForTesting
@theInput varchar(50),
@theOtherInput varchar(50),
@theOutput varchar(100) OUTPUT
AS
SET @theOutput=@theInput+@theOtherInput
"""
try:
crsr.execute("DROP PROCEDURE sp_DeleteMeOnlyForTesting")
self.conn.commit()
except: # Make sure it is empty
pass
crsr.execute(spdef)
retvalues = crsr.callproc(
"sp_DeleteMeOnlyForTesting", ("Dodsworth", "Anne", " ")
)
assert retvalues[0] == "Dodsworth", '%s is not "Dodsworth"' % repr(retvalues[0])
assert retvalues[1] == "Anne", '%s is not "Anne"' % repr(retvalues[1])
assert retvalues[2] == "DodsworthAnne", '%s is not "DodsworthAnne"' % repr(
retvalues[2]
)
self.conn.rollback()
def testMultipleSetReturn(self):
crsr = self.getCursor()
self.helpCreateAndPopulateTableTemp(crsr)
spdef = """
CREATE PROCEDURE sp_DeleteMe_OnlyForTesting
AS
SELECT fldData FROM xx_%s ORDER BY fldData ASC
SELECT fldData From xx_%s where fldData = -9999
SELECT fldData FROM xx_%s ORDER BY fldData DESC
""" % (
config.tmp,
config.tmp,
config.tmp,
)
try:
crsr.execute("DROP PROCEDURE sp_DeleteMe_OnlyForTesting")
self.conn.commit()
except: # Make sure it is empty
pass
crsr.execute(spdef)
retvalues = crsr.callproc("sp_DeleteMe_OnlyForTesting")
row = crsr.fetchone()
self.assertEqual(row[0], 0)
assert crsr.nextset() == True, "Operation should succeed"
assert not crsr.fetchall(), "Should be an empty second set"
assert crsr.nextset() == True, "third set should be present"
rowdesc = crsr.fetchall()
self.assertEqual(rowdesc[0][0], 8)
assert crsr.nextset() == None, "No more return sets, should return None"
self.helpRollbackTblTemp()
def testDatetimeProcedureParameter(self):
crsr = self.conn.cursor()
spdef = """
CREATE PROCEDURE sp_DeleteMeOnlyForTesting
@theInput DATETIME,
@theOtherInput varchar(50),
@theOutput varchar(100) OUTPUT
AS
SET @theOutput = CONVERT(CHARACTER(20), @theInput, 0) + @theOtherInput
"""
try:
crsr.execute("DROP PROCEDURE sp_DeleteMeOnlyForTesting")
self.conn.commit()
except: # Make sure it is empty
pass
crsr.execute(spdef)
result = crsr.callproc(
"sp_DeleteMeOnlyForTesting",
[adodbapi.Timestamp(2014, 12, 25, 0, 1, 0), "Beep", " " * 30],
)
assert result[2] == "Dec 25 2014 12:01AM Beep", 'value was="%s"' % result[2]
self.conn.rollback()
def testIncorrectStoredProcedureParameter(self):
crsr = self.conn.cursor()
spdef = """
CREATE PROCEDURE sp_DeleteMeOnlyForTesting
@theInput DATETIME,
@theOtherInput varchar(50),
@theOutput varchar(100) OUTPUT
AS
SET @theOutput = CONVERT(CHARACTER(20), @theInput) + @theOtherInput
"""
try:
crsr.execute("DROP PROCEDURE sp_DeleteMeOnlyForTesting")
self.conn.commit()
except: # Make sure it is empty
pass
crsr.execute(spdef)
# calling the sproc with a string for the first parameter where a DateTime is expected
result = tryconnection.try_operation_with_expected_exception(
(api.DataError, api.DatabaseError),
crsr.callproc,
["sp_DeleteMeOnlyForTesting"],
{"parameters": ["this is wrong", "Anne", "not Alice"]},
)
if result[0]: # the expected exception was raised
assert "@theInput" in str(result[1]) or "DatabaseError" in str(
result
), "Identifies the wrong erroneous parameter"
else:
assert result[0], result[1] # incorrect or no exception
self.conn.rollback()
class TestADOwithAccessDB(CommonDBTests):
def setUp(self):
self.conn = config.dbAccessconnect(
*config.connStrAccess[0], **config.connStrAccess[1]
)
self.conn.timeout = 30 # turn timeout back up
self.engine = "ACCESS"
self.db = config.dbAccessconnect
self.remote = config.connStrAccess[2]
def tearDown(self):
try:
self.conn.rollback()
except:
pass
try:
self.conn.close()
except:
pass
self.conn = None
def getConnection(self):
return self.conn
def getAnotherConnection(self, addkeys=None):
raise NotImplementedError("Jet cannot use a second connection to the database")
def testOkConnect(self):
c = self.db(*config.connStrAccess[0], **config.connStrAccess[1])
assert c != None
c.close()
class TestADOwithMySql(CommonDBTests):
def setUp(self):
self.conn = config.dbMySqlconnect(
*config.connStrMySql[0], **config.connStrMySql[1]
)
self.conn.timeout = 30 # turn timeout back up
self.engine = "MySQL"
self.db = config.dbMySqlconnect
self.remote = config.connStrMySql[2]
def tearDown(self):
try:
self.conn.rollback()
except:
pass
try:
self.conn.close()
except:
pass
self.conn = None
def getConnection(self):
return self.conn
def getAnotherConnection(self, addkeys=None):
keys = dict(config.connStrMySql[1])
if addkeys:
keys.update(addkeys)
return config.dbMySqlconnect(*config.connStrMySql[0], **keys)
def testOkConnect(self):
c = self.db(*config.connStrMySql[0], **config.connStrMySql[1])
assert c != None
# def testStoredProcedure(self):
# crsr=self.conn.cursor()
# try:
# crsr.execute("DROP PROCEDURE DeleteMeOnlyForTesting")
# self.conn.commit()
# except: #Make sure it is empty
# pass
# spdef= """
# DELIMITER $$
# CREATE PROCEDURE DeleteMeOnlyForTesting (onein CHAR(10), twoin CHAR(10), OUT theout CHAR(20))
# DETERMINISTIC
# BEGIN
# SET theout = onein //|| twoin;
# /* (SELECT 'a small string' as result; */
# END $$
# """
#
# crsr.execute(spdef)
#
# retvalues=crsr.callproc('DeleteMeOnlyForTesting',('Dodsworth','Anne',' '))
# print 'return value (mysql)=',repr(crsr.returnValue) ###
# assert retvalues[0]=='Dodsworth', '%s is not "Dodsworth"'%repr(retvalues[0])
# assert retvalues[1]=='Anne','%s is not "Anne"'%repr(retvalues[1])
# assert retvalues[2]=='DodsworthAnne','%s is not "DodsworthAnne"'%repr(retvalues[2])
#
# try:
# crsr.execute("DROP PROCEDURE, DeleteMeOnlyForTesting")
# self.conn.commit()
# except: #Make sure it is empty
# pass
class TestADOwithPostgres(CommonDBTests):
def setUp(self):
self.conn = config.dbPostgresConnect(
*config.connStrPostgres[0], **config.connStrPostgres[1]
)
self.conn.timeout = 30 # turn timeout back up
self.engine = "PostgreSQL"
self.db = config.dbPostgresConnect
self.remote = config.connStrPostgres[2]
def tearDown(self):
try:
self.conn.rollback()
except:
pass
try:
self.conn.close()
except:
pass
self.conn = None
def getConnection(self):
return self.conn
def getAnotherConnection(self, addkeys=None):
keys = dict(config.connStrPostgres[1])
if addkeys:
keys.update(addkeys)
return config.dbPostgresConnect(*config.connStrPostgres[0], **keys)
def testOkConnect(self):
c = self.db(*config.connStrPostgres[0], **config.connStrPostgres[1])
assert c != None
# def testStoredProcedure(self):
# crsr=self.conn.cursor()
# spdef= """
# CREATE OR REPLACE FUNCTION DeleteMeOnlyForTesting (text, text)
# RETURNS text AS $funk$
# BEGIN
# RETURN $1 || $2;
# END;
# $funk$
# LANGUAGE SQL;
# """
#
# crsr.execute(spdef)
# retvalues = crsr.callproc('DeleteMeOnlyForTesting',('Dodsworth','Anne',' '))
# ### print 'return value (pg)=',repr(crsr.returnValue) ###
# assert retvalues[0]=='Dodsworth', '%s is not "Dodsworth"'%repr(retvalues[0])
# assert retvalues[1]=='Anne','%s is not "Anne"'%repr(retvalues[1])
# assert retvalues[2]=='Dodsworth Anne','%s is not "Dodsworth Anne"'%repr(retvalues[2])
# self.conn.rollback()
# try:
# crsr.execute("DROP PROCEDURE, DeleteMeOnlyForTesting")
# self.conn.commit()
# except: #Make sure it is empty
# pass
class TimeConverterInterfaceTest(unittest.TestCase):
def testIDate(self):
assert self.tc.Date(1990, 2, 2)
def testITime(self):
assert self.tc.Time(13, 2, 2)
def testITimestamp(self):
assert self.tc.Timestamp(1990, 2, 2, 13, 2, 1)
def testIDateObjectFromCOMDate(self):
assert self.tc.DateObjectFromCOMDate(37435.7604282)
def testICOMDate(self):
assert hasattr(self.tc, "COMDate")
def testExactDate(self):
d = self.tc.Date(1994, 11, 15)
comDate = self.tc.COMDate(d)
correct = 34653.0
assert comDate == correct, comDate
def testExactTimestamp(self):
d = self.tc.Timestamp(1994, 11, 15, 12, 0, 0)
comDate = self.tc.COMDate(d)
correct = 34653.5
self.assertEqual(comDate, correct)
d = self.tc.Timestamp(2003, 5, 6, 14, 15, 17)
comDate = self.tc.COMDate(d)
correct = 37747.593946759262
self.assertEqual(comDate, correct)
def testIsoFormat(self):
d = self.tc.Timestamp(1994, 11, 15, 12, 3, 10)
iso = self.tc.DateObjectToIsoFormatString(d)
self.assertEqual(str(iso[:19]), "1994-11-15 12:03:10")
dt = self.tc.Date(2003, 5, 2)
iso = self.tc.DateObjectToIsoFormatString(dt)
self.assertEqual(str(iso[:10]), "2003-05-02")
if config.doMxDateTimeTest:
import mx.DateTime
class TestMXDateTimeConverter(TimeConverterInterfaceTest):
def setUp(self):
self.tc = api.mxDateTimeConverter()
def testCOMDate(self):
t = mx.DateTime.DateTime(2002, 6, 28, 18, 15, 2)
cmd = self.tc.COMDate(t)
assert cmd == t.COMDate()
def testDateObjectFromCOMDate(self):
cmd = self.tc.DateObjectFromCOMDate(37435.7604282)
t = mx.DateTime.DateTime(2002, 6, 28, 18, 15, 0)
t2 = mx.DateTime.DateTime(2002, 6, 28, 18, 15, 2)
assert t2 > cmd > t
def testDate(self):
assert mx.DateTime.Date(1980, 11, 4) == self.tc.Date(1980, 11, 4)
def testTime(self):
assert mx.DateTime.Time(13, 11, 4) == self.tc.Time(13, 11, 4)
def testTimestamp(self):
t = mx.DateTime.DateTime(2002, 6, 28, 18, 15, 1)
obj = self.tc.Timestamp(2002, 6, 28, 18, 15, 1)
assert t == obj
import time
class TestPythonTimeConverter(TimeConverterInterfaceTest):
def setUp(self):
self.tc = api.pythonTimeConverter()
def testCOMDate(self):
mk = time.mktime((2002, 6, 28, 18, 15, 1, 4, 31 + 28 + 31 + 30 + 31 + 28, -1))
t = time.localtime(mk)
# Fri, 28 Jun 2002 18:15:01 +0000
cmd = self.tc.COMDate(t)
assert abs(cmd - 37435.7604282) < 1.0 / 24, "%f more than an hour wrong" % cmd
def testDateObjectFromCOMDate(self):
cmd = self.tc.DateObjectFromCOMDate(37435.7604282)
t1 = time.gmtime(
time.mktime((2002, 6, 28, 0, 14, 1, 4, 31 + 28 + 31 + 30 + 31 + 28, -1))
)
# there are errors in the implementation of gmtime which we ignore
t2 = time.gmtime(
time.mktime((2002, 6, 29, 12, 14, 2, 4, 31 + 28 + 31 + 30 + 31 + 28, -1))
)
assert t1 < cmd < t2, '"%s" should be about 2002-6-28 12:15:01' % repr(cmd)
def testDate(self):
t1 = time.mktime((2002, 6, 28, 18, 15, 1, 4, 31 + 28 + 31 + 30 + 31 + 30, 0))
t2 = time.mktime((2002, 6, 30, 18, 15, 1, 4, 31 + 28 + 31 + 30 + 31 + 28, 0))
obj = self.tc.Date(2002, 6, 29)
assert t1 < time.mktime(obj) < t2, obj
def testTime(self):
self.assertEqual(
self.tc.Time(18, 15, 2), time.gmtime(18 * 60 * 60 + 15 * 60 + 2)
)
def testTimestamp(self):
t1 = time.localtime(
time.mktime((2002, 6, 28, 18, 14, 1, 4, 31 + 28 + 31 + 30 + 31 + 28, -1))
)
t2 = time.localtime(
time.mktime((2002, 6, 28, 18, 16, 1, 4, 31 + 28 + 31 + 30 + 31 + 28, -1))
)
obj = self.tc.Timestamp(2002, 6, 28, 18, 15, 2)
assert t1 < obj < t2, obj
class TestPythonDateTimeConverter(TimeConverterInterfaceTest):
def setUp(self):
self.tc = api.pythonDateTimeConverter()
def testCOMDate(self):
t = datetime.datetime(2002, 6, 28, 18, 15, 1)
# Fri, 28 Jun 2002 18:15:01 +0000
cmd = self.tc.COMDate(t)
assert abs(cmd - 37435.7604282) < 1.0 / 24, "more than an hour wrong"
def testDateObjectFromCOMDate(self):
cmd = self.tc.DateObjectFromCOMDate(37435.7604282)
t1 = datetime.datetime(2002, 6, 28, 18, 14, 1)
t2 = datetime.datetime(2002, 6, 28, 18, 16, 1)
assert t1 < cmd < t2, cmd
tx = datetime.datetime(
2002, 6, 28, 18, 14, 1, 900000
) # testing that microseconds don't become milliseconds
c1 = self.tc.DateObjectFromCOMDate(self.tc.COMDate(tx))
assert t1 < c1 < t2, c1
def testDate(self):
t1 = datetime.date(2002, 6, 28)
t2 = datetime.date(2002, 6, 30)
obj = self.tc.Date(2002, 6, 29)
assert t1 < obj < t2, obj
def testTime(self):
self.assertEqual(self.tc.Time(18, 15, 2).isoformat()[:8], "18:15:02")
def testTimestamp(self):
t1 = datetime.datetime(2002, 6, 28, 18, 14, 1)
t2 = datetime.datetime(2002, 6, 28, 18, 16, 1)
obj = self.tc.Timestamp(2002, 6, 28, 18, 15, 2)
assert t1 < obj < t2, obj
suites = []
suites.append(unittest.makeSuite(TestPythonDateTimeConverter, "test"))
if config.doMxDateTimeTest:
suites.append(unittest.makeSuite(TestMXDateTimeConverter, "test"))
if config.doTimeTest:
suites.append(unittest.makeSuite(TestPythonTimeConverter, "test"))
if config.doAccessTest:
suites.append(unittest.makeSuite(TestADOwithAccessDB, "test"))
if config.doSqlServerTest:
suites.append(unittest.makeSuite(TestADOwithSQLServer, "test"))
if config.doMySqlTest:
suites.append(unittest.makeSuite(TestADOwithMySql, "test"))
if config.doPostgresTest:
suites.append(unittest.makeSuite(TestADOwithPostgres, "test"))
class cleanup_manager(object):
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
config.cleanup(config.testfolder, config.mdb_name)
suite = unittest.TestSuite(suites)
if __name__ == "__main__":
mysuite = copy.deepcopy(suite)
with cleanup_manager():
defaultDateConverter = adodbapi.dateconverter
print(__doc__)
print("Default Date Converter is %s" % (defaultDateConverter,))
dateconverter = defaultDateConverter
tag = "datetime"
unittest.TextTestRunner().run(mysuite)
if config.iterateOverTimeTests:
for test, dateconverter, tag in (
(config.doTimeTest, api.pythonTimeConverter, "pythontime"),
(config.doMxDateTimeTest, api.mxDateTimeConverter, "mx"),
):
if test:
mysuite = copy.deepcopy(
suite
) # work around a side effect of unittest.TextTestRunner
adodbapi.adodbapi.dateconverter = dateconverter()
print("Changed dateconverter to ")
print(adodbapi.adodbapi.dateconverter)
unittest.TextTestRunner().run(mysuite)