Contact: fumanchu@aminus.org

Log in as guest/geniusql to create tickets

root/trunk/geniusql/test/zoo_fixture.py

Revision 5 (checked in by fumanchu, 6 years ago)

More tests. It looks like I'll have to give Column a "pytype" attribute after all.

  • Property svn:eol-style set to native
Line 
1 """Test fixture for Storage Managers."""
2
3 import datetime
4 import os
5 thisdir = os.path.dirname(__file__)
6 logname = os.path.join(thisdir, "geniusqltest.log")
7
8
9 try:
10     import pythoncom
11 except ImportError:
12     pythoncom = None
13
14 try:
15     set
16 except NameError:
17     from sets import Set as set
18
19 import sys
20 import threading
21 import time
22 import traceback
23 import unittest
24 import warnings
25
26
27 import geniusql
28 from geniusql import errors, typerefs
29 from geniusql.test import tools
30
31 from dejavu import logic
32
33
34 Jan_1_2001 = datetime.date(2001, 1, 1)
35 every13days = [Jan_1_2001 + datetime.timedelta(x * 13) for x in range(20)]
36 every17days = [Jan_1_2001 + datetime.timedelta(x * 17) for x in range(20)]
37 del x
38
39
40 class ZooTests(unittest.TestCase):
41    
42     def test_1_create_tables(self):
43         Animal = db.table('Animal')
44         Animal['ID'] = db.column(int, autoincrement=True, key=True)
45         Animal.add_index('ID')
46         Animal['ZooID'] = db.column(int)
47         Animal['Species'] = db.column(hints={'bytes': 100})
48         Animal['Legs'] = db.column(int, default=4)
49         Animal['PreviousZoos'] = db.column(list, hints={'bytes': 8000})
50         Animal['LastEscape'] = db.column(datetime.datetime)
51         Animal['Lifespan'] = db.column(float, hints={'precision': 4})
52         Animal['Age'] = db.column(float, default=1, hints={'precision': 4})
53         Animal['MotherID'] = db.column(int)
54         Animal['PreferredFoodID'] = db.column(int)
55         Animal['AlternateFoodID'] = db.column(int)
56         Animal.add_index('ZooID')
57         Animal.references['Animal'] = ('ID', 'Animal', 'MotherID')
58         Animal.references['Visit'] = ('ID', 'Visit', 'AnimalID')
59         db['Animal'] = Animal
60        
61         Zoo = db.table('Zoo')
62         Zoo['ID'] = db.column(int, autoincrement=True, key=True)
63         Zoo.add_index('ID')
64         Zoo['Name'] = db.column()
65         Zoo['Founded'] = db.column(datetime.date)
66         Zoo['Opens'] = db.column(datetime.time)
67         Zoo['LastEscape'] = db.column(datetime.datetime)
68        
69         if typerefs.fixedpoint:
70             # Explicitly set precision and scale so test_msaccess
71             # can test CURRENCY type
72             Zoo['Admission'] = db.column(typerefs.fixedpoint.FixedPoint,
73                                          hints={'precision': 4, 'scale': 2})
74         else:
75             Zoo['Admission'] = db.column(float)
76        
77         Zoo.references['Animal'] = ('ID', 'Animal', 'ZooID')
78         db['Zoo'] = Zoo
79        
80         Food = db.table('Food')
81         Food['ID'] = db.column(int, autoincrement=True, key=True)
82         Food.add_index('ID')
83         Food['Name'] = db.column()
84         Food['NutritionValue'] = db.column(int)
85         Food.references['Animal'] = ('ID', 'Animal', 'PreferredFoodID')
86         Animal.references['Alternate Food'] = ('AlternateFoodID', 'Food', 'ID')
87         db['Food'] = Food
88        
89         Vet = db.table('Vet')
90         Vet['ID'] = c = db.column(int, autoincrement=True, key=True)
91         c.initial = 200
92         Vet.add_index('ID')
93         Vet['Name'] = db.column()
94         Vet['ZooID'] = db.column(int)
95         Vet.add_index('ZooID')
96         Vet['City'] = db.column()
97         Vet.references['Zoo'] = ('ZooID', 'Zoo', 'ID')
98         Vet.references['Visit'] = ('ID', 'Visit', 'VetID')
99         db['Vet'] = Vet
100        
101         Visit = db.table('Visit')
102         Visit['ID'] = db.column(int, autoincrement=True, key=True)
103         Visit.add_index('ID')
104         Visit['VetID'] = db.column(int)
105         Visit.add_index('VetID')
106         Visit['ZooID'] = db.column(int)
107         Visit.add_index('ZooID')
108         Visit['AnimalID'] = db.column(int)
109         Visit.add_index('AnimalID')
110         Visit['Date'] = db.column(datetime.date)
111         db['Visit'] = Visit
112        
113         Exhibit = db.table('Exhibit')
114         # Make this a string to help test vs unicode.
115         Exhibit['Name'] = db.column(str, key=True)
116         Exhibit.add_index('Name')
117         Exhibit['ZooID'] = db.column(int, key=True)
118         Exhibit.add_index('ZooID')
119         Exhibit['Animals'] = db.column(list)
120         Exhibit['PettingAllowed'] = db.column(bool)
121         Exhibit['Creators'] = db.column(tuple)
122        
123         if typerefs.decimal:
124             Exhibit['Acreage'] = db.column(typerefs.decimal.Decimal)
125         else:
126             Exhibit['Acreage'] = db.column(float)
127        
128         Exhibit.references['Zoo'] = ('ZooID', 'Zoo', 'ID')
129         db['Exhibit'] = Exhibit
130        
131         t = db.table('NothingToDoWithZoos')
132         t['ALong'] = db.column(long, hints={'precision': 1})
133         t['AFloat'] = db.column(float, hints={'precision': 1})
134         if typerefs.decimal:
135             t['ADecimal'] = db.column(typerefs.decimal.Decimal,
136                                       hints={'precision': 1, 'scale': 1})
137         if typerefs.fixedpoint:
138             t['AFixed'] = db.column(typerefs.fixedpoint.FixedPoint,
139                                     hints={'precision': 1, 'scale': 1})
140         db['NothingToDoWithZoos'] = t
141    
142     def test_2_populate(self):
143         newids = db.insert('Zoo', Name='Wild Animal Park',
144                            Founded=datetime.date(2000, 1, 1),
145                            # 59 can give rounding errors with divmod, which
146                            # AdapterFromADO needs to correct.
147                            Opens=datetime.time(8, 15, 59),
148                            LastEscape=datetime.datetime(2004, 7, 29, 5, 6, 7),
149                            Admission=4.95,
150                            )
151         wap = int(newids['ID'])
152        
153         newids = db.insert('Zoo', Name = 'San Diego Zoo',
154                            # This early date should play havoc with a number
155                            # of implementations.
156                            Founded = datetime.date(1835, 9, 13),
157                            Opens = datetime.time(9, 0, 0),
158                            Admission = 0,
159                            )
160         sdz = int(newids['ID'])
161        
162         db.insert('Zoo', Name = u'Montr\xe9al Biod\xf4me',
163                   Founded = datetime.date(1992, 6, 19),
164                   Opens = datetime.time(9, 0, 0),
165                   Admission = 11.75,
166                   )
167        
168         newids = db.insert('Zoo', Name = 'Sea_World', Admission = 60)
169         seaworld = int(newids['ID'])
170        
171         # Animals
172         newids = db.insert('Animal', Species='Leopard', Lifespan=73.5)
173         leopardid = int(newids['ID'])
174         self.assertEqual(leopardid, 1)
175         db.save('Animal', ID=leopardid, ZooID=wap,
176                 LastEscape=datetime.datetime(2004, 12, 21, 8, 15, 0, 999907))
177        
178         lion = db.insert('Animal', Species='Lion', ZooID=wap)['ID']
179         db.insert('Animal', Species='Slug', Legs=1, Lifespan=.75,
180                   # Test our 8000-byte limit
181                   PreviousZoos=["f" * (8000 - 14)])
182        
183         newids = db.insert('Animal', Species='Tiger', ZooID=sdz,
184                            PreviousZoos=['animal\\universe'])
185         tiger = int(newids['ID'])
186        
187         # Override Legs.default with itself just to make sure it works.
188         db.insert('Animal', Species='Bear', Legs=4)
189         # Notice that ostrich.PreviousZoos is [], whereas leopard is None.
190         db.insert('Animal', Species='Ostrich', Legs=2, PreviousZoos=[],
191                             Lifespan=103.2)
192         db.insert('Animal', Species='Centipede', Legs=100)
193        
194         emp = db.insert('Animal', Species='Emperor Penguin', Legs=2, ZooID=seaworld)
195         emp = int(emp['ID'])
196         adelie = db.insert('Animal', Species='Adelie Penguin', Legs=2, ZooID=seaworld)
197         adelie = int(adelie['ID'])
198        
199         db.insert('Animal', Species='Millipede', Legs=1000000, ZooID=sdz,
200                   PreviousZoos=['Wild Animal Park'])
201        
202 ##        # Add a mother and child to test relationships
203 ##        bai_yun = Animal(Species='Ape', Legs=2)
204 ##        box.memorize(bai_yun)   # ID = 11
205 ##        self.assertEqual(bai_yun.ID, 11)
206 ##        hua_mei = Animal(Species='Ape', Legs=2, MotherID=bai_yun.ID)
207 ##        box.memorize(hua_mei)   # ID = 12
208 ##        self.assertEqual(hua_mei.ID, 12)
209        
210         # Exhibits
211         db.insert('Exhibit', Name = 'The Penguin Encounter',
212                   ZooID = seaworld,
213                   Animals = [emp, adelie],
214                   PettingAllowed = True,
215                   Acreage = 3.1,
216                   # See ticket #45
217                   Creators = (u'Richard F\xfcrst', u'Sonja Martin'),
218                   )
219        
220         db.insert('Exhibit', Name = 'Tiger River',
221                   ZooID = sdz,
222                   Animals = [tiger],
223                   PettingAllowed = False,
224                   Acreage = 4,
225                   )
226        
227         # Vets
228         newids = db.insert('Vet', Name = 'Charles Schroeder', ZooID = sdz)
229         cs = int(newids['ID'])
230         self.assertEqual(cs, db['Vet']['ID'].initial)
231        
232         newids = db.insert('Vet', Name = 'Jim McBain', ZooID = seaworld)
233         jm = int(newids['ID'])
234        
235         # Visits
236         for d in every13days:
237             db.insert('Visit', VetID=cs, AnimalID=tiger, Date=d)
238         for d in every17days:
239             db.insert('Visit', VetID=jm, AnimalID=emp, Date=d)
240        
241         # Foods
242         dead_fish = db.insert('Food', Name="Dead Fish", Nutrition=5)['ID']
243         live_fish = db.insert('Food', Name="Live Fish", Nutrition=10)['ID']
244         bunnies = db.insert('Food', Name="Live Bunny Wabbit", Nutrition=10)['ID']
245         steak = db.insert('Food', Name="T-Bone", Nutrition=7)['ID']
246        
247         # Foods --> add preferred and alternate foods
248         db.save('Animal', ID=lion,
249                 PreferredFoodID=steak, AlternateFoodID=bunnies)
250         db.save('Animal', ID=tiger,
251                 PreferredFoodID=bunnies, AlternateFoodID=steak)
252         db.save('Animal', ID=emp,
253                 PreferredFoodID=live_fish, AlternateFoodID=dead_fish)
254         db.save('Animal', ID=adelie,
255                 PreferredFoodID=live_fish, AlternateFoodID=dead_fish)
256    
257     def test_3_Properties(self):
258         # Zoos
259         sel = db.select(db['Zoo'], ('Founded', 'Opens', 'Admission'),
260                         logic.Expression(lambda z: z.Name == 'Wild Animal Park'))
261         data, _ = db.fetch(sel.sql(), db.get_transaction())
262         self.assertEqual(data[0][0], datetime.date(2000, 1, 1))
263         self.assertEqual(data[0][1], datetime.time(8, 15, 59))
264         # This should have been updated when leopard.LastEscape was set.
265 ##        self.assertEqual(WAP.LastEscape,
266 ##                         datetime.datetime(2004, 12, 21, 8, 15, 0, 999907))
267         self.assertEqual(data[0][2], 4.95)
268 ##           
269 ##            SDZ = box.unit(Zoo, Founded=datetime.date(1835, 9, 13))
270 ##            self.assertNotEqual(SDZ, None)
271 ##            self.assertEqual(SDZ.Founded, datetime.date(1835, 9, 13))
272 ##            self.assertEqual(SDZ.Opens, datetime.time(9, 0, 0))
273 ##            self.assertEqual(SDZ.LastEscape, None)
274 ##            self.assertEqual(float(SDZ.Admission), 0)
275 ##           
276 ##            # Try a magic Sandbox recaller method
277 ##            Biodome = box.Zoo(Name = u'Montr\xe9al Biod\xf4me')
278 ##            self.assertNotEqual(Biodome, None)
279 ##            self.assertEqual(Biodome.Name, u'Montr\xe9al Biod\xf4me')
280 ##            self.assertEqual(Biodome.Founded, datetime.date(1992, 6, 19))
281 ##            self.assertEqual(Biodome.Opens, datetime.time(9, 0, 0))
282 ##            self.assertEqual(Biodome.LastEscape, None)
283 ##            self.assertEqual(float(Biodome.Admission), 11.75)
284 ##           
285 ##            if typerefs.fixedpoint:
286 ##                seaworld = box.unit(Zoo, Admission = typerefs.fixedpoint.FixedPoint(60))
287 ##            else:
288 ##                seaworld = box.unit(Zoo, Admission = float(60))
289 ##            self.assertNotEqual(seaworld, None)
290 ##            self.assertEqual(seaworld.Name, u'Sea_World')
291 ##           
292 ##            # Animals
293 ##            leopard = box.unit(Animal, Species='Leopard')
294 ##            self.assertEqual(leopard.Species, 'Leopard')
295 ##            self.assertEqual(leopard.Legs, 4)
296 ##            self.assertEqual(leopard.Lifespan, 73.5)
297 ##            self.assertEqual(leopard.ZooID, WAP.ID)
298 ##            self.assertEqual(leopard.PreviousZoos, None)
299 ##    ##        self.assertEqual(leopard.LastEscape,
300 ##    ##                         datetime.datetime(2004, 12, 21, 8, 15, 0, 999907))
301 ##           
302 ##            ostrich = box.unit(Animal, Species='Ostrich')
303 ##            self.assertEqual(ostrich.Species, 'Ostrich')
304 ##            self.assertEqual(ostrich.Legs, 2)
305 ##            self.assertEqual(ostrich.ZooID, None)
306 ##            self.assertEqual(ostrich.PreviousZoos, [])
307 ##            self.assertEqual(ostrich.LastEscape, None)
308 ##           
309 ##            millipede = box.unit(Animal, Legs=1000000)
310 ##            self.assertEqual(millipede.Species, 'Millipede')
311 ##            self.assertEqual(millipede.Legs, 1000000)
312 ##            self.assertEqual(millipede.ZooID, SDZ.ID)
313 ##            self.assertEqual(millipede.PreviousZoos, [WAP.Name])
314 ##            self.assertEqual(millipede.LastEscape, None)
315 ##           
316 ##            # Test that strings in a list get decoded correctly.
317 ##            # See http://projects.amor.org/dejavu/ticket/50
318 ##            tiger = box.unit(Animal, Species='Tiger')
319 ##            self.assertEqual(tiger.PreviousZoos, ["animal\\universe"])
320 ##           
321 ##            # Test our 8000-byte limit.
322 ##            # len(pickle.dumps(["f" * (8000 - 14)]) == 8000
323 ##            slug = box.unit(Animal, Species='Slug')
324 ##            self.assertEqual(len(slug.PreviousZoos[0]), 8000 - 14)
325 ##           
326 ##            # Exhibits
327 ##            exes = box.recall(Exhibit)
328 ##            self.assertEqual(len(exes), 2)
329 ##            if exes[0].Name == 'The Penguin Encounter':
330 ##                pe = exes[0]
331 ##                tr = exes[1]
332 ##            else:
333 ##                pe = exes[1]
334 ##                tr = exes[0]
335 ##            self.assertEqual(pe.ZooID, seaworld.ID)
336 ##            self.assertEqual(len(pe.Animals), 2)
337 ##            self.assertEqual(float(pe.Acreage), 3.1)
338 ##            self.assertEqual(pe.PettingAllowed, True)
339 ##            self.assertEqual(pe.Creators, (u'Richard F\xfcrst', u'Sonja Martin'))
340 ##           
341 ##            self.assertEqual(tr.ZooID, SDZ.ID)
342 ##            self.assertEqual(len(tr.Animals), 1)
343 ##            self.assertEqual(float(tr.Acreage), 4)
344 ##            self.assertEqual(tr.PettingAllowed, False)
345 ##           
346 ##        finally:
347 ##            box.flush_all()
348 ##   
349 ##    def test_4_Expressions(self):
350 ##        box = arena.new_sandbox()
351 ##        try:
352 ##            def matches(lam, cls=Animal):
353 ##                # We flush_all to ensure a DB hit each time.
354 ##                box.flush_all()
355 ##                return len(box.recall(cls, (lam)))
356 ##           
357 ##            zoos = box.recall(Zoo)
358 ##            self.assertEqual(zoos[0].dirty(), False)
359 ##            self.assertEqual(len(zoos), 4)
360 ##            self.assertEqual(matches(lambda x: True), 12)
361 ##            self.assertEqual(matches(lambda x: x.Legs == 4), 4)
362 ##            self.assertEqual(matches(lambda x: x.Legs == 2), 5)
363 ##            self.assertEqual(matches(lambda x: x.Legs >= 2 and x.Legs < 20), 9)
364 ##            self.assertEqual(matches(lambda x: x.Legs > 10), 2)
365 ##            self.assertEqual(matches(lambda x: x.Lifespan > 70), 2)
366 ##            self.assertEqual(matches(lambda x: x.Species.startswith('L')), 2)
367 ##            self.assertEqual(matches(lambda x: x.Species.endswith('pede')), 2)
368 ##            self.assertEqual(matches(lambda x: x.LastEscape != None), 1)
369 ##            self.assertEqual(matches(lambda x: x.LastEscape is not None), 1)
370 ##            self.assertEqual(matches(lambda x: None == x.LastEscape), 11)
371 ##           
372 ##            # In operator (containedby)
373 ##            self.assertEqual(matches(lambda x: 'pede' in x.Species), 2)
374 ##            self.assertEqual(matches(lambda x: x.Species in ('Lion', 'Tiger', 'Bear')), 3)
375 ##           
376 ##            # Try In with cell references
377 ##            class thing(object): pass
378 ##            pet, pet2 = thing(), thing()
379 ##            pet.Name, pet2.Name = 'Slug', 'Ostrich'
380 ##            self.assertEqual(matches(lambda x: x.Species in (pet.Name, pet2.Name)), 2)
381 ##           
382 ##            # logic and other functions
383 ##            self.assertEqual(matches(lambda x: dejavu.ieq(x.Species, 'slug')), 1)
384 ##            self.assertEqual(matches(lambda x: dejavu.icontains(x.Species, 'PEDE')), 2)
385 ##            self.assertEqual(matches(lambda x: dejavu.icontains(('Lion', 'Banana'), x.Species)), 1)
386 ##            f = lambda x: dejavu.icontainedby(x.Species, ('Lion', 'Bear', 'Leopard'))
387 ##            self.assertEqual(matches(f), 3)
388 ##            name = 'Lion'
389 ##            self.assertEqual(matches(lambda x: len(x.Species) == len(name)), 3)
390 ##           
391 ##            # This broke sometime in 2004. Rev 32 seems to have fixed it.
392 ##            self.assertEqual(matches(lambda x: 'i' in x.Species), 7)
393 ##           
394 ##            # Test now(), today(), year(), month(), day()
395 ##            self.assertEqual(matches(lambda x: x.Founded != None
396 ##                                     and x.Founded < dejavu.today(), Zoo), 3)
397 ##            self.assertEqual(matches(lambda x: x.LastEscape == dejavu.now()), 0)
398 ##            self.assertEqual(matches(lambda x: dejavu.year(x.LastEscape) == 2004), 1)
399 ##            self.assertEqual(matches(lambda x: dejavu.month(x.LastEscape) == 12), 1)
400 ##            self.assertEqual(matches(lambda x: dejavu.day(x.LastEscape) == 21), 1)
401 ##
402 ##           
403 ##            # Test AND, OR with cannot_represent.
404 ##            # Notice that we reference a method ('count') which no
405 ##            # known SM handles, so it will default back to Expr.eval().
406 ##            self.assertEqual(matches(lambda x: 'p' in x.Species
407 ##                                     and x.Species.count('e') > 1), 3)
408 ##           
409 ##            # This broke in MSAccess (storeado) in April 2005, due to a bug in
410 ##            # db.SQLDecompiler.visit_CALL_FUNCTION (append TOS, not replace!).
411 ##            box.flush_all()
412 ##            e = logic.Expression(lambda x, **kw: x.LastEscape != None
413 ##                                 and x.LastEscape >= datetime.datetime(kw['Year'], 12, 1)
414 ##                                 and x.LastEscape < datetime.datetime(kw['Year'], 12, 31)
415 ##                                 )
416 ##            e.bind_args(Year=2004)
417 ##            units = box.recall(Animal, e)
418 ##            self.assertEqual(len(units), 1)
419 ##           
420 ##            # Test wildcards in LIKE. This fails with SQLite <= 3.0.8,
421 ##            # so make sure it's always at the end of this method so
422 ##            # it doesn't preclude running the other tests.
423 ##            box.flush_all()
424 ##            units = box.recall(Zoo, lambda x: "_" in x.Name)
425 ##            self.assertEqual(len(units), 1)
426 ##        finally:
427 ##            box.flush_all()
428 ##   
429 ##    def test_5_Aggregates(self):
430 ##        box = arena.new_sandbox()
431 ##        try:
432 ##            # views
433 ##            legs = [x[0] for x in box.view(Animal, ['Legs'])]
434 ##            legs.sort()
435 ##            self.assertEqual(legs, [1, 2, 2, 2, 2, 2, 4, 4, 4, 4, 100, 1000000])
436 ##           
437 ##            expected = {'Leopard': 73.5,
438 ##                        'Slug': .75,
439 ##                        'Tiger': None,
440 ##                        'Lion': None,
441 ##                        'Bear': None,
442 ##                        'Ostrich': 103.2,
443 ##                        'Centipede': None,
444 ##                        'Emperor Penguin': None,
445 ##                        'Adelie Penguin': None,
446 ##                        'Millipede': None,
447 ##                        'Ape': None,
448 ##                        }
449 ##            for species, lifespan in box.view(Animal, ['Species', 'Lifespan']):
450 ##                if expected[species] is None:
451 ##                    self.assertEqual(lifespan, None)
452 ##                else:
453 ##                    self.assertAlmostEqual(expected[species], lifespan, places=5)
454 ##           
455 ##            expected = [u'Montr\xe9al Biod\xf4me', 'Wild Animal Park']
456 ##            e = (lambda x: x.Founded != None
457 ##                 and x.Founded <= dejavu.today()
458 ##                 and x.Founded >= datetime.date(1990, 1, 1))
459 ##            values =  [val[0] for val in box.view(Zoo, ['Name'], e)]
460 ##            for name in expected:
461 ##                self.assert_(name in values)
462 ##           
463 ##            # distinct
464 ##            legs = box.distinct(Animal, ['Legs'])
465 ##            legs.sort()
466 ##            self.assertEqual(legs, [1, 2, 4, 100, 1000000])
467 ##           
468 ##            # This may raise a warning on some DB's.
469 ##            f = (lambda x: x.Species == 'Lion')
470 ##            escapees = box.distinct(Animal, ['Legs'], f)
471 ##            self.assertEqual(escapees, [4])
472 ##           
473 ##            # range should return a sorted list
474 ##            legs = box.range(Animal, 'Legs', lambda x: x.Legs <= 100)
475 ##            self.assertEqual(legs, range(1, 101))
476 ##            topics = box.range(Exhibit, 'Name')
477 ##            self.assertEqual(topics, ['The Penguin Encounter', 'Tiger River'])
478 ##            vets = box.range(Vet, 'Name')
479 ##            self.assertEqual(vets, ['Charles Schroeder', 'Jim McBain'])
480 ##        finally:
481 ##            box.flush_all()
482 ##   
483 ##    def test_6_Editing(self):
484 ##        # Edit
485 ##        box = arena.new_sandbox()
486 ##        try:
487 ##            SDZ = box.unit(Zoo, Name='San Diego Zoo')
488 ##            SDZ.Name = 'The San Diego Zoo'
489 ##            SDZ.Founded = datetime.date(1900, 1, 1)
490 ##            SDZ.Opens = datetime.time(7, 30, 0)
491 ##            SDZ.Admission = "35.00"
492 ##        finally:
493 ##            box.flush_all()
494 ##       
495 ##        # Test edits
496 ##        box = arena.new_sandbox()
497 ##        try:
498 ##            SDZ = box.unit(Zoo, Name='The San Diego Zoo')
499 ##            self.assertEqual(SDZ.Name, 'The San Diego Zoo')
500 ##            self.assertEqual(SDZ.Founded, datetime.date(1900, 1, 1))
501 ##            self.assertEqual(SDZ.Opens, datetime.time(7, 30, 0))
502 ##            if typerefs.fixedpoint:
503 ##                self.assertEqual(SDZ.Admission, typerefs.fixedpoint.FixedPoint(35, 2))
504 ##            else:
505 ##                self.assertEqual(SDZ.Admission, 35.0)
506 ##        finally:
507 ##            box.flush_all()
508 ##       
509 ##        # Change it back
510 ##        box = arena.new_sandbox()
511 ##        try:
512 ##            SDZ = box.unit(Zoo, Name='The San Diego Zoo')
513 ##            SDZ.Name = 'San Diego Zoo'
514 ##            SDZ.Founded = datetime.date(1835, 9, 13)
515 ##            SDZ.Opens = datetime.time(9, 0, 0)
516 ##            SDZ.Admission = "0"
517 ##        finally:
518 ##            box.flush_all()
519 ##       
520 ##        # Test re-edits
521 ##        box = arena.new_sandbox()
522 ##        try:
523 ##            SDZ = box.unit(Zoo, Name='San Diego Zoo')
524 ##            self.assertEqual(SDZ.Name, 'San Diego Zoo')
525 ##            self.assertEqual(SDZ.Founded, datetime.date(1835, 9, 13))
526 ##            self.assertEqual(SDZ.Opens, datetime.time(9, 0, 0))
527 ##            if typerefs.fixedpoint:
528 ##                self.assertEqual(SDZ.Admission, typerefs.fixedpoint.FixedPoint(0, 2))
529 ##            else:
530 ##                self.assertEqual(SDZ.Admission, 0.0)
531 ##        finally:
532 ##            box.flush_all()
533 ##   
534 ##    def test_7_Multirecall(self):
535 ##        box = arena.new_sandbox()
536 ##        try:
537 ##            f = (lambda z, a: z.Name == 'San Diego Zoo')
538 ##            zooed_animals = box.recall(Zoo & Animal, f)
539 ##            self.assertEqual(len(zooed_animals), 2)
540 ##           
541 ##            SDZ = box.unit(Zoo, Name='San Diego Zoo')
542 ##            aid = 0
543 ##            for z, a in zooed_animals:
544 ##                self.assertEqual(id(z), id(SDZ))
545 ##                self.assertNotEqual(id(a), aid)
546 ##                aid = id(a)
547 ##           
548 ##            # Assert that multirecalls with no matching related units returns
549 ##            # no matches for the initial class, since all joins are INNER.
550 ##            # We're also going to test that you can combine a one-arg expr
551 ##            # with a two-arg expr.
552 ##            sdexpr = logic.filter(Name='San Diego Zoo')
553 ##            leo = lambda z, a: a.Species == 'Leopard'
554 ##            zooed_animals = box.recall(Zoo & Animal, sdexpr + leo)
555 ##            self.assertEqual(len(zooed_animals), 0)
556 ##           
557 ##            # Now try the same expr with INNER, LEFT, and RIGHT JOINs.
558 ##            zooed_animals = box.recall(Zoo & Animal)
559 ##            self.assertEqual(len(zooed_animals), 6)
560 ##            self.assertEqual(set([(z.Name, a.Species) for z, a in zooed_animals]),
561 ##                             set([("Wild Animal Park", "Leopard"),
562 ##                                  ("Wild Animal Park", "Lion"),
563 ##                                  ("San Diego Zoo", "Tiger"),
564 ##                                  ("San Diego Zoo", "Millipede"),
565 ##                                  ("Sea_World", "Emperor Penguin"),
566 ##                                  ("Sea_World", "Adelie Penguin")]))
567 ##           
568 ##            zooed_animals = box.recall(Zoo >> Animal)
569 ##            self.assertEqual(len(zooed_animals), 12)
570 ##            self.assertEqual(set([(z.Name, a.Species) for z, a in zooed_animals]),
571 ##                             set([("Wild Animal Park", "Leopard"),
572 ##                                  ("Wild Animal Park", "Lion"),
573 ##                                  ("San Diego Zoo", "Tiger"),
574 ##                                  ("San Diego Zoo", "Millipede"),
575 ##                                  ("Sea_World", "Emperor Penguin"),
576 ##                                  ("Sea_World", "Adelie Penguin"),
577 ##                                  (None, "Slug"),
578 ##                                  (None, "Bear"),
579 ##                                  (None, "Ostrich"),
580 ##                                  (None, "Centipede"),
581 ##                                  (None, "Ape"),
582 ##                                  (None, "Ape"),
583 ##                                  ]))
584 ##           
585 ##            zooed_animals = box.recall(Zoo << Animal)
586 ##            self.assertEqual(len(zooed_animals), 7)
587 ##            self.assertEqual(set([(z.Name, a.Species) for z, a in zooed_animals]),
588 ##                             set([("Wild Animal Park", "Leopard"),
589 ##                                  ("Wild Animal Park", "Lion"),
590 ##                                  ("San Diego Zoo", "Tiger"),
591 ##                                  ("San Diego Zoo", "Millipede"),
592 ##                                  ("Sea_World", "Emperor Penguin"),
593 ##                                  ("Sea_World", "Adelie Penguin"),
594 ##                                  (u'Montr\xe9al Biod\xf4me', None),
595 ##                                  ]))
596 ##           
597 ##            # Try a multiple-arg expression
598 ##            f = (lambda a, z: a.Legs >= 4 and z.Admission < 10)
599 ##            animal_zoos = box.recall(Animal & Zoo, f)
600 ##            self.assertEqual(len(animal_zoos), 4)
601 ##            names = [a.Species for a, z in animal_zoos]
602 ##            names.sort()
603 ##            self.assertEqual(names, ['Leopard', 'Lion', 'Millipede', 'Tiger'])
604 ##           
605 ##            # Let's try three joined classes just for the sadistic fun of it.
606 ##            tree = (Animal >> Zoo) >> Vet
607 ##            f = (lambda a, z, v: z.Name == 'Sea_World')
608 ##            self.assertEqual(len(box.recall(tree, f)), 2)
609 ##           
610 ##            # MSAccess can't handle an INNER JOIN nested in an OUTER JOIN.
611 ##            # Test that this fails for MSAccess, but works for other SM's.
612 ##            trees = []
613 ##            def make_tree():
614 ##                trees.append( (Animal & Zoo) >> Vet )
615 ##            warnings.filterwarnings("ignore", category=errors.FeatureWarning)
616 ##            try:
617 ##                make_tree()
618 ##            finally:
619 ##                warnings.filters.pop(0)
620 ##           
621 ##            azv = []
622 ##            def set_azv():
623 ##                f = (lambda a, z, v: z.Name == 'Sea_World')
624 ##                azv.append(box.recall(trees[0], f))
625 ##           
626 ##            smname = arena.stores['testSM'].__class__.__name__
627 ##            if smname in ("StorageManagerADO_MSAccess",):
628 ##                self.assertRaises(pythoncom.com_error, set_azv)
629 ##            else:
630 ##                set_azv()
631 ##                self.assertEqual(len(azv[0]), 2)
632 ##           
633 ##            # Try mentioning the same class twice.
634 ##            tree = (Animal << Animal)
635 ##            f = (lambda anim, mother: mother.ID != None)
636 ##            animals = [mother.ID for anim, mother in box.recall(tree, f)]
637 ##            self.assertEqual(animals, [11])
638 ##        finally:
639 ##            box.flush_all()
640 ##   
641 ##    def test_8_CustomAssociations(self):
642 ##        box = arena.new_sandbox()
643 ##        try:
644 ##            # Try different association paths
645 ##            std_expected = ['Live Bunny Wabbit', 'Live Fish', 'Live Fish', 'T-Bone']
646 ##            cus_expected = ['Dead Fish', 'Dead Fish', 'Live Bunny Wabbit', 'T-Bone']
647 ##            uj = Animal & Food
648 ##            for path, expected in [# standard path
649 ##                                   (None, std_expected),
650 ##                                   # custom path
651 ##                                   ('Alternate Food', cus_expected)]:
652 ##               
653 ##                uj.path = path
654 ##                foods = [food for animal, food in box.recall(uj)]
655 ##                foods.sort(dejavu.sort('Name'))
656 ##                self.assertEqual([f.Name for f in foods], expected)
657 ##
658 ##            # Test the magic association methods
659 ##            tiger = box.unit(Animal, Species='Tiger')
660 ##            self.assertEqual(tiger.Food().Name, 'Live Bunny Wabbit')
661 ##            self.assertEqual(tiger.AlternateFood().Name, 'T-Bone')
662 ##           
663 ##        finally:
664 ##            box.flush_all()
665 ##   
666 ##    def test_9_arena_views(self):
667 ##        # views
668 ##        legs = [x[0] for x in arena.view(Animal, ['Legs'])]
669 ##        legs.sort()
670 ##        self.assertEqual(legs, [1, 2, 2, 2, 2, 2, 4, 4, 4, 4, 100, 1000000])
671 ##       
672 ##        expected = {'Leopard': 73.5,
673 ##                    'Slug': .75,
674 ##                    'Tiger': None,
675 ##                    'Lion': None,
676 ##                    'Bear': None,
677 ##                    'Ostrich': 103.2,
678 ##                    'Centipede': None,
679 ##                    'Emperor Penguin': None,
680 ##                    'Adelie Penguin': None,
681 ##                    'Millipede': None,
682 ##                    'Ape': None,
683 ##                    }
684 ##        for species, lifespan in arena.view(Animal, ['Species', 'Lifespan']):
685 ##            if expected[species] is None:
686 ##                self.assertEqual(lifespan, None)
687 ##            else:
688 ##                self.assertAlmostEqual(expected[species], lifespan, places=5)
689 ##       
690 ##        expected = [u'Montr\xe9al Biod\xf4me', 'Wild Animal Park']
691 ##        e = (lambda x: x.Founded != None
692 ##             and x.Founded <= dejavu.today()
693 ##             and x.Founded >= datetime.date(1990, 1, 1))
694 ##        values =  [val[0] for val in arena.view(Zoo, ['Name'], e)]
695 ##        for name in expected:
696 ##            self.assert_(name in values)
697 ##       
698 ##        # distinct
699 ##        legs = arena.distinct(Animal, ['Legs'])
700 ##        legs.sort()
701 ##        self.assertEqual(legs, [1, 2, 4, 100, 1000000])
702 ##       
703 ##        # This may raise a warning on some DB's.
704 ##        f = (lambda x: x.Species == 'Lion')
705 ##        escapees = arena.distinct(Animal, ['Legs'], f)
706 ##        self.assertEqual(escapees, [4])
707 ##       
708 ##        # range should return a sorted list
709 ##        legs = arena.range(Animal, 'Legs', lambda x: x.Legs <= 100)
710 ##        self.assertEqual(legs, range(1, 101))
711 ##        topics = arena.range(Exhibit, 'Name')
712 ##        self.assertEqual(topics, ['The Penguin Encounter', 'Tiger River'])
713 ##        vets = arena.range(Vet, 'Name')
714 ##        self.assertEqual(vets, ['Charles Schroeder', 'Jim McBain'])
715 ##   
716 ##    def test_Iteration(self):
717 ##        box = arena.new_sandbox()
718 ##        try:
719 ##            # Test box.unit inside of xrecall
720 ##            for visit in box.xrecall(Visit, VetID=1):
721 ##                firstvisit = box.unit(Visit, VetID=1, Date=Jan_1_2001)
722 ##                self.assertEqual(firstvisit.VetID, 1)
723 ##                self.assertEqual(visit.VetID, 1)
724 ##           
725 ##            # Test recall inside of xrecall
726 ##            for visit in box.xrecall(Visit, VetID=1):
727 ##                f = (lambda x: x.VetID == 1 and x.ID != visit.ID)
728 ##                othervisits = box.recall(Visit, f)
729 ##                self.assertEqual(len(othervisits), len(every13days) - 1)
730 ##           
731 ##            # Test far associations inside of xrecall
732 ##            for visit in box.xrecall(Visit, VetID=1):
733 ##                # visit.Vet is a ToOne association, so will return a unit or None.
734 ##                vet = visit.Vet()
735 ##                self.assertEqual(vet.ID, 1)
736 ##        finally:
737 ##            box.flush_all()
738 ##   
739 ##    def test_Subclassing(self):
740 ##        box = arena.new_sandbox()
741 ##        try:
742 ##            box.memorize(Visit(VetID=21, ZooID=1, AnimalID=1))
743 ##            box.memorize(Visit(VetID=21, ZooID=1, AnimalID=2))
744 ##            box.memorize(Visit(VetID=32, ZooID=1, AnimalID=3))
745 ##            box.memorize(Lecture(VetID=21, ZooID=1, Topic='Cage Cleaning'))
746 ##            box.memorize(Lecture(VetID=21, ZooID=1, Topic='Ape Mating Habits'))
747 ##            box.memorize(Lecture(VetID=32, ZooID=3, Topic='Your Tiger and Steroids'))
748 ##           
749 ##            visits = box.recall(Visit, inherit=True, ZooID=1)
750 ##            self.assertEqual(len(visits), 5)
751 ##           
752 ##            box.flush_all()
753 ##           
754 ##            box = arena.new_sandbox()
755 ##            visits = box.recall(Visit, inherit=True, VetID=21)
756 ##            self.assertEqual(len(visits), 4)
757 ##            cc = [x for x in visits
758 ##                  if getattr(x, "Topic", None) == "Cage Cleaning"]
759 ##            self.assertEqual(len(cc), 1)
760 ##           
761 ##            # Checking for non-existent attributes in/from subclasses
762 ##            # isn't supported yet.
763 ##    ##        f = logic.filter(AnimalID=2)
764 ##    ##        self.assertEqual(len(box.recall(Visit, f)), 1)
765 ##    ##        self.assertEqual(len(box.recall(Lecture, f)), 0)
766 ##        finally:
767 ##            box.flush_all()
768 ##   
769 ##    def test_DB_Introspection(self):
770 ##        s = arena.stores.values()[0]
771 ##        if not hasattr(s, "db"):
772 ##            print "not a db (skipped) ",
773 ##            return
774 ##       
775 ##        zootable = s.db['Zoo']
776 ##        cols = zootable
777 ##        self.assertEqual(len(cols), 6)
778 ##        idcol = cols['ID']
779 ##        self.assertEqual(s.db.python_type(idcol.dbtype), int)
780 ##        for prop in Zoo.properties:
781 ##            self.assertEqual(cols[prop].key,
782 ##                             prop in Zoo.identifiers)
783 ##   
784 ##    def test_zzz_Schema_Upgrade(self):
785 ##        # Must run last.
786 ##        zs = ZooSchema(arena)
787 ##       
788 ##        # In this first upgrade, we simulate the case where the code was
789 ##        # upgraded, and the database schema upgrade performed afterward.
790 ##        # The Schema.latest property is set, and upgrade() is called with
791 ##        # no argument (which should upgrade us to "latest").
792 ##        Animal.set_property("ExhibitID")
793 ##        # Test numeric default (see hack in storeado for MS Access).
794 ##        prop = Animal.set_property("Stomachs", int)
795 ##        prop.default = 1
796 ##        zs.latest = 2
797 ##        zs.upgrade()
798 ##       
799 ##        # In this example, we simulate the developer who wants to put
800 ##        # model changes inline with database changes (see upgrade_to_3).
801 ##        # We do not set latest, but instead supply an arg to upgrade().
802 ##        zs.upgrade(3)
803 ##       
804 ##        # Test that Animals have a new "Family" property, and an ExhibitID.
805 ##        box = arena.new_sandbox()
806 ##        try:
807 ##            emp = box.unit(Animal, Family='Emperor Penguin')
808 ##            self.assertEqual(emp.ExhibitID, 'The Penguin Encounter')
809 ##        finally:
810 ##            box.flush_all()
811
812
813 class IsolationTests(unittest.TestCase):
814    
815     verbose = False
816     _boxid = 0
817    
818     def setUp(self):
819         s = arena.stores.values()[0]
820         if hasattr(s, "db"):
821             self.db = s.db
822         else:
823             self.db = None
824        
825         try:
826             self.old_implicit = s.db.implicit_trans
827             s.db.implicit_trans = False
828             self.old_tkey = s.db.transaction_key
829             # Use an explicit 'boxid' for the transaction key
830             s.db.transaction_key = lambda: self.boxid
831         except AttributeError:
832             self.old_implicit = None
833        
834    
835     def tearDown(self):
836         if self.db and self.old_implicit is not None:
837             self.db.implicit_trans = self.old_implicit
838             self.db.transaction_key = self.old_tkey
839    
840     def restore(self):
841         self.boxid = 0
842         box = arena.new_sandbox()
843         box.start()
844         jim = box.unit(Vet, Name = 'Jim McBain')
845         jim.City = None
846         box.flush_all()
847    
848     def cleanup_boxes(self):
849         try:
850             self.boxid = 1
851             self.box1.rollback()
852         except: pass
853         try:
854             self.boxid = 2
855             self.box2.rollback()
856         except: pass
857        
858         # Destroy refs so the conns can go back in the pool.
859         del self.box1, self.box2
860    
861     def attempt(self, testfunc, anomaly_name, level):
862         self.restore()
863        
864         self.boxid = 1
865         self.box1 = arena.new_sandbox()
866         self.box1.start(level)
867        
868         self.boxid = 2
869         self.box2 = arena.new_sandbox()
870         self.box2.start(level)
871        
872         try:
873             testfunc(level)
874         except AssertionError:
875             self.cleanup_boxes()
876             if level.forbids(anomaly_name):
877                 warnings.warn("%r allowed anomaly %r." %
878                               (level, anomaly_name))
879         except:
880             if self.db.is_lock_error(sys.exc_info()[1]):
881                 self.cleanup_boxes()
882                 if not level.forbids(anomaly_name):
883                     warnings.warn("%r prevented anomaly %r with an error." %
884                                   (level, anomaly_name))
885             else:
886                 self.cleanup_boxes()
887                 raise
888         else:
889             self.cleanup_boxes()
890             if not level.forbids(anomaly_name):
891                 warnings.warn("%r prevented anomaly %r." %
892                               (level, anomaly_name))
893    
894     def _get_boxid(self):
895         return self._boxid
896     def _set_boxid(self, val):
897         if self.verbose:
898             print val,
899         self._boxid = val
900     boxid = property(_get_boxid, _set_boxid)
901    
902     def test_dirty_read(self):
903         def dirty_read(level):
904             # Write City 1
905             self.boxid = 1
906             jim1 = self.box1.unit(Vet, Name = 'Jim McBain')
907             jim1.City = "Addis Ababa"
908             self.box1.repress(jim1)
909            
910             # Read City 2.
911             self.boxid = 2
912             jim2 = self.box2.unit(Vet, Name = 'Jim McBain')
913             # If READ UNCOMMITTED or lower, this should fail
914             assert jim2.City is None
915        
916         for level in geniusql.levels:
917             if self.verbose:
918                 print
919                 print level,
920             if level.name in self.db.isolation_levels:
921                 self.attempt(dirty_read, "Dirty Read", level)
922    
923     def test_nonrepeatable_read(self):
924         def nonrepeatable_read(level):
925             # Read City 1
926             self.boxid = 1
927             jim1 = self.box1.unit(Vet, Name = 'Jim McBain')
928             val1 = jim1.City
929             assert val1 is None
930             self.box1.repress(jim1)
931            
932             # Write City 2.
933             self.boxid = 2
934             jim2 = self.box2.unit(Vet, Name = 'Jim McBain')
935             jim2.City = "Tehachapi"
936             self.box2.flush_all()
937        
938             # Re-read City 1
939             self.boxid = 1
940             jim1 = self.box1.unit(Vet, Name = 'Jim McBain')
941             # If READ COMMITTED or lower, this should fail
942             assert jim1.City == val1
943        
944         for level in geniusql.levels:
945             if self.verbose:
946                 print
947                 print level,
948             if level.name in self.db.isolation_levels:
949                 self.attempt(nonrepeatable_read, "Nonrepeatable Read", level)
950    
951     def test_phantom(self):
952         def phantom(level):
953             # Read City 1
954             self.boxid = 1
955             pvets = self.box1.recall(Vet, City = 'Poughkeepsie')
956             assert len(pvets) == 0
957            
958             # Write City 2.
959             self.boxid = 2
960             jim2 = self.box2.unit(Vet, Name = 'Jim McBain')
961             jim2.City = "Poughkeepsie"
962             self.box2.flush_all()
963        
964             # Re-read City 1
965             self.boxid = 1
966             pvets = self.box1.recall(Vet, City = 'Poughkeepsie')
967             # If REPEATABLE READ or lower, this should fail
968             assert len(pvets) == 0
969        
970         for level in geniusql.levels:
971             if self.verbose:
972                 print
973                 print level,
974             if level.name in self.db.isolation_levels:
975                 self.attempt(phantom, "Phantom", level)
976
977
978 class ConcurrencyTests(unittest.TestCase):
979    
980     def test_Multithreading(self):
981 ##        print "skipped ",
982 ##        return
983        
984         s = arena.stores.values()[0]
985        
986         # Test threads overlapping on separate sandboxes
987         f = (lambda x: x.Legs == 4)
988         def box_per_thread():
989             # Notice that, although we write changes in each thread,
990             # we only assert the unchanged data, since the order of
991             # thread execution can not be guaranteed.
992             box = arena.new_sandbox()
993             try:
994                 quadrupeds = box.recall(Animal, f)
995                 self.assertEqual(len(quadrupeds), 4)
996                 quadrupeds[0].Age += 1.0
997             finally:
998                 box.flush_all()
999         ts = []
1000         # PostgreSQL, for example, has a default max_connections of 100.
1001         for x in range(99):
1002             t = threading.Thread(target=box_per_thread)
1003             t.start()
1004             ts.append(t)
1005         for t in ts:
1006             t.join()
1007    
1008     def test_Implicit_Transactions(self):
1009         zoostore = arena.storage(Zoo)
1010        
1011         if not hasattr(zoostore, "db"):
1012             print "not a db (skipped) ",
1013             return
1014        
1015         old_implicit = zoostore.db.implicit_trans
1016         try:
1017             def commit_test():
1018                 """Test transaction commit."""
1019                 now = datetime.time(8, 18, 28)
1020                
1021                 box = arena.new_sandbox()
1022                 try:
1023                     WAP = box.unit(Zoo, Name='Wild Animal Park')
1024                     WAP.Opens = now
1025                     box.flush_all()
1026                     WAP = box.unit(Zoo, Name='Wild Animal Park')
1027                     self.assertEqual(WAP.Opens, now)
1028                 finally:
1029                     box.flush_all()
1030            
1031             def rollback_test():
1032                 """Test transaction rollback."""
1033                 box = arena.new_sandbox()
1034                 try:
1035                     SDZ = box.unit(Zoo, Name='San Diego Zoo')
1036                     SDZ.Name = 'The One and Only San Diego Zoo'
1037                     SDZ.Founded = datetime.date(2039, 9, 13)
1038                     box.rollback()
1039                     SDZ = box.unit(Zoo, Name='San Diego Zoo')
1040                     self.assertEqual(SDZ.Name, 'San Diego Zoo')
1041                     self.assertEqual(SDZ.Founded, datetime.date(1835, 9, 13))
1042                 finally:
1043                     box.flush_all()
1044            
1045             zoostore.db.implicit_trans = True
1046             commit_test()
1047             if zoostore.rollback:
1048                 rollback_test()
1049            
1050             zoostore.db.implicit_trans = False
1051             zoostore.start()
1052             commit_test()
1053             if zoostore.rollback:
1054                 zoostore.start()
1055                 rollback_test()
1056         finally:
1057             zoostore.db.implicit_trans = old_implicit
1058    
1059     def test_ContextManagement(self):
1060         # Test context management using Python 2.5 'with ... as'
1061         try:
1062             from dejavu.test import test_context
1063         except SyntaxError:
1064             print "'with ... as' not supported (skipped) ",
1065         else:
1066             test_context.test_with_context(arena)
1067
1068
1069 class NumericTests(unittest.TestCase):
1070    
1071     def test_numbers(self):
1072 ##        print "skipped ",
1073 ##        return
1074        
1075         float_prec = 53
1076         box = arena.new_sandbox()
1077         try:
1078             print "precision:",
1079             # PostgreSQL should be able to go up to 1000 decimal digits (~= 2 ** 10),
1080             # but SQL constants don't actually overflow until 2 ** 15. Meh.
1081             db = getattr(arena.stores['testSM'], "db", None)
1082             if db:
1083                 import math
1084                 maxprec = db.typeadapter.numeric_max_precision
1085                 if maxprec == 0:
1086                     # SQLite, for example, must always use TEXT.
1087                     # So we might as well try... oh... how about 3?
1088                     overflow_prec = 3
1089                 else:
1090                     overflow_prec = int(math.log(maxprec, 2)) + 1
1091             else:
1092                 overflow_prec = 8
1093            
1094             dc = typerefs.decimal.getcontext()
1095            
1096             for prec in xrange(overflow_prec + 1):
1097                 p = 2 ** prec
1098                 print p,
1099                 if p > dc.prec:
1100                     dc.prec = p
1101                
1102                 # We don't need to test <type long> at different 'scales'.
1103                 long_done = False
1104                 # Test scales at both extremes and the median
1105                 for s in (0, int(prec/2), max(prec-1, 0)):
1106                     s = 2 ** s
1107                    
1108                     # Modify the model and storage
1109                     if not long_done:
1110                         arena.drop_property(NothingToDoWithZoos, 'ALong')
1111                         NothingToDoWithZoos.ALong.hints['bytes'] = p
1112                         arena.add_property(NothingToDoWithZoos, 'ALong')
1113                     if p <= float_prec:
1114                         arena.drop_property(NothingToDoWithZoos, 'AFloat')
1115                         NothingToDoWithZoos.AFloat.hints['precision'] = p
1116                         arena.add_property(NothingToDoWithZoos, 'AFloat')
1117                     if typerefs.decimal:
1118                         arena.drop_property(NothingToDoWithZoos, 'ADecimal')
1119                         NothingToDoWithZoos.ADecimal.hints['precision'] = p
1120                         NothingToDoWithZoos.ADecimal.hints['scale'] = s
1121                         arena.add_property(NothingToDoWithZoos, 'ADecimal')
1122                     if typerefs.fixedpoint:
1123                         arena.drop_property(NothingToDoWithZoos, 'AFixed')
1124                         NothingToDoWithZoos.AFixed.hints['precision'] = p
1125                         NothingToDoWithZoos.AFixed.hints['scale'] = s
1126                         arena.add_property(NothingToDoWithZoos, 'AFixed')
1127                    
1128                     # Create an instance and set the specified precision/scale
1129                     nothing = NothingToDoWithZoos()
1130                     if not long_done:
1131                         Lval = (16 ** p) - 1
1132                         setattr(nothing, 'ALong', Lval)
1133                     if p <= float_prec:
1134                         fval = float(((2 ** p) - 1) / (2 ** s))
1135                         setattr(nothing, 'AFloat', fval)
1136                     nval = "1" * p
1137                     nval = nval[:-s] + "." + nval[-s:]
1138                     if typerefs.decimal:
1139                         dval = typerefs.decimal.Decimal(nval)
1140                         setattr(nothing, 'ADecimal', dval)
1141                     if typerefs.fixedpoint:
1142                         # fixedpoint uses "precision" where we use "scale";
1143                         # that is, number of digits after the decimal point.
1144                         fpval = typerefs.fixedpoint.FixedPoint(nval, s)
1145                         setattr(nothing, 'AFixed', fpval)
1146                     box.memorize(nothing)
1147                    
1148                     # Flush and retrieve the object. Use comparisons to test
1149                     # decompilation of imperfect_type when using large numbers.
1150                     if not long_done:
1151                         box.flush_all()
1152                         nothing = box.unit(NothingToDoWithZoos, ALong=Lval)
1153                         if nothing is None:
1154                             self.fail("Unit not found by long property. "
1155                                       "prec=%s scale=%s" % (p, s))
1156                     if p <= float_prec:
1157                         box.flush_all()
1158                         nothing = box.unit(NothingToDoWithZoos, AFloat=fval)
1159                         if nothing is None:
1160                             self.fail("Unit not found by float property. "
1161                                       "prec=%s scale=%s" % (p, s))
1162                     if typerefs.decimal:
1163                         box.flush_all()
1164                         nothing = box.unit(NothingToDoWithZoos, ADecimal=dval)
1165                         if nothing is None:
1166                             self.fail("Unit not found by decimal property. "
1167                                       "prec=%s scale=%s" % (p, s))
1168                     if typerefs.fixedpoint:
1169                         box.flush_all()
1170                         nothing = box.unit(NothingToDoWithZoos, AFixed=fpval)
1171                         if nothing is None:
1172                             self.fail("Unit not found by fixedpoint property. "
1173                                       "prec=%s scale=%s" % (p, s))
1174                    
1175                     # Test retrieved values.
1176                     if not long_done:
1177                         if nothing.ALong != Lval:
1178                             self.fail("%s != %s prec=%s scale=%s" %
1179                                       (`nothing.ALong`, `Lval`, p, s))
1180                     if p <= float_prec:
1181                         if nothing.AFloat != fval:
1182                             self.fail("%s != %s prec=%s scale=%s" %
1183                                       (`nothing.AFloat`, `fval`, p, s))
1184                     if typerefs.decimal:
1185                         if nothing.ADecimal != dval:
1186                             self.fail("%s != %s prec=%s scale=%s" %
1187                                       (`nothing.ADecimal`, `dval`, p, s))
1188                     if typerefs.fixedpoint:
1189                         if nothing.AFixed != fpval:
1190                             self.fail("%s != %s prec=%s scale=%s" %
1191                                       (`nothing.AFixed`, `fpval`, p, s))
1192                     nothing.forget()
1193                     box.flush_all()
1194                     long_done = True
1195         finally:
1196             box.flush_all()
1197
1198
1199 ##class ZooSchema(dejavu.Schema):
1200 ##   
1201 ##    # We set "latest" to 1 so we can test upgrading manually.
1202 ##    latest = 1
1203 ##   
1204 ##    def upgrade_to_2(self):
1205 ##        self.arena.add_property(Animal, "Stomachs")
1206 ##        self.arena.add_property(Animal, "ExhibitID")
1207 ##        box = self.arena.new_sandbox()
1208 ##        for exhibit in box.recall(Exhibit):
1209 ##            for animalID in exhibit.Animals:
1210 ##                # Use the Sandbox magic recaller method.
1211 ##                a = box.Animal(animalID)
1212 ##                if a:
1213 ##                    # Exhibits are identified by ZooID and Name
1214 ##                    a.ZooID = exhibit.ZooID
1215 ##                    a.ExhibitID = exhibit.Name
1216 ##        box.flush_all()
1217 ##   
1218 ##    def upgrade_to_3(self):
1219 ##        Animal.remove_property("Species")
1220 ##        Animal.set_property("Family")
1221 ##       
1222 ##        # Note that we drop this column in a separate step from step 2.
1223 ##        # If we had mixed model properties and SM properties in step 2,
1224 ##        # we could have done this all in one step. But this is a better
1225 ##        # demonstration of the possibilities. ;)
1226 ##        Exhibit.remove_property("Animals")
1227 ##        self.arena.drop_property(Exhibit, "Animals")
1228 ##       
1229 ##        self.arena.rename_property(Animal, "Species", "Family")
1230
1231
1232 db = None
1233
1234 def _geniusqllog(message):
1235     """Dejavu logger (writes to error.log)."""
1236     if isinstance(message, unicode):
1237         message = message.encode('utf8')
1238     s = "%s %s" % (datetime.datetime.now().isoformat(), message)
1239     f = open(logname, 'ab')
1240     f.write(s + '\n')
1241     f.close()
1242
1243 def setup(DB_class, name, opts):
1244     """Set up storage for Zoo classes."""
1245     global db
1246     db = geniusql.db(DB_class, name, opts)
1247     db.log = _geniusqllog
1248     print db.version()
1249     db.create_database()
1250
1251 def teardown():
1252     """Tear down storage for Zoo classes."""
1253     try:
1254         db.drop_database()
1255     except (AttributeError, NotImplementedError):
1256         pass
1257     db.disconnect()
1258
1259 def run(DB_class, name, opts):
1260     """Run the zoo fixture."""
1261     try:
1262         try:
1263             setup(DB_class, name, opts)
1264             loader = unittest.TestLoader().loadTestsFromTestCase
1265            
1266             # Run the ZooTests and time it.
1267             zoocase = loader(ZooTests)
1268             startTime = datetime.datetime.now()
1269             tools.TestRunner.run(zoocase)
1270             print "Ran zoo cases in:", datetime.datetime.now() - startTime
1271 ##           
1272 ##            # Run the other cases.
1273 ##            tools.TestRunner.run(loader(NumericTests))
1274 ##            tools.TestRunner.run(loader(ConcurrencyTests))
1275 ##            s = arena.stores.values()[0]
1276 ##            if hasattr(s, "db"):
1277 ##                tools.TestRunner.run(loader(IsolationTests))
1278 ##                tools.TestRunner.run(loader(DiscoveryTests))
1279         except:
1280             traceback.print_exc()
1281     finally:
1282         teardown()
Note: See TracBrowser for help on using the browser.