testBTrees.py 23 KB
Newer Older
Chris McDonough's avatar
Chris McDonough committed
1
##############################################################################
matt@zope.com's avatar
matt@zope.com committed
2
#
Guido van Rossum's avatar
Guido van Rossum committed
3 4
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
matt@zope.com's avatar
matt@zope.com committed
5 6 7 8 9 10 11
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
Chris McDonough's avatar
Chris McDonough committed
12 13
# 
##############################################################################
14
import sys, os, time, random
15
import os, sys
16

Chris McDonough's avatar
Chris McDonough committed
17 18 19 20
from BTrees.OOBTree import OOBTree, OOBucket, OOSet, OOTreeSet
from BTrees.IOBTree import IOBTree, IOBucket, IOSet, IOTreeSet
from BTrees.IIBTree import IIBTree, IIBucket, IISet, IITreeSet
from BTrees.OIBTree import OIBTree, OIBucket, OISet, OITreeSet
21
from unittest import TestCase, TestSuite, TextTestRunner, makeSuite
22

23 24
from glob import glob

25
class Base:
26
    """ Tests common to all types: sets, buckets, and BTrees """
Chris McDonough's avatar
Chris McDonough committed
27 28 29
    def tearDown(self):
        self.t = None
        del self.t
30 31 32 33 34 35 36 37 38 39 40

    def _getRoot(self):
        from ZODB.FileStorage import FileStorage
        from ZODB.DB import DB
        n = 'fs_tmp__%s' % os.getpid()
        s = FileStorage(n)
        db = DB(s)
        root = db.open().root()
        return root

    def _closeDB(self, root):
41 42
        if root is not None:
            root._p_jar._db.close()
43 44

    def _delDB(self):
45 46 47
        for file in glob('fs_tmp__*'):
            os.remove(file)
        
48
    def testLoadAndStore(self):
49 50 51
        for i in 0, 10, 1000:
            t = self.t.__class__()
            self._populate(t, i)
52
            root = None
53 54 55 56 57 58 59 60 61
            try:
                root = self._getRoot()
                root[i] = t
                get_transaction().commit()
            except:
                self._closeDB(root)
                self._delDB()
                raise

62
            self._closeDB(root)
63

64
            root = None
65 66 67 68
            try:
                root = self._getRoot()
                #XXX BTree stuff doesn't implement comparison
                if hasattr(t, 'items'):
69
                    self.assertEqual(list(root[i].items()) , list(t.items()))
70
                else:
71
                    self.assertEqual(list(root[i].keys()) , list(t.keys()))
72 73 74
            finally:
                self._closeDB(root)
                self._delDB()
75 76
            
    def testGhostUnghost(self):
77 78 79
        for i in 0, 10, 1000:
            t = self.t.__class__()
            self._populate(t, i)
80
            root = None
81 82 83 84 85 86 87 88 89
            try:
                root = self._getRoot()
                root[i] = t
                get_transaction().commit()
            except:
                self._closeDB(root)
                self._delDB()
                raise

90
            self._closeDB(root)
91

92
            root = None
93 94 95 96 97
            try:
                root = self._getRoot()
                root[i]._p_changed = None
                get_transaction().commit()
                if hasattr(t,'items'):
98
                    self.assertEqual(list(root[i].items()) , list(t.items()))
99
                else:
100
                    self.assertEqual(list(root[i].keys()) , list(t.keys()))
101 102 103
            finally:
                self._closeDB(root)
                self._delDB()
104 105 106

class MappingBase(Base):
    """ Tests common to mappings (buckets, btrees) """
107 108 109 110 111

    def _populate(self, t, l):
        # Make some data
        for i in range(l): t[i]=i
    
Chris McDonough's avatar
Chris McDonough committed
112 113 114 115 116 117 118
    def testGetItemFails(self):
        self.assertRaises(KeyError, self._getitemfail)

    def _getitemfail(self):
        return self.t[1]

    def testGetReturnsDefault(self):
119 120
        self.assertEqual(self.t.get(1) , None)
        self.assertEqual(self.t.get(1, 'foo') , 'foo')
121
        
Chris McDonough's avatar
Chris McDonough committed
122 123 124
    def testSetItemGetItemWorks(self):
        self.t[1] = 1
        a = self.t[1]
125
        self.assertEqual(a , 1, `a`)
Chris McDonough's avatar
Chris McDonough committed
126 127 128

    def testReplaceWorks(self):
        self.t[1] = 1
129
        self.assertEqual(self.t[1] , 1, self.t[1])
Chris McDonough's avatar
Chris McDonough committed
130
        self.t[1] = 2
131
        self.assertEqual(self.t[1] , 2, self.t[1])
Chris McDonough's avatar
Chris McDonough committed
132

133 134 135 136
    def testLen(self):
        added = {}
        r = range(1000)
        for x in r:
137
            k = random.choice(r)
138 139 140
            self.t[k] = x
            added[k] = x
        addl = added.keys()
141
        self.assertEqual(len(self.t) , len(addl), len(self.t))
142

Chris McDonough's avatar
Chris McDonough committed
143 144
    def testHasKeyWorks(self):
        self.t[1] = 1
145
        self.assert_(self.t.has_key(1))
Chris McDonough's avatar
Chris McDonough committed
146 147 148

    def testValuesWorks(self):
        for x in range(100):
149
            self.t[x] = x*x
Chris McDonough's avatar
Chris McDonough committed
150
        v = self.t.values()
151
        for i in range(100):
152
            self.assertEqual(v[i],i*i , (i*i,i))
153

154 155 156 157 158 159 160 161 162
    def testValuesWorks1(self):

        for x in range(100):
            self.t[99-x] = x 

        for x in range(40):
            lst = list(self.t.values(0+x,99-x))
            lst.sort()
            self.assertEqual(lst,range(0+x,99-x+1))
163

Chris McDonough's avatar
Chris McDonough committed
164 165 166 167 168 169 170
            
    def testKeysWorks(self):
        for x in range(100):
            self.t[x] = x
        v = self.t.keys()
        i = 0
        for x in v:
171
            self.assertEqual(x,i)
Chris McDonough's avatar
Chris McDonough committed
172
            i = i + 1
173 174 175 176 177

        for x in range(40):
            lst = self.t.keys(0+x,99-x)
            self.assertEqual(list(lst),range(0+x,99-x+1))

178
        # BTree items must lie about their lengths, so we convert to list
179 180
        self.assertEqual(len(v) , 100, len(v))
        #self.assertEqual(len(v) , 100, len(v))
Chris McDonough's avatar
Chris McDonough committed
181 182 183 184 185 186 187

    def testItemsWorks(self):
        for x in range(100):
            self.t[x] = x
        v = self.t.items()
        i = 0
        for x in v:
188 189
            self.assertEqual(x[0] , i, (x[0], i))
            self.assertEqual(x[1] , i, (x[0], i))
Chris McDonough's avatar
Chris McDonough committed
190 191 192 193 194 195 196 197
            i = i + 1

    def testDeleteInvalidKeyRaisesKeyError(self):
        self.assertRaises(KeyError, self._deletefail)

    def _deletefail(self):
        del self.t[1]

198 199 200 201 202 203 204 205 206 207 208
    def testMaxKeyMinKey(self):
        self.t[7] = 6
        self.t[3] = 10
        self.t[8] = 12
        self.t[1] = 100
        self.t[5] = 200
        self.t[10] = 500
        self.t[6] = 99
        self.t[4] = 150
        del self.t[7]
        t = self.t
209 210 211 212 213 214
        self.assertEqual(t.maxKey() , 10)
        self.assertEqual(t.maxKey(6) , 6)
        self.assertEqual(t.maxKey(9) , 8)
        self.assertEqual(t.minKey() , 1)
        self.assertEqual(t.minKey(3) , 3)
        self.assertEqual(t.minKey(9) , 10)
215 216 217 218

    def testClear(self):
        r = range(100)
        for x in r:
219
            rnd = random.choice(r)
220 221 222
            self.t[rnd] = 0
        self.t.clear()
        diff = lsubtract(list(self.t.keys()), [])
223
        self.assertEqual(diff , [], diff)
224

225 226 227 228 229
    def testUpdate(self):
        "mapping update"
        d={}
        l=[]
        for i in range(10000):
230
            k=random.randrange(-2000, 2001)
231 232 233 234 235 236 237
            d[k]=i
            l.append((k, i))
            
        items=d.items()
        items.sort()

        self.t.update(d)
238
        self.assertEqual(list(self.t.items()) , items)
239 240

        self.t.clear()
241
        self.assertEqual(list(self.t.items()) , [])
242 243

        self.t.update(l)
244
        self.assertEqual(list(self.t.items()) , items)
245 246 247 248

    def testEmptyRangeSearches(self):
        t=self.t
        t.update([(1,1),(5,5),(9,9)])
249 250 251 252
        self.assertEqual(list(t.keys(-6,-4)),[], list(t.keys(-6,-4)))
        self.assertEqual(list(t.keys(2,4)),[], list(t.keys(2,4)))
        self.assertEqual(list(t.keys(6,8)),[], list(t.keys(6,8)))
        self.assertEqual(list(t.keys(10,12)),[], list(t.keys(10,12)))
253 254
        

Chris McDonough's avatar
Chris McDonough committed
255
class NormalSetTests(Base):
256
    """ Test common to all set types """
257 258 259 260 261 262 263


    def _populate(self, t, l): 
        # Make some data
        t.update(range(l))


264 265
    def testInsertReturnsValue(self):
        t = self.t
266
        self.assertEqual(t.insert(5) , 1)
267 268 269 270

    def testDuplicateInsert(self):
        t = self.t
        t.insert(5)
271
        self.assertEqual(t.insert(5) , 0)
272 273 274 275
        
    def testInsert(self):
        t = self.t
        t.insert(1)
276
        self.assert_(t.has_key(1))
277 278 279 280 281 282 283

    def testBigInsert(self):
        t = self.t
        r = xrange(10000)
        for x in r:
            t.insert(x)
        for x in r:
284
            self.assert_(t.has_key(x))
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299

    def testRemoveSucceeds(self):
        t = self.t
        r = xrange(10000)
        for x in r: t.insert(x)
        for x in r: t.remove(x)

    def testRemoveFails(self):
        self.assertRaises(KeyError, self._removenonexistent)

    def _removenonexistent(self):
        self.t.remove(1)

    def testHasKeyFails(self):
        t = self.t
300
        self.assert_(not t.has_key(1))
301 302 303 304 305 306

    def testKeys(self):
        t = self.t
        r = xrange(1000)
        for x in r: t.insert(x)
        diff = lsubtract(t.keys(), r)
307
        self.assertEqual(diff , [], diff)
308 309 310 311 312 313 314

    def testClear(self):
        t = self.t
        r = xrange(1000)
        for x in r: t.insert(x)
        t.clear()
        diff = lsubtract(t.keys(), [])
315
        self.assertEqual(diff , [], diff)
316 317 318 319 320 321 322 323 324 325 326

    def testMaxKeyMinKey(self):
        t = self.t
        t.insert(1)
        t.insert(2)
        t.insert(3)
        t.insert(8)
        t.insert(5)
        t.insert(10)
        t.insert(6)
        t.insert(4)
327 328 329 330 331 332
        self.assertEqual(t.maxKey() , 10)
        self.assertEqual(t.maxKey(6) , 6)
        self.assertEqual(t.maxKey(9) , 8)
        self.assertEqual(t.minKey() , 1)
        self.assertEqual(t.minKey(3) , 3)
        self.assertEqual(t.minKey(9) , 10)
333

334 335 336 337 338
    def testUpdate(self):
        "mapping update"
        d={}
        l=[]
        for i in range(10000):
339
            k=random.randrange(-2000, 2001)
340 341 342 343 344 345 346
            d[k]=i
            l.append(k)
            
        items=d.keys()
        items.sort()

        self.t.update(l)
347
        self.assertEqual(list(self.t.keys()) , items)
348 349 350 351

    def testEmptyRangeSearches(self):
        t=self.t
        t.update([1,5,9])
352 353 354 355
        self.assertEqual(list(t.keys(-6,-4)),[], list(t.keys(-6,-4)))
        self.assertEqual(list(t.keys(2,4)),[], list(t.keys(2,4)))
        self.assertEqual(list(t.keys(6,8)),[], list(t.keys(6,8)))
        self.assertEqual(list(t.keys(10,12)),[], list(t.keys(10,12)))
356

Chris McDonough's avatar
Chris McDonough committed
357
class ExtendedSetTests(NormalSetTests):
358 359 360 361
    def testLen(self):
        t = self.t
        r = xrange(10000)
        for x in r: t.insert(x)
362
        self.assertEqual(len(t) , 10000, len(t))
Chris McDonough's avatar
Chris McDonough committed
363 364 365 366 367 368

    def testGetItem(self):
        t = self.t
        r = xrange(10000)
        for x in r: t.insert(x)
        for x in r:
369
            self.assertEqual(t[x] , x)
370 371 372 373 374 375 376 377
        
class BucketTests(MappingBase):
    """ Tests common to all buckets """
    pass

class BTreeTests(MappingBase):
    """ Tests common to all BTrees """
    def testDeleteNoChildrenWorks(self):
Chris McDonough's avatar
Chris McDonough committed
378 379 380 381 382 383 384 385 386
        self.t[5] = 6
        self.t[2] = 10
        self.t[6] = 12
        self.t[1] = 100
        self.t[3] = 200
        self.t[10] = 500
        self.t[4] = 99
        del self.t[4]
        diff = lsubtract(self.t.keys(), [1,2,3,5,6,10])
387
        self.assertEqual(diff , [], diff)
Chris McDonough's avatar
Chris McDonough committed
388

389
    def testDeleteOneChildWorks(self):
Chris McDonough's avatar
Chris McDonough committed
390 391 392 393 394 395 396 397 398
        self.t[5] = 6
        self.t[2] = 10
        self.t[6] = 12
        self.t[1] = 100
        self.t[3] = 200
        self.t[10] = 500
        self.t[4] = 99
        del self.t[3]
        diff = lsubtract(self.t.keys(), [1,2,4,5,6,10])
399
        self.assertEqual(diff , [], diff)
Chris McDonough's avatar
Chris McDonough committed
400

401
    def testDeleteTwoChildrenNoInorderSuccessorWorks(self):
Chris McDonough's avatar
Chris McDonough committed
402 403 404 405 406 407 408 409 410
        self.t[5] = 6
        self.t[2] = 10
        self.t[6] = 12
        self.t[1] = 100
        self.t[3] = 200
        self.t[10] = 500
        self.t[4] = 99
        del self.t[2]
        diff = lsubtract(self.t.keys(), [1,3,4,5,6,10])
411
        self.assertEqual(diff , [], diff)
Chris McDonough's avatar
Chris McDonough committed
412
        
413
    def testDeleteTwoChildrenInorderSuccessorWorks(self):
414 415 416 417
        """ 7, 3, 8, 1, 5, 10, 6, 4 -- del 3 """
        self.t[7] = 6
        self.t[3] = 10
        self.t[8] = 12
Chris McDonough's avatar
Chris McDonough committed
418
        self.t[1] = 100
419
        self.t[5] = 200
Chris McDonough's avatar
Chris McDonough committed
420
        self.t[10] = 500
421 422 423 424
        self.t[6] = 99
        self.t[4] = 150
        del self.t[3]
        diff = lsubtract(self.t.keys(), [1,4,5,6,7,8,10])
425
        self.assertEqual(diff , [], diff)
Chris McDonough's avatar
Chris McDonough committed
426

427
    def testDeleteRootWorks(self):
428 429 430 431
        """ 7, 3, 8, 1, 5, 10, 6, 4 -- del 7 """
        self.t[7] = 6
        self.t[3] = 10
        self.t[8] = 12
Chris McDonough's avatar
Chris McDonough committed
432
        self.t[1] = 100
433
        self.t[5] = 200
Chris McDonough's avatar
Chris McDonough committed
434
        self.t[10] = 500
435 436 437 438
        self.t[6] = 99
        self.t[4] = 150
        del self.t[7]
        diff = lsubtract(self.t.keys(), [1,3,4,5,6,8,10])
439
        self.assertEqual(diff , [], diff)
Chris McDonough's avatar
Chris McDonough committed
440 441 442 443 444

    def testRandomNonOverlappingInserts(self):
        added = {}
        r = range(100)
        for x in r:
445
            k = random.choice(r)
Chris McDonough's avatar
Chris McDonough committed
446 447 448 449 450
            if not added.has_key(k):
                self.t[k] = x
                added[k] = 1
        addl = added.keys()
        addl.sort()
451
        diff = lsubtract(list(self.t.keys()), addl)
452
        self.assertEqual(diff , [], (diff, addl, list(self.t.keys())))
Chris McDonough's avatar
Chris McDonough committed
453 454 455 456 457

    def testRandomOverlappingInserts(self):
        added = {}
        r = range(100)
        for x in r:
458
            k = random.choice(r)
Chris McDonough's avatar
Chris McDonough committed
459 460 461 462 463
            self.t[k] = x
            added[k] = 1
        addl = added.keys()
        addl.sort()
        diff = lsubtract(self.t.keys(), addl)
464
        self.assertEqual(diff , [], diff)
Chris McDonough's avatar
Chris McDonough committed
465

466
    def testRandomDeletes(self):
Chris McDonough's avatar
Chris McDonough committed
467 468 469
        r = range(1000)
        added = []
        for x in r:
470
            k = random.choice(r)
Chris McDonough's avatar
Chris McDonough committed
471 472 473 474
            self.t[k] = x
            added.append(k)
        deleted = []
        for x in r:
475
            k = random.choice(r)
Chris McDonough's avatar
Chris McDonough committed
476 477 478 479 480 481 482 483 484
            if self.t.has_key(k):
                del self.t[k]
                deleted.append(k)
                if self.t.has_key(k):
                    raise "had problems deleting %s" % k
        badones = []
        for x in deleted:
            if self.t.has_key(x):
                badones.append(x)
485
        self.assertEqual(badones , [], (badones, added, deleted))
Chris McDonough's avatar
Chris McDonough committed
486

487
    def testTargetedDeletes(self):
Chris McDonough's avatar
Chris McDonough committed
488 489
        r = range(1000)
        for x in r:
490
            k = random.choice(r)
Chris McDonough's avatar
Chris McDonough committed
491 492 493 494 495 496
            self.t[k] = x
        for x in r:
            try:
                del self.t[x]
            except KeyError:
                pass
497
        self.assertEqual(realseq(self.t.keys()) , [], realseq(self.t.keys()))
Chris McDonough's avatar
Chris McDonough committed
498
        
499
    def testPathologicalRightBranching(self):
Chris McDonough's avatar
Chris McDonough committed
500 501 502
        r = range(1000)
        for x in r:
            self.t[x] = 1
503
        self.assertEqual(realseq(self.t.keys()) , r, realseq(self.t.keys()))
Chris McDonough's avatar
Chris McDonough committed
504 505
        for x in r:
            del self.t[x]
506
        self.assertEqual(realseq(self.t.keys()) , [], realseq(self.t.keys()))
Chris McDonough's avatar
Chris McDonough committed
507

508
    def testPathologicalLeftBranching(self):
Chris McDonough's avatar
Chris McDonough committed
509 510 511 512 513
        r = range(1000)
        revr = r[:]
        revr.reverse()
        for x in revr:
            self.t[x] = 1
514
        self.assertEqual(realseq(self.t.keys()) , r, realseq(self.t.keys()))
Chris McDonough's avatar
Chris McDonough committed
515 516 517

        for x in revr:
            del self.t[x]
518
        self.assertEqual(realseq(self.t.keys()) , [], realseq(self.t.keys()))
Chris McDonough's avatar
Chris McDonough committed
519

520
    def testSuccessorChildParentRewriteExerciseCase(self):
Chris McDonough's avatar
Chris McDonough committed
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
        add_order = [
            85, 73, 165, 273, 215, 142, 233, 67, 86, 166, 235, 225, 255,
            73, 175, 171, 285, 162, 108, 28, 283, 258, 232, 199, 260,
            298, 275, 44, 261, 291, 4, 181, 285, 289, 216, 212, 129,
            243, 97, 48, 48, 159, 22, 285, 92, 110, 27, 55, 202, 294,
            113, 251, 193, 290, 55, 58, 239, 71, 4, 75, 129, 91, 111,
            271, 101, 289, 194, 218, 77, 142, 94, 100, 115, 101, 226,
            17, 94, 56, 18, 163, 93, 199, 286, 213, 126, 240, 245, 190,
            195, 204, 100, 199, 161, 292, 202, 48, 165, 6, 173, 40, 218,
            271, 228, 7, 166, 173, 138, 93, 22, 140, 41, 234, 17, 249,
            215, 12, 292, 246, 272, 260, 140, 58, 2, 91, 246, 189, 116,
            72, 259, 34, 120, 263, 168, 298, 118, 18, 28, 299, 192, 252,
            112, 60, 277, 273, 286, 15, 263, 141, 241, 172, 255, 52, 89,
            127, 119, 255, 184, 213, 44, 116, 231, 173, 298, 178, 196,
            89, 184, 289, 98, 216, 115, 35, 132, 278, 238, 20, 241, 128,
            179, 159, 107, 206, 194, 31, 260, 122, 56, 144, 118, 283,
            183, 215, 214, 87, 33, 205, 183, 212, 221, 216, 296, 40,
            108, 45, 188, 139, 38, 256, 276, 114, 270, 112, 214, 191,
            147, 111, 299, 107, 101, 43, 84, 127, 67, 205, 251, 38, 91,
            297, 26, 165, 187, 19, 6, 73, 4, 176, 195, 90, 71, 30, 82,
            139, 210, 8, 41, 253, 127, 190, 102, 280, 26, 233, 32, 257,
            194, 263, 203, 190, 111, 218, 199, 29, 81, 207, 18, 180,
            157, 172, 192, 135, 163, 275, 74, 296, 298, 265, 105, 191,
            282, 277, 83, 188, 144, 259, 6, 173, 81, 107, 292, 231,
            129, 65, 161, 113, 103, 136, 255, 285, 289, 1
            ]
        delete_order = [
            276, 273, 12, 275, 2, 286, 127, 83, 92, 33, 101, 195,
            299, 191, 22, 232, 291, 226, 110, 94, 257, 233, 215, 184,
            35, 178, 18, 74, 296, 210, 298, 81, 265, 175, 116, 261,
            212, 277, 260, 234, 6, 129, 31, 4, 235, 249, 34, 289, 105,
            259, 91, 93, 119, 7, 183, 240, 41, 253, 290, 136, 75, 292,
            67, 112, 111, 256, 163, 38, 126, 139, 98, 56, 282, 60, 26,
            55, 245, 225, 32, 52, 40, 271, 29, 252, 239, 89, 87, 205,
            213, 180, 97, 108, 120, 218, 44, 187, 196, 251, 202, 203,
            172, 28, 188, 77, 90, 199, 297, 282, 141, 100, 161, 216,
            73, 19, 17, 189, 30, 258
            ]
        for x in add_order:
            self.t[x] = 1
        for x in delete_order:
            try: del self.t[x]
            except KeyError:
564
                if self.t.has_key(x): self.assertEqual(1,2,"failed to delete %s" % x)
Chris McDonough's avatar
Chris McDonough committed
565

566 567 568 569 570
    def testRangeSearchAfterSequentialInsert(self):
        r = range(100)
        for x in r:
            self.t[x] = 0
        diff = lsubtract(list(self.t.keys(0, 100)), r)
571
        self.assertEqual(diff , [], diff)
572 573 574 575 576

    def testRangeSearchAfterRandomInsert(self):
        r = range(100)
        a = {}
        for x in r:
577
            rnd = random.choice(r)
578 579 580
            self.t[rnd] = 0
            a[rnd] = 0
        diff = lsubtract(list(self.t.keys(0, 100)), a.keys())
581
        self.assertEqual(diff , [], diff)
582 583 584 585

    def testInsertMethod(self):
        t = self.t
        t[0] = 1
586 587 588
        self.assertEqual(t.insert(0, 1) , 0)
        self.assertEqual(t.insert(1, 1) , 1)
        self.assertEqual(lsubtract(list(t.keys()), [0,1]) , [])
589

590
## BTree tests
591

592
class TestIOBTrees(BTreeTests, TestCase):
593 594 595 596 597 598
    def setUp(self):
        self.t = IOBTree()

    def nonIntegerKeyRaises(self):
        self.assertRaises(TypeError, self._stringraises)
        self.assertRaises(TypeError, self._floatraises)
599
        self.assertRaises(TypeError, self._noneraises)
600 601 602 603 604 605 606

    def _stringraises(self):
        self.t['c'] = 1

    def _floatraises(self):
        self.t[2.5] = 1

607 608 609
    def _noneraises(self):
        self.t[None] = 1

610 611 612 613 614 615 616 617 618 619
    def testEmptyFirstBucketReportedByGuido(self):
        b = self.t
        for i in xrange(29972): # reduce to 29971 and it works
            b[i] = i
        for i in xrange(30): # reduce to 29 and it works
            del b[i]
            b[i+40000] = i

        self.assertEqual(b.keys()[0], 30)

620
class TestOOBTrees(BTreeTests, TestCase):
621 622 623
    def setUp(self):
        self.t = OOBTree()

624 625 626 627
class TestOIBTrees(BTreeTests, TestCase):
    def setUp(self):
        self.t = OIBTree()

628 629 630 631 632 633 634 635 636 637 638 639 640 641
    def testNonIntegerValueRaises(self):
        self.assertRaises(TypeError, self._stringraises)
        self.assertRaises(TypeError, self._floatraises)
        self.assertRaises(TypeError, self._noneraises)

    def _stringraises(self):
        self.t[1] = 'c'

    def _floatraises(self):
        self.t[1] = 1.4

    def _noneraises(self):
        self.t[1] = None

642
class TestIIBTrees(BTreeTests, TestCase):
643 644 645
    def setUp(self):
        self.t = IIBTree()

646 647 648 649
    def testNonIntegerKeyRaises(self):
        self.assertRaises(TypeError, self._stringraiseskey)
        self.assertRaises(TypeError, self._floatraiseskey)
        self.assertRaises(TypeError, self._noneraiseskey)
Chris McDonough's avatar
Chris McDonough committed
650

651 652 653 654 655 656
    def testNonIntegerValueRaises(self):
        self.assertRaises(TypeError, self._stringraisesvalue)
        self.assertRaises(TypeError, self._floatraisesvalue)
        self.assertRaises(TypeError, self._noneraisesvalue)

    def _stringraiseskey(self):
Chris McDonough's avatar
Chris McDonough committed
657 658
        self.t['c'] = 1

659
    def _floatraiseskey(self):
Chris McDonough's avatar
Chris McDonough committed
660 661
        self.t[2.5] = 1

662 663 664 665 666 667 668 669 670 671 672 673
    def _noneraiseskey(self):
        self.t[None] = 1

    def _stringraisesvalue(self):
        self.t[1] = 'c'

    def _floatraisesvalue(self):
        self.t[1] = 1.4

    def _noneraisesvalue(self):
        self.t[1] = None

674 675
## Set tests

Chris McDonough's avatar
Chris McDonough committed
676
class TestIOSets(ExtendedSetTests, TestCase):
677
    def setUp(self):
678 679
        self.t = IOSet()

680 681 682 683 684 685 686 687 688 689 690 691 692 693
    def testNonIntegerInsertRaises(self):
        self.assertRaises(TypeError,self._insertstringraises)
        self.assertRaises(TypeError,self._insertfloatraises)
        self.assertRaises(TypeError,self._insertnoneraises)

    def _insertstringraises(self):
        self.t.insert('a')

    def _insertfloatraises(self):
        self.t.insert(1.4)

    def _insertnoneraises(self):
        self.t.insert(None)

Chris McDonough's avatar
Chris McDonough committed
694
class TestOOSets(ExtendedSetTests, TestCase):
695 696 697
    def setUp(self):
        self.t = OOSet()

Chris McDonough's avatar
Chris McDonough committed
698
class TestIISets(ExtendedSetTests, TestCase):
699 700 701
    def setUp(self):
        self.t = IISet()

Chris McDonough's avatar
Chris McDonough committed
702
class TestOISets(ExtendedSetTests, TestCase):
703 704 705
    def setUp(self):
        self.t = OISet()

Chris McDonough's avatar
Chris McDonough committed
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
class TestIOTreeSets(NormalSetTests, TestCase):
    def setUp(self):
        self.t = IOTreeSet()
        
class TestOOTreeSets(NormalSetTests, TestCase):
    def setUp(self):
        self.t = OOTreeSet()

class TestIITreeSets(NormalSetTests, TestCase):
    def setUp(self):
        self.t = IITreeSet()

class TestOITreeSets(NormalSetTests, TestCase):
    def setUp(self):
        self.t = OITreeSet()
        
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
## Bucket tests

class TestIOBuckets(BucketTests, TestCase):
    def setUp(self):
        self.t = IOBucket()

class TestOOBuckets(BucketTests, TestCase):
    def setUp(self):
        self.t = OOBucket()

class TestIIBuckets(BucketTests, TestCase):
    def setUp(self):
        self.t = IIBucket()

class TestOIBuckets(BucketTests, TestCase):
    def setUp(self):
        self.t = OIBucket()

740
def test_suite():
741 742 743 744 745 746 747 748 749 750
    TIOBTree = makeSuite(TestIOBTrees, 'test')
    TOOBTree = makeSuite(TestOOBTrees, 'test')
    TOIBTree = makeSuite(TestOIBTrees, 'test')
    TIIBTree = makeSuite(TestIIBTrees, 'test')

    TIOSet = makeSuite(TestIOSets, 'test')
    TOOSet = makeSuite(TestOOSets, 'test')
    TOISet = makeSuite(TestIOSets, 'test')
    TIISet = makeSuite(TestOOSets, 'test')

Chris McDonough's avatar
Chris McDonough committed
751 752 753 754 755
    TIOTreeSet = makeSuite(TestIOTreeSets, 'test')
    TOOTreeSet = makeSuite(TestOOTreeSets, 'test')
    TOITreeSet = makeSuite(TestIOTreeSets, 'test')
    TIITreeSet = makeSuite(TestOOTreeSets, 'test')

756 757 758 759 760 761
    TIOBucket = makeSuite(TestIOBuckets, 'test')
    TOOBucket = makeSuite(TestOOBuckets, 'test')
    TOIBucket = makeSuite(TestOIBuckets, 'test')
    TIIBucket = makeSuite(TestIIBuckets, 'test')
    
    alltests = TestSuite((TIOSet, TOOSet, TOISet, TIISet,
Chris McDonough's avatar
Chris McDonough committed
762
                          TIOTreeSet, TOOTreeSet, TOITreeSet, TIITreeSet,
763 764
                          TIOBucket, TOOBucket, TOIBucket, TIIBucket,
                          TOOBTree, TIOBTree, TOIBTree, TIIBTree))
765 766 767

    return alltests

Andreas Jung's avatar
Andreas Jung committed
768 769


770
## utility functions
771

Chris McDonough's avatar
Chris McDonough committed
772
def lsubtract(l1, l2):
773 774 775 776 777
   l1=list(l1)
   l2=list(l2)
   l = filter(lambda x, l1=l1: x not in l1, l2)
   l = l + filter(lambda x, l2=l2: x not in l2, l1)
   return l
Chris McDonough's avatar
Chris McDonough committed
778 779 780 781

def realseq(itemsob):
    return map(lambda x: x, itemsob)

Andreas Jung's avatar
Andreas Jung committed
782 783 784 785 786 787 788

def main():
    TextTestRunner().run(test_suite())

if __name__ == '__main__':
    main()