| 
									
										
										
										
											2005-06-03 07:03:07 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | TestCases for python DB Btree key comparison function. | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  | import sys, os, re | 
					
						
							| 
									
										
										
										
											2005-06-03 07:03:07 +00:00
										 |  |  | import test_all | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  | from cStringIO import StringIO | 
					
						
							| 
									
										
										
										
											2005-06-03 07:03:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | import unittest | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  | from test_all import db, dbshelve, test_support, \ | 
					
						
							|  |  |  |         get_new_environment_path, get_new_database_path | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-02 20:00:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-22 14:22:26 +00:00
										 |  |  | # Needed for python 3. "cmp" vanished in 3.0.1 | 
					
						
							|  |  |  | def cmp(a, b) : | 
					
						
							|  |  |  |     if a==b : return 0 | 
					
						
							|  |  |  |     if a<b : return -1 | 
					
						
							|  |  |  |     return 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  | lexical_cmp = cmp | 
					
						
							| 
									
										
										
										
											2005-06-03 07:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  | def lowercase_cmp(left, right): | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |     return cmp (left.lower(), right.lower()) | 
					
						
							| 
									
										
										
										
											2005-06-03 07:03:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def make_reverse_comparator (cmp): | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  |     def reverse (left, right, delegate=cmp): | 
					
						
							|  |  |  |         return - delegate (left, right) | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |     return reverse | 
					
						
							| 
									
										
										
										
											2005-06-03 07:03:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | _expected_lexical_test_data = ['', 'CCCP', 'a', 'aaa', 'b', 'c', 'cccce', 'ccccf'] | 
					
						
							|  |  |  | _expected_lowercase_test_data = ['', 'a', 'aaa', 'b', 'c', 'CC', 'cccce', 'ccccf', 'CCCP'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ComparatorTests (unittest.TestCase): | 
					
						
							| 
									
										
										
										
											2010-03-22 14:22:26 +00:00
										 |  |  |     if sys.version_info < (2, 4) : | 
					
						
							|  |  |  |         def assertTrue(self, expr, msg=None) : | 
					
						
							|  |  |  |             return self.failUnless(expr,msg=msg) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |     def comparator_test_helper (self, comparator, expected_data): | 
					
						
							|  |  |  |         data = expected_data[:] | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         import sys | 
					
						
							| 
									
										
										
										
											2010-03-22 14:22:26 +00:00
										 |  |  |         if sys.version_info < (2, 6) : | 
					
						
							|  |  |  |             if sys.version_info < (2, 4) : | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |                 data.sort(comparator) | 
					
						
							|  |  |  |             else : | 
					
						
							|  |  |  |                 data.sort(cmp=comparator) | 
					
						
							|  |  |  |         else :  # Insertion Sort. Please, improve | 
					
						
							|  |  |  |             data2 = [] | 
					
						
							|  |  |  |             for i in data : | 
					
						
							|  |  |  |                 for j, k in enumerate(data2) : | 
					
						
							|  |  |  |                     r = comparator(k, i) | 
					
						
							|  |  |  |                     if r == 1 : | 
					
						
							|  |  |  |                         data2.insert(j, i) | 
					
						
							|  |  |  |                         break | 
					
						
							|  |  |  |                 else : | 
					
						
							|  |  |  |                     data2.append(i) | 
					
						
							|  |  |  |             data = data2 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-22 14:22:26 +00:00
										 |  |  |         self.assertEqual(data, expected_data, | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |                          "comparator `%s' is not right: %s vs. %s" | 
					
						
							|  |  |  |                          % (comparator, expected_data, data)) | 
					
						
							|  |  |  |     def test_lexical_comparator (self): | 
					
						
							|  |  |  |         self.comparator_test_helper (lexical_cmp, _expected_lexical_test_data) | 
					
						
							|  |  |  |     def test_reverse_lexical_comparator (self): | 
					
						
							|  |  |  |         rev = _expected_lexical_test_data[:] | 
					
						
							|  |  |  |         rev.reverse () | 
					
						
							|  |  |  |         self.comparator_test_helper (make_reverse_comparator (lexical_cmp), | 
					
						
							|  |  |  |                                      rev) | 
					
						
							|  |  |  |     def test_lowercase_comparator (self): | 
					
						
							|  |  |  |         self.comparator_test_helper (lowercase_cmp, | 
					
						
							|  |  |  |                                      _expected_lowercase_test_data) | 
					
						
							| 
									
										
										
										
											2005-06-03 07:03:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class AbstractBtreeKeyCompareTestCase (unittest.TestCase): | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |     env = None | 
					
						
							|  |  |  |     db = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-22 14:22:26 +00:00
										 |  |  |     if sys.version_info < (2, 4) : | 
					
						
							|  |  |  |         def assertTrue(self, expr, msg=None): | 
					
						
							|  |  |  |             self.failUnless(expr,msg=msg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (sys.version_info < (2, 7)) or ((sys.version_info >= (3,0)) and | 
					
						
							|  |  |  |             (sys.version_info < (3, 2))) : | 
					
						
							|  |  |  |         def assertLess(self, a, b, msg=None) : | 
					
						
							|  |  |  |             return self.assertTrue(a<b, msg=msg) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |     def setUp (self): | 
					
						
							|  |  |  |         self.filename = self.__class__.__name__ + '.db' | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         self.homeDir = get_new_environment_path() | 
					
						
							|  |  |  |         env = db.DBEnv() | 
					
						
							|  |  |  |         env.open (self.homeDir, | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |                   db.DB_CREATE | db.DB_INIT_MPOOL | 
					
						
							|  |  |  |                   | db.DB_INIT_LOCK | db.DB_THREAD) | 
					
						
							|  |  |  |         self.env = env | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def tearDown (self): | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         self.closeDB() | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |         if self.env is not None: | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |             self.env.close() | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |             self.env = None | 
					
						
							| 
									
										
										
										
											2008-02-24 18:47:03 +00:00
										 |  |  |         test_support.rmtree(self.homeDir) | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def addDataToDB (self, data): | 
					
						
							|  |  |  |         i = 0 | 
					
						
							|  |  |  |         for item in data: | 
					
						
							|  |  |  |             self.db.put (item, str (i)) | 
					
						
							|  |  |  |             i = i + 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def createDB (self, key_comparator): | 
					
						
							|  |  |  |         self.db = db.DB (self.env) | 
					
						
							|  |  |  |         self.setupDB (key_comparator) | 
					
						
							|  |  |  |         self.db.open (self.filename, "test", db.DB_BTREE, db.DB_CREATE) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setupDB (self, key_comparator): | 
					
						
							|  |  |  |         self.db.set_bt_compare (key_comparator) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def closeDB (self): | 
					
						
							|  |  |  |         if self.db is not None: | 
					
						
							|  |  |  |             self.db.close () | 
					
						
							|  |  |  |             self.db = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def startTest (self): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def finishTest (self, expected = None): | 
					
						
							|  |  |  |         if expected is not None: | 
					
						
							|  |  |  |             self.check_results (expected) | 
					
						
							|  |  |  |         self.closeDB () | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def check_results (self, expected): | 
					
						
							|  |  |  |         curs = self.db.cursor () | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             index = 0 | 
					
						
							|  |  |  |             rec = curs.first () | 
					
						
							|  |  |  |             while rec: | 
					
						
							|  |  |  |                 key, ignore = rec | 
					
						
							| 
									
										
										
										
											2010-03-22 14:22:26 +00:00
										 |  |  |                 self.assertLess(index, len (expected), | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |                                  "to many values returned from cursor") | 
					
						
							| 
									
										
										
										
											2010-03-22 14:22:26 +00:00
										 |  |  |                 self.assertEqual(expected[index], key, | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |                                  "expected value `%s' at %d but got `%s'" | 
					
						
							|  |  |  |                                  % (expected[index], index, key)) | 
					
						
							|  |  |  |                 index = index + 1 | 
					
						
							|  |  |  |                 rec = curs.next () | 
					
						
							| 
									
										
										
										
											2010-03-22 14:22:26 +00:00
										 |  |  |             self.assertEqual(index, len (expected), | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |                              "not enough values returned from cursor") | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             curs.close () | 
					
						
							| 
									
										
										
										
											2005-06-03 07:03:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class BtreeKeyCompareTestCase (AbstractBtreeKeyCompareTestCase): | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |     def runCompareTest (self, comparator, data): | 
					
						
							|  |  |  |         self.startTest () | 
					
						
							|  |  |  |         self.createDB (comparator) | 
					
						
							|  |  |  |         self.addDataToDB (data) | 
					
						
							|  |  |  |         self.finishTest (data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_lexical_ordering (self): | 
					
						
							|  |  |  |         self.runCompareTest (lexical_cmp, _expected_lexical_test_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_reverse_lexical_ordering (self): | 
					
						
							|  |  |  |         expected_rev_data = _expected_lexical_test_data[:] | 
					
						
							|  |  |  |         expected_rev_data.reverse () | 
					
						
							|  |  |  |         self.runCompareTest (make_reverse_comparator (lexical_cmp), | 
					
						
							|  |  |  |                              expected_rev_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_compare_function_useless (self): | 
					
						
							|  |  |  |         self.startTest () | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  |         def socialist_comparator (l, r): | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |             return 0 | 
					
						
							|  |  |  |         self.createDB (socialist_comparator) | 
					
						
							|  |  |  |         self.addDataToDB (['b', 'a', 'd']) | 
					
						
							|  |  |  |         # all things being equal the first key will be the only key | 
					
						
							|  |  |  |         # in the database...  (with the last key's value fwiw) | 
					
						
							|  |  |  |         self.finishTest (['b']) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-03 07:03:07 +00:00
										 |  |  | class BtreeExceptionsTestCase (AbstractBtreeKeyCompareTestCase): | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |     def test_raises_non_callable (self): | 
					
						
							|  |  |  |         self.startTest () | 
					
						
							|  |  |  |         self.assertRaises (TypeError, self.createDB, 'abc') | 
					
						
							|  |  |  |         self.assertRaises (TypeError, self.createDB, None) | 
					
						
							|  |  |  |         self.finishTest () | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_set_bt_compare_with_function (self): | 
					
						
							|  |  |  |         self.startTest () | 
					
						
							|  |  |  |         self.createDB (lexical_cmp) | 
					
						
							|  |  |  |         self.finishTest () | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def check_results (self, results): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_compare_function_incorrect (self): | 
					
						
							|  |  |  |         self.startTest () | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  |         def bad_comparator (l, r): | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |             return 1 | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  |         # verify that set_bt_compare checks that comparator('', '') == 0 | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |         self.assertRaises (TypeError, self.createDB, bad_comparator) | 
					
						
							|  |  |  |         self.finishTest () | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  |     def verifyStderr(self, method, successRe): | 
					
						
							| 
									
										
										
										
											2005-06-08 04:35:50 +00:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Call method() while capturing sys.stderr output internally and | 
					
						
							|  |  |  |         call self.fail() if successRe.search() does not match the stderr | 
					
						
							|  |  |  |         output.  This is used to test for uncatchable exceptions. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         stdErr = sys.stderr | 
					
						
							|  |  |  |         sys.stderr = StringIO() | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             method() | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             temp = sys.stderr | 
					
						
							|  |  |  |             sys.stderr = stdErr | 
					
						
							|  |  |  |             errorOut = temp.getvalue() | 
					
						
							|  |  |  |             if not successRe.search(errorOut): | 
					
						
							|  |  |  |                 self.fail("unexpected stderr output:\n"+errorOut) | 
					
						
							| 
									
										
										
										
											2010-03-22 14:22:26 +00:00
										 |  |  |         if sys.version_info < (3, 0) :  # XXX: How to do this in Py3k ??? | 
					
						
							|  |  |  |             sys.exc_traceback = sys.last_traceback = None | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _test_compare_function_exception (self): | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |         self.startTest () | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  |         def bad_comparator (l, r): | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |             if l == r: | 
					
						
							|  |  |  |                 # pass the set_bt_compare test | 
					
						
							|  |  |  |                 return 0 | 
					
						
							|  |  |  |             raise RuntimeError, "i'm a naughty comparison function" | 
					
						
							|  |  |  |         self.createDB (bad_comparator) | 
					
						
							| 
									
										
										
										
											2005-06-08 04:35:50 +00:00
										 |  |  |         #print "\n*** test should print 2 uncatchable tracebacks ***" | 
					
						
							|  |  |  |         self.addDataToDB (['a', 'b', 'c'])  # this should raise, but... | 
					
						
							|  |  |  |         self.finishTest () | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  |     def test_compare_function_exception(self): | 
					
						
							| 
									
										
										
										
											2005-06-08 04:35:50 +00:00
										 |  |  |         self.verifyStderr( | 
					
						
							|  |  |  |                 self._test_compare_function_exception, | 
					
						
							|  |  |  |                 re.compile('(^RuntimeError:.* naughty.*){2}', re.M|re.S) | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _test_compare_function_bad_return (self): | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |         self.startTest () | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  |         def bad_comparator (l, r): | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |             if l == r: | 
					
						
							|  |  |  |                 # pass the set_bt_compare test | 
					
						
							|  |  |  |                 return 0 | 
					
						
							|  |  |  |             return l | 
					
						
							|  |  |  |         self.createDB (bad_comparator) | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  |         #print "\n*** test should print 2 errors about returning an int ***" | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |         self.addDataToDB (['a', 'b', 'c'])  # this should raise, but... | 
					
						
							|  |  |  |         self.finishTest () | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  |     def test_compare_function_bad_return(self): | 
					
						
							| 
									
										
										
										
											2005-06-08 04:35:50 +00:00
										 |  |  |         self.verifyStderr( | 
					
						
							|  |  |  |                 self._test_compare_function_bad_return, | 
					
						
							|  |  |  |                 re.compile('(^TypeError:.* return an int.*){2}', re.M|re.S) | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_cannot_assign_twice (self): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-06 17:30:22 +00:00
										 |  |  |         def my_compare (a, b): | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |             return 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-22 14:22:26 +00:00
										 |  |  |         self.startTest() | 
					
						
							|  |  |  |         self.createDB(my_compare) | 
					
						
							| 
									
										
										
										
											2010-02-02 15:57:45 +00:00
										 |  |  |         self.assertRaises (RuntimeError, self.db.set_bt_compare, my_compare) | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-03 07:03:07 +00:00
										 |  |  | def test_suite (): | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |     res = unittest.TestSuite () | 
					
						
							| 
									
										
										
										
											2005-06-03 07:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |     res.addTest (unittest.makeSuite (ComparatorTests)) | 
					
						
							| 
									
										
										
										
											2008-07-23 11:38:42 +00:00
										 |  |  |     res.addTest (unittest.makeSuite (BtreeExceptionsTestCase)) | 
					
						
							|  |  |  |     res.addTest (unittest.makeSuite (BtreeKeyCompareTestCase)) | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |     return res | 
					
						
							| 
									
										
										
										
											2005-06-03 07:03:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							| 
									
										
										
										
											2005-06-03 22:40:27 +00:00
										 |  |  |     unittest.main (defaultTest = 'suite') |