1 #-*- coding: ISO-8859-1 -*- 2 # pysqlite2/test/hooks.py: tests for various SQLite-specific hooks 3 # 4 # Copyright (C) 2006-2007 Gerhard Hring <gh (at] ghaering.de> 5 # 6 # This file is part of pysqlite. 7 # 8 # This software is provided 'as-is', without any express or implied 9 # warranty. In no event will the authors be held liable for any damages 10 # arising from the use of this software. 11 # 12 # Permission is granted to anyone to use this software for any purpose, 13 # including commercial applications, and to alter it and redistribute it 14 # freely, subject to the following restrictions: 15 # 16 # 1. The origin of this software must not be misrepresented; you must not 17 # claim that you wrote the original software. If you use this software 18 # in a product, an acknowledgment in the product documentation would be 19 # appreciated but is not required. 20 # 2. Altered source versions must be plainly marked as such, and must not be 21 # misrepresented as being the original software. 22 # 3. This notice may not be removed or altered from any source distribution. 23 24 import os, unittest 25 import sqlite3 as sqlite 26 27 class CollationTests(unittest.TestCase): 28 def setUp(self): 29 pass 30 31 def tearDown(self): 32 pass 33 34 def CheckCreateCollationNotCallable(self): 35 con = sqlite.connect(":memory:") 36 try: 37 con.create_collation("X", 42) 38 self.fail("should have raised a TypeError") 39 except TypeError, e: 40 self.assertEqual(e.args[0], "parameter must be callable") 41 42 def CheckCreateCollationNotAscii(self): 43 con = sqlite.connect(":memory:") 44 try: 45 con.create_collation("coll", cmp) 46 self.fail("should have raised a ProgrammingError") 47 except sqlite.ProgrammingError, e: 48 pass 49 50 def CheckCollationIsUsed(self): 51 if sqlite.version_info < (3, 2, 1): # old SQLite versions crash on this test 52 return 53 def mycoll(x, y): 54 # reverse order 55 return -cmp(x, y) 56 57 con = sqlite.connect(":memory:") 58 con.create_collation("mycoll", mycoll) 59 sql = """ 60 select x from ( 61 select 'a' as x 62 union 63 select 'b' as x 64 union 65 select 'c' as x 66 ) order by x collate mycoll 67 """ 68 result = con.execute(sql).fetchall() 69 if result[0][0] != "c" or result[1][0] != "b" or result[2][0] != "a": 70 self.fail("the expected order was not returned") 71 72 con.create_collation("mycoll", None) 73 try: 74 result = con.execute(sql).fetchall() 75 self.fail("should have raised an OperationalError") 76 except sqlite.OperationalError, e: 77 self.assertEqual(e.args[0].lower(), "no such collation sequence: mycoll") 78 79 def CheckCollationReturnsLargeInteger(self): 80 def mycoll(x, y): 81 # reverse order 82 return -((x > y) - (x < y)) * 2**32 83 con = sqlite.connect(":memory:") 84 con.create_collation("mycoll", mycoll) 85 sql = """ 86 select x from ( 87 select 'a' as x 88 union 89 select 'b' as x 90 union 91 select 'c' as x 92 ) order by x collate mycoll 93 """ 94 result = con.execute(sql).fetchall() 95 self.assertEqual(result, [('c',), ('b',), ('a',)], 96 msg="the expected order was not returned") 97 98 def CheckCollationRegisterTwice(self): 99 """ 100 Register two different collation functions under the same name. 101 Verify that the last one is actually used. 102 """ 103 con = sqlite.connect(":memory:") 104 con.create_collation("mycoll", cmp) 105 con.create_collation("mycoll", lambda x, y: -cmp(x, y)) 106 result = con.execute(""" 107 select x from (select 'a' as x union select 'b' as x) order by x collate mycoll 108 """).fetchall() 109 if result[0][0] != 'b' or result[1][0] != 'a': 110 self.fail("wrong collation function is used") 111 112 def CheckDeregisterCollation(self): 113 """ 114 Register a collation, then deregister it. Make sure an error is raised if we try 115 to use it. 116 """ 117 con = sqlite.connect(":memory:") 118 con.create_collation("mycoll", cmp) 119 con.create_collation("mycoll", None) 120 try: 121 con.execute("select 'a' as x union select 'b' as x order by x collate mycoll") 122 self.fail("should have raised an OperationalError") 123 except sqlite.OperationalError, e: 124 if not e.args[0].startswith("no such collation sequence"): 125 self.fail("wrong OperationalError raised") 126 127 class ProgressTests(unittest.TestCase): 128 def CheckProgressHandlerUsed(self): 129 """ 130 Test that the progress handler is invoked once it is set. 131 """ 132 con = sqlite.connect(":memory:") 133 progress_calls = [] 134 def progress(): 135 progress_calls.append(None) 136 return 0 137 con.set_progress_handler(progress, 1) 138 con.execute(""" 139 create table foo(a, b) 140 """) 141 self.assertTrue(progress_calls) 142 143 144 def CheckOpcodeCount(self): 145 """ 146 Test that the opcode argument is respected. 147 """ 148 con = sqlite.connect(":memory:") 149 progress_calls = [] 150 def progress(): 151 progress_calls.append(None) 152 return 0 153 con.set_progress_handler(progress, 1) 154 curs = con.cursor() 155 curs.execute(""" 156 create table foo (a, b) 157 """) 158 first_count = len(progress_calls) 159 progress_calls = [] 160 con.set_progress_handler(progress, 2) 161 curs.execute(""" 162 create table bar (a, b) 163 """) 164 second_count = len(progress_calls) 165 self.assertTrue(first_count > second_count) 166 167 def CheckCancelOperation(self): 168 """ 169 Test that returning a non-zero value stops the operation in progress. 170 """ 171 con = sqlite.connect(":memory:") 172 progress_calls = [] 173 def progress(): 174 progress_calls.append(None) 175 return 1 176 con.set_progress_handler(progress, 1) 177 curs = con.cursor() 178 self.assertRaises( 179 sqlite.OperationalError, 180 curs.execute, 181 "create table bar (a, b)") 182 183 def CheckClearHandler(self): 184 """ 185 Test that setting the progress handler to None clears the previously set handler. 186 """ 187 con = sqlite.connect(":memory:") 188 action = [] 189 def progress(): 190 action.append(1) 191 return 0 192 con.set_progress_handler(progress, 1) 193 con.set_progress_handler(None, 1) 194 con.execute("select 1 union select 2 union select 3").fetchall() 195 self.assertEqual(len(action), 0, "progress handler was not cleared") 196 197 def suite(): 198 collation_suite = unittest.makeSuite(CollationTests, "Check") 199 progress_suite = unittest.makeSuite(ProgressTests, "Check") 200 return unittest.TestSuite((collation_suite, progress_suite)) 201 202 def test(): 203 runner = unittest.TextTestRunner() 204 runner.run(suite()) 205 206 if __name__ == "__main__": 207 test() 208