def testIoCGeneralQueryWithDictionaryRowMapper(self):
        appContext = ApplicationContext(XMLConfig("support/databaseTestSqliteApplicationContext.xml"))
        factory = appContext.get_object("connection_factory")

        databaseTemplate = DatabaseTemplate(factory)

        databaseTemplate.execute("DROP TABLE IF EXISTS animal")
        databaseTemplate.execute("""
            CREATE TABLE animal (
              id serial PRIMARY KEY,
              name VARCHAR(11),
              category VARCHAR(20),
              population integer
            )
        """)
        factory.commit()
        databaseTemplate.execute("DELETE FROM animal")
        factory.commit()
        self.assertEquals(len(databaseTemplate.query_for_list("SELECT * FROM animal")), 0)
        databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES ('snake', 'reptile', 1)")
        databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES ('racoon', 'mammal', 0)")
        databaseTemplate.execute ("INSERT INTO animal (name, category, population) VALUES ('black mamba', 'kill_bill_viper', 1)")
        databaseTemplate.execute ("INSERT INTO animal (name, category, population) VALUES ('cottonmouth', 'kill_bill_viper', 1)")
        factory.commit()
        self.assertEquals(len(databaseTemplate.query_for_list("SELECT * FROM animal")), 4)

        results = databaseTemplate.query("select * from animal", rowhandler=DictionaryRowMapper())
    def testIoCGeneralQueryWithDictionaryRowMapper(self):
        appContext = ApplicationContext(XMLConfig("support/databaseTestSqliteApplicationContext.xml"))
        factory = appContext.get_object("connection_factory")

        databaseTemplate = DatabaseTemplate(factory)

        databaseTemplate.execute("DROP TABLE IF EXISTS animal")
        databaseTemplate.execute("""
            CREATE TABLE animal (
              id serial PRIMARY KEY,
              name VARCHAR(11),
              category VARCHAR(20),
              population integer
            )
        """)
        factory.commit()
        databaseTemplate.execute("DELETE FROM animal")
        factory.commit()
        self.assertEquals(len(databaseTemplate.query_for_list("SELECT * FROM animal")), 0)
        databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES ('snake', 'reptile', 1)")
        databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES ('racoon', 'mammal', 0)")
        databaseTemplate.execute ("INSERT INTO animal (name, category, population) VALUES ('black mamba', 'kill_bill_viper', 1)")
        databaseTemplate.execute ("INSERT INTO animal (name, category, population) VALUES ('cottonmouth', 'kill_bill_viper', 1)")
        factory.commit()
        self.assertEquals(len(databaseTemplate.query_for_list("SELECT * FROM animal")), 4)

        results = databaseTemplate.query("select * from animal", rowhandler=DictionaryRowMapper())
class AbstractTransactionTestCase(unittest.TestCase):

    def __init__(self, methodName='runTest'):
        unittest.TestCase.__init__(self, methodName)
        self.factory = None
        self.createdTables = False

    def setUp(self):
        if not self.createdTables:
            self.createTables()
        self.createTables()
        self.dt = DatabaseTemplate(self.factory)
        self.dt.execute("DELETE FROM animal")
        self.dt.execute("DELETE FROM account")
        self.factory.commit()
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 0)
        self.transactionManager = ConnectionFactoryTransactionManager(self.factory)
        self.transactionTemplate = TransactionTemplate(self.transactionManager)

    def tearDown(self):
        self.factory.getConnection().rollback()

    def testInsertingRowsIntoTheDatabase(self):
        rows = self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba',))
        self.assertEquals(rows, 1)

        name = self.dt.query_for_object("SELECT name FROM animal WHERE name = 'black mamba'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")

    def testInsertingTwoRowsWithoutaTransactionButManuallyCommitted(self):
        self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba',))
        self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('copperhead',))
        self.factory.commit()
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 2)

    def testInsertingTwoRowsWithoutaTransactionButManuallyRolledBack(self):
        self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba',))
        self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('copperhead',))
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 2)
        self.dt.connection_factory.getConnection().rollback()
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 0)

    def testInsertingTwoRowsWithaTransactionAndNoErrorsAndNoResults(self):
        class txDefinition(TransactionCallbackWithoutResult):
            def do_in_tx_without_result(s, status):
                self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba',))
                self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('copperhead',))
                
        self.transactionTemplate.execute(txDefinition())
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 2)

    def testInsertingTwoRowsWithaTransactionAndAnIntermediateErrorAndNoResults(self):
        class txDefinition(TransactionCallbackWithoutResult):
            def do_in_tx_without_result(s, status):
                self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba',))
                self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 1)
                raise DataAccessException("This should break the transaction, and rollback the insert.")
                
        self.assertRaises(DataAccessException, self.transactionTemplate.execute, txDefinition())
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 0)

    def testInsertingTwoRowsWithaTransactionAndNoErrorsAndResults(self):
        class txDefinition(TransactionCallback):
            def do_in_transaction(s, status):
                self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba',))
                self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('copperhead',))
                results = self.dt.query_for_object("SELECT name FROM animal WHERE name like 'c%'", required_type=types.StringType)
                return results
                
        self.assertEquals(self.transactionTemplate.execute(txDefinition()), "copperhead")
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 2)

    def testInsertingTwoRowsWithaTransactionAndAnIntermediateErrorAndResults(self):
        class txDefinition(TransactionCallback):
            def do_in_transaction(s, status):
                self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba'))
                self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 1)
                raise DataAccessException("This should break the transaction, and rollback the insert.")
                
        self.assertRaises(DataAccessException, self.transactionTemplate.execute, txDefinition())
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 0)

    def testDeclarativeTransactions(self):
        appContext = ApplicationContext(DatabaseTxTestAppContext(self.factory))
        bank = appContext.get_object("bank")

        bank.open("Checking")
        bank.open("Savings")

        bank.deposit(125.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 125.00)

        bank.deposit(250.00, "Savings")
        self.assertEquals(bank.balance("Savings"), 250.00)

        bank.transfer(25.00, "Savings", "Checking")
        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 150.00)

        bank.withdraw(10.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 140.00)

        amount = 0.0
        try:
            amount = bank.withdraw(1000, "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(amount, 0.0)

        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 140.00)

        try:
            bank.transfer(200, "Checking", "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass

        self.assertEquals(bank.balance("Savings"), 225.00, "Bad transfer did NOT fail atomically!")
        self.assertEquals(bank.balance("Checking"), 140.00, "Bad transfer did NOT fail atomically!")

    def testDecoratorBasedTransactions(self):
        appContext = ApplicationContext(DatabaseTxTestDecorativeTransactions(self.factory))
        bank = appContext.get_object("bank")

        bank.open("Checking")
        bank.open("Savings")

        bank.deposit(125.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 125.00)

        bank.deposit(250.00, "Savings")
        self.assertEquals(bank.balance("Savings"), 250.00)

        bank.transfer(25.00, "Savings", "Checking")
        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 150.00)

        bank.withdraw(10.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 140.00)

        amount = 0.0
        try:
            amount = bank.withdraw(1000, "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(amount, 0.0)

        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 140.00)

        try:
            bank.transfer(200, "Checking", "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(bank.balance("Savings"), 225.00, "Bad transfer did NOT fail atomically!")
        self.assertEquals(bank.balance("Checking"), 140.00, "Bad transfer did NOT fail atomically!")

    def testDecoratorBasedTransactionsWithNoArguments(self):
        appContext = ApplicationContext(DatabaseTxTestDecorativeTransactionsWithNoArguments(self.factory))
        bank = appContext.get_object("bank")

        bank.open("Checking")
        bank.open("Savings")

        bank.deposit(125.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 125.00)

        bank.deposit(250.00, "Savings")
        self.assertEquals(bank.balance("Savings"), 250.00)

        bank.transfer(25.00, "Savings", "Checking")
        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 150.00)

        bank.withdraw(10.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 140.00)

        amount = 0.0
        try:
            amount = bank.withdraw(1000, "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(amount, 0.0)

        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 140.00)

        try:
            bank.transfer(200, "Checking", "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass

        self.assertEquals(bank.balance("Savings"), 225.00, "Bad transfer did NOT fail atomically!")
        self.assertEquals(bank.balance("Checking"), 140.00, "Bad transfer did NOT fail atomically!")
        
    def testDecoratorBasedTransactionsWithLotsOfArguments(self):
        appContext = ApplicationContext(DatabaseTxTestDecorativeTransactionsWithLotsOfArguments(self.factory))
        bank = appContext.get_object("bank")

        bank.open("Checking")
        bank.open("Savings")

        bank.deposit(125.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 125.00)

        bank.deposit(250.00, "Savings")
        self.assertEquals(bank.balance("Savings"), 250.00)

        bank.transfer(25.00, "Savings", "Checking")
        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 150.00)

        bank.withdraw(10.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 140.00)

        amount = 0.0
        try:
            amount = bank.withdraw(1000, "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(amount, 0.0)

        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 140.00)

        try:
            bank.transfer(200, "Checking", "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass

        self.assertEquals(bank.balance("Savings"), 225.00, "Bad transfer did NOT fail atomically!")
        logging.getLogger("springpythontest.databaseTransactionTestCases").debug(bank.balance("Checking"))
        self.assertEquals(bank.balance("Checking"), 140.00, "Bad transfer did NOT fail atomically!")
        
    def testOtherPropagationLevels(self):
        appContext = ApplicationContext(DatabaseTxTestDecorativeTransactionsWithLotsOfArguments(self.factory))
        bank = appContext.get_object("bank")

        # Call a mandatory operation outside a transaction, and verify it fails.
        try:
            bank.mandatoryOperation()
            self.fail("Expected a TransactionPropagationException!")
        except TransactionPropagationException:
            pass

        # Call a mandatory operation from within a transactional routine, and verify it works.
        bank.mandatoryOperationTransactionalWrapper()

        # Call a non-transactional operation from outside a transaction, and verify it works.
        bank.nonTransactionalOperation()

        # Call a non-tranactional operation from within a transaction, and verify it fails.
        try:
            bank.nonTransactionalOperationTransactionalWrapper()
            self.fail("Expected a TransactionPropagationException!")
        except TransactionPropagationException:
            pass

    def testTransactionProxyMethodFilters(self):
        appContext = ApplicationContext(DatabaseTxTestAppContext(self.factory))
        bank = appContext.get_object("bank")
 
        bank.open("Checking")
        bank.open("Savings")

        bank.deposit(125.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 125.00)

        bank.deposit(250.00, "Savings")
        self.assertEquals(bank.balance("Savings"), 250.00)

        bank.transfer(25.00, "Savings", "Checking")
        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 150.00)

        bank.withdraw(10.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 140.00)

        amount = 0.0
        try:
            amount = bank.withdraw(1000, "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(amount, 0.0)

        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 140.00)

        try:
            bank.transfer(200, "Checking", "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass

        self.assertEquals(bank.balance("Savings"), 225.00, "Bad transfer did NOT fail atomically!")
        self.assertEquals(bank.balance("Checking"), 140.00, "Bad transfer did NOT fail atomically!")
 
    def testTransactionalBankWithNoAutoTransactionalObject(self):
        appContext = ApplicationContext(DatabaseTxTestAppContextWithNoAutoTransactionalObject(self.factory))
        bank = appContext.get_object("bank")
 
        bank.open("Checking")
        bank.open("Savings")

        bank.deposit(125.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 125.00)

        bank.deposit(250.00, "Savings")
        self.assertEquals(bank.balance("Savings"), 250.00)

        bank.transfer(25.00, "Savings", "Checking")
        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 150.00)

        bank.withdraw(10.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 140.00)

        amount = 0.0
        try:
            amount = bank.withdraw(1000, "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(amount, 0.0)

        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 140.00)

        try:
            bank.transfer(200, "Checking", "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass

        self.assertEquals(bank.balance("Savings"), 225.00, "Bad transfer did NOT fail atomically!")
        self.assertEquals(bank.balance("Checking"), -60.00, "Bad transfer did NOT fail as expected (not atomically due to lack of AutoTransactionalObject)")
class AbstractDatabaseTemplateTestCase(unittest.TestCase):
    def __init__(self, methodName='runTest'):
        unittest.TestCase.__init__(self, methodName)
        self.factory = None
        self.createdTables = False

    def setUp(self):
        if not self.createdTables:
            self.createTables()
        self.databaseTemplate = DatabaseTemplate(self.factory)
        self.databaseTemplate.execute("DELETE FROM animal")
        self.factory.commit()
        self.assertEquals(len(self.databaseTemplate.query_for_list("SELECT * FROM animal")), 0)
        self.databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES ('snake', 'reptile', 1)")
        self.databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES ('racoon', 'mammal', 0)")
        self.databaseTemplate.execute ("INSERT INTO animal (name, category, population) VALUES ('black mamba', 'kill_bill_viper', 1)")
        self.databaseTemplate.execute ("INSERT INTO animal (name, category, population) VALUES ('cottonmouth', 'kill_bill_viper', 1)")
        self.factory.commit()
        self.assertEquals(len(self.databaseTemplate.query_for_list("SELECT * FROM animal")), 4)

    def tearDown(self):
        self.factory.rollback()

    def testProgrammaticallyInstantiatingAnAbstractDatabaseTemplate(self):
        emptyTemplate = DatabaseTemplate()
        self.assertRaises(AttributeError, emptyTemplate.query, "sql query shouldn't work", None)

    def testProgrammaticHandlingInvalidRowHandler(self):
        self.assertRaises(AttributeError, self.databaseTemplate.query, "select * from animal", rowhandler=testSupportClasses.InvalidCallbackHandler())

    def testProgrammaticHandlingImproperRowHandler(self):
        self.assertRaises(TypeError, self.databaseTemplate.query, "select * from animal", rowhandler=testSupportClasses.ImproperCallbackHandler())
        
    def testProgrammaticHandlingValidDuckTypedRowHandler(self):
        results = self.databaseTemplate.query("select * from animal", rowhandler=testSupportClasses.ValidHandler())

    def testProgrammaticStaticQuery(self):
        self.assertRaises(ArgumentMustBeNamed, self.databaseTemplate.query, "select * from animal", testSupportClasses.AnimalRowMapper())

        animals = self.databaseTemplate.query("select name, category from animal", rowhandler=testSupportClasses.AnimalRowMapper())
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")
        self.assertEquals(animals[1].name, "racoon")
        self.assertEquals(animals[1].category, "mammal")

    def testProgrammaticStaticQueryWithSimpleRowMapper(self):
        animals = self.databaseTemplate.query("select name, category from animal", rowhandler=SimpleRowMapper(testSupportClasses.Animal))
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")
        self.assertEquals(animals[1].name, "racoon")
        self.assertEquals(animals[1].category, "mammal")

    def testProgrammaticStaticQueryWithDictionaryRowMapper(self):
        animals = self.databaseTemplate.query("select name, category from animal", rowhandler=DictionaryRowMapper())
        self.assertEquals(animals[0]["name"], "snake")
        self.assertEquals(animals[0]["category"], "reptile")
        self.assertEquals(animals[1]["name"], "racoon")
        self.assertEquals(animals[1]["category"], "mammal")
        
    def testProgrammaticQueryWithBoundArguments(self):
        animals = self.databaseTemplate.query("select name, category from animal where name = %s", ("snake",), testSupportClasses.AnimalRowMapper())
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")

        animals = self.databaseTemplate.query("select name, category from animal where name = ?", ("snake",), testSupportClasses.AnimalRowMapper())
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")
        
    def testProgrammaticQueryWithBoundArgumentsWithSimpleRowMapper(self):
        animals = self.databaseTemplate.query("select name, category from animal where name = %s", ("snake",), SimpleRowMapper(testSupportClasses.Animal))
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")

        animals = self.databaseTemplate.query("select name, category from animal where name = ?", ("snake",), SimpleRowMapper(testSupportClasses.Animal))
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")

    def testProgrammaticQueryWithBoundArgumentsWithDictionaryRowMapper(self):
        animals = self.databaseTemplate.query("select name, category from animal where name = %s", ("snake",), DictionaryRowMapper())
        self.assertEquals(animals[0]["name"], "snake")
        self.assertEquals(animals[0]["category"], "reptile")

        animals = self.databaseTemplate.query("select name, category from animal where name = ?", ("snake",), DictionaryRowMapper())
        self.assertEquals(animals[0]["name"], "snake")
        self.assertEquals(animals[0]["category"], "reptile")

    def testProgrammaticStaticQueryForList(self):
        animals = self.databaseTemplate.query_for_list("select name, category from animal")
        self.assertEquals(animals[0][0], "snake")
        self.assertEquals(animals[0][1], "reptile")
        self.assertEquals(animals[1][0], "racoon")
        self.assertEquals(animals[1][1], "mammal")
        
    def testProgrammaticQueryForListWithBoundArguments(self):
        animals = self.databaseTemplate.query_for_list("select name, category from animal where name = %s", ("snake",))
        self.assertEquals(animals[0][0], "snake")
        self.assertEquals(animals[0][1], "reptile")
        
        animals = self.databaseTemplate.query_for_list("select name, category from animal where name = ?", ("snake",))
        self.assertEquals(animals[0][0], "snake")
        self.assertEquals(animals[0][1], "reptile")

    def testProgrammaticQueryForListWithBoundArgumentsNotProperlyTuplized(self):
        self.assertRaises(InvalidArgumentType, self.databaseTemplate.query_for_list, "select * from animal where name = %s", "snake")
        self.assertRaises(InvalidArgumentType, self.databaseTemplate.query_for_list, "select * from animal where name = ?", "snake")

    def testProgrammaticStaticQueryForInt(self):
        count = self.databaseTemplate.query_for_int("select population from animal where name = 'snake'")
        self.assertEquals(count, 1)
        
    def testProgrammaticQueryForIntWithBoundArguments(self):
        count = self.databaseTemplate.query_for_int("select population from animal where name = %s", ("snake",))
        self.assertEquals(count, 1)

        count = self.databaseTemplate.query_for_int("select population from animal where name = ?", ("snake",))
        self.assertEquals(count, 1)
        
    def testProgrammaticStaticQueryForLong(self):
        count = self.databaseTemplate.query_for_object("select count(*) from animal", required_type=self.factory.count_type())
        self.assertEquals(count, 4)
        
    def testProgrammaticQueryForLongWithBoundVariables(self):
        count = self.databaseTemplate.query_for_object("select count(*) from animal where name = %s", ("snake",), self.factory.count_type())
        self.assertEquals(count, 1)

        count = self.databaseTemplate.query_for_object("select count(*) from animal where name = ?", ("snake",), self.factory.count_type())
        self.assertEquals(count, 1)
        
    def testProgrammaticStaticQueryForObject(self):
        self.assertRaises(ArgumentMustBeNamed, self.databaseTemplate.query_for_object, "select name from animal where category = 'reptile'", types.StringType)

        name = self.databaseTemplate.query_for_object("select name from animal where category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "snake")
        
    def testProgrammaticQueryForObjectWithBoundVariables(self):
        name = self.databaseTemplate.query_for_object("select name from animal where category = %s", ("reptile",), types.StringType)
        self.assertEquals(name, "snake")

        name = self.databaseTemplate.query_for_object("select name from animal where category = ?", ("reptile",), types.StringType)
        self.assertEquals(name, "snake")
        
    def testProgrammaticStaticUpdate(self):
        rows = self.databaseTemplate.update("UPDATE animal SET name = 'python' WHERE name = 'snake'")
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "python")
        
    def testProgrammaticUpdateWithBoundVariables(self):
        rows = self.databaseTemplate.update("UPDATE animal SET name = ? WHERE category = ?", ("python", "reptile"))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "python")

        rows = self.databaseTemplate.update("UPDATE animal SET name = ? WHERE category = %s", ("coily", "reptile"))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "coily")

    def testProgrammaticStaticInsert(self):
        self.databaseTemplate.execute("DELETE FROM animal")
        rows = self.databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES ('black mamba', 'kill_bill_viper', 1)")
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'kill_bill_viper'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")
        
    def testProgrammaticInsertWithBoundVariables(self):
        self.databaseTemplate.execute("DELETE FROM animal")
        rows = self.databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES (?, ?, ?)", ('black mamba', 'kill_bill_viper', 1))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'kill_bill_viper'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")

        rows = self.databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES (%s, %s, %s)", ('cottonmouth', 'kill_bill_viper', 1))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("select name from animal where name = 'cottonmouth'", required_type=types.StringType)
        self.assertEquals(name, "cottonmouth")
class DatabaseTemplateMockTestCase(MockTestCase):
    """Testing the DatabaseTemplate utilizes stubbing and mocking, in order to isolate from different
    vendor implementations. This reduces the overhead in making changes to core functionality."""

    def setUp(self):
        self.mock = self.mock()
        connection_factory = testSupportClasses.StubDBFactory()
        connection_factory.stubConnection.mockCursor = self.mock
        self.databaseTemplate = DatabaseTemplate(connection_factory)

    def testProgrammaticallyInstantiatingAnAbstractDatabaseTemplate(self):
        emptyTemplate = DatabaseTemplate()
        self.assertRaises(AttributeError, emptyTemplate.query, "sql query shouldn't work", None)

    def testProgrammaticHandlingInvalidRowHandler(self):
        self.mock.expects(once()).method("execute")
        self.mock.expects(once()).method("fetchall").will(return_value([("me", "myphone")]))
        
        self.assertRaises(AttributeError, self.databaseTemplate.query, "select * from foobar", rowhandler=testSupportClasses.InvalidCallbackHandler())
        
    def testProgrammaticHandlingImproperRowHandler(self):
        self.mock.expects(once()).method("execute")
        self.mock.expects(once()).method("fetchall").will(return_value([("me", "myphone")]))

        self.assertRaises(TypeError, self.databaseTemplate.query, "select * from foobar", rowhandler=testSupportClasses.ImproperCallbackHandler())
        
    def testProgrammaticHandlingValidDuckTypedRowHandler(self):
        self.mock.expects(once()).method("execute")
        self.mock.expects(once()).method("fetchall").will(return_value([("me", "myphone")]))

        results = self.databaseTemplate.query("select * from foobar", rowhandler=testSupportClasses.ValidHandler())

    def testIoCGeneralQuery(self):
        appContext = ApplicationContext(XMLConfig("support/databaseTestApplicationContext.xml"))
        mockConnectionFactory = appContext.get_object("mockConnectionFactory")
        mockConnectionFactory.stubConnection.mockCursor = self.mock
        
        self.mock.expects(once()).method("execute")
        self.mock.expects(once()).method("fetchall").will(return_value([("me", "myphone")]))
        

        databaseTemplate = DatabaseTemplate(connection_factory = mockConnectionFactory)
        results = databaseTemplate.query("select * from foobar", rowhandler=testSupportClasses.SampleRowMapper())

    def testProgrammaticStaticQuery(self):
        self.assertRaises(ArgumentMustBeNamed, self.databaseTemplate.query, "select * from animal", testSupportClasses.AnimalRowMapper())

        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([('snake', 'reptile', 1), ('racoon', 'mammal', 1)])).id("#2").after("#1")

        animals = self.databaseTemplate.query("select * from animal", rowhandler=testSupportClasses.AnimalRowMapper())
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")
        self.assertEquals(animals[1].name, "racoon")
        self.assertEquals(animals[1].category, "mammal")

    def testProgrammaticQueryWithBoundArguments(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([('snake', 'reptile', 1)])).id("#2").after("#1")
        self.mock.expects(once()).method("execute").id("#3").after("#2")
        self.mock.expects(once()).method("fetchall").will(return_value([('snake', 'reptile', 1)])).id("#4").after("#3")

        animals = self.databaseTemplate.query("select * from animal where name = %s", ("snake",), testSupportClasses.AnimalRowMapper())
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")

        animals = self.databaseTemplate.query("select * from animal where name = ?", ("snake",), testSupportClasses.AnimalRowMapper())
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")
        
    def testProgrammaticStaticQueryForList(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([('snake', 'reptile', 1), ('racoon', 'mammal', 1)])).id("#2").after("#1")

        animals = self.databaseTemplate.query_for_list("select * from animal")
        self.assertEquals(animals[0][0], "snake")
        self.assertEquals(animals[0][1], "reptile")
        self.assertEquals(animals[1][0], "racoon")
        self.assertEquals(animals[1][1], "mammal")
        
    def testProgrammaticQueryForListWithBoundArguments(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([('snake', 'reptile', 1)])).id("#2").after("#1")
        self.mock.expects(once()).method("execute").id("#3").after("#2")
        self.mock.expects(once()).method("fetchall").will(return_value([('snake', 'reptile', 1)])).id("#4").after("#3")

        animals = self.databaseTemplate.query_for_list("select * from animal where name = %s", ("snake",))
        self.assertEquals(animals[0][0], "snake")
        self.assertEquals(animals[0][1], "reptile")
        
        animals = self.databaseTemplate.query_for_list("select * from animal where name = ?", ("snake",))
        self.assertEquals(animals[0][0], "snake")
        self.assertEquals(animals[0][1], "reptile")

    def testProgrammaticQueryForListWithBoundArgumentsNotProperlyTuplized(self):
        self.assertRaises(InvalidArgumentType, self.databaseTemplate.query_for_list, "select * from animal where name = %s", "snake")
        self.assertRaises(InvalidArgumentType, self.databaseTemplate.query_for_list, "select * from animal where name = ?", "snake")

    def testProgrammaticStaticQueryForInt(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([(1,)])).id("#2").after("#1")

        count = self.databaseTemplate.query_for_int("select population from animal where name = 'snake'")
        self.assertEquals(count, 1)
        
    def testProgrammaticQueryForIntWithBoundArguments(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([(1,)])).id("#2").after("#1")
        self.mock.expects(once()).method("execute").id("#3").after("#2")
        self.mock.expects(once()).method("fetchall").will(return_value([(1,)])).id("#4").after("#3")

        count = self.databaseTemplate.query_for_int("select population from animal where name = %s", ("snake",))
        self.assertEquals(count, 1)

        count = self.databaseTemplate.query_for_int("select population from animal where name = ?", ("snake",))
        self.assertEquals(count, 1)
        
    def testProgrammaticStaticQueryForLong(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([(4,)])).id("#2").after("#1")

        count = self.databaseTemplate.query_for_object("select count(*) from animal", required_type=types.IntType)
        self.assertEquals(count, 4)
        
    def testProgrammaticQueryForLongWithBoundVariables(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([(1,)])).id("#2").after("#1")
        self.mock.expects(once()).method("execute").id("#3").after("#2")
        self.mock.expects(once()).method("fetchall").will(return_value([(1,)])).id("#4").after("#3")

        count = self.databaseTemplate.query_for_object("select count(*) from animal where name = %s", ("snake",), types.IntType)
        self.assertEquals(count, 1)

        count = self.databaseTemplate.query_for_object("select count(*) from animal where name = ?", ("snake",), types.IntType)
        self.assertEquals(count, 1)
        
    def testProgrammaticStaticQueryForObject(self):
        self.assertRaises(ArgumentMustBeNamed, self.databaseTemplate.query_for_object, "select name from animal where category = 'reptile'", types.StringType)

        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("snake",)])).id("#2").after("#1")

        name = self.databaseTemplate.query_for_object("select name from animal where category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "snake")
        
    def testProgrammaticQueryForObjectWithBoundVariables(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("snake",)])).id("#2").after("#1")
        self.mock.expects(once()).method("execute").id("#3").after("#2")
        self.mock.expects(once()).method("fetchall").will(return_value([("snake",)])).id("#4").after("#3")

        name = self.databaseTemplate.query_for_object("select name from animal where category = %s", ("reptile",), types.StringType)
        self.assertEquals(name, "snake")

        name = self.databaseTemplate.query_for_object("select name from animal where category = ?", ("reptile",), types.StringType)
        self.assertEquals(name, "snake")
        
    def testProgrammaticStaticUpdate(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("execute").id("#2").after("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("python",)])).id("#3").after("#2")
        self.mock.rowcount = 1

        rows = self.databaseTemplate.update("UPDATE animal SET name = 'python' WHERE name = 'snake'")
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "python")
        
    def testProgrammaticUpdateWithBoundVariables(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("execute").id("#2").after("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("python",)])).id("#3").after("#2")
        self.mock.expects(once()).method("execute").id("#4").after("#3")
        self.mock.expects(once()).method("execute").id("#5").after("#4")
        self.mock.expects(once()).method("fetchall").will(return_value([("coily",)])).id("#6").after("#5")
        self.mock.rowcount = 1

        rows = self.databaseTemplate.update("UPDATE animal SET name = ? WHERE category = ?", ("python", "reptile"))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "python")

        rows = self.databaseTemplate.update("UPDATE animal SET name = ? WHERE category = %s", ("coily", "reptile"))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "coily")

    def testProgrammaticStaticInsert(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("execute").id("#2").after("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("black mamba",)])).id("#3").after("#2")
        self.mock.rowcount = 1

        rows = self.databaseTemplate.execute ("INSERT INTO animal (name, category, population) VALUES ('black mamba', 'kill_bill_viper', 1)")
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'kill_bill_viper'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")
        
    def testProgrammaticInsertWithBoundVariables(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("execute").id("#2").after("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("black mamba",)])).id("#3").after("#2")
        self.mock.expects(once()).method("execute").id("#4").after("#3")
        self.mock.expects(once()).method("execute").id("#5").after("#4")
        self.mock.expects(once()).method("fetchall").will(return_value([("cottonmouth",)])).id("#6").after("#5")
        self.mock.rowcount = 1
        
        rows = self.databaseTemplate.execute ("INSERT INTO animal (name, category, population) VALUES (?, ?, ?)", ('black mamba', 'kill_bill_viper', 1))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'kill_bill_viper'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")

        rows = self.databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES (%s, %s, %s)", ('cottonmouth', 'kill_bill_viper', 1))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("select name from animal where name = 'cottonmouth'", required_type=types.StringType)
        self.assertEquals(name, "cottonmouth")
class AbstractDatabaseTemplateTestCase(unittest.TestCase):
    def __init__(self, methodName='runTest'):
        unittest.TestCase.__init__(self, methodName)
        self.factory = None
        self.createdTables = False

    def setUp(self):
        if not self.createdTables:
            self.createTables()
        self.databaseTemplate = DatabaseTemplate(self.factory)
        self.databaseTemplate.execute("DELETE FROM animal")
        self.factory.commit()
        self.assertEquals(len(self.databaseTemplate.query_for_list("SELECT * FROM animal")), 0)
        self.databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES ('snake', 'reptile', 1)")
        self.databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES ('racoon', 'mammal', 0)")
        self.databaseTemplate.execute ("INSERT INTO animal (name, category, population) VALUES ('black mamba', 'kill_bill_viper', 1)")
        self.databaseTemplate.execute ("INSERT INTO animal (name, category, population) VALUES ('cottonmouth', 'kill_bill_viper', 1)")
        self.factory.commit()
        self.assertEquals(len(self.databaseTemplate.query_for_list("SELECT * FROM animal")), 4)

    def tearDown(self):
        self.factory.rollback()

    def testProgrammaticallyInstantiatingAnAbstractDatabaseTemplate(self):
        emptyTemplate = DatabaseTemplate()
        self.assertRaises(AttributeError, emptyTemplate.query, "sql query shouldn't work", None)

    def testProgrammaticHandlingInvalidRowHandler(self):
        self.assertRaises(AttributeError, self.databaseTemplate.query, "select * from animal", rowhandler=testSupportClasses.InvalidCallbackHandler())

    def testProgrammaticHandlingImproperRowHandler(self):
        self.assertRaises(TypeError, self.databaseTemplate.query, "select * from animal", rowhandler=testSupportClasses.ImproperCallbackHandler())
        
    def testProgrammaticHandlingValidDuckTypedRowHandler(self):
        results = self.databaseTemplate.query("select * from animal", rowhandler=testSupportClasses.ValidHandler())

    def testProgrammaticStaticQuery(self):
        self.assertRaises(ArgumentMustBeNamed, self.databaseTemplate.query, "select * from animal", testSupportClasses.AnimalRowMapper())

        animals = self.databaseTemplate.query("select name, category from animal", rowhandler=testSupportClasses.AnimalRowMapper())
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")
        self.assertEquals(animals[1].name, "racoon")
        self.assertEquals(animals[1].category, "mammal")

    def testProgrammaticStaticQueryWithSimpleRowMapper(self):
        animals = self.databaseTemplate.query("select name, category from animal", rowhandler=SimpleRowMapper(testSupportClasses.Animal))
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")
        self.assertEquals(animals[1].name, "racoon")
        self.assertEquals(animals[1].category, "mammal")

    def testProgrammaticStaticQueryWithDictionaryRowMapper(self):
        animals = self.databaseTemplate.query("select name, category from animal", rowhandler=DictionaryRowMapper())
        self.assertEquals(animals[0]["name"], "snake")
        self.assertEquals(animals[0]["category"], "reptile")
        self.assertEquals(animals[1]["name"], "racoon")
        self.assertEquals(animals[1]["category"], "mammal")
        
    def testProgrammaticQueryWithBoundArguments(self):
        animals = self.databaseTemplate.query("select name, category from animal where name = %s", ("snake",), testSupportClasses.AnimalRowMapper())
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")

        animals = self.databaseTemplate.query("select name, category from animal where name = ?", ("snake",), testSupportClasses.AnimalRowMapper())
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")
        
    def testProgrammaticQueryWithBoundArgumentsWithSimpleRowMapper(self):
        animals = self.databaseTemplate.query("select name, category from animal where name = %s", ("snake",), SimpleRowMapper(testSupportClasses.Animal))
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")

        animals = self.databaseTemplate.query("select name, category from animal where name = ?", ("snake",), SimpleRowMapper(testSupportClasses.Animal))
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")

    def testProgrammaticQueryWithBoundArgumentsWithDictionaryRowMapper(self):
        animals = self.databaseTemplate.query("select name, category from animal where name = %s", ("snake",), DictionaryRowMapper())
        self.assertEquals(animals[0]["name"], "snake")
        self.assertEquals(animals[0]["category"], "reptile")

        animals = self.databaseTemplate.query("select name, category from animal where name = ?", ("snake",), DictionaryRowMapper())
        self.assertEquals(animals[0]["name"], "snake")
        self.assertEquals(animals[0]["category"], "reptile")

    def testProgrammaticStaticQueryForList(self):
        animals = self.databaseTemplate.query_for_list("select name, category from animal")
        self.assertEquals(animals[0][0], "snake")
        self.assertEquals(animals[0][1], "reptile")
        self.assertEquals(animals[1][0], "racoon")
        self.assertEquals(animals[1][1], "mammal")
        
    def testProgrammaticQueryForListWithBoundArguments(self):
        animals = self.databaseTemplate.query_for_list("select name, category from animal where name = %s", ("snake",))
        self.assertEquals(animals[0][0], "snake")
        self.assertEquals(animals[0][1], "reptile")
        
        animals = self.databaseTemplate.query_for_list("select name, category from animal where name = ?", ("snake",))
        self.assertEquals(animals[0][0], "snake")
        self.assertEquals(animals[0][1], "reptile")

    def testProgrammaticQueryForListWithBoundArgumentsNotProperlyTuplized(self):
        self.assertRaises(InvalidArgumentType, self.databaseTemplate.query_for_list, "select * from animal where name = %s", "snake")
        self.assertRaises(InvalidArgumentType, self.databaseTemplate.query_for_list, "select * from animal where name = ?", "snake")

    def testProgrammaticStaticQueryForInt(self):
        count = self.databaseTemplate.query_for_int("select population from animal where name = 'snake'")
        self.assertEquals(count, 1)
        
    def testProgrammaticQueryForIntWithBoundArguments(self):
        count = self.databaseTemplate.query_for_int("select population from animal where name = %s", ("snake",))
        self.assertEquals(count, 1)

        count = self.databaseTemplate.query_for_int("select population from animal where name = ?", ("snake",))
        self.assertEquals(count, 1)
        
    def testProgrammaticStaticQueryForLong(self):
        count = self.databaseTemplate.query_for_object("select count(*) from animal", required_type=self.factory.count_type())
        self.assertEquals(count, 4)
        
    def testProgrammaticQueryForLongWithBoundVariables(self):
        count = self.databaseTemplate.query_for_object("select count(*) from animal where name = %s", ("snake",), self.factory.count_type())
        self.assertEquals(count, 1)

        count = self.databaseTemplate.query_for_object("select count(*) from animal where name = ?", ("snake",), self.factory.count_type())
        self.assertEquals(count, 1)
        
    def testProgrammaticStaticQueryForObject(self):
        self.assertRaises(ArgumentMustBeNamed, self.databaseTemplate.query_for_object, "select name from animal where category = 'reptile'", types.StringType)

        name = self.databaseTemplate.query_for_object("select name from animal where category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "snake")
        
    def testProgrammaticQueryForObjectWithBoundVariables(self):
        name = self.databaseTemplate.query_for_object("select name from animal where category = %s", ("reptile",), types.StringType)
        self.assertEquals(name, "snake")

        name = self.databaseTemplate.query_for_object("select name from animal where category = ?", ("reptile",), types.StringType)
        self.assertEquals(name, "snake")
        
    def testProgrammaticStaticUpdate(self):
        rows = self.databaseTemplate.update("UPDATE animal SET name = 'python' WHERE name = 'snake'")
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "python")
        
    def testProgrammaticUpdateWithBoundVariables(self):
        rows = self.databaseTemplate.update("UPDATE animal SET name = ? WHERE category = ?", ("python", "reptile"))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "python")

        rows = self.databaseTemplate.update("UPDATE animal SET name = ? WHERE category = %s", ("coily", "reptile"))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "coily")

    def testProgrammaticStaticInsert(self):
        self.databaseTemplate.execute("DELETE FROM animal")
        rows = self.databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES ('black mamba', 'kill_bill_viper', 1)")
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'kill_bill_viper'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")

    def testProgrammaticStaticInsertWithInsertApi(self):
        self.databaseTemplate.execute("DELETE FROM animal")
        id = self.databaseTemplate.insert_and_return_id("INSERT INTO animal (name, category, population) VALUES ('black mamba', 'kill_bill_viper', 1)")
        self.assertEquals(id, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'kill_bill_viper'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")
        
    def testProgrammaticInsertWithBoundVariables(self):
        self.databaseTemplate.execute("DELETE FROM animal")
        rows = self.databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES (?, ?, ?)", ('black mamba', 'kill_bill_viper', 1))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'kill_bill_viper'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")

        rows = self.databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES (%s, %s, %s)", ('cottonmouth', 'kill_bill_viper', 1))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("select name from animal where name = 'cottonmouth'", required_type=types.StringType)
        self.assertEquals(name, "cottonmouth")

    def testProgrammaticInsertWithBoundVariablesWithInsertApi(self):
        self.databaseTemplate.execute("DELETE FROM animal")
        id = self.databaseTemplate.insert_and_return_id("INSERT INTO animal (name, category, population) VALUES (?, ?, ?)", ('black mamba', 'kill_bill_viper', 1))
        self.assertEquals(id, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'kill_bill_viper'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")

        id = self.databaseTemplate.insert_and_return_id("INSERT INTO animal (name, category, population) VALUES (%s, %s, %s)", ('cottonmouth', 'kill_bill_viper', 1))
        self.assertEquals(id, 2)

        name = self.databaseTemplate.query_for_object("select name from animal where name = 'cottonmouth'", required_type=types.StringType)
        self.assertEquals(name, "cottonmouth")
class DatabaseTemplateMockTestCase(MockTestCase):
    """Testing the DatabaseTemplate utilizes stubbing and mocking, in order to isolate from different
    vendor implementations. This reduces the overhead in making changes to core functionality."""

    def setUp(self):
        self.mock = self.mock()
        connection_factory = testSupportClasses.StubDBFactory()
        connection_factory.stubConnection.mockCursor = self.mock
        self.databaseTemplate = DatabaseTemplate(connection_factory)

    def testProgrammaticallyInstantiatingAnAbstractDatabaseTemplate(self):
        emptyTemplate = DatabaseTemplate()
        self.assertRaises(AttributeError, emptyTemplate.query, "sql query shouldn't work", None)

    def testProgrammaticHandlingInvalidRowHandler(self):
        self.mock.expects(once()).method("execute")
        self.mock.expects(once()).method("fetchall").will(return_value([("me", "myphone")]))
        
        self.assertRaises(AttributeError, self.databaseTemplate.query, "select * from foobar", rowhandler=testSupportClasses.InvalidCallbackHandler())
        
    def testProgrammaticHandlingImproperRowHandler(self):
        self.mock.expects(once()).method("execute")
        self.mock.expects(once()).method("fetchall").will(return_value([("me", "myphone")]))

        self.assertRaises(TypeError, self.databaseTemplate.query, "select * from foobar", rowhandler=testSupportClasses.ImproperCallbackHandler())
        
    def testProgrammaticHandlingValidDuckTypedRowHandler(self):
        self.mock.expects(once()).method("execute")
        self.mock.expects(once()).method("fetchall").will(return_value([("me", "myphone")]))

        results = self.databaseTemplate.query("select * from foobar", rowhandler=testSupportClasses.ValidHandler())

    def testIoCGeneralQuery(self):
        appContext = ApplicationContext(XMLConfig("support/databaseTestApplicationContext.xml"))
        mockConnectionFactory = appContext.get_object("mockConnectionFactory")
        mockConnectionFactory.stubConnection.mockCursor = self.mock
        
        self.mock.expects(once()).method("execute")
        self.mock.expects(once()).method("fetchall").will(return_value([("me", "myphone")]))
        

        databaseTemplate = DatabaseTemplate(connection_factory = mockConnectionFactory)
        results = databaseTemplate.query("select * from foobar", rowhandler=testSupportClasses.SampleRowMapper())

    def testProgrammaticStaticQuery(self):
        self.assertRaises(ArgumentMustBeNamed, self.databaseTemplate.query, "select * from animal", testSupportClasses.AnimalRowMapper())

        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([('snake', 'reptile', 1), ('racoon', 'mammal', 1)])).id("#2").after("#1")

        animals = self.databaseTemplate.query("select * from animal", rowhandler=testSupportClasses.AnimalRowMapper())
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")
        self.assertEquals(animals[1].name, "racoon")
        self.assertEquals(animals[1].category, "mammal")

    def testProgrammaticQueryWithBoundArguments(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([('snake', 'reptile', 1)])).id("#2").after("#1")
        self.mock.expects(once()).method("execute").id("#3").after("#2")
        self.mock.expects(once()).method("fetchall").will(return_value([('snake', 'reptile', 1)])).id("#4").after("#3")

        animals = self.databaseTemplate.query("select * from animal where name = %s", ("snake",), testSupportClasses.AnimalRowMapper())
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")

        animals = self.databaseTemplate.query("select * from animal where name = ?", ("snake",), testSupportClasses.AnimalRowMapper())
        self.assertEquals(animals[0].name, "snake")
        self.assertEquals(animals[0].category, "reptile")
        
    def testProgrammaticStaticQueryForList(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([('snake', 'reptile', 1), ('racoon', 'mammal', 1)])).id("#2").after("#1")

        animals = self.databaseTemplate.query_for_list("select * from animal")
        self.assertEquals(animals[0][0], "snake")
        self.assertEquals(animals[0][1], "reptile")
        self.assertEquals(animals[1][0], "racoon")
        self.assertEquals(animals[1][1], "mammal")
        
    def testProgrammaticQueryForListWithBoundArguments(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([('snake', 'reptile', 1)])).id("#2").after("#1")
        self.mock.expects(once()).method("execute").id("#3").after("#2")
        self.mock.expects(once()).method("fetchall").will(return_value([('snake', 'reptile', 1)])).id("#4").after("#3")

        animals = self.databaseTemplate.query_for_list("select * from animal where name = %s", ("snake",))
        self.assertEquals(animals[0][0], "snake")
        self.assertEquals(animals[0][1], "reptile")
        
        animals = self.databaseTemplate.query_for_list("select * from animal where name = ?", ("snake",))
        self.assertEquals(animals[0][0], "snake")
        self.assertEquals(animals[0][1], "reptile")

    def testProgrammaticQueryForListWithBoundArgumentsNotProperlyTuplized(self):
        self.assertRaises(InvalidArgumentType, self.databaseTemplate.query_for_list, "select * from animal where name = %s", "snake")
        self.assertRaises(InvalidArgumentType, self.databaseTemplate.query_for_list, "select * from animal where name = ?", "snake")

    def testProgrammaticStaticQueryForInt(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([(1,)])).id("#2").after("#1")

        count = self.databaseTemplate.query_for_int("select population from animal where name = 'snake'")
        self.assertEquals(count, 1)
        
    def testProgrammaticQueryForIntWithBoundArguments(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([(1,)])).id("#2").after("#1")
        self.mock.expects(once()).method("execute").id("#3").after("#2")
        self.mock.expects(once()).method("fetchall").will(return_value([(1,)])).id("#4").after("#3")

        count = self.databaseTemplate.query_for_int("select population from animal where name = %s", ("snake",))
        self.assertEquals(count, 1)

        count = self.databaseTemplate.query_for_int("select population from animal where name = ?", ("snake",))
        self.assertEquals(count, 1)
        
    def testProgrammaticStaticQueryForLong(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([(4,)])).id("#2").after("#1")

        count = self.databaseTemplate.query_for_object("select count(*) from animal", required_type=types.IntType)
        self.assertEquals(count, 4)
        
    def testProgrammaticQueryForLongWithBoundVariables(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([(1,)])).id("#2").after("#1")
        self.mock.expects(once()).method("execute").id("#3").after("#2")
        self.mock.expects(once()).method("fetchall").will(return_value([(1,)])).id("#4").after("#3")

        count = self.databaseTemplate.query_for_object("select count(*) from animal where name = %s", ("snake",), types.IntType)
        self.assertEquals(count, 1)

        count = self.databaseTemplate.query_for_object("select count(*) from animal where name = ?", ("snake",), types.IntType)
        self.assertEquals(count, 1)
        
    def testProgrammaticStaticQueryForObject(self):
        self.assertRaises(ArgumentMustBeNamed, self.databaseTemplate.query_for_object, "select name from animal where category = 'reptile'", types.StringType)

        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("snake",)])).id("#2").after("#1")

        name = self.databaseTemplate.query_for_object("select name from animal where category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "snake")
        
    def testProgrammaticQueryForObjectWithBoundVariables(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("snake",)])).id("#2").after("#1")
        self.mock.expects(once()).method("execute").id("#3").after("#2")
        self.mock.expects(once()).method("fetchall").will(return_value([("snake",)])).id("#4").after("#3")

        name = self.databaseTemplate.query_for_object("select name from animal where category = %s", ("reptile",), types.StringType)
        self.assertEquals(name, "snake")

        name = self.databaseTemplate.query_for_object("select name from animal where category = ?", ("reptile",), types.StringType)
        self.assertEquals(name, "snake")
        
    def testProgrammaticStaticUpdate(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("execute").id("#2").after("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("python",)])).id("#3").after("#2")
        self.mock.rowcount = 1

        rows = self.databaseTemplate.update("UPDATE animal SET name = 'python' WHERE name = 'snake'")
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "python")
        
    def testProgrammaticUpdateWithBoundVariables(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("execute").id("#2").after("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("python",)])).id("#3").after("#2")
        self.mock.expects(once()).method("execute").id("#4").after("#3")
        self.mock.expects(once()).method("execute").id("#5").after("#4")
        self.mock.expects(once()).method("fetchall").will(return_value([("coily",)])).id("#6").after("#5")
        self.mock.rowcount = 1

        rows = self.databaseTemplate.update("UPDATE animal SET name = ? WHERE category = ?", ("python", "reptile"))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "python")

        rows = self.databaseTemplate.update("UPDATE animal SET name = ? WHERE category = %s", ("coily", "reptile"))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'reptile'", required_type=types.StringType)
        self.assertEquals(name, "coily")

    def testProgrammaticStaticInsert(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("execute").id("#2").after("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("black mamba",)])).id("#3").after("#2")
        self.mock.rowcount = 1

        rows = self.databaseTemplate.execute ("INSERT INTO animal (name, category, population) VALUES ('black mamba', 'kill_bill_viper', 1)")
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'kill_bill_viper'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")

    def testProgrammaticStaticInsertWithInsertApi(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("execute").id("#2").after("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("black mamba",)])).id("#3").after("#2")
        self.mock.lastrowid = 42 

        id = self.databaseTemplate.insert_and_return_id("INSERT INTO animal (name, category, population) VALUES ('black mamba', 'kill_bill_viper', 1)")
        self.assertEquals(id, 42)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'kill_bill_viper'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")
        
    def testProgrammaticInsertWithBoundVariables(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("execute").id("#2").after("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("black mamba",)])).id("#3").after("#2")
        self.mock.expects(once()).method("execute").id("#4").after("#3")
        self.mock.expects(once()).method("execute").id("#5").after("#4")
        self.mock.expects(once()).method("fetchall").will(return_value([("cottonmouth",)])).id("#6").after("#5")
        self.mock.rowcount = 1
        
        rows = self.databaseTemplate.execute ("INSERT INTO animal (name, category, population) VALUES (?, ?, ?)", ('black mamba', 'kill_bill_viper', 1))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'kill_bill_viper'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")

        rows = self.databaseTemplate.execute("INSERT INTO animal (name, category, population) VALUES (%s, %s, %s)", ('cottonmouth', 'kill_bill_viper', 1))
        self.assertEquals(rows, 1)

        name = self.databaseTemplate.query_for_object("select name from animal where name = 'cottonmouth'", required_type=types.StringType)
        self.assertEquals(name, "cottonmouth")

    def testProgrammaticInsertWithBoundVariablesWithInsertApi(self):
        self.mock.expects(once()).method("execute").id("#1")
        self.mock.expects(once()).method("execute").id("#2").after("#1")
        self.mock.expects(once()).method("fetchall").will(return_value([("black mamba",)])).id("#3").after("#2")
        self.mock.expects(once()).method("execute").id("#4").after("#3")
        self.mock.expects(once()).method("execute").id("#5").after("#4")
        self.mock.expects(once()).method("fetchall").will(return_value([("cottonmouth",)])).id("#6").after("#5")
        self.mock.lastrowid = 42

        id = self.databaseTemplate.insert_and_return_id ("INSERT INTO animal (name, category, population) VALUES (?, ?, ?)", ('black mamba', 'kill_bill_viper', 1))
        self.assertEquals(id, 42)

        name = self.databaseTemplate.query_for_object("SELECT name FROM animal WHERE category = 'kill_bill_viper'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")

        id = self.databaseTemplate.insert_and_return_id("INSERT INTO animal (name, category, population) VALUES (%s, %s, %s)", ('cottonmouth', 'kill_bill_viper', 1))
        self.assertEquals(id, 42)

        name = self.databaseTemplate.query_for_object("select name from animal where name = 'cottonmouth'", required_type=types.StringType)
        self.assertEquals(name, "cottonmouth")
class AbstractTransactionTestCase(unittest.TestCase):

    def __init__(self, methodName='runTest'):
        unittest.TestCase.__init__(self, methodName)
        self.factory = None
        self.createdTables = False

    def setUp(self):
        if not self.createdTables:
            self.createTables()
        self.createTables()
        self.dt = DatabaseTemplate(self.factory)
        self.dt.execute("DELETE FROM animal")
        self.dt.execute("DELETE FROM account")
        self.factory.commit()
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 0)
        self.transactionManager = ConnectionFactoryTransactionManager(self.factory)
        self.transactionTemplate = TransactionTemplate(self.transactionManager)

    def tearDown(self):
        self.factory.getConnection().rollback()

    def testInsertingRowsIntoTheDatabase(self):
        rows = self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba',))
        self.assertEquals(rows, 1)

        name = self.dt.query_for_object("SELECT name FROM animal WHERE name = 'black mamba'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")

    def testInsertingRowsIntoTheDatabaseWithInsertApi(self):
        id = self.dt.insert_and_return_id("INSERT INTO animal (name) VALUES (?)", ('black mamba',))
        self.assertEquals(id, 1)

        name = self.dt.query_for_object("SELECT name FROM animal WHERE name = 'black mamba'", required_type=types.StringType)
        self.assertEquals(name, "black mamba")

    def testInsertingTwoRowsWithoutaTransactionButManuallyCommitted(self):
        self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba',))
        self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('copperhead',))
        self.factory.commit()
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 2)

    def testInsertingTwoRowsWithoutaTransactionButManuallyRolledBack(self):
        self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba',))
        self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('copperhead',))
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 2)
        self.dt.connection_factory.getConnection().rollback()
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 0)

    def testInsertingTwoRowsWithaTransactionAndNoErrorsAndNoResults(self):
        class txDefinition(TransactionCallbackWithoutResult):
            def do_in_tx_without_result(s, status):
                self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba',))
                self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('copperhead',))
                
        self.transactionTemplate.execute(txDefinition())
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 2)

    def testInsertingTwoRowsWithaTransactionAndAnIntermediateErrorAndNoResults(self):
        class txDefinition(TransactionCallbackWithoutResult):
            def do_in_tx_without_result(s, status):
                self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba',))
                self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 1)
                raise DataAccessException("This should break the transaction, and rollback the insert.")
                
        self.assertRaises(DataAccessException, self.transactionTemplate.execute, txDefinition())
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 0)

    def testInsertingTwoRowsWithaTransactionAndNoErrorsAndResults(self):
        class txDefinition(TransactionCallback):
            def do_in_transaction(s, status):
                self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba',))
                self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('copperhead',))
                results = self.dt.query_for_object("SELECT name FROM animal WHERE name like 'c%'", required_type=types.StringType)
                return results
                
        self.assertEquals(self.transactionTemplate.execute(txDefinition()), "copperhead")
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 2)

    def testInsertingTwoRowsWithaTransactionAndAnIntermediateErrorAndResults(self):
        class txDefinition(TransactionCallback):
            def do_in_transaction(s, status):
                self.dt.execute("INSERT INTO animal (name) VALUES (?)", ('black mamba'))
                self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 1)
                raise DataAccessException("This should break the transaction, and rollback the insert.")
                
        self.assertRaises(DataAccessException, self.transactionTemplate.execute, txDefinition())
        self.assertEquals(len(self.dt.query_for_list("SELECT * FROM animal")), 0)

    def testDeclarativeTransactions(self):
        appContext = ApplicationContext(DatabaseTxTestAppContext(self.factory))
        bank = appContext.get_object("bank")

        bank.open("Checking")
        bank.open("Savings")

        bank.deposit(125.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 125.00)

        bank.deposit(250.00, "Savings")
        self.assertEquals(bank.balance("Savings"), 250.00)

        bank.transfer(25.00, "Savings", "Checking")
        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 150.00)

        bank.withdraw(10.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 140.00)

        amount = 0.0
        try:
            amount = bank.withdraw(1000, "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(amount, 0.0)

        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 140.00)

        try:
            bank.transfer(200, "Checking", "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass

        self.assertEquals(bank.balance("Savings"), 225.00, "Bad transfer did NOT fail atomically!")
        self.assertEquals(bank.balance("Checking"), 140.00, "Bad transfer did NOT fail atomically!")

    def testDecoratorBasedTransactions(self):
        appContext = ApplicationContext(DatabaseTxTestDecorativeTransactions(self.factory))
        bank = appContext.get_object("bank")

        bank.open("Checking")
        bank.open("Savings")

        bank.deposit(125.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 125.00)

        bank.deposit(250.00, "Savings")
        self.assertEquals(bank.balance("Savings"), 250.00)

        bank.transfer(25.00, "Savings", "Checking")
        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 150.00)

        bank.withdraw(10.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 140.00)

        amount = 0.0
        try:
            amount = bank.withdraw(1000, "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(amount, 0.0)

        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 140.00)

        try:
            bank.transfer(200, "Checking", "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(bank.balance("Savings"), 225.00, "Bad transfer did NOT fail atomically!")
        self.assertEquals(bank.balance("Checking"), 140.00, "Bad transfer did NOT fail atomically!")

    def testDecoratorBasedTransactionsWithNoArguments(self):
        appContext = ApplicationContext(DatabaseTxTestDecorativeTransactionsWithNoArguments(self.factory))
        bank = appContext.get_object("bank")

        bank.open("Checking")
        bank.open("Savings")

        bank.deposit(125.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 125.00)

        bank.deposit(250.00, "Savings")
        self.assertEquals(bank.balance("Savings"), 250.00)

        bank.transfer(25.00, "Savings", "Checking")
        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 150.00)

        bank.withdraw(10.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 140.00)

        amount = 0.0
        try:
            amount = bank.withdraw(1000, "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(amount, 0.0)

        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 140.00)

        try:
            bank.transfer(200, "Checking", "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass

        self.assertEquals(bank.balance("Savings"), 225.00, "Bad transfer did NOT fail atomically!")
        self.assertEquals(bank.balance("Checking"), 140.00, "Bad transfer did NOT fail atomically!")
        
    def testDecoratorBasedTransactionsWithLotsOfArguments(self):
        appContext = ApplicationContext(DatabaseTxTestDecorativeTransactionsWithLotsOfArguments(self.factory))
        bank = appContext.get_object("bank")

        bank.open("Checking")
        bank.open("Savings")

        bank.deposit(125.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 125.00)

        bank.deposit(250.00, "Savings")
        self.assertEquals(bank.balance("Savings"), 250.00)

        bank.transfer(25.00, "Savings", "Checking")
        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 150.00)

        bank.withdraw(10.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 140.00)

        amount = 0.0
        try:
            amount = bank.withdraw(1000, "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(amount, 0.0)

        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 140.00)

        try:
            bank.transfer(200, "Checking", "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass

        self.assertEquals(bank.balance("Savings"), 225.00, "Bad transfer did NOT fail atomically!")
        logging.getLogger("springpythontest.databaseTransactionTestCases").debug(bank.balance("Checking"))
        self.assertEquals(bank.balance("Checking"), 140.00, "Bad transfer did NOT fail atomically!")
        
    def testOtherPropagationLevels(self):
        appContext = ApplicationContext(DatabaseTxTestDecorativeTransactionsWithLotsOfArguments(self.factory))
        bank = appContext.get_object("bank")

        # Call a mandatory operation outside a transaction, and verify it fails.
        try:
            bank.mandatoryOperation()
            self.fail("Expected a TransactionPropagationException!")
        except TransactionPropagationException:
            pass

        # Call a mandatory operation from within a transactional routine, and verify it works.
        bank.mandatoryOperationTransactionalWrapper()

        # Call a non-transactional operation from outside a transaction, and verify it works.
        bank.nonTransactionalOperation()

        # Call a non-tranactional operation from within a transaction, and verify it fails.
        try:
            bank.nonTransactionalOperationTransactionalWrapper()
            self.fail("Expected a TransactionPropagationException!")
        except TransactionPropagationException:
            pass

    def testTransactionProxyMethodFilters(self):
        appContext = ApplicationContext(DatabaseTxTestAppContext(self.factory))
        bank = appContext.get_object("bank")
 
        bank.open("Checking")
        bank.open("Savings")

        bank.deposit(125.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 125.00)

        bank.deposit(250.00, "Savings")
        self.assertEquals(bank.balance("Savings"), 250.00)

        bank.transfer(25.00, "Savings", "Checking")
        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 150.00)

        bank.withdraw(10.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 140.00)

        amount = 0.0
        try:
            amount = bank.withdraw(1000, "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(amount, 0.0)

        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 140.00)

        try:
            bank.transfer(200, "Checking", "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass

        self.assertEquals(bank.balance("Savings"), 225.00, "Bad transfer did NOT fail atomically!")
        self.assertEquals(bank.balance("Checking"), 140.00, "Bad transfer did NOT fail atomically!")
 
    def testTransactionalBankWithNoAutoTransactionalObject(self):
        appContext = ApplicationContext(DatabaseTxTestAppContextWithNoAutoTransactionalObject(self.factory))
        bank = appContext.get_object("bank")
 
        bank.open("Checking")
        bank.open("Savings")

        bank.deposit(125.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 125.00)

        bank.deposit(250.00, "Savings")
        self.assertEquals(bank.balance("Savings"), 250.00)

        bank.transfer(25.00, "Savings", "Checking")
        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 150.00)

        bank.withdraw(10.00, "Checking")
        self.assertEquals(bank.balance("Checking"), 140.00)

        amount = 0.0
        try:
            amount = bank.withdraw(1000, "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass
        self.assertEquals(amount, 0.0)

        self.assertEquals(bank.balance("Savings"), 225.00)
        self.assertEquals(bank.balance("Checking"), 140.00)

        try:
            bank.transfer(200, "Checking", "Nowhere")
            self.fail("Expected a BankException!")
        except BankException:
            pass

        self.assertEquals(bank.balance("Savings"), 225.00, "Bad transfer did NOT fail atomically!")
        self.assertEquals(bank.balance("Checking"), -60.00, "Bad transfer did NOT fail as expected (not atomically due to lack of AutoTransactionalObject)")