1import codecs
2import datetime
3import os
4import sys
5import unittest
6import tempfile
7import shutil
8import stat
9import warnings
10from unittest import skipIf, skipUnless, TestCase as unittest_TestCase
11
12py_ver = sys.version_info[:2]
13module = globals()
14
15from dbf import *
16import dbf
17
18try:
19    import pytz
20except ImportError:
21    pytz = None
22
23if py_ver < (3, 0):
24    MISC = ''.join([chr(i) for i in range(256)])
25    PHOTO = ''.join(reversed([chr(i) for i in range(256)]))
26else:
27    unicode = str
28    xrange = range
29    module.update(dbf.LatinByte.__members__)
30    MISC = ''.join([chr(i) for i in range(256)]).encode('latin-1')
31    PHOTO = ''.join(reversed([chr(i) for i in range(256)])).encode('latin-1')
32
33try:
34    with warnings.catch_warnings():
35        warnings.warn('test if warning is an exception', dbf.DbfWarning, stacklevel=1)
36        warnings_are_exceptions = False
37except dbf.DbfWarning:
38    warnings_are_exceptions = True
39
40print("\nTesting dbf version %d.%02d.%03d on %s with Python %s\n" % (
41    dbf.version[:3] + (sys.platform, sys.version) ))
42
43
44class TestCase(unittest_TestCase):
45
46    def __init__(self, *args, **kwds):
47        regex = getattr(self, 'assertRaisesRegex', None)
48        if regex is None:
49            self.assertRaisesRegex = getattr(self, 'assertRaisesRegexp')
50        super(TestCase, self).__init__(*args, **kwds)
51
52
53# Walker in Leaves -- by Scot Noel -- http://www.scienceandfantasyfiction.com/sciencefiction/Walker-in-Leaves/walker-in-leaves.htm
54
55words = """
56Soft rains, given time, have rounded the angles of great towers. Generation after generation, wind borne seeds have brought down cities amid the gentle tangle of their roots. All statues of stone have been worn away.
57Still one statue, not of stone, holds its lines against the passing years.
58Sunlight, fading autumn light, warms the sculpture as best it can, almost penetrating to its dreaming core. The figure is that of a woman, once the fair sex of a species now untroubled and long unseen. Man sleeps the sleep of extinction. This one statue remains. Behind the grace of its ivory brow and gentle, unseeing eyes, the statue dreams.
59A susurrus of voices, a flutter of images, and the dream tumbles down through the long morning. Suspended. Floating on the stream that brings from the heart of time the wandering self. Maya  for that is the statue s name-- is buoyed by the sensation, rising within the cage of consciousness, but asleep. She has been this way for months: the unmoving figure of a woman caught in mid stride across the glade. The warmth of sunlight on her face makes her wonder if she will ever wake again.
60Even at the end, there was no proper word for what Maya has become. Robot. Cybernetic Organism. Android. These are as appropriate to her condition as calling the stars campfires of the night sky and equally precise. It is enough to know that her motive energies are no longer sun and sustenance, and though Maya was once a living woman, a scientist, now she inhabits a form of ageless attraction. It is a form whose energies are flagging.
61With great determination, Maya moves toward wakefulness. Flex a finger. Move a hand. Think of the lemurs, their tongues reaching out in stroke after stroke for the drip of the honeyed thorns. Though there is little time left to save her charges, Maya s only choice is the patience of the trees. On the day her energies return, it is autumn of the year following the morning her sleep began. Maya opens her eyes. The woman, the frozen machine --that which is both-- moves once more.
62Two lemur cubs tumbling near the edge of the glade take notice. One rushes forward to touch Maya s knee and laugh. Maya reaches out with an arthritic hand, cold in its sculpted smoothness, but the lemur darts away. Leaves swirl about its retreat, making a crisp sound. The cub displays a playfulness Maya s fevered mind cannot match. The second cub rolls between her moss covered feet, laughing. The lemurs are her charges, and she is failing them. Still, it is good to be awake.
63Sugar maples and sumacs shoulder brilliant robes. In the low sun, their orange and purple hues startle the heart. Of course, Maya has no beating organ, no heart. Her life energies are transmitted from deep underground. Nor are the cubs truly lemurs, nor the sugar maples the trees of old. The names have carried for ten million seasons, but the species have changed. Once the lemurs inhabited an island off the southeast coast of a place called Africa. Now they are here, much changed, in the great forests of the northern climes.
64The young lemurs seem hale, and it speaks well for their consanguine fellows. But their true fate lies in the story of DNA, of a few strands in the matriarchal line, of a sequence code-named "hope." No doubt a once clever acronym, today Maya s clouded mind holds nothing of the ancient codes. She knows only that a poet once spoke of hope as "the thing with feathers that perches in the soul." Emily Dickinson. A strange name, and so unlike the agnomen of the lemurs. What has become of Giver-of-Corn?
65Having no reason to alarm the cubs, Maya moves with her hands high, so that any movement will be down as leaves fall. Though anxious about Giver-of-Corn, she ambles on to finish the mission begun six months earlier. Ahead, the shadow of a mound rises up beneath a great oak. A door awaits. Somewhere below the forest, the engine that gives her life weakens. Held in sway to its faltering beat her mind and body froze, sending her into an abyss of dreams. She has been striding toward that door for half a year, unknowing if she would ever wake again.
66Vines lose their toughened grip as the door responds to Maya s approach. Regretfully, a tree root snaps, but the door shudders to a halt before its whine of power can cross the glade. Suddenly, an opening has been made into the earth, and Maya steps lightly on its downward slope. Without breathing, she catches a scent of mold and of deep, uncirculated water. A flutter like the sound of wings echoes from the hollow. Her vision adjusts as she descends. In spots, lights attempt to greet her, but it is a basement she enters, flickering and ancient, where the footfalls of millipedes wear tracks in grime older than the forest above. After a long descent, she steps into water.
67How long ago was it that the floor was dry? The exactitude of such time, vast time, escapes her.
68Once this place sustained great scholars, scientists. Now sightless fish skip through broken walls, retreating as Maya wades their private corridors, finding with each step that she remembers the labyrinthine path to the heart of power. A heart that flutters like dark wings. And with it, she flutters too. The closer she comes to the vault in which the great engine is housed, the less hopeful she becomes.
69The vault housing the engine rests beneath a silvered arch. Its mirrored surface denies age, even as a new generation of snails rise up out of the dark pool, mounting first the dais of pearled stone left by their ancestors, the discarded shells of millions, then higher to where the overhang drips, layered in egg sacs bright as coral.
70Maya has no need to set the vault door in motion, to break the dance of the snails. The state of things tells her all she needs to know. There shall be no repairs, no rescue; the engine will die, and she with it. Still, it is impossible not to check. At her touch, a breath of firefly lights coalesces within the patient dampness of the room. They confirm. The heart is simply too tired to go on. Its last reserves wield processes of great weight and care, banking the fires of its blood, dimming the furnace into safe resolve. Perhaps a month or two in cooling, then the last fire kindled by man shall die.
71For the figure standing knee deep in water the issues are more immediate. The powers that allow her to live will be the first to fade. It is amazing, even now, that she remains cognizant.
72For a moment, Maya stands transfixed by her own reflection. The silvered arch holds it as moonlight does a ghost. She is a sculpted thing with shoulders of white marble. Lips of stone. A child s face. No, the grace of a woman resides in the features, as though eternity can neither deny the sage nor touch the youth. Demeter. The Earth Mother.
73Maya smiles at the Greek metaphor. She has never before thought of herself as divine, nor monumental. When the energies of the base are withdrawn entirely, she will become immobile. Once a goddess, then a statue to be worn away by endless time, the crumbling remnant of something the self has ceased to be. Maya trembles at the thought. The last conscious reserve of man will soon fade forever from the halls of time.
74As if hewn of irresolute marble, Maya begins to shake; were she still human there would be sobs; there would be tears to moisten her grief and add to the dark waters at her feet.
75In time, Maya breaks the spell. She sets aside her grief to work cold fingers over the dim firefly controls, giving what priorities remain to her survival. In response, the great engine promises little, but does what it can.
76While life remains, Maya determines to learn what she can of the lemurs, of their progress, and the fate of the matriarchal line. There will be time enough for dreams. Dreams. The one that tumbled down through the long morning comes to her and she pauses to consider it. There was a big table. Indistinct voices gathered around it, but the energy of a family gathering filled the space. The warmth of the room curled about her, perfumed by the smell of cooking. An ancient memory, from a time before the shedding of the flesh. Outside, children laughed. A hand took hers in its own, bringing her to a table filled with colorful dishes and surrounded by relatives and friends. Thanksgiving?
77They re calling me home, Maya thinks. If indeed her ancestors could reach across time and into a form not of the flesh, perhaps that was the meaning of the dream. I am the last human consciousness, and I am being called home.
78With a flutter, Maya is outside, and the trees all but bare of leaves. Something has happened. Weeks have passed and she struggles to take in her situation. This time she has neither dreamed nor stood immobile, but she has been active without memory.
79Her arms cradle a lemur, sheltering the pubescent female against the wind. They sit atop a ridge that separates the valley from the forest to the west, and Walker-in-Leaves has been gone too long. That much Maya remembers. The female lemur sighs. It is a rumbling, mournful noise, and she buries her head tighter against Maya. This is Giver-of-Corn, and Walker is her love.
80With her free hand, Maya works at a stiff knitting of pine boughs, the blanket which covers their legs. She pulls it up to better shelter Giver-of-Corn. Beside them, on a shell of bark, a sliver of fish has gone bad from inattention.
81They wait through the long afternoon, but Walker does not return. When it is warmest and Giver sleeps, Maya rises in stages, gently separating herself from the lemur. She covers her charge well. Soon it will snow.
82There are few memories after reaching the vault, only flashes, and that she has been active in a semi-consciousness state frightens Maya. She stumbles away, shaking, but there is no comfort to seek. She does not know if her diminished abilities endanger the lemurs, and considers locking herself beneath the earth. But the sun is warm, and for the moment every thought is a cloudless sky. Memories descend from the past like a lost tribe wandering for home.
83To the east lie once powerful lands and remembered sepulchers. The life of the gods, the pulse of kings, it has all vanished and gone. Maya thinks back to the days of man. There was no disaster at the end. Just time. Civilization did not fail, it succumbed to endless seasons. Each vast stretch of years drawn on by the next saw the conquest of earth and stars, then went on, unheeding, until man dwindled and his monuments frayed.
84To the west rise groves of oaks and grassland plains, beyond them, mountains that shrugged off civilization more easily than the rest.
85Where is the voyager in those leaves?
86A flash of time and Maya finds herself deep in the forests to the west. A lemur call escapes her throat, and suddenly she realizes she is searching for Walker-in-Leaves. The season is the same. Though the air is crisp, the trees are not yet unburdened of their color.
87"Walker!" she calls out. "Your love is dying. She mourns your absence."
88At the crest of a rise, Maya finds another like herself, but one long devoid of life. This sculpted form startles her at first. It has been almost wholly absorbed into the trunk of a great tree. The knee and calf of one leg escape the surrounding wood, as does a shoulder, the curve of a breast, a mournful face. A single hand reaches out from the tree toward the valley below.
89In the distance, Maya sees the remnants of a fallen orbiter. Its power nacelle lies buried deep beneath the river that cushioned its fall. Earth and water, which once heaved at the impact, have worn down impenetrable metals and grown a forest over forgotten technologies.
90Had the watcher in the tree come to see the fall, or to stand vigil over the corpse? Maya knows only that she must go on before the hills and the trees conspire to bury her. She moves on, continuing to call for Walker-in-Leaves.
91In the night, a coyote finally answers Maya, its frenetic howls awakening responses from many cousins, hunting packs holding court up and down the valley.
92Giver-of-Corn holds the spark of her generation. It is not much. A gene here and there, a deep manipulation of the flesh. The consciousness that was man is not easy to engender. Far easier to make an eye than a mind to see. Along a path of endless complication, today Giver-of-Corn mourns the absence of her mate. That Giver may die of such stubborn love before passing on her genes forces Maya deeper into the forest, using the last of her strength to call endlessly into the night.
93Maya is dreaming. It s Thanksgiving, but the table is cold. The chairs are empty, and no one answers her call. As she walks from room to room, the lights dim and it begins to rain within the once familiar walls.
94When Maya opens her eyes, it is to see Giver-of-Corm sleeping beneath a blanket of pine boughs, the young lemur s bushy tail twitching to the rhythm of sorrowful dreams. Maya is awake once more, but unaware of how much time has passed, or why she decided to return. Her most frightening thought is that she may already have found Walker-in-Leaves, or what the coyotes left behind.
95Up from the valley, two older lemurs walk arm in arm, supporting one another along the rise. They bring with them a twig basket and a pouch made of hide. The former holds squash, its hollowed interior brimming with water, the latter a corn mash favored by the tribe. They are not without skills, these lemurs. Nor is language unknown to them. They have known Maya forever and treat her, not as a god, but as a force of nature.
96With a few brief howls, by clicks, chatters, and the sweeping gestures of their tails, the lemurs make clear their plea. Their words all but rhyme. Giver-of-Corn will not eat for them. Will she eat for Maya?
97Thus has the mission to found a new race come down to this: with her last strength, Maya shall spoon feed a grieving female. The thought strikes her as both funny and sad, while beyond her thoughts, the lemurs continue to chatter.
98Scouts have been sent, the elders assure Maya, brave sires skilled in tracking. They hope to find Walker before the winter snows. Their voices stir Giver, and she howls in petty anguish at her benefactors, then disappears beneath the blanket. The elders bow their heads and turn to go, oblivious of Maya s failures.
99Days pass upon the ridge in a thickness of clouds. Growing. Advancing. Dimmed by the mountainous billows above, the sun gives way to snow, and Maya watches Giver focus ever more intently on the line to the west. As the lemur s strength fails, her determination to await Walker s return seems to grow stronger still.
100Walker-in-Leaves holds a spark of his own. He alone ventures west after the harvest. He has done it before, always returning with a colored stone, a bit of metal, or a flower never before seen by the tribe. It is as if some mad vision compels him, for the journey s end brings a collection of smooth and colored booty to be arranged in a crescent beneath a small monolith Walker himself toiled to raise. Large stones and small, the lemur has broken two fingers of its left hand doing this. To Maya, it seems the ambition of butterflies and falling leaves, of no consequence beyond a motion in the sun. The only importance now is to keep the genes within Giver alive.
101Long ago, an ambition rose among the last generation of men, of what had once been men: to cultivate a new consciousness upon the Earth. Maya neither led nor knew the masters of the effort, but she was there when the first prosimians arrived, fresh from their land of orchids and baobabs. Men gathered lemurs and said to them "we shall make you men." Long years followed in the work of the genes, gentling the generations forward. Yet with each passing season, the cultivators grew fewer and their skills less true. So while the men died of age, or boredom, or despair, the lemurs prospered in their youth.
102To warm the starving lemur, Maya builds a fire. For this feat the tribe has little skill, nor do they know zero, nor that a lever can move the world. She holds Giver close and pulls the rough blanket of boughs about them both.
103All this time, Maya s thoughts remain clear, and the giving of comfort comforts her as well.
104The snow begins to cover the monument Walker-in-Leaves has built upon the ridge. As Maya stares on and on into the fire, watching it absorb the snow, watching the snow conquer the cold stones and the grasses already bowed under a cloak of white, she drifts into a flutter of reverie, a weakening of consciousness. The gate to the end is closing, and she shall never know  never know.
105"I ll take it easy like, an  stay around de house this winter," her father said. "There s carpenter work for me to do."
106Other voices joined in around a table upon which a vast meal had been set. Thanksgiving. At the call of their names, the children rushed in from outside, their laughter quick as sunlight, their jackets smelling of autumn and leaves. Her mother made them wash and bow their heads in prayer. Those already seated joined in.
107Grandmother passed the potatoes and called Maya her little kolache, rattling on in a series of endearments and concerns Maya s ear could not follow. Her mother passed on the sense of it and reminded Maya of the Czech for Thank you, Grandma.
108It s good to be home, she thinks at first, then: where is the walker in those leaves?
109A hand on which two fingers lay curled by the power of an old wound touches Maya. It shakes her, then gently moves her arms so that its owner can pull back the warm pine boughs hiding Giver-of Corn. Eyes first, then smile to tail, Giver opens herself to the returning wanderer. Walker-in-Leaves has returned, and the silence of their embrace brings the whole of the ridge alive in a glitter of sun-bright snow. Maya too comes awake, though this time neither word nor movement prevails entirely upon the fog of sleep.
110When the answering howls come to the ridge, those who follow help Maya to stand. She follows them back to the shelter of the valley, and though she stumbles, there is satisfaction in the hurried gait, in the growing pace of the many as they gather to celebrate the return of the one. Songs of rejoicing join the undisciplined and cacophonous barks of youth. Food is brought, from the deep stores, from the caves and their recesses. Someone heats fish over coals they have kept sheltered and going for months. The thought of this ingenuity heartens Maya.
111A delicacy of honeyed thorns is offered with great ceremony to Giver-of-Corn, and she tastes at last something beyond the bitterness of loss.
112Though Walker-in-Leaves hesitates to leave the side of his love, the others demand stories, persuading him to the center where he begins a cacophonous song of his own.
113Maya hopes to see what stones Walker has brought from the west this time, but though she tries to speak, the sounds are forgotten. The engine fades. The last flicker of man s fire is done, and with it the effort of her desires overcome her. She is gone.
114Around a table suited for the Queen of queens, a thousand and a thousand sit. Mother to daughter, side-by-side, generation after generation of lemurs share in the feast. Maya is there, hearing the excited voices and the stern warnings to prayer. To her left and her right, each daughter speaks freely. Then the rhythms change, rising along one side to the cadence of Shakespeare and falling along the other to howls the forest first knew.
115Unable to contain herself, Maya rises. She pushes on toward the head of a table she cannot see, beginning at last to run. What is the height her charges have reached? How far have they advanced? Lemur faces turn to laugh, their wide eyes joyous and amused. As the generations pass, she sees herself reflected in spectacles, hears the jangle of bracelets and burnished metal, watches matrons laugh behind scarves of silk. Then at last, someone with sculpted hands directs her outside, where the other children are at play in the leaves, now and forever.
116THE END""".split()
117
118# data
119numbers = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541]
120floats = []
121last = 1
122for number in numbers:
123    floats.append(float(number ** 2 / last))
124    last = number
125
126def permutate(Xs, N):
127    if N <= 0:
128        yield []
129        return
130    for x in Xs:
131        for sub in permutate(Xs, N-1):
132            result = [x]+sub                    # don't allow duplicates
133            for item in result:
134                if result.count(item) > 1:
135                    break
136            else:
137                yield result
138
139def combinate(Xs, N):
140    """Generate combinations of N items from list Xs"""
141    if N == 0:
142        yield []
143        return
144    for i in xrange(len(Xs)-N+1):
145        for r in combinate(Xs[i+1:], N-1):
146            yield [Xs[i]] + r
147
148def index(sequence):
149    "returns integers 0 - len(sequence)"
150    for i in xrange(len(sequence)):
151        yield i
152
153# tests
154def active(rec):
155    if is_deleted(rec):
156        return DoNotIndex
157    return dbf.recno(rec)
158
159def inactive(rec):
160    if is_deleted(rec):
161        return recno(rec)
162    return DoNotIndex
163
164def unicodify(data):
165    if isinstance(data, list):
166        for i, item in enumerate(data):
167            data[i] = unicode(item)
168        return data
169    elif isinstance(data, dict):
170        new_data = {}
171        for k, v in data.items():
172            new_data[unicode(k)] = v
173        return new_data
174    else:
175        raise TypeError('unknown type: %r' % (data, ))
176
177class TestChar(TestCase):
178
179    def test_exceptions(self):
180        "exceptions"
181        self.assertRaises(ValueError, Char, 7)
182        self.assertRaises(ValueError, Char, [u'nope'])
183        self.assertRaises(ValueError, Char, True)
184        self.assertRaises(ValueError, Char, False)
185        self.assertRaises(ValueError, Char, type)
186        self.assertRaises(ValueError, Char, str)
187        self.assertRaises(ValueError, Char, None)
188
189    def test_bools_and_none(self):
190        "booleans and None"
191        empty = Char()
192        self.assertFalse(bool(empty))
193        one = Char(u' ')
194        self.assertFalse(bool(one))
195        actual = Char(u'1')
196        self.assertTrue(bool(actual))
197
198    def test_equality(self):
199        "equality"
200        a1 = Char(u'a')
201        a2 = u'a '
202        self.assertEqual(a1, a2)
203        self.assertEqual(a2, a1)
204        a3 = u'a '
205        a4 = Char(u'a ')
206        self.assertEqual(a3, a4)
207        self.assertEqual(a4, a3)
208
209    def test_inequality(self):
210        "inequality"
211        a1 = Char(u'ab ')
212        a2 = u'a b'
213        self.assertNotEqual(a1, a2)
214        self.assertNotEqual(a2, a1)
215        a3 = u'ab '
216        a4 = Char(u'a b')
217        self.assertNotEqual(a3, a4)
218        self.assertNotEqual(a4, a3)
219
220    def test_less_than(self):
221        "less-than"
222        a1 = Char(u'a')
223        a2 = u'a '
224        self.assertFalse(a1 < a2)
225        self.assertFalse(a2 < a1)
226        a3 = u'a '
227        a4 = Char(u'a ')
228        self.assertFalse(a3 < a4)
229        self.assertFalse(a4 < a3)
230        a5 = u'abcd'
231        a6 = u'abce'
232        self.assertTrue(a5 < a6)
233        self.assertFalse(a6 < a5)
234
235    def test_less_than_equal(self):
236        "less-than or equal"
237        a1 = Char(u'a')
238        a2 = u'a '
239        self.assertTrue(a1 <= a2)
240        self.assertTrue(a2 <= a1)
241        a3 = u'a '
242        a4 = Char(u'a ')
243        self.assertTrue(a3 <= a4)
244        self.assertTrue(a4 <= a3)
245        a5 = u'abcd'
246        a6 = u'abce'
247        self.assertTrue(a5 <= a6)
248        self.assertFalse(a6 <= a5)
249
250    def test_greater_than(self):
251        "greater-than or equal"
252        a1 = Char(u'a')
253        a2 = u'a '
254        self.assertTrue(a1 >= a2)
255        self.assertTrue(a2 >= a1)
256        a3 = u'a '
257        a4 = Char(u'a ')
258        self.assertTrue(a3 >= a4)
259        self.assertTrue(a4 >= a3)
260        a5 = u'abcd'
261        a6 = u'abce'
262        self.assertFalse(a5 >= a6)
263        self.assertTrue(a6 >= a5)
264
265    def test_greater_than_equal(self):
266        "greater-than"
267        a1 = Char(u'a')
268        a2 = u'a '
269        self.assertFalse(a1 > a2)
270        self.assertFalse(a2 > a1)
271        a3 = u'a '
272        a4 = Char(u'a ')
273        self.assertFalse(a3 > a4)
274        self.assertFalse(a4 > a3)
275        a5 = u'abcd'
276        a6 = u'abce'
277        self.assertFalse(a5 > a6)
278        self.assertTrue(a6 > a5)
279
280
281class TestDateTime(TestCase):
282    "Testing Date"
283
284    def test_date_creation(self):
285        "Date creation"
286        self.assertEqual(Date(), NullDate)
287        self.assertEqual(Date.fromymd('        '), NullDate)
288        self.assertEqual(Date.fromymd('00000000'), NullDate)
289        self.assertEqual(Date.fromordinal(0), NullDate)
290        self.assertEqual(Date.today(), datetime.date.today())
291        self.assertEqual(Date.max, datetime.date.max)
292        self.assertEqual(Date.min, datetime.date.min)
293        self.assertEqual(Date(2018, 5, 21), datetime.date(2018, 5, 21))
294        self.assertEqual(Date.strptime('2018-01-01'), datetime.date(2018, 1, 1))
295        self.assertRaises(ValueError, Date.fromymd, '00000')
296        self.assertRaises(ValueError, Date, 0, 0, 0)
297
298    def test_date_compare(self):
299        "Date comparisons"
300        nodate1 = Date()
301        nodate2 = Date()
302        date1 = Date.fromordinal(1000)
303        date2 = Date.fromordinal(2000)
304        date3 = Date.fromordinal(3000)
305        self.compareTimes(nodate1, nodate2, date1, date2, date3)
306
307    def test_datetime_creation(self):
308        "DateTime creation"
309        self.assertEqual(DateTime(), NullDateTime)
310        self.assertEqual(DateTime.fromordinal(0), NullDateTime)
311        self.assertTrue(DateTime.today())
312        self.assertEqual(DateTime.max, datetime.datetime.max)
313        self.assertEqual(DateTime.min, datetime.datetime.min)
314        self.assertEqual(DateTime(2018, 5, 21, 19, 17, 16), datetime.datetime(2018, 5, 21, 19, 17 ,16))
315        self.assertEqual(DateTime.strptime('2018-01-01 19:17:16'), datetime.datetime(2018, 1, 1, 19, 17, 16))
316
317    def test_datetime_compare(self):
318        "DateTime comparisons"
319        nodatetime1 = DateTime()
320        nodatetime2 = DateTime()
321        datetime1 = DateTime.fromordinal(1000)
322        datetime2 = DateTime.fromordinal(20000)
323        datetime3 = DateTime.fromordinal(300000)
324        self.compareTimes(nodatetime1, nodatetime2, datetime1, datetime2, datetime3)
325
326    def test_datetime_replace(self):
327        "DateTime replacements"
328        datetime_target = DateTime(2001, 5, 31, 23, 59, 59, 999000)
329        datetime1 = datetime.datetime(2001, 5, 31, 23, 59, 59, 999230)
330        datetime2 = datetime.datetime(2001, 5, 31, 23, 59, 59, 999500)
331        datetime3 = datetime.datetime(2001, 5, 31, 23, 59, 59, 999728)
332        original_datetime = datetime.datetime
333        for dt in (datetime1, datetime2, datetime3):
334            class DateTimeNow(datetime.datetime):
335                @classmethod
336                def now(self):
337                    datetime.datetime = original_datetime
338                    return dt
339            datetime.datetime = DateTimeNow
340            result = DateTime.now()
341            self.assertEqual(result, datetime_target, 'in: %r  out: %r  desired: %r' % (dt, result, datetime_target))
342
343    def test_time_creation(self):
344        "Time creation"
345        self.assertEqual(Time(), NullTime)
346        self.assertEqual(Time.max, datetime.time.max)
347        self.assertEqual(Time.min, datetime.time.min)
348        self.assertEqual(Time(19, 17, 16), datetime.time(19, 17 ,16))
349        self.assertEqual(Time.strptime('19:17:16'), datetime.time(19, 17, 16))
350
351    def test_time_compare(self):
352        "Time comparisons"
353        notime1 = Time()
354        notime2 = Time()
355        time1 = Time.fromfloat(7.75)
356        time2 = Time.fromfloat(9.5)
357        time3 = Time.fromfloat(16.25)
358        self.compareTimes(notime1, notime2, time1, time2, time3)
359
360    @unittest.skipIf(pytz is None, 'pytz not installed')
361    def test_datetime_tz(self):
362        "DateTime with Time Zones"
363        pst = pytz.timezone('America/Los_Angeles')
364        mst = pytz.timezone('America/Boise')
365        cst = pytz.timezone('America/Chicago')
366        est = pytz.timezone('America/New_York')
367        utc = pytz.timezone('UTC')
368        #
369        pdt = DateTime(2018, 5, 20, 5, 41, 33, tzinfo=pst)
370        mdt = DateTime(2018, 5, 20, 6, 41, 33, tzinfo=mst)
371        cdt = DateTime(2018, 5, 20, 7, 41, 33, tzinfo=cst)
372        edt = DateTime(2018, 5, 20, 8, 41, 33, tzinfo=est)
373        udt = DateTime(2018, 5, 20, 12, 41, 33, tzinfo=utc)
374        self.assertTrue(pdt == mdt == cdt == edt == udt)
375        #
376        dup1 = DateTime.combine(pdt.date(), mdt.timetz())
377        dup2 = DateTime.combine(cdt.date(), Time(5, 41, 33, tzinfo=pst))
378        self.assertTrue(dup1 == dup2 == udt)
379        #
380        udt2 = DateTime(2018, 5, 20, 13, 41, 33, tzinfo=utc)
381        mdt2 = mdt.replace(tzinfo=pst)
382        self.assertTrue(mdt2 == udt2)
383        #
384        with self.assertRaisesRegex(ValueError, 'not naive datetime'):
385            DateTime(pdt, tzinfo=mst)
386        with self.assertRaisesRegex(ValueError, 'not naive datetime'):
387            DateTime(datetime.datetime(2018, 5, 27, 15, 57, 11, tzinfo=pst), tzinfo=pst)
388        with self.assertRaisesRegex(ValueError, 'not naive time'):
389            Time(pdt.timetz(), tzinfo=mst)
390        with self.assertRaisesRegex(ValueError, 'not naive time'):
391            Time(datetime.time(15, 58, 59, tzinfo=mst), tzinfo=mst)
392        #
393        if py_ver < (3, 0):
394            from xmlrpclib import Marshaller, loads
395        else:
396            from xmlrpc.client import Marshaller, loads
397        self.assertEqual(
398                udt.utctimetuple(),
399                loads(Marshaller().dumps([pdt]), use_datetime=True)[0][0].utctimetuple(),
400                )
401        #
402        self.assertEqual(
403                pdt,
404                DateTime.combine(Date(2018, 5, 20), Time(5, 41, 33), tzinfo=pst),
405                )
406
407    def test_arithmetic(self):
408        "Date, DateTime, & Time Arithmetic"
409        one_day = datetime.timedelta(1)
410        a_day = Date(1970, 5, 20)
411        self.assertEqual(a_day + one_day, Date(1970, 5, 21))
412        self.assertEqual(a_day - one_day, Date(1970, 5, 19))
413        self.assertEqual(datetime.date(1970, 5, 21) - a_day, one_day)
414        a_time = Time(12)
415        one_second = datetime.timedelta(0, 1, 0)
416        self.assertEqual(a_time + one_second, Time(12, 0, 1))
417        self.assertEqual(a_time - one_second, Time(11, 59, 59))
418        self.assertEqual(datetime.time(12, 0, 1) - a_time, one_second)
419        an_appt = DateTime(2012, 4, 15, 12, 30, 00)
420        displacement = datetime.timedelta(1, 60*60*2+60*15)
421        self.assertEqual(an_appt + displacement, DateTime(2012, 4, 16, 14, 45, 0))
422        self.assertEqual(an_appt - displacement, DateTime(2012, 4, 14, 10, 15, 0))
423        self.assertEqual(datetime.datetime(2012, 4, 16, 14, 45, 0) - an_appt, displacement)
424
425    def test_none_compare(self):
426        "comparisons to None"
427        empty_date = Date()
428        empty_time = Time()
429        empty_datetime = DateTime()
430        self.assertEqual(empty_date, None)
431        self.assertEqual(empty_time, None)
432        self.assertEqual(empty_datetime, None)
433
434    def test_singletons(self):
435        "singletons"
436        empty_date = Date()
437        empty_time = Time()
438        empty_datetime = DateTime()
439        self.assertTrue(empty_date is NullDate)
440        self.assertTrue(empty_time is NullTime)
441        self.assertTrue(empty_datetime is NullDateTime)
442
443    def test_boolean_value(self):
444        "boolean evaluation"
445        empty_date = Date()
446        empty_time = Time()
447        empty_datetime = DateTime()
448        self.assertEqual(bool(empty_date), False)
449        self.assertEqual(bool(empty_time), False)
450        self.assertEqual(bool(empty_datetime), False)
451        actual_date = Date.today()
452        actual_time = Time.now()
453        actual_datetime = DateTime.now()
454        self.assertEqual(bool(actual_date), True)
455        self.assertEqual(bool(actual_time), True)
456        self.assertEqual(bool(actual_datetime), True)
457
458    def compareTimes(self, empty1, empty2, uno, dos, tres):
459        self.assertTrue(empty1 is empty2)
460        self.assertTrue(empty1 < uno, '%r is not less than %r' % (empty1, uno))
461        self.assertFalse(empty1 > uno, '%r is less than %r' % (empty1, uno))
462        self.assertTrue(uno > empty1, '%r is not greater than %r' % (empty1, uno))
463        self.assertFalse(uno < empty1, '%r is greater than %r' % (empty1, uno))
464        self.assertEqual(uno < dos, True)
465        self.assertEqual(uno <= dos, True)
466        self.assertEqual(dos <= dos, True)
467        self.assertEqual(dos <= tres, True)
468        self.assertEqual(dos < tres, True)
469        self.assertEqual(tres <= tres, True)
470        self.assertEqual(uno == uno, True)
471        self.assertEqual(dos == dos, True)
472        self.assertEqual(tres == tres, True)
473        self.assertEqual(uno != dos, True)
474        self.assertEqual(dos != tres, True)
475        self.assertEqual(tres != uno, True)
476        self.assertEqual(tres >= tres, True)
477        self.assertEqual(tres > dos, True)
478        self.assertEqual(dos >= dos, True)
479        self.assertEqual(dos >= uno, True)
480        self.assertEqual(dos > uno, True)
481        self.assertEqual(uno >= uno, True)
482        self.assertEqual(uno >= dos, False)
483        self.assertEqual(uno >= tres, False)
484        self.assertEqual(dos >= tres, False)
485        self.assertEqual(tres <= dos, False)
486        self.assertEqual(tres <= uno, False)
487        self.assertEqual(tres < tres, False)
488        self.assertEqual(tres < dos, False)
489        self.assertEqual(tres < uno, False)
490        self.assertEqual(dos < dos, False)
491        self.assertEqual(dos < uno, False)
492        self.assertEqual(uno < uno, False)
493        self.assertEqual(uno == dos, False)
494        self.assertEqual(uno == tres, False)
495        self.assertEqual(dos == uno, False)
496        self.assertEqual(dos == tres, False)
497        self.assertEqual(tres == uno, False)
498        self.assertEqual(tres == dos, False)
499        self.assertEqual(uno != uno, False)
500        self.assertEqual(dos != dos, False)
501        self.assertEqual(tres != tres, False)
502
503
504class TestNull(TestCase):
505
506    def test_all(self):
507        NULL = Null = dbf.Null()
508        self.assertTrue(NULL is dbf.Null())
509
510        self.assertTrue(NULL + 1 is Null)
511        self.assertTrue(1 + NULL is Null)
512        NULL += 4
513        self.assertTrue(NULL is Null)
514        value = 5
515        value += NULL
516        self.assertTrue(value is Null)
517
518        self.assertTrue(NULL - 2 is Null)
519        self.assertTrue(2 - NULL is Null)
520        NULL -= 5
521        self.assertTrue(NULL is Null)
522        value = 6
523        value -= NULL
524        self.assertTrue(value is Null)
525
526        self.assertTrue(NULL / 0 is Null)
527        self.assertTrue(3 / NULL is Null)
528        NULL /= 6
529        self.assertTrue(NULL is Null)
530        value = 7
531        value /= NULL
532        self.assertTrue(value is Null)
533
534        self.assertTrue(NULL * -3 is Null)
535        self.assertTrue(4 * NULL is Null)
536        NULL *= 7
537        self.assertTrue(NULL is Null)
538        value = 8
539        value *= NULL
540        self.assertTrue(value is Null)
541
542        self.assertTrue(NULL % 1 is Null)
543        self.assertTrue(7 % NULL is Null)
544        NULL %= 1
545        self.assertTrue(NULL is Null)
546        value = 9
547        value %= NULL
548        self.assertTrue(value is Null)
549
550        self.assertTrue(NULL ** 2 is Null)
551        self.assertTrue(4 ** NULL is Null)
552        NULL **= 3
553        self.assertTrue(NULL is Null)
554        value = 9
555        value **= NULL
556        self.assertTrue(value is Null)
557
558        self.assertTrue(NULL & 1 is Null)
559        self.assertTrue(1 & NULL is Null)
560        NULL &= 1
561        self.assertTrue(NULL is Null)
562        value = 1
563        value &= NULL
564        self.assertTrue(value is Null)
565
566        self.assertTrue(NULL ^ 1 is Null)
567        self.assertTrue(1 ^ NULL is Null)
568        NULL ^= 1
569        self.assertTrue(NULL is Null)
570        value = 1
571        value ^= NULL
572        self.assertTrue(value is Null)
573
574        self.assertTrue(NULL | 1 is Null)
575        self.assertTrue(1 | NULL is Null)
576        NULL |= 1
577        self.assertTrue(NULL is Null)
578        value = 1
579        value |= NULL
580        self.assertTrue(value is Null)
581
582        self.assertTrue(str(divmod(NULL, 1)) == '(<null>, <null>)')
583        self.assertTrue(str(divmod(1, NULL)) == '(<null>, <null>)')
584
585        self.assertTrue(NULL << 1 is Null)
586        self.assertTrue(2 << NULL is Null)
587        NULL <<=3
588        self.assertTrue(NULL is Null)
589        value = 9
590        value <<= NULL
591        self.assertTrue(value is Null)
592
593        self.assertTrue(NULL >> 1 is Null)
594        self.assertTrue(2 >> NULL is Null)
595        NULL >>= 3
596        self.assertTrue(NULL is Null)
597        value = 9
598        value >>= NULL
599        self.assertTrue(value is Null)
600
601        self.assertTrue(-NULL is Null)
602        self.assertTrue(+NULL is Null)
603        self.assertTrue(abs(NULL) is Null)
604        self.assertTrue(~NULL is Null)
605
606        self.assertTrue(NULL.attr is Null)
607        self.assertTrue(NULL() is Null)
608        self.assertTrue(getattr(NULL, 'fake') is Null)
609
610        self.assertRaises(TypeError, hash, NULL)
611
612class TestLogical(TestCase):
613    "Testing Logical"
614
615    def test_unknown(self):
616        "Unknown"
617        for unk in '', '?', ' ', None, Null, Unknown, Other:
618            huh = Logical(unk)
619            self.assertEqual(huh == None, True, "huh is %r from %r, which is not None" % (huh, unk))
620            self.assertEqual(huh != None, False, "huh is %r from %r, which is not None" % (huh, unk))
621            self.assertEqual(huh != True, True, "huh is %r from %r, which is not None" % (huh, unk))
622            self.assertEqual(huh == True, False, "huh is %r from %r, which is not None" % (huh, unk))
623            self.assertEqual(huh != False, True, "huh is %r from %r, which is not None" % (huh, unk))
624            self.assertEqual(huh == False, False, "huh is %r from %r, which is not None" % (huh, unk))
625            self.assertRaises(ValueError, lambda : (0, 1, 2)[huh])
626
627    def test_true(self):
628        "true"
629        for true in 'True', 'yes', 't', 'Y', 7, ['blah']:
630            huh = Logical(true)
631            self.assertEqual(huh == True, True)
632            self.assertEqual(huh != True, False)
633            self.assertEqual(huh == False, False, "%r is not True" % true)
634            self.assertEqual(huh != False, True)
635            self.assertEqual(huh == None, False)
636            self.assertEqual(huh != None, True)
637            self.assertEqual((0, 1, 2)[huh], 1)
638
639    def test_false(self):
640        "false"
641        for false in 'false', 'No', 'F', 'n', 0, []:
642            huh = Logical(false)
643            self.assertEqual(huh != False, False)
644            self.assertEqual(huh == False, True)
645            self.assertEqual(huh != True, True)
646            self.assertEqual(huh == True, False)
647            self.assertEqual(huh != None, True)
648            self.assertEqual(huh == None, False)
649            self.assertEqual((0, 1, 2)[huh], 0)
650
651    def test_singletons(self):
652        "singletons"
653        heh = Logical(True)
654        hah = Logical('Yes')
655        ick = Logical(False)
656        ack = Logical([])
657        unk = Logical('?')
658        bla = Logical(None)
659        self.assertEqual(heh is hah, True)
660        self.assertEqual(ick is ack, True)
661        self.assertEqual(unk is bla, True)
662
663    def test_error(self):
664        "errors"
665        self.assertRaises(ValueError, Logical, 'wrong')
666
667    def test_and(self):
668        "and"
669        true = Logical(True)
670        false = Logical(False)
671        unknown = Logical(None)
672        self.assertEqual((true & true) is true, True)
673        self.assertEqual((true & false) is false, True)
674        self.assertEqual((false & true) is false, True)
675        self.assertEqual((false & false) is false, True)
676        self.assertEqual((true & unknown) is unknown, True)
677        self.assertEqual((false & unknown) is false, True)
678        self.assertEqual((unknown & true) is unknown, True)
679        self.assertEqual((unknown & false) is false, True)
680        self.assertEqual((unknown & unknown) is unknown, True)
681        self.assertEqual((true & True) is true, True)
682        self.assertEqual((true & False) is false, True)
683        self.assertEqual((false & True) is false, True)
684        self.assertEqual((false & False) is false, True)
685        self.assertEqual((true & None) is unknown, True)
686        self.assertEqual((false & None) is false, True)
687        self.assertEqual((unknown & True) is unknown, True)
688        self.assertEqual((unknown & False) is false, True)
689        self.assertEqual((unknown & None) is unknown, True)
690        self.assertEqual((True & true) is true, True)
691        self.assertEqual((True & false) is false, True)
692        self.assertEqual((False & true) is false, True)
693        self.assertEqual((False & false) is false, True)
694        self.assertEqual((True & unknown) is unknown, True)
695        self.assertEqual((False & unknown) is false, True)
696        self.assertEqual((None & true) is unknown, True)
697        self.assertEqual((None & false) is false, True)
698        self.assertEqual((None & unknown) is unknown, True)
699        self.assertEqual(type(true & 0), int)
700        self.assertEqual(true & 0, 0)
701        self.assertEqual(type(true & 3), int)
702        self.assertEqual(true & 3, 1)
703        self.assertEqual(type(false & 0), int)
704        self.assertEqual(false & 0, 0)
705        self.assertEqual(type(false & 2), int)
706        self.assertEqual(false & 2, 0)
707        self.assertEqual(type(unknown & 0), int)
708        self.assertEqual(unknown & 0, 0)
709        self.assertEqual(unknown & 2, unknown)
710
711        t = true
712        t &= true
713        self.assertEqual(t is true, True)
714        t = true
715        t &= false
716        self.assertEqual(t is false, True)
717        f = false
718        f &= true
719        self.assertEqual(f is false, True)
720        f = false
721        f &= false
722        self.assertEqual(f is false, True)
723        t = true
724        t &= unknown
725        self.assertEqual(t is unknown, True)
726        f = false
727        f &= unknown
728        self.assertEqual(f is false, True)
729        u = unknown
730        u &= true
731        self.assertEqual(u is unknown, True)
732        u = unknown
733        u &= false
734        self.assertEqual(u is false, True)
735        u = unknown
736        u &= unknown
737        self.assertEqual(u is unknown, True)
738        t = true
739        t &= True
740        self.assertEqual(t is true, True)
741        t = true
742        t &= False
743        self.assertEqual(t is false, True)
744        f = false
745        f &= True
746        self.assertEqual(f is false, True)
747        f = false
748        f &= False
749        self.assertEqual(f is false, True)
750        t = true
751        t &= None
752        self.assertEqual(t is unknown, True)
753        f = false
754        f &= None
755        self.assertEqual(f is false, True)
756        u = unknown
757        u &= True
758        self.assertEqual(u is unknown, True)
759        u = unknown
760        u &= False
761        self.assertEqual(u is false, True)
762        u = unknown
763        u &= None
764        self.assertEqual(u is unknown, True)
765        t = True
766        t &= true
767        self.assertEqual(t is true, True)
768        t = True
769        t &= false
770        self.assertEqual(t is false, True)
771        f = False
772        f &= true
773        self.assertEqual(f is false, True)
774        f = False
775        f &= false
776        self.assertEqual(f is false, True)
777        t = True
778        t &= unknown
779        self.assertEqual(t is unknown, True)
780        f = False
781        f &= unknown
782        self.assertEqual(f is false, True)
783        u = None
784        u &= true
785        self.assertEqual(u is unknown, True)
786        u = None
787        u &= false
788        self.assertEqual(u is false, True)
789        u = None
790        u &= unknown
791        self.assertEqual(u is unknown, True)
792        t = true
793        t &= 0
794        self.assertEqual(type(true & 0), int)
795        t = true
796        t &= 0
797        self.assertEqual(true & 0, 0)
798        t = true
799        t &= 3
800        self.assertEqual(type(true & 3), int)
801        t = true
802        t &= 3
803        self.assertEqual(true & 3, 1)
804        f = false
805        f &= 0
806        self.assertEqual(type(false & 0), int)
807        f = false
808        f &= 0
809        self.assertEqual(false & 0, 0)
810        f = false
811        f &= 2
812        self.assertEqual(type(false & 2), int)
813        f = false
814        f &= 2
815        self.assertEqual(false & 2, 0)
816        u = unknown
817        u &= 0
818        self.assertEqual(type(unknown & 0), int)
819        u = unknown
820        u &= 0
821        self.assertEqual(unknown & 0, 0)
822        u = unknown
823        u &= 2
824        self.assertEqual(unknown & 2, unknown)
825
826    def test_or(self):
827        "or"
828        true = Logical(True)
829        false = Logical(False)
830        unknown = Logical(None)
831        self.assertEqual((true | true) is true, True)
832        self.assertEqual((true | false) is true, True)
833        self.assertEqual((false | true) is true, True)
834        self.assertEqual((false | false) is false, True)
835        self.assertEqual((true | unknown) is true, True)
836        self.assertEqual((false | unknown) is unknown, True)
837        self.assertEqual((unknown | true) is true, True)
838        self.assertEqual((unknown | false) is unknown, True)
839        self.assertEqual((unknown | unknown) is unknown, True)
840        self.assertEqual((true | True) is true, True)
841        self.assertEqual((true | False) is true, True)
842        self.assertEqual((false | True) is true, True)
843        self.assertEqual((false | False) is false, True)
844        self.assertEqual((true | None) is true, True)
845        self.assertEqual((false | None) is unknown, True)
846        self.assertEqual((unknown | True) is true, True)
847        self.assertEqual((unknown | False) is unknown, True)
848        self.assertEqual((unknown | None) is unknown, True)
849        self.assertEqual((True | true) is true, True)
850        self.assertEqual((True | false) is true, True)
851        self.assertEqual((False | true) is true, True)
852        self.assertEqual((False | false) is false, True)
853        self.assertEqual((True | unknown) is true, True)
854        self.assertEqual((False | unknown) is unknown, True)
855        self.assertEqual((None | true) is true, True)
856        self.assertEqual((None | false) is unknown, True)
857        self.assertEqual((None | unknown) is unknown, True)
858        self.assertEqual(type(true | 0), int)
859        self.assertEqual(true | 0, 1)
860        self.assertEqual(type(true | 2), int)
861        self.assertEqual(true | 2, 3)
862        self.assertEqual(type(false | 0), int)
863        self.assertEqual(false | 0, 0)
864        self.assertEqual(type(false | 2), int)
865        self.assertEqual(false | 2, 2)
866        self.assertEqual(unknown | 0, unknown)
867        self.assertEqual(unknown | 2, unknown)
868
869        t = true
870        t |= true
871        self.assertEqual(t is true, True)
872        t = true
873        t |= false
874        self.assertEqual(t is true, True)
875        f = false
876        f |= true
877        self.assertEqual(f is true, True)
878        f = false
879        f |= false
880        self.assertEqual(f is false, True)
881        t = true
882        t |= unknown
883        self.assertEqual(t is true, True)
884        f = false
885        f |= unknown
886        self.assertEqual(f is unknown, True)
887        u = unknown
888        u |= true
889        self.assertEqual(u is true, True)
890        u = unknown
891        u |= false
892        self.assertEqual(u is unknown, True)
893        u = unknown
894        u |= unknown
895        self.assertEqual(u is unknown, True)
896        t = true
897        t |= True
898        self.assertEqual(t is true, True)
899        t = true
900        t |= False
901        self.assertEqual(t is true, True)
902        f = false
903        f |= True
904        self.assertEqual(f is true, True)
905        f = false
906        f |= False
907        self.assertEqual(f is false, True)
908        t = true
909        t |= None
910        self.assertEqual(t is true, True)
911        f = false
912        f |= None
913        self.assertEqual(f is unknown, True)
914        u = unknown
915        u |= True
916        self.assertEqual(u is true, True)
917        u = unknown
918        u |= False
919        self.assertEqual(u is unknown, True)
920        u = unknown
921        u |= None
922        self.assertEqual(u is unknown, True)
923        t = True
924        t |= true
925        self.assertEqual(t is true, True)
926        t = True
927        t |= false
928        self.assertEqual(t is true, True)
929        f = False
930        f |= true
931        self.assertEqual(f is true, True)
932        f = False
933        f |= false
934        self.assertEqual(f is false, True)
935        t = True
936        t |= unknown
937        self.assertEqual(t is true, True)
938        f = False
939        f |= unknown
940        self.assertEqual(f is unknown, True)
941        u = None
942        u |= true
943        self.assertEqual(u is true, True)
944        u = None
945        u |= false
946        self.assertEqual(u is unknown, True)
947        u = None
948        u |= unknown
949        self.assertEqual(u is unknown, True)
950        t = true
951        t |= 0
952        self.assertEqual(type(t), int)
953        t = true
954        t |= 0
955        self.assertEqual(t, 1)
956        t = true
957        t |= 2
958        self.assertEqual(type(t), int)
959        t = true
960        t |= 2
961        self.assertEqual(t, 3)
962        f = false
963        f |= 0
964        self.assertEqual(type(f), int)
965        f = false
966        f |= 0
967        self.assertEqual(f, 0)
968        f = false
969        f |= 2
970        self.assertEqual(type(f), int)
971        f = false
972        f |= 2
973        self.assertEqual(f, 2)
974        u = unknown
975        u |= 0
976        self.assertEqual(u, unknown)
977
978    def test_xor(self):
979        "xor"
980        true = Logical(True)
981        false = Logical(False)
982        unknown = Logical(None)
983        self.assertEqual((true ^ true) is false, True)
984        self.assertEqual((true ^ false) is true, True)
985        self.assertEqual((false ^ true) is true, True)
986        self.assertEqual((false ^ false) is false, True)
987        self.assertEqual((true ^ unknown) is unknown, True)
988        self.assertEqual((false ^ unknown) is unknown, True)
989        self.assertEqual((unknown ^ true) is unknown, True)
990        self.assertEqual((unknown ^ false) is unknown, True)
991        self.assertEqual((unknown ^ unknown) is unknown, True)
992        self.assertEqual((true ^ True) is false, True)
993        self.assertEqual((true ^ False) is true, True)
994        self.assertEqual((false ^ True) is true, True)
995        self.assertEqual((false ^ False) is false, True)
996        self.assertEqual((true ^ None) is unknown, True)
997        self.assertEqual((false ^ None) is unknown, True)
998        self.assertEqual((unknown ^ True) is unknown, True)
999        self.assertEqual((unknown ^ False) is unknown, True)
1000        self.assertEqual((unknown ^ None) is unknown, True)
1001        self.assertEqual((True ^ true) is false, True)
1002        self.assertEqual((True ^ false) is true, True)
1003        self.assertEqual((False ^ true) is true, True)
1004        self.assertEqual((False ^ false) is false, True)
1005        self.assertEqual((True ^ unknown) is unknown, True)
1006        self.assertEqual((False ^ unknown) is unknown, True)
1007        self.assertEqual((None ^ true) is unknown, True)
1008        self.assertEqual((None ^ false) is unknown, True)
1009        self.assertEqual((None ^ unknown) is unknown, True)
1010        self.assertEqual(type(true ^ 2), int)
1011        self.assertEqual(true ^ 2, 3)
1012        self.assertEqual(type(true ^ 0), int)
1013        self.assertEqual(true ^ 0, 1)
1014        self.assertEqual(type(false ^ 0), int)
1015        self.assertEqual(false ^ 0, 0)
1016        self.assertEqual(type(false ^ 2), int)
1017        self.assertEqual(false ^ 2, 2)
1018        self.assertEqual(unknown ^ 0, unknown)
1019        self.assertEqual(unknown ^ 2, unknown)
1020
1021        t = true
1022        t ^= true
1023        self.assertEqual(t is false, True)
1024        t = true
1025        t ^= false
1026        self.assertEqual(t is true, True)
1027        f = false
1028        f ^= true
1029        self.assertEqual(f is true, True)
1030        f = false
1031        f ^= false
1032        self.assertEqual(f is false, True)
1033        t = true
1034        t ^= unknown
1035        self.assertEqual(t is unknown, True)
1036        f = false
1037        f ^= unknown
1038        self.assertEqual(f is unknown, True)
1039        u = unknown
1040        u ^= true
1041        self.assertEqual(u is unknown, True)
1042        u = unknown
1043        u ^= false
1044        self.assertEqual(u is unknown, True)
1045        u = unknown
1046        u ^= unknown
1047        self.assertEqual(u is unknown, True)
1048        t = true
1049        t ^= True
1050        self.assertEqual(t is false, True)
1051        t = true
1052        t ^= False
1053        self.assertEqual(t is true, True)
1054        f = false
1055        f ^= True
1056        self.assertEqual(f is true, True)
1057        f = false
1058        f ^= False
1059        self.assertEqual(f is false, True)
1060        t = true
1061        t ^= None
1062        self.assertEqual(t is unknown, True)
1063        f = false
1064        f ^= None
1065        self.assertEqual(f is unknown, True)
1066        u = unknown
1067        u ^= True
1068        self.assertEqual(u is unknown, True)
1069        u = unknown
1070        u ^= False
1071        self.assertEqual(u is unknown, True)
1072        u = unknown
1073        u ^= None
1074        self.assertEqual(u is unknown, True)
1075        t = True
1076        t ^= true
1077        self.assertEqual(t is false, True)
1078        t = True
1079        t ^= false
1080        self.assertEqual(t is true, True)
1081        f = False
1082        f ^= true
1083        self.assertEqual(f is true, True)
1084        f = False
1085        f ^= false
1086        self.assertEqual(f is false, True)
1087        t = True
1088        t ^= unknown
1089        self.assertEqual(t is unknown, True)
1090        f = False
1091        f ^= unknown
1092        self.assertEqual(f is unknown, True)
1093        u = None
1094        u ^= true
1095        self.assertEqual(u is unknown, True)
1096        u = None
1097        u ^= false
1098        self.assertEqual(u is unknown, True)
1099        u = None
1100        u ^= unknown
1101        self.assertEqual(u is unknown, True)
1102        t = true
1103        t ^= 0
1104        self.assertEqual(type(true ^ 0), int)
1105        t = true
1106        t ^= 0
1107        self.assertEqual(true ^ 0, 1)
1108        t = true
1109        t ^= 2
1110        self.assertEqual(type(true ^ 2), int)
1111        t = true
1112        t ^= 2
1113        self.assertEqual(true ^ 2, 3)
1114        f = false
1115        f ^= 0
1116        self.assertEqual(type(false ^ 0), int)
1117        f = false
1118        f ^= 0
1119        self.assertEqual(false ^ 0, 0)
1120        f = false
1121        f ^= 2
1122        self.assertEqual(type(false ^ 2), int)
1123        f = false
1124        f ^= 2
1125        self.assertEqual(false ^ 2, 2)
1126        u = unknown
1127        u ^= 0
1128        self.assertEqual(unknown ^ 0, unknown)
1129        u = unknown
1130        u ^= 2
1131        self.assertEqual(unknown ^ 2, unknown)
1132
1133    def test_negation(self):
1134        "negation"
1135        true = Logical(True)
1136        false = Logical(False)
1137        none = Logical(None)
1138        self.assertEqual(-true, -1)
1139        self.assertEqual(-false, 0)
1140        self.assertEqual(-none, none)
1141
1142    def test_posation(self):
1143        "posation"
1144        true = Logical(True)
1145        false = Logical(False)
1146        none = Logical(None)
1147        self.assertEqual(+true, 1)
1148        self.assertEqual(+false, 0)
1149        self.assertEqual(+none, none)
1150
1151    def test_abs(self):
1152        "abs()"
1153        true = Logical(True)
1154        false = Logical(False)
1155        none = Logical(None)
1156        self.assertEqual(abs(true), 1)
1157        self.assertEqual(abs(false), 0)
1158        self.assertEqual(abs(none), none)
1159
1160    def test_invert(self):
1161        "~ operator"
1162        true = Logical(True)
1163        false = Logical(False)
1164        none = Logical(None)
1165        self.assertEqual(~true, -2)
1166        self.assertEqual(~false, -1)
1167        self.assertEqual(~none, none)
1168
1169    def test_complex(self):
1170        "complex"
1171        true = Logical(True)
1172        false = Logical(False)
1173        none = Logical(None)
1174        self.assertEqual(complex(true), complex(1))
1175        self.assertEqual(complex(false), complex(0))
1176        self.assertRaises(ValueError, complex, none)
1177
1178    def test_int(self):
1179        "int"
1180        true = Logical(True)
1181        false = Logical(False)
1182        none = Logical(None)
1183        self.assertEqual(int(true), 1)
1184        self.assertEqual(int(false), 0)
1185        self.assertRaises(ValueError, int, none)
1186
1187    if py_ver < (3, 0):
1188        def test_long(self):
1189            "long"
1190            true = Logical(True)
1191            false = Logical(False)
1192            none = Logical(None)
1193            self.assertEqual(long(true), long(1))
1194            self.assertEqual(long(false), long(0))
1195            self.assertRaises(ValueError, long, none)
1196
1197    def test_float(self):
1198        "float"
1199        true = Logical(True)
1200        false = Logical(False)
1201        none = Logical(None)
1202        self.assertEqual(float(true), 1.0)
1203        self.assertEqual(float(false), 0.0)
1204        self.assertRaises(ValueError, float, none)
1205
1206    def test_oct(self):
1207        "oct"
1208        true = Logical(True)
1209        false = Logical(False)
1210        none = Logical(None)
1211        self.assertEqual(oct(true), oct(1))
1212        self.assertEqual(oct(false), oct(0))
1213        self.assertRaises(ValueError, oct, none)
1214
1215    def test_hex(self):
1216        "hex"
1217        true = Logical(True)
1218        false = Logical(False)
1219        none = Logical(None)
1220        self.assertEqual(hex(true), hex(1))
1221        self.assertEqual(hex(false), hex(0))
1222        self.assertRaises(ValueError, hex, none)
1223
1224    def test_addition(self):
1225        "addition"
1226        true = Logical(True)
1227        false = Logical(False)
1228        unknown = Logical(None)
1229        self.assertEqual(true + true, 2)
1230        self.assertEqual(true + false, 1)
1231        self.assertEqual(false + true, 1)
1232        self.assertEqual(false + false, 0)
1233        self.assertEqual(true + unknown, unknown)
1234        self.assertEqual(false + unknown, unknown)
1235        self.assertEqual(unknown + true, unknown)
1236        self.assertEqual(unknown + false, unknown)
1237        self.assertEqual(unknown + unknown, unknown)
1238        self.assertEqual(true + True, 2)
1239        self.assertEqual(true + False, 1)
1240        self.assertEqual(false + True, 1)
1241        self.assertEqual(false + False, 0)
1242        self.assertEqual(true + None, unknown)
1243        self.assertEqual(false + None, unknown)
1244        self.assertEqual(unknown + True, unknown)
1245        self.assertEqual(unknown + False, unknown)
1246        self.assertEqual(unknown + None, unknown)
1247        self.assertEqual(True + true, 2)
1248        self.assertEqual(True + false, 1)
1249        self.assertEqual(False + true, 1)
1250        self.assertEqual(False + false, 0)
1251        self.assertEqual(True + unknown, unknown)
1252        self.assertEqual(False + unknown, unknown)
1253        self.assertEqual(None + true, unknown)
1254        self.assertEqual(None + false, unknown)
1255        self.assertEqual(None + unknown, unknown)
1256
1257        t = true
1258        t += true
1259        self.assertEqual(t, 2)
1260        t = true
1261        t += false
1262        self.assertEqual(t, 1)
1263        f = false
1264        f += true
1265        self.assertEqual(f, 1)
1266        f = false
1267        f += false
1268        self.assertEqual(f, 0)
1269        t = true
1270        t += unknown
1271        self.assertEqual(t, unknown)
1272        f = false
1273        f += unknown
1274        self.assertEqual(f, unknown)
1275        u = unknown
1276        u += true
1277        self.assertEqual(u, unknown)
1278        u = unknown
1279        u += false
1280        self.assertEqual(u, unknown)
1281        u = unknown
1282        u += unknown
1283        self.assertEqual(u, unknown)
1284        t = true
1285        t += True
1286        self.assertEqual(t, 2)
1287        t = true
1288        t += False
1289        self.assertEqual(t, 1)
1290        f = false
1291        f += True
1292        self.assertEqual(f, 1)
1293        f = false
1294        f += False
1295        self.assertEqual(f, 0)
1296        t = true
1297        t += None
1298        self.assertEqual(t, unknown)
1299        f = false
1300        f += None
1301        self.assertEqual(f, unknown)
1302        u = unknown
1303        u += True
1304        self.assertEqual(u, unknown)
1305        u = unknown
1306        u += False
1307        self.assertEqual(u, unknown)
1308        u = unknown
1309        u += None
1310        self.assertEqual(u, unknown)
1311        t = True
1312        t += true
1313        self.assertEqual(t, 2)
1314        t = True
1315        t += false
1316        self.assertEqual(t, 1)
1317        f = False
1318        f += true
1319        self.assertEqual(f, 1)
1320        f = False
1321        f += false
1322        self.assertEqual(f, 0)
1323        t = True
1324        t += unknown
1325        self.assertEqual(t, unknown)
1326        f = False
1327        f += unknown
1328        self.assertEqual(f, unknown)
1329        u = None
1330        u += true
1331        self.assertEqual(u, unknown)
1332        u = None
1333        u += false
1334        self.assertEqual(u, unknown)
1335        u = None
1336        u += unknown
1337        self.assertEqual(u, unknown)
1338
1339    def test_multiplication(self):
1340        "multiplication"
1341        true = Logical(True)
1342        false = Logical(False)
1343        unknown = Logical(None)
1344        self.assertEqual(true * true, 1)
1345        self.assertEqual(true * false, 0)
1346        self.assertEqual(false * true, 0)
1347        self.assertEqual(false * false, 0)
1348        self.assertEqual(true * unknown, unknown)
1349        self.assertEqual(false * unknown, 0)
1350        self.assertEqual(unknown * true, unknown)
1351        self.assertEqual(unknown * false, 0)
1352        self.assertEqual(unknown * unknown, unknown)
1353        self.assertEqual(true * True, 1)
1354        self.assertEqual(true * False, 0)
1355        self.assertEqual(false * True, 0)
1356        self.assertEqual(false * False, 0)
1357        self.assertEqual(true * None, unknown)
1358        self.assertEqual(false * None, 0)
1359        self.assertEqual(unknown * True, unknown)
1360        self.assertEqual(unknown * False, 0)
1361        self.assertEqual(unknown * None, unknown)
1362        self.assertEqual(True * true, 1)
1363        self.assertEqual(True * false, 0)
1364        self.assertEqual(False * true, 0)
1365        self.assertEqual(False * false, 0)
1366        self.assertEqual(True * unknown, unknown)
1367        self.assertEqual(False * unknown, 0)
1368        self.assertEqual(None * true, unknown)
1369        self.assertEqual(None * false, 0)
1370        self.assertEqual(None * unknown, unknown)
1371
1372        t = true
1373        t *= true
1374        self.assertEqual(t, 1)
1375        t = true
1376        t *= false
1377        self.assertEqual(t, 0)
1378        f = false
1379        f *= true
1380        self.assertEqual(f, 0)
1381        f = false
1382        f *= false
1383        self.assertEqual(f, 0)
1384        t = true
1385        t *= unknown
1386        self.assertEqual(t, unknown)
1387        f = false
1388        f *= unknown
1389        self.assertEqual(f, 0)
1390        u = unknown
1391        u *= true
1392        self.assertEqual(u, unknown)
1393        u = unknown
1394        u *= false
1395        self.assertEqual(u, 0)
1396        u = unknown
1397        u *= unknown
1398        self.assertEqual(u, unknown)
1399        t = true
1400        t *= True
1401        self.assertEqual(t, 1)
1402        t = true
1403        t *= False
1404        self.assertEqual(t, 0)
1405        f = false
1406        f *= True
1407        self.assertEqual(f, 0)
1408        f = false
1409        f *= False
1410        self.assertEqual(f, 0)
1411        t = true
1412        t *= None
1413        self.assertEqual(t, unknown)
1414        f = false
1415        f *= None
1416        self.assertEqual(f, 0)
1417        u = unknown
1418        u *= True
1419        self.assertEqual(u, unknown)
1420        u = unknown
1421        u *= False
1422        self.assertEqual(u, 0)
1423        u = unknown
1424        u *= None
1425        self.assertEqual(u, unknown)
1426        t = True
1427        t *= true
1428        self.assertEqual(t, 1)
1429        t = True
1430        t *= false
1431        self.assertEqual(t, 0)
1432        f = False
1433        f *= true
1434        self.assertEqual(f, 0)
1435        f = False
1436        f *= false
1437        self.assertEqual(f, 0)
1438        t = True
1439        t *= unknown
1440        self.assertEqual(t, unknown)
1441        f = False
1442        f *= unknown
1443        self.assertEqual(f, 0)
1444        u = None
1445        u *= true
1446        self.assertEqual(u, unknown)
1447        u = None
1448        u *= false
1449        self.assertEqual(u, 0)
1450        u = None
1451        u *= unknown
1452        self.assertEqual(u, unknown)
1453
1454    def test_subtraction(self):
1455        "subtraction"
1456        true = Logical(True)
1457        false = Logical(False)
1458        unknown = Logical(None)
1459        self.assertEqual(true - true, 0)
1460        self.assertEqual(true - false, 1)
1461        self.assertEqual(false - true, -1)
1462        self.assertEqual(false - false, 0)
1463        self.assertEqual(true - unknown, unknown)
1464        self.assertEqual(false - unknown, unknown)
1465        self.assertEqual(unknown - true, unknown)
1466        self.assertEqual(unknown - false, unknown)
1467        self.assertEqual(unknown - unknown, unknown)
1468        self.assertEqual(true - True, 0)
1469        self.assertEqual(true - False, 1)
1470        self.assertEqual(false - True, -1)
1471        self.assertEqual(false - False, 0)
1472        self.assertEqual(true - None, unknown)
1473        self.assertEqual(false - None, unknown)
1474        self.assertEqual(unknown - True, unknown)
1475        self.assertEqual(unknown - False, unknown)
1476        self.assertEqual(unknown - None, unknown)
1477        self.assertEqual(True - true, 0)
1478        self.assertEqual(True - false, 1)
1479        self.assertEqual(False - true, -1)
1480        self.assertEqual(False - false, 0)
1481        self.assertEqual(True - unknown, unknown)
1482        self.assertEqual(False - unknown, unknown)
1483        self.assertEqual(None - true, unknown)
1484        self.assertEqual(None - false, unknown)
1485        self.assertEqual(None - unknown, unknown)
1486
1487        t = true
1488        t -= true
1489        self.assertEqual(t, 0)
1490        t = true
1491        t -= false
1492        self.assertEqual(t, 1)
1493        f = false
1494        f -= true
1495        self.assertEqual(f, -1)
1496        f = false
1497        f -= false
1498        self.assertEqual(f, 0)
1499        t = true
1500        t -= unknown
1501        self.assertEqual(t, unknown)
1502        f = false
1503        f -= unknown
1504        self.assertEqual(f, unknown)
1505        u = unknown
1506        u -= true
1507        self.assertEqual(u, unknown)
1508        u = unknown
1509        u -= false
1510        self.assertEqual(u, unknown)
1511        u = unknown
1512        u -= unknown
1513        self.assertEqual(u, unknown)
1514        t = true
1515        t -= True
1516        self.assertEqual(t, 0)
1517        t = true
1518        t -= False
1519        self.assertEqual(t, 1)
1520        f = false
1521        f -= True
1522        self.assertEqual(f, -1)
1523        f = false
1524        f -= False
1525        self.assertEqual(f, 0)
1526        t = true
1527        t -= None
1528        self.assertEqual(t, unknown)
1529        f = false
1530        f -= None
1531        self.assertEqual(f, unknown)
1532        u = unknown
1533        u -= True
1534        self.assertEqual(u, unknown)
1535        u = unknown
1536        u -= False
1537        self.assertEqual(u, unknown)
1538        u = unknown
1539        u -= None
1540        self.assertEqual(u, unknown)
1541        t = True
1542        t -= true
1543        self.assertEqual(t, 0)
1544        t = True
1545        t -= false
1546        self.assertEqual(t, 1)
1547        f = False
1548        f -= true
1549        self.assertEqual(f, -1)
1550        f = False
1551        f -= false
1552        self.assertEqual(f, 0)
1553        t = True
1554        t -= unknown
1555        self.assertEqual(t, unknown)
1556        f = False
1557        f -= unknown
1558        self.assertEqual(f, unknown)
1559        u = None
1560        u -= true
1561        self.assertEqual(u, unknown)
1562        u = None
1563        u -= false
1564        self.assertEqual(u, unknown)
1565        u = None
1566        u -= unknown
1567        self.assertEqual(u, unknown)
1568
1569    def test_division(self):
1570        "division"
1571        true = Logical(True)
1572        false = Logical(False)
1573        unknown = Logical(None)
1574        self.assertEqual(true / true, 1)
1575        self.assertEqual(true / false, unknown)
1576        self.assertEqual(false / true, 0)
1577        self.assertEqual(false / false, unknown)
1578        self.assertEqual(true / unknown, unknown)
1579        self.assertEqual(false / unknown, unknown)
1580        self.assertEqual(unknown / true, unknown)
1581        self.assertEqual(unknown / false, unknown)
1582        self.assertEqual(unknown / unknown, unknown)
1583        self.assertEqual(true / True, 1)
1584        self.assertEqual(true / False, unknown)
1585        self.assertEqual(false / True, 0)
1586        self.assertEqual(false / False, unknown)
1587        self.assertEqual(true / None, unknown)
1588        self.assertEqual(false / None, unknown)
1589        self.assertEqual(unknown / True, unknown)
1590        self.assertEqual(unknown / False, unknown)
1591        self.assertEqual(unknown / None, unknown)
1592        self.assertEqual(True / true, 1)
1593        self.assertEqual(True / false, unknown)
1594        self.assertEqual(False / true, 0)
1595        self.assertEqual(False / false, unknown)
1596        self.assertEqual(True / unknown, unknown)
1597        self.assertEqual(False / unknown, unknown)
1598        self.assertEqual(None / true, unknown)
1599        self.assertEqual(None / false, unknown)
1600        self.assertEqual(None / unknown, unknown)
1601
1602        t = true
1603        t /= true
1604        self.assertEqual(t, 1)
1605        t = true
1606        t /= false
1607        self.assertEqual(t, unknown)
1608        f = false
1609        f /= true
1610        self.assertEqual(f, 0)
1611        f = false
1612        f /= false
1613        self.assertEqual(f, unknown)
1614        t = true
1615        t /= unknown
1616        self.assertEqual(t, unknown)
1617        f = false
1618        f /= unknown
1619        self.assertEqual(f, unknown)
1620        u = unknown
1621        u /= true
1622        self.assertEqual(u, unknown)
1623        u = unknown
1624        u /= false
1625        self.assertEqual(u, unknown)
1626        u = unknown
1627        u /= unknown
1628        self.assertEqual(u, unknown)
1629        t = true
1630        t /= True
1631        self.assertEqual(t, 1)
1632        t = true
1633        t /= False
1634        self.assertEqual(t, unknown)
1635        f = false
1636        f /= True
1637        self.assertEqual(f, 0)
1638        f = false
1639        f /= False
1640        self.assertEqual(f, unknown)
1641        t = true
1642        t /= None
1643        self.assertEqual(t, unknown)
1644        f = false
1645        f /= None
1646        self.assertEqual(f, unknown)
1647        u = unknown
1648        u /= True
1649        self.assertEqual(u, unknown)
1650        u = unknown
1651        u /= False
1652        self.assertEqual(u, unknown)
1653        u = unknown
1654        u /= None
1655        self.assertEqual(u, unknown)
1656        t = True
1657        t /= true
1658        self.assertEqual(t, 1)
1659        t = True
1660        t /= false
1661        self.assertEqual(t, unknown)
1662        f = False
1663        f /= true
1664        self.assertEqual(f, 0)
1665        f = False
1666        f /= false
1667        self.assertEqual(f, unknown)
1668        t = True
1669        t /= unknown
1670        self.assertEqual(t, unknown)
1671        f = False
1672        f /= unknown
1673        self.assertEqual(f, unknown)
1674        u = None
1675        u /= true
1676        self.assertEqual(u, unknown)
1677        u = None
1678        u /= false
1679        self.assertEqual(u, unknown)
1680        u = None
1681        u /= unknown
1682        self.assertEqual(u, unknown)
1683
1684
1685        self.assertEqual(true // true, 1)
1686        self.assertEqual(true // false, unknown)
1687        self.assertEqual(false // true, 0)
1688        self.assertEqual(false // false, unknown)
1689        self.assertEqual(true // unknown, unknown)
1690        self.assertEqual(false // unknown, unknown)
1691        self.assertEqual(unknown // true, unknown)
1692        self.assertEqual(unknown // false, unknown)
1693        self.assertEqual(unknown // unknown, unknown)
1694        self.assertEqual(true // True, 1)
1695        self.assertEqual(true // False, unknown)
1696        self.assertEqual(false // True, 0)
1697        self.assertEqual(false // False, unknown)
1698        self.assertEqual(true // None, unknown)
1699        self.assertEqual(false // None, unknown)
1700        self.assertEqual(unknown // True, unknown)
1701        self.assertEqual(unknown // False, unknown)
1702        self.assertEqual(unknown // None, unknown)
1703        self.assertEqual(True // true, 1)
1704        self.assertEqual(True // false, unknown)
1705        self.assertEqual(False // true, 0)
1706        self.assertEqual(False // false, unknown)
1707        self.assertEqual(True // unknown, unknown)
1708        self.assertEqual(False // unknown, unknown)
1709        self.assertEqual(None // true, unknown)
1710        self.assertEqual(None // false, unknown)
1711        self.assertEqual(None // unknown, unknown)
1712
1713        t = true
1714        t //= true
1715        self.assertEqual(t, 1)
1716        t = true
1717        t //= false
1718        self.assertEqual(t, unknown)
1719        f = false
1720        f //= true
1721        self.assertEqual(f, 0)
1722        f = false
1723        f //= false
1724        self.assertEqual(f, unknown)
1725        t = true
1726        t //= unknown
1727        self.assertEqual(t, unknown)
1728        f = false
1729        f //= unknown
1730        self.assertEqual(f, unknown)
1731        u = unknown
1732        u //= true
1733        self.assertEqual(u, unknown)
1734        u = unknown
1735        u //= false
1736        self.assertEqual(u, unknown)
1737        u = unknown
1738        u //= unknown
1739        self.assertEqual(u, unknown)
1740        t = true
1741        t //= True
1742        self.assertEqual(t, 1)
1743        t = true
1744        t //= False
1745        self.assertEqual(t, unknown)
1746        f = false
1747        f //= True
1748        self.assertEqual(f, 0)
1749        f = false
1750        f //= False
1751        self.assertEqual(f, unknown)
1752        t = true
1753        t //= None
1754        self.assertEqual(t, unknown)
1755        f = false
1756        f //= None
1757        self.assertEqual(f, unknown)
1758        u = unknown
1759        u //= True
1760        self.assertEqual(u, unknown)
1761        u = unknown
1762        u //= False
1763        self.assertEqual(u, unknown)
1764        u = unknown
1765        u //= None
1766        self.assertEqual(u, unknown)
1767        t = True
1768        t //= true
1769        self.assertEqual(t, 1)
1770        t = True
1771        t //= false
1772        self.assertEqual(t, unknown)
1773        f = False
1774        f //= true
1775        self.assertEqual(f, 0)
1776        f = False
1777        f //= false
1778        self.assertEqual(f, unknown)
1779        t = True
1780        t //= unknown
1781        self.assertEqual(t, unknown)
1782        f = False
1783        f //= unknown
1784        self.assertEqual(f, unknown)
1785        u = None
1786        u //= true
1787        self.assertEqual(u, unknown)
1788        u = None
1789        u //= false
1790        self.assertEqual(u, unknown)
1791        u = None
1792        u //= unknown
1793        self.assertEqual(u, unknown)
1794
1795    def test_shift(self):
1796        "<< and >>"
1797        true = Logical(True)
1798        false = Logical(False)
1799        unknown = Logical(None)
1800
1801        self.assertEqual(true >> true, 0)
1802        self.assertEqual(true >> false, 1)
1803        self.assertEqual(false >> true, 0)
1804        self.assertEqual(false >> false, 0)
1805        self.assertEqual(true >> unknown, unknown)
1806        self.assertEqual(false >> unknown, unknown)
1807        self.assertEqual(unknown >> true, unknown)
1808        self.assertEqual(unknown >> false, unknown)
1809        self.assertEqual(unknown >> unknown, unknown)
1810        self.assertEqual(true >> True, 0)
1811        self.assertEqual(true >> False, 1)
1812        self.assertEqual(false >> True, 0)
1813        self.assertEqual(false >> False, 0)
1814        self.assertEqual(true >> None, unknown)
1815        self.assertEqual(false >> None, unknown)
1816        self.assertEqual(unknown >> True, unknown)
1817        self.assertEqual(unknown >> False, unknown)
1818        self.assertEqual(unknown >> None, unknown)
1819        self.assertEqual(True >> true, 0)
1820        self.assertEqual(True >> false, 1)
1821        self.assertEqual(False >> true, 0)
1822        self.assertEqual(False >> false, 0)
1823        self.assertEqual(True >> unknown, unknown)
1824        self.assertEqual(False >> unknown, unknown)
1825        self.assertEqual(None >> true, unknown)
1826        self.assertEqual(None >> false, unknown)
1827        self.assertEqual(None >> unknown, unknown)
1828
1829        self.assertEqual(true << true, 2)
1830        self.assertEqual(true << false, 1)
1831        self.assertEqual(false << true, 0)
1832        self.assertEqual(false << false, 0)
1833        self.assertEqual(true << unknown, unknown)
1834        self.assertEqual(false << unknown, unknown)
1835        self.assertEqual(unknown << true, unknown)
1836        self.assertEqual(unknown << false, unknown)
1837        self.assertEqual(unknown << unknown, unknown)
1838        self.assertEqual(true << True, 2)
1839        self.assertEqual(true << False, 1)
1840        self.assertEqual(false << True, 0)
1841        self.assertEqual(false << False, 0)
1842        self.assertEqual(true << None, unknown)
1843        self.assertEqual(false << None, unknown)
1844        self.assertEqual(unknown << True, unknown)
1845        self.assertEqual(unknown << False, unknown)
1846        self.assertEqual(unknown << None, unknown)
1847        self.assertEqual(True << true, 2)
1848        self.assertEqual(True << false, 1)
1849        self.assertEqual(False << true, 0)
1850        self.assertEqual(False << false, 0)
1851        self.assertEqual(True << unknown, unknown)
1852        self.assertEqual(False << unknown, unknown)
1853        self.assertEqual(None << true, unknown)
1854        self.assertEqual(None << false, unknown)
1855        self.assertEqual(None << unknown, unknown)
1856
1857        t = true
1858        t >>= true
1859        self.assertEqual(t, 0)
1860        t = true
1861        t >>= false
1862        self.assertEqual(t, 1)
1863        f = false
1864        f >>= true
1865        self.assertEqual(f, 0)
1866        f = false
1867        f >>= false
1868        self.assertEqual(f, 0)
1869        t = true
1870        t >>= unknown
1871        self.assertEqual(t, unknown)
1872        f = false
1873        f >>= unknown
1874        self.assertEqual(f, unknown)
1875        u = unknown
1876        u >>= true
1877        self.assertEqual(u, unknown)
1878        u = unknown
1879        u >>= false
1880        self.assertEqual(u, unknown)
1881        u = unknown
1882        u >>= unknown
1883        self.assertEqual(u, unknown)
1884        t = true
1885        t >>= True
1886        self.assertEqual(t, 0)
1887        t = true
1888        t >>= False
1889        self.assertEqual(t, 1)
1890        f = false
1891        f >>= True
1892        self.assertEqual(f, 0)
1893        f = false
1894        f >>= False
1895        self.assertEqual(f, 0)
1896        t = true
1897        t >>= None
1898        self.assertEqual(t, unknown)
1899        f = false
1900        f >>= None
1901        self.assertEqual(f, unknown)
1902        u = unknown
1903        u >>= True
1904        self.assertEqual(u, unknown)
1905        u = unknown
1906        u >>= False
1907        self.assertEqual(u, unknown)
1908        u = unknown
1909        u >>= None
1910        self.assertEqual(u, unknown)
1911        t = True
1912        t >>= true
1913        self.assertEqual(t, 0)
1914        t = True
1915        t >>= false
1916        self.assertEqual(t, 1)
1917        f = False
1918        f >>= true
1919        self.assertEqual(f, 0)
1920        f = False
1921        f >>= false
1922        self.assertEqual(f, 0)
1923        t = True
1924        t >>= unknown
1925        self.assertEqual(t, unknown)
1926        f = False
1927        f >>= unknown
1928        self.assertEqual(f, unknown)
1929        u = None
1930        u >>= true
1931        self.assertEqual(u, unknown)
1932        u = None
1933        u >>= false
1934        self.assertEqual(u, unknown)
1935        u = None
1936        u >>= unknown
1937        self.assertEqual(u, unknown)
1938
1939        t = true
1940        t <<= true
1941        self.assertEqual(t, 2)
1942        t = true
1943        t <<= false
1944        self.assertEqual(t, 1)
1945        f = false
1946        f <<= true
1947        self.assertEqual(f, 0)
1948        f = false
1949        f <<= false
1950        self.assertEqual(f, 0)
1951        t = true
1952        t <<= unknown
1953        self.assertEqual(t, unknown)
1954        f = false
1955        f <<= unknown
1956        self.assertEqual(f, unknown)
1957        u = unknown
1958        u <<= true
1959        self.assertEqual(u, unknown)
1960        u = unknown
1961        u <<= false
1962        self.assertEqual(u, unknown)
1963        u = unknown
1964        u <<= unknown
1965        self.assertEqual(u, unknown)
1966        t = true
1967        t <<= True
1968        self.assertEqual(t, 2)
1969        t = true
1970        t <<= False
1971        self.assertEqual(t, 1)
1972        f = false
1973        f <<= True
1974        self.assertEqual(f, 0)
1975        f = false
1976        f <<= False
1977        self.assertEqual(f, 0)
1978        t = true
1979        t <<= None
1980        self.assertEqual(t, unknown)
1981        f = false
1982        f <<= None
1983        self.assertEqual(f, unknown)
1984        u = unknown
1985        u <<= True
1986        self.assertEqual(u, unknown)
1987        u = unknown
1988        u <<= False
1989        self.assertEqual(u, unknown)
1990        u = unknown
1991        u <<= None
1992        self.assertEqual(u, unknown)
1993        t = True
1994        t <<= true
1995        self.assertEqual(t, 2)
1996        t = True
1997        t <<= false
1998        self.assertEqual(t, 1)
1999        f = False
2000        f <<= true
2001        self.assertEqual(f, 0)
2002        f = False
2003        f <<= false
2004        self.assertEqual(f, 0)
2005        t = True
2006        t <<= unknown
2007        self.assertEqual(t, unknown)
2008        f = False
2009        f <<= unknown
2010        self.assertEqual(f, unknown)
2011        u = None
2012        u <<= true
2013        self.assertEqual(u, unknown)
2014        u = None
2015        u <<= false
2016        self.assertEqual(u, unknown)
2017        u = None
2018        u <<= unknown
2019        self.assertEqual(u, unknown)
2020
2021    def test_pow(self):
2022        "**"
2023        true = Logical(True)
2024        false = Logical(False)
2025        unknown = Logical(None)
2026
2027        self.assertEqual(true ** true, 1)
2028        self.assertEqual(true ** false, 1)
2029        self.assertEqual(false ** true, 0)
2030        self.assertEqual(false ** false, 1)
2031        self.assertEqual(true ** unknown, unknown)
2032        self.assertEqual(false ** unknown, unknown)
2033        self.assertEqual(unknown ** true, unknown)
2034        self.assertEqual(unknown ** false, 1)
2035        self.assertEqual(unknown ** unknown, unknown)
2036        self.assertEqual(true ** True, 1)
2037        self.assertEqual(true ** False, 1)
2038        self.assertEqual(false ** True, 0)
2039        self.assertEqual(false ** False, 1)
2040        self.assertEqual(true ** None, unknown)
2041        self.assertEqual(false ** None, unknown)
2042        self.assertEqual(unknown ** True, unknown)
2043        self.assertEqual(unknown ** False, 1)
2044        self.assertEqual(unknown ** None, unknown)
2045        self.assertEqual(True ** true, 1)
2046        self.assertEqual(True ** false, 1)
2047        self.assertEqual(False ** true, 0)
2048        self.assertEqual(False ** false, 1)
2049        self.assertEqual(True ** unknown, unknown)
2050        self.assertEqual(False ** unknown, unknown)
2051        self.assertEqual(None ** true, unknown)
2052        self.assertEqual(None ** false, 1)
2053        self.assertEqual(None ** unknown, unknown)
2054
2055        t = true
2056        t **= true
2057        self.assertEqual(t, 1)
2058        t = true
2059        t **= false
2060        self.assertEqual(t, 1)
2061        f = false
2062        f **= true
2063        self.assertEqual(f, 0)
2064        f = false
2065        f **= false
2066        self.assertEqual(f, 1)
2067        t = true
2068        t **= unknown
2069        self.assertEqual(t, unknown)
2070        f = false
2071        f **= unknown
2072        self.assertEqual(f, unknown)
2073        u = unknown
2074        u **= true
2075        self.assertEqual(u, unknown)
2076        u = unknown
2077        u **= false
2078        self.assertEqual(u, 1)
2079        u = unknown
2080        u **= unknown
2081        self.assertEqual(u, unknown)
2082        t = true
2083        t **= True
2084        self.assertEqual(t, 1)
2085        t = true
2086        t **= False
2087        self.assertEqual(t, 1)
2088        f = false
2089        f **= True
2090        self.assertEqual(f, 0)
2091        f = false
2092        f **= False
2093        self.assertEqual(f, 1)
2094        t = true
2095        t **= None
2096        self.assertEqual(t, unknown)
2097        f = false
2098        f **= None
2099        self.assertEqual(f, unknown)
2100        u = unknown
2101        u **= True
2102        self.assertEqual(u, unknown)
2103        u = unknown
2104        u **= False
2105        self.assertEqual(u, 1)
2106        u = unknown
2107        u **= None
2108        self.assertEqual(u, unknown)
2109        t = True
2110        t **= true
2111        self.assertEqual(t, 1)
2112        t = True
2113        t **= false
2114        self.assertEqual(t, 1)
2115        f = False
2116        f **= true
2117        self.assertEqual(f, 0)
2118        f = False
2119        f **= false
2120        self.assertEqual(f, 1)
2121        t = True
2122        t **= unknown
2123        self.assertEqual(t, unknown)
2124        f = False
2125        f **= unknown
2126        self.assertEqual(f, unknown)
2127        u = None
2128        u **= true
2129        self.assertEqual(u, unknown)
2130        u = None
2131        u **= false
2132        self.assertEqual(u, 1)
2133        u = None
2134        u **= unknown
2135        self.assertEqual(u, unknown)
2136
2137    def test_mod(self):
2138        "%"
2139        true = Logical(True)
2140        false = Logical(False)
2141        unknown = Logical(None)
2142
2143        self.assertEqual(true % true, 0)
2144        self.assertEqual(true % false, unknown)
2145        self.assertEqual(false % true, 0)
2146        self.assertEqual(false % false, unknown)
2147        self.assertEqual(true % unknown, unknown)
2148        self.assertEqual(false % unknown, unknown)
2149        self.assertEqual(unknown % true, unknown)
2150        self.assertEqual(unknown % false, unknown)
2151        self.assertEqual(unknown % unknown, unknown)
2152        self.assertEqual(true % True, 0)
2153        self.assertEqual(true % False, unknown)
2154        self.assertEqual(false % True, 0)
2155        self.assertEqual(false % False, unknown)
2156        self.assertEqual(true % None, unknown)
2157        self.assertEqual(false % None, unknown)
2158        self.assertEqual(unknown % True, unknown)
2159        self.assertEqual(unknown % False, unknown)
2160        self.assertEqual(unknown % None, unknown)
2161        self.assertEqual(True % true, 0)
2162        self.assertEqual(True % false, unknown)
2163        self.assertEqual(False % true, 0)
2164        self.assertEqual(False % false, unknown)
2165        self.assertEqual(True % unknown, unknown)
2166        self.assertEqual(False % unknown, unknown)
2167        self.assertEqual(None % true, unknown)
2168        self.assertEqual(None % false, unknown)
2169        self.assertEqual(None % unknown, unknown)
2170
2171        t = true
2172        t %= true
2173        self.assertEqual(t, 0)
2174        t = true
2175        t %= false
2176        self.assertEqual(t, unknown)
2177        f = false
2178        f %= true
2179        self.assertEqual(f, 0)
2180        f = false
2181        f %= false
2182        self.assertEqual(f, unknown)
2183        t = true
2184        t %= unknown
2185        self.assertEqual(t, unknown)
2186        f = false
2187        f %= unknown
2188        self.assertEqual(f, unknown)
2189        u = unknown
2190        u %= true
2191        self.assertEqual(u, unknown)
2192        u = unknown
2193        u %= false
2194        self.assertEqual(u, unknown)
2195        u = unknown
2196        u %= unknown
2197        self.assertEqual(u, unknown)
2198        t = true
2199        t %= True
2200        self.assertEqual(t, 0)
2201        t = true
2202        t %= False
2203        self.assertEqual(t, unknown)
2204        f = false
2205        f %= True
2206        self.assertEqual(f, 0)
2207        f = false
2208        f %= False
2209        self.assertEqual(f, unknown)
2210        t = true
2211        t %= None
2212        self.assertEqual(t, unknown)
2213        f = false
2214        f %= None
2215        self.assertEqual(f, unknown)
2216        u = unknown
2217        u %= True
2218        self.assertEqual(u, unknown)
2219        u = unknown
2220        u %= False
2221        self.assertEqual(u, unknown)
2222        u = unknown
2223        u %= None
2224        self.assertEqual(u, unknown)
2225        t = True
2226        t %= true
2227        self.assertEqual(t, 0)
2228        t = True
2229        t %= false
2230        self.assertEqual(t, unknown)
2231        f = False
2232        f %= true
2233        self.assertEqual(f, 0)
2234        f = False
2235        f %= false
2236        self.assertEqual(f, unknown)
2237        t = True
2238        t %= unknown
2239        self.assertEqual(t, unknown)
2240        f = False
2241        f %= unknown
2242        self.assertEqual(f, unknown)
2243        u = None
2244        u %= true
2245        self.assertEqual(u, unknown)
2246        u = None
2247        u %= false
2248        self.assertEqual(u, unknown)
2249        u = None
2250        u %= unknown
2251        self.assertEqual(u, unknown)
2252
2253    def test_divmod(self):
2254        "divmod()"
2255        true = Logical(True)
2256        false = Logical(False)
2257        unknown = Logical(None)
2258
2259        self.assertEqual(divmod(true, true), (1, 0))
2260        self.assertEqual(divmod(true, false), (unknown, unknown))
2261        self.assertEqual(divmod(false, true), (0, 0))
2262        self.assertEqual(divmod(false, false), (unknown, unknown))
2263        self.assertEqual(divmod(true, unknown), (unknown, unknown))
2264        self.assertEqual(divmod(false, unknown), (unknown, unknown))
2265        self.assertEqual(divmod(unknown, true), (unknown, unknown))
2266        self.assertEqual(divmod(unknown, false), (unknown, unknown))
2267        self.assertEqual(divmod(unknown, unknown), (unknown, unknown))
2268        self.assertEqual(divmod(true, True), (1, 0))
2269        self.assertEqual(divmod(true, False), (unknown, unknown))
2270        self.assertEqual(divmod(false, True), (0, 0))
2271        self.assertEqual(divmod(false, False), (unknown, unknown))
2272        self.assertEqual(divmod(true, None), (unknown, unknown))
2273        self.assertEqual(divmod(false, None), (unknown, unknown))
2274        self.assertEqual(divmod(unknown, True), (unknown, unknown))
2275        self.assertEqual(divmod(unknown, False), (unknown, unknown))
2276        self.assertEqual(divmod(unknown, None), (unknown, unknown))
2277        self.assertEqual(divmod(True, true), (1, 0))
2278        self.assertEqual(divmod(True, false), (unknown, unknown))
2279        self.assertEqual(divmod(False, true), (0, 0))
2280        self.assertEqual(divmod(False, false), (unknown, unknown))
2281        self.assertEqual(divmod(True, unknown), (unknown, unknown))
2282        self.assertEqual(divmod(False, unknown), (unknown, unknown))
2283        self.assertEqual(divmod(None, true), (unknown, unknown))
2284        self.assertEqual(divmod(None, false), (unknown, unknown))
2285        self.assertEqual(divmod(None, unknown), (unknown, unknown))
2286
2287
2288class TestQuantum(TestCase):
2289    "Testing Quantum"
2290
2291    def test_exceptions(self):
2292        "errors"
2293        self.assertRaises(ValueError, Quantum, 'wrong')
2294        self.assertRaises(TypeError, lambda : (0, 1, 2)[On])
2295        self.assertRaises(TypeError, lambda : (0, 1, 2)[Off])
2296        self.assertRaises(TypeError, lambda : (0, 1, 2)[Other])
2297
2298    def test_other(self):
2299        "Other"
2300        huh = unknown = Quantum('')
2301        self.assertEqual(huh is dbf.Other, True)
2302        self.assertEqual((huh != huh) is unknown, True)
2303        self.assertEqual((huh != True) is unknown, True)
2304        self.assertEqual((huh != False) is unknown, True)
2305
2306        huh = Quantum('?')
2307        self.assertEqual(huh is dbf.Other, True)
2308        self.assertEqual((huh != huh) is unknown, True)
2309        self.assertEqual((huh != True) is unknown, True)
2310        self.assertEqual((huh != False) is unknown, True)
2311
2312        huh = Quantum(' ')
2313        self.assertEqual(huh is dbf.Other, True)
2314        self.assertEqual((huh != huh) is unknown, True)
2315        self.assertEqual((huh != True) is unknown, True)
2316        self.assertEqual((huh != False) is unknown, True)
2317
2318        huh = Quantum(None)
2319        self.assertEqual(huh is dbf.Other, True)
2320        self.assertEqual((huh != huh) is unknown, True)
2321        self.assertEqual((huh != True) is unknown, True)
2322        self.assertEqual((huh != False) is unknown, True)
2323
2324        huh = Quantum(Null())
2325        self.assertEqual(huh is dbf.Other, True)
2326        self.assertEqual((huh != huh) is unknown, True)
2327        self.assertEqual((huh != True) is unknown, True)
2328        self.assertEqual((huh != False) is unknown, True)
2329
2330        huh = Quantum(Other)
2331        self.assertEqual(huh is dbf.Other, True)
2332        self.assertEqual((huh != huh) is unknown, True)
2333        self.assertEqual((huh != True) is unknown, True)
2334        self.assertEqual((huh != False) is unknown, True)
2335
2336        huh = Quantum(Unknown)
2337        self.assertEqual(huh is dbf.Other, True)
2338        self.assertEqual((huh != huh) is unknown, True)
2339        self.assertEqual((huh != True) is unknown, True)
2340        self.assertEqual((huh != False) is unknown, True)
2341
2342    def test_true(self):
2343        "true"
2344        huh = Quantum('True')
2345        unknown = Quantum('?')
2346        self.assertEqual(huh, True)
2347        self.assertNotEqual(huh, False)
2348        self.assertEqual((huh != None) is unknown, True)
2349
2350        huh = Quantum('yes')
2351        unknown = Quantum('?')
2352        self.assertEqual(huh, True)
2353        self.assertNotEqual(huh, False)
2354        self.assertEqual((huh != None) is unknown, True)
2355
2356        huh = Quantum('t')
2357        unknown = Quantum('?')
2358        self.assertEqual(huh, True)
2359        self.assertNotEqual(huh, False)
2360        self.assertEqual((huh != None) is unknown, True)
2361
2362        huh = Quantum('Y')
2363        unknown = Quantum('?')
2364        self.assertEqual(huh, True)
2365        self.assertNotEqual(huh, False)
2366        self.assertEqual((huh != None) is unknown, True)
2367
2368        huh = Quantum(7)
2369        unknown = Quantum('?')
2370        self.assertEqual(huh, True)
2371        self.assertNotEqual(huh, False)
2372        self.assertEqual((huh != None) is unknown, True)
2373
2374        huh = Quantum(['blah'])
2375        unknown = Quantum('?')
2376        self.assertEqual(huh, True)
2377        self.assertNotEqual(huh, False)
2378        self.assertEqual((huh != None) is unknown, True)
2379
2380    def test_false(self):
2381        "false"
2382        huh = Quantum('false')
2383        unknown = Quantum('?')
2384        self.assertEqual(huh, False)
2385        self.assertNotEqual(huh, True)
2386        self.assertEqual((huh != None) is unknown, True)
2387
2388        huh = Quantum('No')
2389        unknown = Quantum('?')
2390        self.assertEqual(huh, False)
2391        self.assertNotEqual(huh, True)
2392        self.assertEqual((huh != None) is unknown, True)
2393
2394        huh = Quantum('F')
2395        unknown = Quantum('?')
2396        self.assertEqual(huh, False)
2397        self.assertNotEqual(huh, True)
2398        self.assertEqual((huh != None) is unknown, True)
2399
2400        huh = Quantum('n')
2401        unknown = Quantum('?')
2402        self.assertEqual(huh, False)
2403        self.assertNotEqual(huh, True)
2404        self.assertEqual((huh != None) is unknown, True)
2405
2406        huh = Quantum(0)
2407        unknown = Quantum('?')
2408        self.assertEqual(huh, False)
2409        self.assertNotEqual(huh, True)
2410        self.assertEqual((huh != None) is unknown, True)
2411
2412        huh = Quantum([])
2413        unknown = Quantum('?')
2414        self.assertEqual(huh, False)
2415        self.assertNotEqual(huh, True)
2416        self.assertEqual((huh != None) is unknown, True)
2417
2418    def test_singletons(self):
2419        "singletons"
2420        heh = Quantum(True)
2421        hah = Quantum('Yes')
2422        ick = Quantum(False)
2423        ack = Quantum([])
2424        unk = Quantum('?')
2425        bla = Quantum(None)
2426        self.assertEqual(heh is hah, True)
2427        self.assertEqual(ick is ack, True)
2428        self.assertEqual(unk is bla, True)
2429
2430    def test_or(self):
2431        "or"
2432        true = Quantum(True)
2433        false = Quantum(False)
2434        unknown = Quantum(None)
2435        self.assertEqual(true + true, true)
2436        self.assertEqual(true + false, true)
2437        self.assertEqual(false + true, true)
2438        self.assertEqual(false + false, false)
2439        self.assertEqual(true + unknown, true)
2440        self.assertEqual(false + unknown is unknown, True)
2441        self.assertEqual(unknown + unknown is unknown, True)
2442        self.assertEqual(true | true, true)
2443        self.assertEqual(true | false, true)
2444        self.assertEqual(false | true, true)
2445        self.assertEqual(false | false, false)
2446        self.assertEqual(true | unknown, true)
2447        self.assertEqual(false | unknown is unknown, True)
2448        self.assertEqual(unknown | unknown is unknown, True)
2449        self.assertEqual(true + True, true)
2450        self.assertEqual(true + False, true)
2451        self.assertEqual(false + True, true)
2452        self.assertEqual(false + False, false)
2453        self.assertEqual(true + None, true)
2454        self.assertEqual(false + None is unknown, True)
2455        self.assertEqual(unknown + None is unknown, True)
2456        self.assertEqual(true | True, true)
2457        self.assertEqual(true | False, true)
2458        self.assertEqual(false | True, true)
2459        self.assertEqual(false | False, false)
2460        self.assertEqual(true | None, true)
2461        self.assertEqual(false | None is unknown, True)
2462        self.assertEqual(unknown | None is unknown, True)
2463        self.assertEqual(True + true, true)
2464        self.assertEqual(True + false, true)
2465        self.assertEqual(False + true, true)
2466        self.assertEqual(False + false, false)
2467        self.assertEqual(True + unknown, true)
2468        self.assertEqual(False + unknown is unknown, True)
2469        self.assertEqual(None + unknown is unknown, True)
2470        self.assertEqual(True | true, true)
2471        self.assertEqual(True | false, true)
2472        self.assertEqual(False | true, true)
2473        self.assertEqual(False | false, false)
2474        self.assertEqual(True | unknown, true)
2475        self.assertEqual(False | unknown is unknown, True)
2476        self.assertEqual(None | unknown is unknown, True)
2477
2478    def test_and(self):
2479        "and"
2480        true = Quantum(True)
2481        false = Quantum(False)
2482        unknown = Quantum(None)
2483        self.assertEqual(true * true, true)
2484        self.assertEqual(true * false, false)
2485        self.assertEqual(false * true, false)
2486        self.assertEqual(false * false, false)
2487        self.assertEqual(true * unknown is unknown, True)
2488        self.assertEqual(false * unknown, false)
2489        self.assertEqual(unknown * unknown is unknown, True)
2490        self.assertEqual(true & true, true)
2491        self.assertEqual(true & false, false)
2492        self.assertEqual(false & true, false)
2493        self.assertEqual(false & false, false)
2494        self.assertEqual(true & unknown is unknown, True)
2495        self.assertEqual(false & unknown, false)
2496        self.assertEqual(unknown & unknown is unknown, True)
2497        self.assertEqual(true * True, true)
2498        self.assertEqual(true * False, false)
2499        self.assertEqual(false * True, false)
2500        self.assertEqual(false * False, false)
2501        self.assertEqual(true * None is unknown, True)
2502        self.assertEqual(false * None, false)
2503        self.assertEqual(unknown * None is unknown, True)
2504        self.assertEqual(true & True, true)
2505        self.assertEqual(true & False, false)
2506        self.assertEqual(false & True, false)
2507        self.assertEqual(false & False, false)
2508        self.assertEqual(true & None is unknown, True)
2509        self.assertEqual(false & None, false)
2510        self.assertEqual(unknown & None is unknown, True)
2511        self.assertEqual(True * true, true)
2512        self.assertEqual(True * false, false)
2513        self.assertEqual(False * true, false)
2514        self.assertEqual(False * false, false)
2515        self.assertEqual(True * unknown is unknown, True)
2516        self.assertEqual(False * unknown, false)
2517        self.assertEqual(None * unknown is unknown, True)
2518        self.assertEqual(True & true, true)
2519        self.assertEqual(True & false, false)
2520        self.assertEqual(False & true, false)
2521        self.assertEqual(False & false, false)
2522        self.assertEqual(True & unknown is unknown, True)
2523        self.assertEqual(False & unknown, false)
2524        self.assertEqual(None & unknown is unknown, True)
2525
2526    def test_xor(self):
2527        "xor"
2528        true = Quantum(True)
2529        false = Quantum(False)
2530        unknown = Quantum(None)
2531        self.assertEqual(true ^ true, false)
2532        self.assertEqual(true ^ false, true)
2533        self.assertEqual(false ^ true, true)
2534        self.assertEqual(false ^ false, false)
2535        self.assertEqual(true ^ unknown is unknown, True)
2536        self.assertEqual(false ^ unknown is unknown, True)
2537        self.assertEqual(unknown ^ unknown is unknown, True)
2538        self.assertEqual(true ^ True, false)
2539        self.assertEqual(true ^ False, true)
2540        self.assertEqual(false ^ True, true)
2541        self.assertEqual(false ^ False, false)
2542        self.assertEqual(true ^ None is unknown, True)
2543        self.assertEqual(false ^ None is unknown, True)
2544        self.assertEqual(unknown ^ None is unknown, True)
2545        self.assertEqual(True ^ true, false)
2546        self.assertEqual(True ^ false, true)
2547        self.assertEqual(False ^ true, true)
2548        self.assertEqual(False ^ false, false)
2549        self.assertEqual(True ^ unknown is unknown, True)
2550        self.assertEqual(False ^ unknown is unknown, True)
2551        self.assertEqual(None ^ unknown is unknown, True)
2552
2553    def test_implication_material(self):
2554        "implication, material"
2555        true = Quantum(True)
2556        false = Quantum(False)
2557        unknown = Quantum(None)
2558        self.assertEqual(true >> true, true)
2559        self.assertEqual(true >> false, false)
2560        self.assertEqual(false >> true, true)
2561        self.assertEqual(false >> false, true)
2562        self.assertEqual(true >> unknown is unknown, True)
2563        self.assertEqual(false >> unknown, true)
2564        self.assertEqual(unknown >> unknown is unknown, True)
2565        self.assertEqual(true >> True, true)
2566        self.assertEqual(true >> False, false)
2567        self.assertEqual(false >> True, true)
2568        self.assertEqual(false >> False, true)
2569        self.assertEqual(true >> None is unknown, True)
2570        self.assertEqual(false >> None, true)
2571        self.assertEqual(unknown >> None is unknown, True)
2572        self.assertEqual(True >> true, true)
2573        self.assertEqual(True >> false, false)
2574        self.assertEqual(False >> true, true)
2575        self.assertEqual(False >> false, true)
2576        self.assertEqual(True >> unknown is unknown, True)
2577        self.assertEqual(False >> unknown, true)
2578        self.assertEqual(None >> unknown is unknown, True)
2579
2580    def test_implication_relevant(self):
2581        "implication, relevant"
2582        true = Quantum(True)
2583        false = Quantum(False)
2584        unknown = Quantum(None)
2585        Quantum.set_implication('relevant')
2586        self.assertEqual(true >> true, true)
2587        self.assertEqual(true >> false, false)
2588        self.assertEqual(false >> true is unknown, True)
2589        self.assertEqual(false >> false is unknown, True)
2590        self.assertEqual(true >> unknown is unknown, True)
2591        self.assertEqual(false >> unknown is unknown, True)
2592        self.assertEqual(unknown >> unknown is unknown, True)
2593        self.assertEqual(true >> True, true)
2594        self.assertEqual(true >> False, false)
2595        self.assertEqual(false >> True is unknown, True)
2596        self.assertEqual(false >> False is unknown, True)
2597        self.assertEqual(true >> None is unknown, True)
2598        self.assertEqual(false >> None is unknown, True)
2599        self.assertEqual(unknown >> None is unknown, True)
2600        self.assertEqual(True >> true, true)
2601        self.assertEqual(True >> false, false)
2602        self.assertEqual(False >> true is unknown, True)
2603        self.assertEqual(False >> false is unknown, True)
2604        self.assertEqual(True >> unknown is unknown, True)
2605        self.assertEqual(False >> unknown is unknown, True)
2606        self.assertEqual(None >> unknown is unknown, True)
2607
2608    def test_nand(self):
2609        "negative and"
2610        true = Quantum(True)
2611        false = Quantum(False)
2612        unknown = Quantum(None)
2613        self.assertEqual(true.D(true), false)
2614        self.assertEqual(true.D(false), true)
2615        self.assertEqual(false.D(true), true)
2616        self.assertEqual(false.D(false), true)
2617        self.assertEqual(true.D(unknown) is unknown, True)
2618        self.assertEqual(false.D(unknown), true)
2619        self.assertEqual(unknown.D(unknown) is unknown, True)
2620        self.assertEqual(true.D(True), false)
2621        self.assertEqual(true.D(False), true)
2622        self.assertEqual(false.D(True), true)
2623        self.assertEqual(false.D(False), true)
2624        self.assertEqual(true.D(None) is unknown, True)
2625        self.assertEqual(false.D(None), true)
2626        self.assertEqual(unknown.D(None) is unknown, True)
2627
2628    def test_negation(self):
2629        "negation"
2630        true = Quantum(True)
2631        false = Quantum(False)
2632        none = Quantum(None)
2633        self.assertEqual(-true, false)
2634        self.assertEqual(-false, true)
2635        self.assertEqual(-none is none, True)
2636
2637
2638class TestExceptions(TestCase):
2639
2640    def test_bad_field_specs_on_creation(self):
2641        self.assertRaises(FieldSpecError, Table, 'blah', 'age N(3,2)', on_disk=False)
2642        self.assertRaises(FieldSpecError, Table, 'blah', 'name C(300)', on_disk=False)
2643        self.assertRaises(FieldSpecError, Table, 'blah', 'born L(9)', on_disk=False)
2644        self.assertRaises(FieldSpecError, Table, 'blah', 'married D(12)', on_disk=False)
2645        self.assertRaises(FieldSpecError, Table, 'blah', 'desc M(1)', on_disk=False)
2646        self.assertRaises(FieldSpecError, Table, 'blah', 'desc', on_disk=False)
2647
2648    def test_too_many_fields_on_creation(self):
2649        fields = []
2650        for i in range(255):
2651            fields.append('a%03d C(10)' % i)
2652        Table(':test:', ';'.join(fields), on_disk=False)
2653        fields.append('a255 C(10)')
2654        self.assertRaises(DbfError, Table, ':test:', ';'.join(fields), on_disk=False)
2655
2656    def test_adding_too_many_fields(self):
2657        fields = []
2658        for i in range(255):
2659            fields.append('a%03d C(10)' % i)
2660        table = Table(':test:', ';'.join(fields), on_disk=False)
2661        table.open(mode=READ_WRITE)
2662        self.assertRaises(DbfError, table.add_fields, 'a255 C(10)')
2663
2664    def test_adding_too_many_fields_with_null(self):
2665        fields = []
2666        for i in range(254):
2667            fields.append(u'a%03d C(10) NULL' % i)
2668        table = Table(':test:', u';'.join(fields), dbf_type='vfp', on_disk=False)
2669        table.open(mode=READ_WRITE)
2670        self.assertRaises(DbfError, table.add_fields, u'a255 C(10)')
2671        fields = []
2672        for i in range(254):
2673            fields.append(u'a%03d C(10) NULL' % i)
2674        table = Table(':test:', u';'.join(fields), dbf_type='vfp', on_disk=False)
2675        table.open(mode=READ_WRITE)
2676        self.assertRaises(DbfError, table.add_fields, u'a255 C(10)')
2677
2678    def test_too_many_records_in_table(self):
2679        "skipped -- test takes waaaaaaay too long"
2680
2681    def test_too_many_fields_to_change_to_null(self):
2682        fields = []
2683        for i in range(255):
2684            fields.append('a%03d C(10)' % i)
2685        table = Table(':test:', ';'.join(fields), on_disk=False)
2686        table.open(mode=READ_WRITE)
2687        try:
2688            self.assertRaises(DbfError, table.allow_nulls, 'a001')
2689        finally:
2690            table.close()
2691
2692    def test_adding_existing_field_to_table(self):
2693        table = Table(':blah:', 'name C(50)', on_disk=False)
2694        self.assertRaises(DbfError, table.add_fields, 'name C(10)')
2695
2696    def test_deleting_non_existing_field_from_table(self):
2697        table = Table(':bleh:', 'name C(25)', on_disk=False)
2698        self.assertRaises(DbfError, table.delete_fields, 'age')
2699
2700    def test_modify_packed_record(self):
2701        table = Table(':ummm:', 'name C(3); age N(3,0)', on_disk=False)
2702        table.open(mode=READ_WRITE)
2703        for person in (('me', 25), ('you', 35), ('her', 29)):
2704            table.append(person)
2705        record = table[1]
2706        dbf.delete(record)
2707        table.pack()
2708        self.assertEqual(('you', 35), record)
2709        self.assertRaises(DbfError, dbf.write, record, **{'age':33})
2710
2711    def test_read_only(self):
2712        table = Table(':ahhh:', 'name C(10)', on_disk=False)
2713        table.open(mode=dbf.READ_ONLY)
2714        self.assertRaises(DbfError, table.append, dict(name='uh uh!'))
2715
2716    def test_clipper(self):
2717        Table(os.path.join(tempdir, 'temptable'), 'name C(377); thesis C(20179)', dbf_type='clp')
2718        self.assertRaises(BadDataError, Table, os.path.join(tempdir, 'temptable'))
2719
2720    def test_data_overflow(self):
2721        table = Table(os.path.join(tempdir, 'temptable'), 'mine C(2); yours C(15)')
2722        table.open(mode=READ_WRITE)
2723        table.append(('me',))
2724        try:
2725            table.append(('yours',))
2726        except DataOverflowError:
2727            pass
2728        finally:
2729            table.close()
2730
2731    def test_change_null_field(self):
2732        "cannot making an existing field nullable"
2733        table = Table(
2734                os.path.join(tempdir, 'vfp_table'),
2735                'name C(25); paid L; qty N(11,5); orderdate D; desc M; mass B;' +
2736                ' weight F(18,3); age I; meeting T; misc G; photo P; price Y;' +
2737                ' dist B',
2738                dbf_type='vfp',
2739                default_data_types='enhanced',
2740                )
2741        table.open(mode=READ_WRITE)
2742        namelist = []
2743        paidlist = []
2744        qtylist = []
2745        orderlist = []
2746        desclist = []
2747        for i in range(10):
2748            name = words[i]
2749            paid = len(words[i]) % 3 == 0
2750            qty = floats[i]
2751            orderdate = datetime.date((numbers[i] + 1) * 2, (numbers[i] % 12) +1, (numbers[i] % 27) + 1)
2752            desc = ' '.join(words[i:i+50])
2753            namelist.append(name)
2754            paidlist.append(paid)
2755            qtylist.append(qty)
2756            orderlist.append(orderdate)
2757            desclist.append(desc)
2758            table.append({u'name':name, u'paid':paid, u'qty':qty, u'orderdate':orderdate, u'desc':desc})
2759        # plus a blank record
2760        namelist.append('')
2761        paidlist.append(None)
2762        qtylist.append(None)
2763        orderlist.append(None)
2764        desclist.append('')
2765        table.append()
2766        for field in table.field_names:
2767            self.assertEqual(table.nullable_field(field), False)
2768        self.assertRaises(DbfError, table.allow_nulls, (u'name, qty'))
2769        table.close()
2770
2771
2772class TestWarnings(TestCase):
2773
2774    @skipIf(warnings_are_exceptions, '-W error specified')
2775    def test_field_name_warning(self):
2776        with warnings.catch_warnings(record=True) as w:
2777            huh = dbf.Table('cloud', 'p^type C(25)', on_disk=False).open(dbf.READ_WRITE)
2778            self.assertEqual(len(w), 1, str(w))
2779            warning = w[-1]
2780            self.assertTrue(issubclass(warning.category, dbf.FieldNameWarning))
2781            huh.resize_field('p^type', 30)
2782            self.assertEqual(len(w), 1, 'warning objects\n'+'\n'.join([str(warning) for warning in w]))
2783            huh.add_fields('c^word C(50)')
2784            self.assertEqual(len(w), 2, str(w))
2785            warning = w[-1]
2786            self.assertTrue(issubclass(warning.category, dbf.FieldNameWarning))
2787
2788    @skipUnless(warnings_are_exceptions, 'warnings are just warnings')
2789    def test_field_name_exceptions(self):
2790        with self.assertRaisesRegex(dbf.FieldNameWarning, "is invalid"):
2791            huh = dbf.Table('cloud', 'p^type C(25)', on_disk=False).open(dbf.READ_WRITE)
2792        with self.assertRaisesRegex(dbf.FieldNameWarning, "is invalid"):
2793            huh = dbf.Table('cloud', 'name C(25)', on_disk=False).open(dbf.READ_WRITE)
2794            try:
2795                huh.add_fields('c^word C(50)')
2796            finally:
2797                huh.close()
2798
2799
2800class TestIndexLocation(TestCase):
2801
2802    def test_false(self):
2803        self.assertFalse(IndexLocation(0, False))
2804        self.assertFalse(IndexLocation(42, False))
2805
2806    def test_true(self):
2807        self.assertTrue(IndexLocation(0, True))
2808        self.assertTrue(IndexLocation(42, True))
2809
2810
2811class TestDbfCreation(TestCase):
2812    "Testing table creation..."
2813
2814    def test_db3_memory_tables(self):
2815        "dbf tables in memory"
2816        fields = unicodify(['name C(25)', 'hiredate D', 'male L', 'wisdom M', 'qty N(3,0)', 'weight F(7,3)'])
2817        for i in range(1, len(fields)+1):
2818            for fieldlist in combinate(fields, i):
2819                table = Table(':memory:', fieldlist, dbf_type='db3', on_disk=False)
2820                actualFields = table.structure()
2821                self.assertEqual(fieldlist, actualFields)
2822                self.assertTrue(all([type(x) is unicode for x in table.field_names]))
2823
2824    def test_db3_disk_tables(self):
2825        "dbf table on disk"
2826        fields = unicodify(['name C(25)', 'hiredate D', 'male L', 'wisdom M', 'qty N(3,0)', 'weight F(7,3)'])
2827        for i in range(1, len(fields)+1):
2828            for fieldlist in combinate(fields, i):
2829                table = Table(os.path.join(tempdir, 'temptable'), ';'.join(fieldlist), dbf_type='db3')
2830                table = Table(os.path.join(tempdir, 'temptable'), dbf_type='db3')
2831                actualFields = table.structure()
2832                self.assertEqual(fieldlist, actualFields)
2833                table = open(table.filename, 'rb')
2834                try:
2835                    last_byte = ord(table.read()[-1])
2836                finally:
2837                    table.close()
2838                self.assertEqual(last_byte, EOF)
2839
2840    def test_clp_memory_tables(self):
2841        "clp tables in memory"
2842        fields = unicodify(['name C(10977)', 'hiredate D', 'male L', 'wisdom M', 'qty N(3,0)', 'weight F(7,3)'])
2843        for i in range(1, len(fields)+1):
2844            for fieldlist in combinate(fields, i):
2845                table = Table(':memory:', fieldlist, dbf_type='clp', on_disk=False)
2846                actualFields = table.structure()
2847                self.assertEqual(fieldlist, actualFields)
2848                self.assertTrue(all([type(x) is unicode for x in table.field_names]))
2849
2850    def test_clp_disk_tables(self):
2851        "clp table on disk"
2852        table = Table(os.path.join(tempdir, 'temptable'), u'name C(377); thesis C(20179)', dbf_type='clp')
2853        self.assertEqual(table.record_length, 20557)
2854        fields = unicodify(['name C(10977)', 'hiredate D', 'male L', 'wisdom M', 'qty N(3,0)', 'weight F(7,3)'])
2855        for i in range(1, len(fields)+1):
2856            for fieldlist in combinate(fields, i):
2857                table = Table(os.path.join(tempdir, 'temptable'), u';'.join(fieldlist), dbf_type='clp')
2858                table = Table(os.path.join(tempdir, 'temptable'), dbf_type='clp')
2859                actualFields = table.structure()
2860                self.assertEqual(fieldlist, actualFields)
2861                table = open(table.filename, 'rb')
2862                try:
2863                    last_byte = ord(table.read()[-1])
2864                finally:
2865                    table.close()
2866                self.assertEqual(last_byte, EOF)
2867
2868    def test_fp_memory_tables(self):
2869        "fp tables in memory"
2870        fields = unicodify(['name C(25)', 'hiredate D', 'male L', 'wisdom M', 'qty N(3,0)',
2871                  'litres F(11,5)', 'blob G', 'graphic P', 'weight F(7,3)'])
2872        for i in range(1, len(fields)+1):
2873            for fieldlist in combinate(fields, i):
2874                table = Table(':memory:', u';'.join(fieldlist), dbf_type='fp', on_disk=False)
2875                actualFields = table.structure()
2876                self.assertEqual(fieldlist, actualFields)
2877
2878    def test_fp_disk_tables(self):
2879        "fp tables on disk"
2880        fields = unicodify(['name C(25)', 'hiredate D', 'male L', 'wisdom M', 'qty N(3,0)',
2881                  'litres F(11,5)', 'blob G', 'graphic P', 'weight F(7,3)'])
2882        for i in range(1, len(fields)+1):
2883            for fieldlist in combinate(fields, i):
2884                table = Table(os.path.join(tempdir, 'tempfp'), u';'.join(fieldlist), dbf_type='fp')
2885                table = Table(os.path.join(tempdir, 'tempfp'), dbf_type='fp')
2886                actualFields = table.structure()
2887                self.assertEqual(fieldlist, actualFields)
2888
2889    def test_vfp_memory_tables(self):
2890        "vfp tables in memory"
2891        fields = unicodify(['name C(25)', 'hiredate D', 'male L', 'wisdom M', 'qty N(3,0)',
2892                  'mass B', 'litres F(11,5)', 'int I', 'birth T', 'blob G', 'graphic P',
2893                  'menu C(50) BINARY', 'graduated L NULL', 'fired D NULL', 'cipher C(50) NOCPTRANS NULL',
2894                  'weight F(7,3)'])
2895
2896        for i in range(1, len(fields)+1):
2897            for fieldlist in combinate(fields, i):
2898                table = Table(':memory:', u';'.join(fieldlist), dbf_type='vfp', on_disk=False)
2899                actualFields = table.structure()
2900                fieldlist = [f.replace('NOCPTRANS','BINARY') for f in fieldlist]
2901                self.assertEqual(fieldlist, actualFields)
2902
2903    def test_vfp_disk_tables(self):
2904        "vfp tables on disk"
2905        fields = unicodify(['name C(25)', 'hiredate D', 'male L', 'wisdom M', 'qty N(3,0)',
2906                  'mass B', 'litres F(11,5)', 'int I', 'birth T', 'blob G', 'graphic P',
2907                  'menu C(50) binary', 'graduated L null', 'fired D NULL', 'cipher C(50) nocptrans NULL',
2908                  'weight F(7,3)'])
2909        for i in range(1, len(fields)+1):
2910            for fieldlist in combinate(fields, i):
2911                table = Table(os.path.join(tempdir, 'tempvfp'), u';'.join(fieldlist), dbf_type='vfp')
2912                table = Table(os.path.join(tempdir, 'tempvfp'), dbf_type='vfp')
2913                actualFields = table.structure()
2914                fieldlist = [f.replace('nocptrans','BINARY') for f in fieldlist]
2915                self.assertEqual(fieldlist, actualFields)
2916
2917    def test_codepage(self):
2918        table = Table(os.path.join(tempdir, 'tempvfp'), u'name C(25); male L; fired D NULL', dbf_type='vfp')
2919        table.close()
2920        self.assertEqual(dbf.default_codepage, 'ascii')
2921        self.assertEqual(table.codepage, dbf.CodePage('ascii'))
2922        table.close()
2923        table.open(mode=READ_WRITE)
2924        table.close()
2925        table = Table(os.path.join(tempdir, 'tempvfp'), u'name C(25); male L; fired D NULL', dbf_type='vfp', codepage='cp850')
2926        table.close()
2927        self.assertEqual(table.codepage, dbf.CodePage('cp850'))
2928
2929        newtable = table.new('tempvfp2', codepage='cp437')
2930        self.assertEqual(newtable.codepage, dbf.CodePage('cp437'))
2931        newtable.open(mode=READ_WRITE)
2932        newtable.create_backup()
2933        newtable.close()
2934        bckup = Table(os.path.join(tempdir, newtable.backup))
2935        self.assertEqual(bckup.codepage, newtable.codepage)
2936
2937    def test_db3_ignore_memos(self):
2938        table = Table(os.path.join(tempdir, 'tempdb3'), u'name C(25); wisdom M', dbf_type='db3').open(mode=READ_WRITE)
2939        table.append(('QC Tester', 'check it twice!  check it thrice!  check it . . . uh . . . again!'))
2940        table.close()
2941        table = Table(os.path.join(tempdir, 'tempdb3'), dbf_type='db3', ignore_memos=True)
2942        table.open(mode=READ_WRITE)
2943        try:
2944            self.assertEqual(table[0].wisdom, u'')
2945        finally:
2946            table.close()
2947
2948    def test_fp_ignore_memos(self):
2949        table = Table(os.path.join(tempdir, 'tempdb3'), u'name C(25); wisdom M', dbf_type='fp').open(mode=READ_WRITE)
2950        table.append(('QC Tester', 'check it twice!  check it thrice!  check it . . . uh . . . again!'))
2951        table.close()
2952        table = Table(os.path.join(tempdir, 'tempdb3'), dbf_type='fp', ignore_memos=True)
2953        table.open(mode=READ_WRITE)
2954        try:
2955            self.assertEqual(table[0].wisdom, u'')
2956        finally:
2957            table.close()
2958
2959    def test_vfp_ignore_memos(self):
2960        table = Table(os.path.join(tempdir, 'tempdb3'), u'name C(25); wisdom M', dbf_type='vfp').open(mode=READ_WRITE)
2961        table.append(('QC Tester', 'check it twice!  check it thrice!  check it . . . uh . . . again!'))
2962        table.close()
2963        table = Table(os.path.join(tempdir, 'tempdb3'), dbf_type='vfp', ignore_memos=True)
2964        table.open(mode=READ_WRITE)
2965        try:
2966            self.assertEqual(table[0].wisdom, u'')
2967        finally:
2968            table.close()
2969
2970    def test_clp_ignore_memos(self):
2971        table = Table(os.path.join(tempdir, 'tempdb3'), u'name C(25); wisdom M', dbf_type='clp').open(mode=READ_WRITE)
2972        table.append(('QC Tester', 'check it twice!  check it thrice!  check it . . . uh . . . again!'))
2973        table.close()
2974        table = Table(os.path.join(tempdir, 'tempdb3'), dbf_type='clp', ignore_memos=True)
2975        table.open(mode=READ_WRITE)
2976        try:
2977            self.assertEqual(table[0].wisdom, u'')
2978        finally:
2979            table.close()
2980
2981
2982class TestDbfRecords(TestCase):
2983    "Testing records"
2984
2985    def setUp(self):
2986        self.dbf_table = Table(
2987                os.path.join(tempdir, 'dbf_table'),
2988                u'name C(25); paid L; qty N(11,5); orderdate D; desc M',
2989                dbf_type='db3',
2990                )
2991        self.vfp_table = Table(
2992                os.path.join(tempdir, 'vfp_table'),
2993                u'name C(25); paid L; qty N(11,5); orderdate D; desc M; mass B;' +
2994                u' weight F(18,3); age I; meeting T; misc G; photo P; price Y;' +
2995                u' dist B',
2996                dbf_type='vfp',
2997                default_data_types='enhanced',
2998                )
2999        self.null_vfp_table = null_table = Table(
3000                os.path.join(tempdir, 'null_vfp_table'),
3001                'first C(25) null; last C(25); height N(3,1) null; age N(3,0); life_story M null; plans M',
3002                dbf_type='vfp',
3003                )
3004        null_table.open(dbf.READ_WRITE)
3005        null_table.append()
3006        null_table.close()
3007
3008    def tearDown(self):
3009        self.dbf_table.close()
3010        self.vfp_table.close()
3011        self.null_vfp_table.close()
3012
3013    def test_slicing(self):
3014        table = self.dbf_table
3015        table.open(mode=READ_WRITE)
3016        table.append(('myself', True, 5.97, dbf.Date(2012, 5, 21), 'really cool'))
3017        self.assertEqual(table.first_record[u'name':u'qty'], table[0][:3])
3018
3019    def test_dbf_adding_records(self):
3020        "dbf table:  adding records"
3021        table = self.dbf_table
3022        table.open(mode=READ_WRITE)
3023        namelist = []
3024        paidlist = []
3025        qtylist = []
3026        orderlist = []
3027        desclist = []
3028        for i in range(len(floats)):
3029            name = words[i]
3030            paid = len(words[i]) % 3 == 0
3031            qty = floats[i]
3032            orderdate = datetime.date((numbers[i] + 1) * 2, (numbers[i] % 12) +1, (numbers[i] % 27) + 1)
3033            desc = ' '.join(words[i:i+50])
3034            namelist.append(name)
3035            paidlist.append(paid)
3036            qtylist.append(qty)
3037            orderlist.append(orderdate)
3038            desclist.append(desc)
3039            table.append(unicodify({'name':name, 'paid':paid, 'qty':qty, 'orderdate':orderdate, 'desc':desc}))
3040            record = table[-1]
3041
3042            t = open(table.filename, 'rb')
3043            last_byte = ord(t.read()[-1])
3044            t.close()
3045            self.assertEqual(last_byte, EOF)
3046            self.assertEqual(record.name.strip(), name)
3047            self.assertEqual(record.paid, paid)
3048            self.assertEqual(record.qty, round(qty, 5))
3049            self.assertEqual(record.orderdate, orderdate)
3050            self.assertEqual(record.desc.strip(), desc)
3051        # plus a blank record
3052        namelist.append('')
3053        paidlist.append(None)
3054        qtylist.append(None)
3055        orderlist.append(None)
3056        desclist.append('')
3057        blank_record = table.append()
3058        self.assertEqual(len(table), len(floats)+1)
3059        for field in table.field_names:
3060            self.assertEqual(1, table.field_names.count(field))
3061        table.close()
3062        t = open(table.filename, 'rb')
3063        last_byte = ord(t.read()[-1])
3064        t.close()
3065        self.assertEqual(last_byte, EOF)
3066        table = Table(table.filename, dbf_type='db3')
3067        table.open(mode=READ_WRITE)
3068        self.assertEqual(len(table), len(floats)+1)
3069        for field in table.field_names:
3070            self.assertEqual(1, table.field_names.count(field))
3071        i = 0
3072        for record in table[:-1]:
3073            i += 1
3074            continue
3075            self.assertEqual(dbf.recno(record), i)
3076            self.assertEqual(table[i].name.strip(), namelist[i])
3077            self.assertEqual(record.name.strip(), namelist[i])
3078            self.assertEqual(table[i].paid, paidlist[i])
3079            self.assertEqual(record.paid, paidlist[i])
3080            self.assertEqual(abs(table[i].qty - qtylist[i]) < .00001, True)
3081            self.assertEqual(abs(record.qty - qtylist[i]) < .00001, True)
3082            self.assertEqual(table[i].orderdate, orderlist[i])
3083            self.assertEqual(record.orderdate, orderlist[i])
3084            self.assertEqual(table[i].desc.strip(), desclist[i])
3085            self.assertEqual(record.desc.strip(), desclist[i])
3086            i += 1
3087        record = table[-1]
3088        self.assertEqual(dbf.recno(record), i)
3089        self.assertEqual(table[i].name.strip(), namelist[i])
3090        self.assertEqual(record.name.strip(), namelist[i])
3091        self.assertEqual(table[i].paid, paidlist[i])
3092        self.assertEqual(record.paid, paidlist[i])
3093        self.assertEqual(table[i].qty, qtylist[i])
3094        self.assertEqual(record.qty, qtylist[i])
3095        self.assertEqual(table[i].orderdate, orderlist[i])
3096        self.assertEqual(record.orderdate, orderlist[i])
3097        self.assertEqual(table[i].desc, desclist[i])
3098        self.assertEqual(record.desc, desclist[i])
3099        i += 1
3100        self.assertEqual(i, len(table))
3101        table.close()
3102
3103    def test_vfp_adding_records(self):
3104        "vfp table:  adding records"
3105        table = self.vfp_table
3106        table.open(mode=READ_WRITE)
3107        namelist = []
3108        paidlist = []
3109        qtylist = []
3110        orderlist = []
3111        desclist = []
3112        masslist = []
3113        weightlist = []
3114        agelist = []
3115        meetlist = []
3116        misclist = []
3117        photolist = []
3118        pricelist = []
3119        distlist = []
3120        for i in range(len(floats)):
3121            name = words[i]
3122            paid = len(words[i]) % 3 == 0
3123            qty = floats[i]
3124            orderdate = datetime.date((numbers[i] + 1) * 2, (numbers[i] % 12) +1, (numbers[i] % 27) + 1)
3125            desc = ' '.join(words[i:i+50])
3126            mass = floats[i] * floats[i] / 2.0
3127            weight = floats[i] * 3
3128            dist = floats[i] * 2
3129            age = numbers[i]
3130            meeting = datetime.datetime((numbers[i] + 2000), (numbers[i] % 12)+1, (numbers[i] % 28)+1,
3131                      (numbers[i] % 24), numbers[i] % 60, (numbers[i] * 3) % 60)
3132            misc = (' '.join(words[i:i+50:3])).encode('ascii')
3133            photo = (' '.join(words[i:i+50:7])).encode('ascii')
3134            price = Decimal(round(floats[i] * 2.182737, 4))
3135            namelist.append(name)
3136            paidlist.append(paid)
3137            qtylist.append(qty)
3138            orderlist.append(orderdate)
3139            desclist.append(desc)
3140            masslist.append(mass)
3141            distlist.append(dist)
3142            weightlist.append(weight)
3143            agelist.append(age)
3144            meetlist.append(meeting)
3145            misclist.append(misc)
3146            photolist.append(photo)
3147            pricelist.append(price)
3148            table.append(unicodify({'name':name, 'paid':paid, 'qty':qty, 'orderdate':orderdate, 'desc':desc,
3149                    'mass':mass, 'weight':weight, 'age':age, 'meeting':meeting, 'misc':misc, 'photo':photo,
3150                    'dist': dist, 'price':price}))
3151            record = table[-1]
3152            self.assertEqual(record.name.strip(), name)
3153            self.assertEqual(record.paid, paid)
3154            self.assertEqual(round(record.qty, 5), round(qty, 5))
3155            self.assertEqual(record.orderdate, orderdate)
3156            self.assertEqual(record.desc.strip(), desc)
3157            self.assertEqual(record.mass, mass)
3158            self.assertEqual(record.dist, dist)
3159            self.assertEqual(round(record.weight, 3), round(weight, 3))
3160            self.assertEqual(record.age, age)
3161            self.assertEqual(record.meeting, meeting)
3162            self.assertEqual(record.misc, misc)
3163            self.assertEqual(record.photo, photo)
3164            self.assertEqual(round(record.price, 4), round(price, 4))
3165        # plus a blank record
3166        namelist.append('')
3167        paidlist.append(Unknown)
3168        qtylist.append(None)
3169        orderlist.append(NullDate)
3170        desclist.append('')
3171        masslist.append(0.0)
3172        distlist.append(0.0)
3173        weightlist.append(None)
3174        agelist.append(0)
3175        meetlist.append(NullDateTime)
3176        misclist.append(''.encode('ascii'))
3177        photolist.append(''.encode('ascii'))
3178        pricelist.append(Decimal('0.0'))
3179        table.append()
3180        table.close()
3181        table = Table(table.filename, dbf_type='vfp')
3182        table.open(mode=READ_WRITE)
3183        self.assertEqual(len(table), len(floats)+1)
3184        i = 0
3185        for record in table[:-1]:
3186            self.assertEqual(dbf.recno(record), i)
3187            self.assertEqual(table[i].name.strip(), namelist[i])
3188            self.assertEqual(record.name.strip(), namelist[i])
3189            self.assertEqual(table[i].paid, paidlist[i])
3190            self.assertEqual(record.paid, paidlist[i])
3191            self.assertEqual(abs(table[i].qty - qtylist[i]) < .00001, True)
3192            self.assertEqual(abs(record.qty - qtylist[i]) < .00001, True)
3193            self.assertEqual(table[i].orderdate, orderlist[i])
3194            self.assertEqual(record.orderdate, orderlist[i])
3195            self.assertEqual(table[i].desc.strip(), desclist[i])
3196            self.assertEqual(record.desc.strip(), desclist[i])
3197            self.assertEqual(record.mass, masslist[i])
3198            self.assertEqual(record.dist, distlist[i])
3199            self.assertEqual(table[i].mass, masslist[i])
3200            self.assertEqual(record.weight, round(weightlist[i], 3))
3201            self.assertEqual(table[i].weight, round(weightlist[i], 3))
3202            self.assertEqual(record.age, agelist[i])
3203            self.assertEqual(table[i].age, agelist[i])
3204            self.assertEqual(record.meeting, meetlist[i])
3205            self.assertEqual(table[i].meeting, meetlist[i])
3206            self.assertEqual(record.misc, misclist[i])
3207            self.assertEqual(table[i].misc, misclist[i])
3208            self.assertEqual(record.photo, photolist[i])
3209            self.assertEqual(table[i].photo, photolist[i])
3210            self.assertEqual(round(record.price, 4), round(pricelist[i], 4))
3211            self.assertEqual(round(table[i].price, 4), round(pricelist[i], 4))
3212            i += 1
3213        record = table[-1]
3214        self.assertEqual(dbf.recno(record), i)
3215        self.assertEqual(table[i].name.strip(), namelist[i])
3216        self.assertEqual(record.name.strip(), namelist[i])
3217        self.assertEqual(table[i].paid is None, True)
3218        self.assertEqual(record.paid is None, True)
3219        self.assertEqual(table[i].qty, None)
3220        self.assertEqual(record.qty, None)
3221        self.assertEqual(table[i].orderdate, orderlist[i])
3222        self.assertEqual(record.orderdate, orderlist[i])
3223        self.assertEqual(table[i].desc, desclist[i])
3224        self.assertEqual(record.desc, desclist[i])
3225        self.assertEqual(record.mass, masslist[i])
3226        self.assertEqual(table[i].mass, masslist[i])
3227        self.assertEqual(record.dist, distlist[i])
3228        self.assertEqual(table[i].dist, distlist[i])
3229        self.assertEqual(record.weight, weightlist[i])
3230        self.assertEqual(table[i].weight, weightlist[i])
3231        self.assertEqual(record.age, agelist[i])
3232        self.assertEqual(table[i].age, agelist[i])
3233        self.assertEqual(record.meeting, meetlist[i])
3234        self.assertEqual(table[i].meeting, meetlist[i])
3235        self.assertEqual(record.misc, misclist[i])
3236        self.assertEqual(table[i].misc, misclist[i])
3237        self.assertEqual(record.photo, photolist[i])
3238        self.assertEqual(table[i].photo, photolist[i])
3239        self.assertEqual(record.price, 0)
3240        self.assertEqual(table[i].price, 0)
3241        i += 1
3242        table.close()
3243
3244    def test_char_memo_return_type(self):
3245        "check character fields return type"
3246        table = Table(':memory:', 'text C(50); memo M', codepage='cp1252', dbf_type='vfp', on_disk=False)
3247        table.open(mode=READ_WRITE)
3248        table.append(('another one bites the dust', "and another one's gone, and another one's gone..."))
3249        table.append()
3250        for record in table:
3251            self.assertTrue(type(record.text) is unicode)
3252            self.assertTrue(type(record.memo) is unicode)
3253
3254        table = Table(':memory:', 'text C(50); memo M', codepage='cp1252', dbf_type='vfp',
3255            default_data_types=dict(C=Char, M=Char), on_disk=False)
3256        table.open(mode=READ_WRITE)
3257        table.append(('another one bites the dust', "and another one's gone, and another one's gone..."))
3258        table.append()
3259        for record in table:
3260            self.assertTrue(type(record.text) is Char)
3261            self.assertTrue(type(record.memo) is Char)
3262
3263        table = Table(':memory:', 'text C(50); memo M', codepage='cp1252', dbf_type='vfp',
3264            default_data_types=dict(C=(Char, NoneType), M=(Char, NoneType)), on_disk=False)
3265        table.open(mode=READ_WRITE)
3266        table.append(('another one bites the dust', "and another one's gone, and another one's gone..."))
3267        table.append()
3268        record = table[0]
3269        self.assertTrue(type(record.text) is Char)
3270        self.assertTrue(type(record.memo) is Char)
3271        record = table[1]
3272        self.assertTrue(type(record.text) is NoneType)
3273        self.assertTrue(type(record.memo) is NoneType)
3274
3275    def test_empty_is_none(self):
3276        "empty and None values"
3277        table = Table(':memory:', 'name C(20); born L; married D; appt T; wisdom M', dbf_type='vfp', on_disk=False)
3278        table.open(mode=READ_WRITE)
3279        table.append()
3280        record = table[-1]
3281        self.assertTrue(record.born is None)
3282        self.assertTrue(record.married is None)
3283        self.assertTrue(record.appt is None)
3284        self.assertEqual(record.wisdom, '')
3285        appt = DateTime.now()
3286        dbf.write(
3287                record,
3288                born = True,
3289                married = Date(1992, 6, 27),
3290                appt = appt,
3291                wisdom = 'Choose Python',
3292                )
3293        self.assertTrue(record.born)
3294        self.assertEqual(record.married, Date(1992, 6, 27))
3295        self.assertEqual(record.appt, appt)
3296        self.assertEqual(record.wisdom, 'Choose Python')
3297        dbf.write(
3298                record,
3299                born = Unknown,
3300                married = NullDate,
3301                appt = NullDateTime,
3302                wisdom = '',
3303                )
3304        self.assertTrue(record.born is None)
3305        self.assertTrue(record.married is None)
3306        self.assertTrue(record.appt is None)
3307        self.assertEqual(record.wisdom, '')
3308
3309    def test_custom_data_type(self):
3310        "custom data types"
3311        table = Table(
3312            filename=':memory:',
3313            field_specs='name C(20); born L; married D; appt T; wisdom M',
3314            field_data_types=dict(name=Char, born=Logical, married=Date, appt=DateTime, wisdom=Char,),
3315            dbf_type='vfp',
3316            on_disk=False,
3317            )
3318        table.open(mode=READ_WRITE)
3319        table.append()
3320        record = table[-1]
3321        self.assertTrue(type(record.name) is Char, "record.name is %r, not Char" % type(record.name))
3322        self.assertTrue(type(record.born) is Logical, "record.born is %r, not Logical" % type(record.born))
3323        self.assertTrue(type(record.married) is Date, "record.married is %r, not Date" % type(record.married))
3324        self.assertTrue(type(record.appt) is DateTime, "record.appt is %r, not DateTime" % type(record.appt))
3325        self.assertTrue(type(record.wisdom) is Char, "record.wisdom is %r, not Char" % type(record.wisdom))
3326        self.assertEqual(record.name, ' ' * 20)
3327        self.assertTrue(record.born is Unknown, "record.born is %r, not Unknown" % record.born)
3328        self.assertTrue(record.married is NullDate, "record.married is %r, not NullDate" % record.married)
3329        self.assertEqual(record.married, None)
3330        self.assertTrue(record.appt is NullDateTime, "record.appt is %r, not NullDateTime" % record.appt)
3331        self.assertEqual(record.appt, None)
3332        appt = DateTime.now()
3333        dbf.write(
3334                record,
3335                name = 'Ethan               ',
3336                born = True,
3337                married = Date(1992, 6, 27),
3338                appt = appt,
3339                wisdom = 'Choose Python',
3340                )
3341        self.assertEqual(type(record.name), Char, "record.wisdom is %r, but should be Char" % record.wisdom)
3342        self.assertTrue(record.born is Truth)
3343        self.assertEqual(record.married, Date(1992, 6, 27))
3344        self.assertEqual(record.appt, appt)
3345        self.assertEqual(type(record.wisdom), Char, "record.wisdom is %r, but should be Char" % record.wisdom)
3346        self.assertEqual(record.wisdom, 'Choose Python')
3347        dbf.write(record, born=Falsth)
3348        self.assertEqual(record.born, False)
3349        dbf.write(record, born=None, married=None, appt=None, wisdom=None)
3350        self.assertTrue(record.born is Unknown)
3351        self.assertTrue(record.married is NullDate)
3352        self.assertTrue(record.appt is NullDateTime)
3353        self.assertTrue(type(record.wisdom) is Char, "record.wisdom is %r, but should be Char" % type(record.wisdom))
3354
3355    def test_datatypes_param(self):
3356        "field_types with normal data type but None on empty"
3357        table = Table(
3358            filename=':memory:',
3359            field_specs='name C(20); born L; married D; wisdom M',
3360            field_data_types=dict(name=(str, NoneType), born=(bool, bool)),
3361            dbf_type='db3',
3362            on_disk=False,
3363            )
3364        table.open(mode=READ_WRITE)
3365        table.append()
3366        record = table[-1]
3367        self.assertTrue(type(record.name) is type(None), "record.name is %r, not None" % type(record.name))
3368        self.assertTrue(type(record.born) is bool, "record.born is %r, not bool" % type(record.born))
3369        self.assertTrue(record.name is None)
3370        self.assertTrue(record.born is False, "record.born is %r, not False" % record.born)
3371        dbf.write(record, name='Ethan               ', born=True)
3372        self.assertEqual(type(record.name), str, "record.name is %r, but should be Char" % record.wisdom)
3373        self.assertTrue(record.born is True)
3374        dbf.write(record, born=False)
3375        self.assertEqual(record.born, False)
3376        dbf.write(
3377            record,
3378            name = None,
3379            born = None,
3380            )
3381        self.assertTrue(record.name is None)
3382        self.assertTrue(record.born is False)
3383
3384    def test_null_type(self):
3385        "NullType"
3386        table = Table(
3387            filename=':memory:',
3388            field_specs='name C(20) NULL; born L NULL; married D NULL; appt T NULL; wisdom M NULL',
3389            default_data_types=dict(
3390                    C=(Char, NoneType, NullType),
3391                    L=(Logical, NoneType, NullType),
3392                    D=(Date, NoneType, NullType),
3393                    T=(DateTime, NoneType, NullType),
3394                    M=(Char, NoneType, NullType),
3395                    ),
3396            dbf_type='vfp',
3397            on_disk=False,
3398            )
3399        table.open(mode=READ_WRITE)
3400        table.append()
3401        record = table[-1]
3402        self.assertIs(record.name, Null)
3403        self.assertIs(record.born, Null)
3404        self.assertIs(record.married, Null)
3405        self.assertIs(record.appt, Null)
3406        self.assertIs(record.wisdom, Null)
3407        appt = datetime.datetime(2012, 12, 15, 9, 37, 11)
3408        dbf.write(
3409                record,
3410                name = 'Ethan               ',
3411                born = True,
3412                married = datetime.date(2001, 6, 27),
3413                appt = appt,
3414                wisdom = 'timing is everything',
3415                )
3416        record = table[-1]
3417        self.assertEqual(record.name, u'Ethan')
3418        self.assertEqual(type(record.name), Char)
3419        self.assertTrue(record.born)
3420        self.assertTrue(record.born is Truth)
3421        self.assertEqual(record.married, datetime.date(2001, 6, 27))
3422        self.assertEqual(type(record.married), Date)
3423        self.assertEqual(record.appt, datetime.datetime(2012, 12, 15, 9, 37, 11))
3424        self.assertEqual(type(record.appt), DateTime)
3425        self.assertEqual(record.wisdom, u'timing is everything')
3426        self.assertEqual(type(record.wisdom), Char)
3427        dbf.write(record, name=Null, born=Null, married=Null, appt=Null, wisdom=Null)
3428        self.assertTrue(record.name is Null)
3429        self.assertTrue(record.born is Null)
3430        self.assertTrue(record.married is Null)
3431        self.assertTrue(record.appt is Null)
3432        self.assertTrue(record.wisdom is Null)
3433        dbf.write(
3434                record,
3435                name = None,
3436                born = None,
3437                married = None,
3438                appt = None,
3439                wisdom = None,
3440                )
3441        record = table[-1]
3442        self.assertTrue(record.name is None)
3443        self.assertTrue(record.born is None)
3444        self.assertTrue(record.married is None)
3445        self.assertTrue(record.appt is None)
3446        self.assertTrue(record.wisdom is None)
3447        table = Table(
3448            filename=':memory:',
3449            field_specs='name C(20); born L; married D NULL; appt T; wisdom M; pets L; cars N(3,0) NULL; story M; died D NULL;',
3450            default_data_types=dict(
3451                    C=(Char, NoneType, NullType),
3452                    L=(Logical, NoneType, NullType),
3453                    D=(Date, NoneType, NullType),
3454                    T=(DateTime, NoneType, NullType),
3455                    M=(Char, NoneType, NullType),
3456                    N=(int, NoneType, NullType),
3457                    ),
3458            dbf_type='vfp',
3459            on_disk=False,
3460            )
3461        table.open(mode=READ_WRITE)
3462        table.append()
3463        record = table[-1]
3464        self.assertTrue(record.name is None)
3465        self.assertTrue(record.born is None)
3466        self.assertTrue(record.married is Null)
3467        self.assertTrue(record.appt is None)
3468        self.assertTrue(record.wisdom is None)
3469        self.assertTrue(record.pets is None)
3470        self.assertTrue(record.cars is Null)
3471        self.assertTrue(record.story is None)
3472        self.assertTrue(record.died is Null)
3473        dbf.write(
3474                record,
3475                name = 'Ethan               ',
3476                born = True,
3477                married = datetime.date(2001, 6, 27),
3478                appt = appt,
3479                wisdom = 'timing is everything',
3480                pets = True,
3481                cars = 10,
3482                story = 'a poor farm boy who made  good',
3483                died = datetime.date(2018, 5, 30),
3484                )
3485        record = table[-1]
3486        self.assertEqual(record.name, 'Ethan')
3487        self.assertTrue(record.born)
3488        self.assertTrue(record.born is Truth)
3489        self.assertEqual(record.married, datetime.date(2001, 6, 27))
3490        self.assertEqual(record.appt, datetime.datetime(2012, 12, 15, 9, 37, 11))
3491        self.assertEqual(record.wisdom, 'timing is everything')
3492        self.assertTrue(record.pets)
3493        self.assertEqual(record.cars, 10)
3494        self.assertEqual(record.story, 'a poor farm boy who made  good',)
3495        self.assertEqual(record.died, datetime.date(2018, 5, 30))
3496        dbf.write(record, married=Null, died=Null)
3497        record = table[-1]
3498        self.assertTrue(record.married is Null)
3499        self.assertTrue(record.died is Null)
3500
3501    def test_nonascii_text_cptrans(self):
3502        "check non-ascii text to unicode"
3503        table = Table(':memory:', 'data C(50); memo M', codepage='cp437', dbf_type='vfp', on_disk=False)
3504        table.open(mode=READ_WRITE)
3505        decoder = codecs.getdecoder('cp437')
3506        if py_ver < (3, 0):
3507            high_ascii = decoder(''.join(chr(c) for c in range(128, 128+50)))[0]
3508        else:
3509            high_ascii = bytes(range(128, 128+50)).decode('cp437')
3510        table.append(dict(data=high_ascii, memo=high_ascii))
3511        self.assertEqual(table[0].data, high_ascii)
3512        self.assertEqual(table[0].memo, high_ascii)
3513        table.close()
3514
3515    def test_nonascii_text_no_cptrans(self):
3516        "check non-ascii text to bytes"
3517        table = Table(':memory:', 'bindata C(50) BINARY; binmemo M BINARY', codepage='cp1252', dbf_type='vfp', on_disk=False)
3518        table.open(mode=READ_WRITE)
3519        if py_ver < (3, 0):
3520            high_ascii = ''.join(chr(c) for c in range(128, 128+50))
3521        else:
3522            high_ascii = bytes(range(128, 128+50))
3523        table.append(dict(bindata=high_ascii, binmemo=high_ascii))
3524        bindata = table[0].bindata
3525        binmemo = table[0].binmemo
3526        self.assertTrue(isinstance(bindata, bytes))
3527        self.assertTrue(isinstance(binmemo, bytes))
3528        self.assertEqual(table[0].bindata, high_ascii)
3529        self.assertEqual(table[0].binmemo, high_ascii)
3530        table.close()
3531
3532    def test_add_null_field(self):
3533        "adding a NULL field to an existing table"
3534        table = Table(
3535            self.vfp_table.filename,
3536            'name C(50); age N(3,0)',
3537            dbf_type='vfp',
3538            )
3539        table.open(mode=READ_WRITE)
3540        def _50(text):
3541            return text + ' ' * (50 - len(text))
3542        data = ( (_50('Ethan'), 29), (_50('Joseph'), 33), (_50('Michael'), 54), )
3543        for datum in data:
3544            table.append(datum)
3545        for datum, recordnum in zip(data, table):
3546            self.assertEqual(datum, tuple(recordnum))
3547        table.add_fields('fired D NULL')
3548        for datum, recordnum in zip(data, table):
3549            self.assertEqual(datum, tuple(recordnum)[:2])
3550        data += ((_50('Daniel'), 44, Null), )
3551        table.append(('Daniel', 44, Null))
3552        for datum, recordnum in zip(data, table):
3553            self.assertEqual(datum[:2], tuple(recordnum)[:2])
3554        self.assertTrue(datum[2] is recordnum[2])
3555        table.close()
3556        table = Table(table.filename)
3557        table.open(mode=READ_WRITE)
3558        for datum, recordnum in zip(data, table):
3559            self.assertEqual(datum[0:2], tuple(recordnum)[:2])
3560        self.assertTrue(datum[2] is recordnum[2])
3561        table.close()
3562
3563    def test_remove_null_field(self):
3564        "removing NULL fields from an existing table"
3565        table = Table(
3566            self.vfp_table.filename,
3567            'name C(50); age N(3,0); fired D NULL',
3568            dbf_type='vfp',
3569            )
3570        table.open(mode=READ_WRITE)
3571        def _50(text):
3572            return text + ' ' * (50 - len(text))
3573        data = ( (_50('Ethan'), 29, Null), (_50('Joseph'), 33, Null), (_50('Michael'), 54, Date(2010, 5, 3)))
3574        for datum in data:
3575            table.append(datum)
3576        for datum, recordnum in zip(data, table):
3577            self.assertEqual(datum[:2], tuple(recordnum)[:2])
3578            self.assertTrue(datum[2] is recordnum[2] or datum[2] == recordnum[2])
3579        table.delete_fields('fired')
3580        for datum, recordnum in zip(data, table):
3581            self.assertEqual(datum[:2], tuple(recordnum))
3582        data += ((_50('Daniel'), 44), )
3583        table.append(('Daniel', 44))
3584        for datum, recordnum in zip(data, table):
3585            self.assertEqual(datum[:2], tuple(recordnum))
3586        table.close()
3587        table = Table(table.filename)
3588        table.open(mode=READ_WRITE)
3589        for datum, recordnum in zip(data, table):
3590            self.assertEqual(datum[:2], tuple(recordnum))
3591        table.close()
3592
3593    def test_add_field_to_null(self):
3594        "adding a normal field to a table with NULL fields"
3595        table = Table(
3596            self.vfp_table.filename,
3597            'name C(50); age N(3,0); fired D NULL',
3598            dbf_type='vfp',
3599            )
3600        table.open(mode=READ_WRITE)
3601        def _50(text):
3602            return text + ' ' * (50 - len(text))
3603        data = ( (_50('Ethan'), 29, Null), (_50('Joseph'), 33, Null), (_50('Michael'), 54, Date(2010, 7, 4)), )
3604        for datum in data:
3605            table.append(datum)
3606        for datum, recordnum in zip(data, table):
3607            self.assertEqual(datum[:2], tuple(recordnum)[:2])
3608            self.assertTrue(datum[2] is recordnum[2] or datum[2] == recordnum[2])
3609        table.add_fields('tenure N(3,0)')
3610        for datum, recordnum in zip(data, table):
3611            self.assertEqual(datum[:2], tuple(recordnum)[:2])
3612            self.assertTrue(datum[2] is recordnum[2] or datum[2] == recordnum[2])
3613        data += ((_50('Daniel'), 44, Date(2005, 1, 31), 15 ), )
3614        table.append(('Daniel', 44, Date(2005, 1, 31), 15))
3615        for datum, recordnum in zip(data, table):
3616            self.assertEqual(datum[:2], tuple(recordnum)[:2])
3617            self.assertTrue(datum[2] is recordnum[2] or datum[2] == recordnum[2])
3618        self.assertEqual(datum[3], recordnum[3])
3619        table.close()
3620        table = Table(table.filename)
3621        table.open(mode=READ_WRITE)
3622        for datum, recordnum in zip(data, table):
3623            self.assertEqual(datum[:2], tuple(recordnum)[:2])
3624            self.assertTrue(datum[2] is recordnum[2] or datum[2] == recordnum[2])
3625        self.assertEqual(datum[3], recordnum[3])
3626        table.close()
3627
3628    def test_remove_field_from_null(self):
3629        "removing a normal field from a table with NULL fields"
3630        table = Table(
3631            self.vfp_table.filename,
3632            'name C(50); age N(3,0); fired D NULL',
3633            dbf_type='vfp',
3634            )
3635        table.open(mode=READ_WRITE)
3636        def _50(text):
3637            return text + ' ' * (50 - len(text))
3638        data = ( (_50('Ethan'), 29, Null), (_50('Joseph'), 33, Null), (_50('Michael'), 54, Date(2010, 7, 4)), )
3639        for datum in data:
3640            table.append(datum)
3641        for datum, recordnum in zip(data, table):
3642            self.assertEqual(datum[:2], tuple(recordnum)[:2])
3643            self.assertTrue(datum[2] is recordnum[2] or datum[2] == recordnum[2])
3644        table.delete_fields('age')
3645        for datum, recordnum in zip(data, table):
3646            self.assertEqual(datum[0], recordnum[0])
3647            self.assertTrue(datum[-1] is recordnum[1] or datum[-1] == recordnum[1])
3648        data += ((_50('Daniel'), Date(2001, 11, 13)), )
3649        table.append(('Daniel', Date(2001, 11, 13)))
3650        for datum, recordnum in zip(data, table):
3651            self.assertEqual(datum[0], recordnum[0])
3652            self.assertTrue(datum[-1] is recordnum[1] or datum[-1] == recordnum[1])
3653        table.close()
3654        table = Table(table.filename)
3655        table.open(mode=READ_WRITE)
3656        for datum, recordnum in zip(data, table):
3657            self.assertEqual(datum[0], recordnum[0])
3658            self.assertTrue(datum[-1] is recordnum[-1] or datum[-1] == recordnum[-1], "name = %s; datum[-1] = %r;  recordnum[-1] = %r" % (datum[0], datum[-1], recordnum[-1]))
3659        table.close()
3660
3661    def test_blank_record_template_uses_null(self):
3662        nullable = self.null_vfp_table
3663        with nullable:
3664            rec = nullable[-1]
3665            self.assertTrue(rec.first is Null, "rec.first is %r" % (rec.first, ))
3666            self.assertTrue(rec.last == ' '*25, "rec.last is %r" % (rec.last, ))
3667            self.assertTrue(rec.height is Null, "rec.height is %r" % (rec.height, ))
3668            self.assertTrue(rec.age is None, "rec.age is %r" % (rec.age, ))
3669            self.assertTrue(rec.life_story is Null, "rec.life_story is %r" % (rec.life_story, ))
3670            self.assertTrue(rec.plans == '', "rec.plans is %r" % (rec.plans, ))
3671        nullable.close()
3672        nullable = Table(
3673                self.null_vfp_table.filename,
3674                default_data_types='enhanced',
3675                )
3676        with nullable:
3677            rec = nullable[-1]
3678            self.assertTrue(rec.first is Null, "rec.first is %r" % (rec.first, ))
3679            self.assertTrue(rec.last == '', "rec.last is %r" % (rec.last, ))
3680            self.assertTrue(rec.height is Null, "rec.height is %r" % (rec.height, ))
3681            self.assertTrue(rec.age is None, "rec.age is %r" % (rec.age, ))
3682            self.assertTrue(rec.life_story is Null, "rec.life_story is %r" % (rec.life_story, ))
3683            self.assertTrue(rec.plans == '', "rec.plans is %r" % (rec.plans, ))
3684        nullable.close()
3685        nullable = Table(
3686                self.null_vfp_table.filename,
3687                default_data_types=dict(
3688                        C=(Char, NoneType, NullType),
3689                        L=(Logical, NoneType, NullType),
3690                        D=(Date, NoneType, NullType),
3691                        T=(DateTime, NoneType, NullType),
3692                        M=(Char, NoneType, NullType),
3693                        ),
3694                )
3695        with nullable:
3696            rec = nullable[-1]
3697            self.assertTrue(rec.first is Null, "rec.first is %r" % (rec.first, ))
3698            self.assertTrue(rec.last is None, "rec.last is %r" % (rec.last, ))
3699            self.assertTrue(rec.height is Null, "rec.height is %r" % (rec.height, ))
3700            self.assertTrue(rec.age is None, "rec.age is %r" % (rec.age, ))
3701            self.assertTrue(rec.life_story is Null, "rec.life_story is %r" % (rec.life_story, ))
3702            self.assertTrue(rec.plans is None, "rec.plans is %r" % (rec.plans, ))
3703
3704    def test_new_record_with_partial_fields_respects_null(self):
3705        nullable = self.null_vfp_table
3706        nullable.close()
3707        nullable = Table(
3708                self.null_vfp_table.filename,
3709                default_data_types=dict(
3710                        C=(Char, NoneType, NullType),
3711                        L=(Logical, NoneType, NullType),
3712                        D=(Date, NoneType, NullType),
3713                        T=(DateTime, NoneType, NullType),
3714                        M=(Char, NoneType, NullType),
3715                        ),
3716                )
3717        with nullable:
3718            nullable.append({'first': 'ethan', 'last':'doe'})
3719            rec = nullable[-1]
3720            self.assertTrue(rec.first == 'ethan', "rec.first is %r" % (rec.first, ))
3721            self.assertTrue(rec.last == 'doe', "rec.last is %r" % (rec.last, ))
3722            self.assertTrue(rec.height is Null, "rec.height is %r" % (rec.height, ))
3723            self.assertTrue(rec.age is None, "rec.age is %r" % (rec.age, ))
3724            self.assertTrue(rec.life_story is Null, "rec.life_story is %r" % (rec.life_story, ))
3725            self.assertTrue(rec.plans is None, "rec.plans is %r" % (rec.plans, ))
3726        nullable.close()
3727
3728    def test_flux_internal(self):
3729        "commit and rollback of flux record (implementation detail)"
3730        table = self.dbf_table
3731        table.open(mode=READ_WRITE)
3732        table.append(('dbf master', True, 77, Date(2012, 5, 20), "guru of some things dbf-y"))
3733        record = table[-1]
3734        old_data = dbf.scatter(record)
3735        record._start_flux()
3736        record.name = 'novice'
3737        record.paid = False
3738        record.qty = 69
3739        record.orderdate = Date(2011, 1, 1)
3740        record.desc = 'master of all he surveys'
3741        try:
3742            self.assertEqual(
3743                dbf.scatter(record),
3744                dict(
3745                    name=unicode('novice                   '),
3746                    paid=False,
3747                    qty=69,
3748                    orderdate=datetime.date(2011, 1, 1),
3749                    desc='master of all he surveys',
3750                    ))
3751        finally:
3752            record._rollback_flux()
3753        self.assertEqual(old_data, dbf.scatter(record))
3754        record._start_flux()
3755        record.name = 'novice'
3756        record.paid = False
3757        record.qty = 69
3758        record.orderdate = Date(2011, 1, 1)
3759        record._commit_flux()
3760        self.assertEqual(
3761                dbf.scatter(record),
3762                dict(
3763                    name=unicode('novice                   '),
3764                    paid=False,
3765                    qty=69,
3766                    orderdate=datetime.date(2011, 1, 1),
3767                    desc='guru of some things dbf-y',
3768                    ))
3769        self.assertNotEqual(old_data, dbf.scatter(record))
3770
3771    def test_field_capitalization(self):
3772        "ensure mixed- and upper-case field names work"
3773        table = dbf.Table('mixed', 'NAME C(30); Age N(5,2)', on_disk=False)
3774        self.assertEqual(['NAME', 'AGE'], field_names(table))
3775        table.open(dbf.READ_WRITE)
3776        table.append({'Name':'Ethan', 'AGE': 99})
3777        rec = table[0]
3778        self.assertEqual(rec.NaMe.strip(), 'Ethan')
3779        table.rename_field('NaMe', 'My_NAME')
3780        self.assertEqual(rec.My_NaMe.strip(), 'Ethan')
3781        self.assertEqual(['MY_NAME', 'AGE'], field_names(table))
3782        table.append({'MY_Name':'Allen', 'AGE': 7})
3783        rec = table[1]
3784        self.assertEqual(rec.my_NaMe.strip(), 'Allen')
3785
3786class TestDbfRecordTemplates(TestCase):
3787    "Testing records"
3788
3789    def setUp(self):
3790        self.dbf_table = Table(
3791                os.path.join(tempdir, 'dbf_table'),
3792                'name C(25); paid L; qty N(11,5); orderdate D; desc M',
3793                dbf_type='db3',
3794                )
3795        self.vfp_table = Table(
3796                os.path.join(tempdir, 'vfp_table'),
3797                'name C(25); paid L; qty N(11,5); orderdate D; desc M; mass B;' +
3798                ' weight F(18,3); age I; meeting T; misc G; photo P; price Y',
3799                dbf_type='vfp',
3800                )
3801
3802    def tearDown(self):
3803        self.dbf_table.close()
3804        self.vfp_table.close()
3805
3806    def test_dbf_storage(self):
3807        table = self.dbf_table
3808        table.open(mode=READ_WRITE)
3809        record = table.create_template()
3810        record.name = 'Stoneleaf'
3811        record.paid = True
3812        record.qty = 1
3813        record.orderdate = Date.today()
3814        record.desc = 'some Python dude'
3815        table.append(record)
3816
3817    def test_vfp_storage(self):
3818        table = self.vfp_table
3819        table.open(mode=READ_WRITE)
3820        record = table.create_template()
3821        record.name = 'Stoneleaf'
3822        record.paid = True
3823        record.qty = 1
3824        record.orderdate = Date.today()
3825        record.desc = 'some Python dude'
3826        record.mass = 251.9287
3827        record.weight = 971204.39
3828        record.age = 29
3829        record.meeting = DateTime.now()
3830        record.misc = MISC
3831        record.photo = PHOTO
3832        record.price = 19.99
3833        table.append(record)
3834
3835
3836class TestDbfFunctions(TestCase):
3837
3838    def setUp(self):
3839        "create a dbf and vfp table"
3840        self.empty_dbf_table = Table(
3841            os.path.join(tempdir, 'emptytemptable'),
3842            'name C(25); paid L; qty N(11,5); orderdate D; desc M', dbf_type='db3'
3843            )
3844        self.dbf_table = table = Table(
3845            os.path.join(tempdir, 'temptable'),
3846            'name C(25); paid L; qty N(11,5); orderdate D; desc M', dbf_type='db3'
3847            )
3848        table.open(mode=READ_WRITE)
3849        namelist = self.dbf_namelist = []
3850        paidlist = self.dbf_paidlist = []
3851        qtylist = self.dbf_qtylist = []
3852        orderlist = self.dbf_orderlist = []
3853        desclist = self.dbf_desclist = []
3854        for i in range(len(floats)):
3855            name = '%-25s' % words[i]
3856            paid = len(words[i]) % 3 == 0
3857            qty = floats[i]
3858            orderdate = datetime.date((numbers[i] + 1) * 2, (numbers[i] % 12) +1, (numbers[i] % 27) + 1)
3859            desc = ' '.join(words[i:i+50])
3860            namelist.append(name)
3861            paidlist.append(paid)
3862            qtylist.append(qty)
3863            orderlist.append(orderdate)
3864            desclist.append(desc)
3865            table.append({'name':name, 'paid':paid, 'qty':qty, 'orderdate':orderdate, 'desc':desc})
3866        table.close()
3867
3868        self.empty_vfp_table = Table(
3869                os.path.join(tempdir, 'emptytempvfp'),
3870                'name C(25); paid L; qty N(11,5); orderdate D; desc M; mass B;'
3871                ' weight F(18,3); age I; meeting T; misc G; photo P; price Y;'
3872                ' dist B BINARY; atom I BINARY; wealth Y BINARY;'
3873                ,
3874                dbf_type='vfp',
3875                )
3876        self.odd_memo_vfp_table = Table(
3877                os.path.join(tempdir, 'emptytempvfp'),
3878                'name C(25); paid L; qty N(11,5); orderdate D; desc M; mass B;'
3879                ' weight F(18,3); age I; meeting T; misc G; photo P; price Y;'
3880                ' dist B BINARY; atom I BINARY; wealth Y BINARY;'
3881                ,
3882                dbf_type='vfp',
3883                memo_size=48,
3884                )
3885        self.vfp_table = table = Table(
3886                os.path.join(tempdir, 'tempvfp'),
3887                'name C(25); paid L; qty N(11,5); orderdate D; desc M; mass B;'
3888                ' weight F(18,3); age I; meeting T; misc G; photo P; price Y;'
3889                ' dist B BINARY; atom I BINARY; wealth Y BINARY;'
3890                ,
3891                dbf_type='vfp',
3892                )
3893        table.open(mode=READ_WRITE)
3894        namelist = self.vfp_namelist = []
3895        paidlist = self.vfp_paidlist = []
3896        qtylist = self.vfp_qtylist = []
3897        orderlist = self.vfp_orderlist = []
3898        desclist = self.vfp_desclist = []
3899        masslist = self.vfp_masslist = []
3900        weightlist = self.vfp_weightlist = []
3901        agelist = self.vfp_agelist = []
3902        meetlist = self.vfp_meetlist = []
3903        misclist = self.vfp_misclist = []
3904        photolist = self.vfp_photolist = []
3905        pricelist = self.vfp_pricelist = []
3906        for i in range(len(floats)):
3907            name = words[i]
3908            paid = len(words[i]) % 3 == 0
3909            qty = floats[i]
3910            price = Decimal(round(floats[i] * 2.182737, 4))
3911            orderdate = datetime.date((numbers[i] + 1) * 2, (numbers[i] % 12) +1, (numbers[i] % 27) + 1)
3912            desc = ' '.join(words[i:i+50])
3913            mass = floats[i] * floats[i] / 2.0
3914            weight = round(floats[i] * 3, 3)
3915            age = numbers[i]
3916            meeting = datetime.datetime((numbers[i] + 2000), (numbers[i] % 12)+1, (numbers[i] % 28)+1, \
3917                      (numbers[i] % 24), numbers[i] % 60, (numbers[i] * 3) % 60)
3918            misc = ' '.join(words[i:i+50:3]).encode('latin1')
3919            photo = ' '.join(words[i:i+50:7]).encode('latin1')
3920            namelist.append('%-25s' % name)
3921            paidlist.append(paid)
3922            qtylist.append(qty)
3923            pricelist.append(price)
3924            orderlist.append(orderdate)
3925            desclist.append(desc)
3926            masslist.append(mass)
3927            weightlist.append(weight)
3928            agelist.append(age)
3929            meetlist.append(meeting)
3930            misclist.append(misc)
3931            photolist.append(photo)
3932            meeting = datetime.datetime((numbers[i] + 2000), (numbers[i] % 12)+1, (numbers[i] % 28)+1,
3933                      (numbers[i] % 24), numbers[i] % 60, (numbers[i] * 3) % 60)
3934            table.append({'name':name, 'paid':paid, 'qty':qty, 'orderdate':orderdate, 'desc':desc,
3935                    'mass':mass, 'weight':weight, 'age':age, 'meeting':meeting, 'misc':misc, 'photo':photo,
3936                    'price':price, 'dist':mass, 'atom':age, 'wealth':price})
3937        table.close()
3938
3939    def tearDown(self):
3940        self.dbf_table.close()
3941        self.vfp_table.close()
3942
3943    def test_add_fields_to_dbf_table(self):
3944        "dbf table:  adding and deleting fields"
3945        table = self.dbf_table
3946        table.open(mode=READ_WRITE)
3947        dbf._debug = True
3948        namelist = self.dbf_namelist
3949        paidlist = self.dbf_paidlist
3950        qtylist = self.dbf_qtylist
3951        orderlist = self.dbf_orderlist
3952        desclist = self.dbf_desclist
3953        table.delete_fields('name')
3954        table.close()
3955        table = Table(table.filename, dbf_type='db3')
3956        table.open(mode=READ_WRITE)
3957        for field in table.field_names:
3958            self.assertEqual(1, table.field_names.count(field))
3959        i = 0
3960        for record in table:
3961            self.assertEqual(dbf.recno(record), i)
3962            self.assertEqual(table[i].paid, paidlist[i])
3963            self.assertEqual(record.paid, paidlist[i])
3964            self.assertEqual(abs(table[i].qty - qtylist[i]) < .00001, True)
3965            self.assertEqual(abs(record.qty - qtylist[i]) < .00001, True)
3966            self.assertEqual(table[i].orderdate, orderlist[i])
3967            self.assertEqual(record.orderdate, orderlist[i])
3968            self.assertEqual(table[i].desc, desclist[i])
3969            self.assertEqual(record.desc, desclist[i])
3970            i += 1
3971        first, middle, last = table[0], table[len(table)//2], table[-1]
3972        table.delete_fields('paid, orderdate')
3973        for field in table.field_names:
3974            self.assertEqual(1, table.field_names.count(field))
3975        i = 0
3976        for record in table:
3977            self.assertEqual(dbf.recno(record), i)
3978            self.assertEqual(abs(table[i].qty - qtylist[i]) < .00001, True)
3979            self.assertEqual(abs(record.qty - qtylist[i]) < .00001, True)
3980            self.assertEqual(table[i].desc, desclist[i])
3981            self.assertEqual(record.desc, desclist[i])
3982            i += 1
3983        self.assertEqual(i, len(table))
3984        self.assertTrue('paid' not in dbf.field_names(first))
3985        self.assertTrue('orderdate' not in dbf.field_names(middle))
3986        self.assertTrue('name' not in dbf.field_names(last))
3987        table.add_fields('name C(25); paid L; orderdate D')
3988        for field in table.field_names:
3989            self.assertEqual(1, table.field_names.count(field))
3990        self.assertEqual(i, len(table))
3991        i = 0
3992        for i, record in enumerate(table):
3993            self.assertEqual(record.name, ' ' * 25)
3994            self.assertEqual(record.paid, None)
3995            self.assertEqual(record.orderdate, None)
3996            self.assertEqual(record.desc, desclist[i])
3997            i += 1
3998        self.assertEqual(i, len(table))
3999        i = 0
4000        for record in table:
4001            data = dict()
4002            data['name'] = namelist[dbf.recno(record)]
4003            data['paid'] = paidlist[dbf.recno(record)]
4004            data['orderdate'] = orderlist[dbf.recno(record)]
4005            dbf.gather(record, data)
4006            i += 1
4007        self.assertEqual(i, len(table))
4008        i = 0
4009        for record in table:
4010            self.assertEqual(dbf.recno(record), i)
4011            self.assertEqual(table[i].name, namelist[i])
4012            self.assertEqual(record.name, namelist[i])
4013            self.assertEqual(table[i].paid, paidlist[i])
4014            self.assertEqual(record.paid, paidlist[i])
4015            self.assertEqual(abs(table[i].qty - qtylist[i]) < .00001, True)
4016            self.assertEqual(abs(record.qty - qtylist[i]) < .00001, True)
4017            self.assertEqual(table[i].orderdate, orderlist[i])
4018            self.assertEqual(record.orderdate, orderlist[i])
4019            self.assertEqual(table[i].desc, desclist[i])
4020            self.assertEqual(record.desc, desclist[i])
4021            i += 1
4022        table.close()
4023
4024    def test_add_fields_to_vfp_table(self):
4025        "vfp table:  adding and deleting fields"
4026        table = self.vfp_table
4027        table.open(mode=READ_WRITE)
4028        namelist = self.vfp_namelist
4029        paidlist = self.vfp_paidlist
4030        qtylist = self.vfp_qtylist
4031        orderlist = self.vfp_orderlist
4032        desclist = self.vfp_desclist
4033        masslist = self.vfp_masslist
4034        weightlist = self.vfp_weightlist
4035        agelist = self.vfp_agelist
4036        meetlist = self.vfp_meetlist
4037        misclist = self.vfp_misclist
4038        photolist = self.vfp_photolist
4039        pricelist = self.vfp_pricelist
4040        self.assertEqual(len(table), len(floats))
4041        i = 0
4042        for record in table:
4043            self.assertEqual(dbf.recno(record), i)
4044            self.assertEqual(table[i].name, namelist[i])
4045            self.assertEqual(record.name, namelist[i])
4046            self.assertEqual(table[i].paid, paidlist[i])
4047            self.assertEqual(record.paid, paidlist[i])
4048            self.assertTrue(abs(table[i].qty - qtylist[i]) < .00001)
4049            self.assertTrue(abs(record.qty - qtylist[i]) < .00001)
4050            self.assertEqual(table[i].orderdate, orderlist[i])
4051            self.assertEqual(record.orderdate, orderlist[i])
4052            self.assertEqual(table[i].desc, desclist[i])
4053            self.assertEqual(record.desc, desclist[i])
4054            self.assertEqual(record.mass, masslist[i])
4055            self.assertEqual(table[i].mass, masslist[i])
4056            self.assertEqual(record.dist, masslist[i])
4057            self.assertEqual(table[i].dist, masslist[i])
4058            self.assertEqual(record.weight, weightlist[i])
4059            self.assertEqual(table[i].weight, weightlist[i])
4060            self.assertEqual(record.age, agelist[i])
4061            self.assertEqual(table[i].age, agelist[i])
4062            self.assertEqual(record.atom, agelist[i])
4063            self.assertEqual(table[i].atom, agelist[i])
4064            self.assertEqual(record.meeting, meetlist[i])
4065            self.assertEqual(table[i].meeting, meetlist[i])
4066            self.assertEqual(record.misc, misclist[i])
4067            self.assertEqual(table[i].misc, misclist[i])
4068            self.assertEqual(record.photo, photolist[i])
4069            self.assertEqual(table[i].photo, photolist[i])
4070            self.assertEqual(round(record.price, 4), round(pricelist[i], 4))
4071            self.assertEqual(round(table[i].price, 4), round(pricelist[i], 4))
4072            self.assertTrue(round(record.wealth, 4), round(pricelist[i], 4))
4073            self.assertTrue(round(table[i].wealth, 4), round(pricelist[i], 4))
4074            i += 1
4075        table.delete_fields('desc')
4076        i = 0
4077        for record in table:
4078            self.assertEqual(dbf.recno(record), i)
4079            self.assertEqual(table[i].name, namelist[i])
4080            self.assertEqual(record.name, namelist[i])
4081            self.assertEqual(table[i].paid, paidlist[i])
4082            self.assertEqual(record.paid, paidlist[i])
4083            self.assertEqual(abs(table[i].qty - qtylist[i]) < .00001, True)
4084            self.assertEqual(abs(record.qty - qtylist[i]) < .00001, True)
4085            self.assertEqual(table[i].orderdate, orderlist[i])
4086            self.assertEqual(record.orderdate, orderlist[i])
4087            self.assertEqual(record.weight, weightlist[i])
4088            self.assertEqual(table[i].weight, weightlist[i])
4089            self.assertEqual(record.age, agelist[i])
4090            self.assertEqual(table[i].age, agelist[i])
4091            self.assertEqual(record.atom, agelist[i])
4092            self.assertEqual(table[i].atom, agelist[i])
4093            self.assertEqual(record.meeting, meetlist[i])
4094            self.assertEqual(table[i].meeting, meetlist[i])
4095            self.assertEqual(record.misc, misclist[i])
4096            self.assertEqual(table[i].misc, misclist[i])
4097            self.assertEqual(record.photo, photolist[i])
4098            self.assertEqual(table[i].photo, photolist[i])
4099            self.assertEqual(record.mass, masslist[i])
4100            self.assertEqual(table[i].mass, masslist[i])
4101            self.assertEqual(record.dist, masslist[i])
4102            self.assertEqual(table[i].dist, masslist[i])
4103            self.assertEqual(round(record.price, 4), round(pricelist[i], 4))
4104            self.assertEqual(round(table[i].price, 4), round(pricelist[i], 4))
4105            self.assertTrue(round(record.wealth, 4), round(pricelist[i], 4))
4106            self.assertTrue(round(table[i].wealth, 4), round(pricelist[i], 4))
4107            i += 1
4108        table.delete_fields('paid, mass')
4109        i = 0
4110        for record in table:
4111            self.assertEqual(dbf.recno(record), i)
4112            self.assertEqual(table[i].name, namelist[i])
4113            self.assertEqual(record.name, namelist[i])
4114            self.assertEqual(abs(table[i].qty - qtylist[i]) < .00001, True)
4115            self.assertEqual(abs(record.qty - qtylist[i]) < .00001, True)
4116            self.assertEqual(table[i].orderdate, orderlist[i])
4117            self.assertEqual(record.orderdate, orderlist[i])
4118            self.assertEqual(record.weight, weightlist[i])
4119            self.assertEqual(table[i].weight, weightlist[i])
4120            self.assertEqual(record.age, agelist[i])
4121            self.assertEqual(table[i].age, agelist[i])
4122            self.assertEqual(record.atom, agelist[i])
4123            self.assertEqual(table[i].atom, agelist[i])
4124            self.assertEqual(record.meeting, meetlist[i])
4125            self.assertEqual(table[i].meeting, meetlist[i])
4126            self.assertEqual(record.misc, misclist[i])
4127            self.assertEqual(table[i].misc, misclist[i])
4128            self.assertEqual(record.photo, photolist[i])
4129            self.assertEqual(table[i].photo, photolist[i])
4130            self.assertEqual(record.dist, masslist[i])
4131            self.assertEqual(table[i].dist, masslist[i])
4132            self.assertEqual(round(record.price, 4), round(pricelist[i], 4))
4133            self.assertEqual(round(table[i].price, 4), round(pricelist[i], 4))
4134            self.assertTrue(round(record.wealth, 4), round(pricelist[i], 4))
4135            self.assertTrue(round(table[i].wealth, 4), round(pricelist[i], 4))
4136            i += 1
4137        table.add_fields('desc M; paid L; mass B')
4138        i = 0
4139        for record in table:
4140            self.assertEqual(record.desc, unicode(''))
4141            self.assertEqual(record.paid is None, True)
4142            self.assertEqual(record.mass, 0.0)
4143            i += 1
4144        self.assertEqual(i, len(table))
4145        i = 0
4146        for record in Process(table):
4147            record.desc = desclist[dbf.recno(record)]
4148            record.paid = paidlist[dbf.recno(record)]
4149            record.mass = masslist[dbf.recno(record)]
4150            i += 1
4151        self.assertEqual(i, len(table))
4152        i = 0
4153        for record in table:
4154            self.assertEqual(dbf.recno(record), i)
4155            self.assertEqual(table[i].name, namelist[i])
4156            self.assertEqual(record.name, namelist[i])
4157            self.assertEqual(table[i].paid, paidlist[i])
4158            self.assertEqual(record.paid, paidlist[i])
4159            self.assertEqual(abs(table[i].qty - qtylist[i]) < .00001, True)
4160            self.assertEqual(abs(record.qty - qtylist[i]) < .00001, True)
4161            self.assertEqual(table[i].orderdate, orderlist[i])
4162            self.assertEqual(record.orderdate, orderlist[i])
4163            self.assertEqual(table[i].desc, desclist[i])
4164            self.assertEqual(record.desc, desclist[i])
4165            self.assertEqual(record.mass, masslist[i])
4166            self.assertEqual(table[i].mass, masslist[i])
4167            self.assertEqual(record.dist, masslist[i])
4168            self.assertEqual(table[i].dist, masslist[i])
4169            self.assertEqual(record.weight, weightlist[i])
4170            self.assertEqual(table[i].weight, weightlist[i])
4171            self.assertEqual(record.age, agelist[i])
4172            self.assertEqual(table[i].age, agelist[i])
4173            self.assertEqual(record.atom, agelist[i])
4174            self.assertEqual(table[i].atom, agelist[i])
4175            self.assertEqual(record.meeting, meetlist[i])
4176            self.assertEqual(table[i].meeting, meetlist[i])
4177            self.assertEqual(record.misc, misclist[i])
4178            self.assertEqual(table[i].misc, misclist[i])
4179            self.assertEqual(record.photo, photolist[i])
4180            self.assertEqual(table[i].photo, photolist[i])
4181            self.assertEqual(round(record.price, 4), round(pricelist[i], 4))
4182            self.assertEqual(round(table[i].price, 4), round(pricelist[i], 4))
4183            self.assertTrue(round(record.wealth, 4), round(pricelist[i], 4))
4184            self.assertTrue(round(table[i].wealth, 4), round(pricelist[i], 4))
4185            i += 1
4186        table.close()
4187
4188    def test_len_contains_iter(self):
4189        "basic function tests - len, contains & iterators"
4190        table = self.dbf_table.open()
4191        for field in table.field_names:
4192            self.assertEqual(1, table.field_names.count(field))
4193        length = sum([1 for rec in table])
4194        self.assertEqual(length, len(table))
4195        i = 0
4196        for record in table:
4197            self.assertEqual(record, table[i])
4198            self.assertTrue(record in table)
4199            self.assertTrue(tuple(record) in table)
4200            self.assertTrue(scatter(record) in table)
4201            self.assertTrue(create_template(record) in table)
4202            i += 1
4203        self.assertEqual(i, len(table))
4204        table.close()
4205
4206    def test_undelete(self):
4207        "delete, undelete"
4208        table = Table(':memory:', 'name C(10)', dbf_type='db3', on_disk=False)
4209        table.open(mode=READ_WRITE)
4210        table.append()
4211        self.assertEqual(table.next_record, table[0])
4212        table = Table(':memory:', 'name C(10)', dbf_type='db3', on_disk=False)
4213        table.open(mode=READ_WRITE)
4214        table.append(multiple=10)
4215        self.assertEqual(table.next_record, table[0])
4216        table = self.dbf_table              # Table(os.path.join(tempdir, 'temptable'), dbf_type='db3')
4217        table.open(mode=READ_WRITE)
4218        total = len(table)
4219        table.bottom()
4220        self.assertEqual(dbf.recno(table.current_record), total)
4221        table.top()
4222        self.assertEqual(dbf.recno(table.current_record), -1)
4223        table.goto(27)
4224        self.assertEqual(dbf.recno(table.current_record), 27)
4225        table.goto(total-1)
4226        self.assertEqual(dbf.recno(table.current_record), total-1)
4227        table.goto(0)
4228        self.assertEqual(dbf.recno(table.current_record), 0)
4229        self.assertRaises(IndexError, table.goto, total)
4230        self.assertRaises(IndexError, table.goto, -len(table)-1)
4231        table.top()
4232        self.assertRaises(dbf.Bof, table.skip, -1)
4233        table.bottom()
4234        self.assertRaises(Eof, table.skip)
4235        for record in table:
4236            dbf.delete(record)
4237        active_records = table.create_index(active)
4238        active_records.top()
4239        self.assertRaises(Eof, active_records.skip)
4240        dbf._debug = True
4241        active_records.bottom()
4242        self.assertRaises(Bof, active_records.skip, -1)
4243        for record in table:
4244            dbf.undelete(record)
4245
4246        # delete every third record
4247        i = 0
4248        for record in table:
4249            self.assertEqual(dbf.recno(record), i)
4250            if i % 3 == 0:
4251                dbf.delete(record)
4252            i += 1
4253        i = 0
4254        # and verify
4255        for record in table:
4256            self.assertEqual(dbf.is_deleted(record), i%3==0)
4257            self.assertEqual(dbf.is_deleted(table[i]), i%3==0)
4258            i += 1
4259
4260        # check that deletes were saved to disk..
4261        table.close()
4262        table = Table(os.path.join(tempdir, 'temptable'), dbf_type='db3')
4263        table.open(mode=READ_WRITE)
4264        active_records = table.create_index(active)
4265        i = 0
4266        for record in table:
4267            self.assertEqual(dbf.is_deleted(record), i%3==0)
4268            self.assertEqual(dbf.is_deleted(table[i]), i%3==0)
4269            i += 1
4270
4271        # verify record numbers
4272        i = 0
4273        for record in table:
4274            self.assertEqual(dbf.recno(record), i)
4275            i += 1
4276
4277        # verify that deleted records are skipped
4278        i = 0
4279        for record in active_records:
4280            self.assertNotEqual(dbf.recno(record)%3, 0)
4281        active_records.goto(1)
4282        active_records.skip()
4283        self.assertEqual(dbf.recno(active_records.current_record), 4)
4284        active_records.skip(-1)
4285        self.assertEqual(dbf.recno(active_records.current_record), 2)
4286
4287        # verify that deleted records are skipped in slices
4288        list_of_records = active_records[3:6]
4289        self.assertEqual(len(list_of_records), 3)
4290        self.assertEqual(dbf.recno(list_of_records[0]), 5)
4291        self.assertEqual(dbf.recno(list_of_records[1]), 7)
4292        self.assertEqual(dbf.recno(list_of_records[2]), 8)
4293
4294        # verify behavior when all records are deleted
4295        for record in table:
4296            dbf.delete(record)
4297        active_records.bottom()
4298        self.assertRaises(Eof, active_records.skip)
4299        self.assertEqual(active_records.eof, True)
4300        active_records.top()
4301        self.assertRaises(Bof, active_records.skip, -1)
4302        self.assertEqual(active_records.bof, True)
4303
4304        # verify deleted records are seen with active record index
4305        deleted_records = table.create_index(inactive)
4306        i = 0
4307        for record in deleted_records:
4308            self.assertEqual(dbf.recno(record), i)
4309            i += 1
4310
4311        # verify undelete using table[index]
4312        for record in table:
4313            dbf.delete(record)
4314            self.assertTrue(dbf.is_deleted(record))
4315        for i, record in enumerate(table):
4316            dbf.undelete(table[i])
4317            self.assertEqual(dbf.is_deleted(record), False)
4318            self.assertEqual(dbf.is_deleted(table[i]), False)
4319            self.assertFalse(record in deleted_records)
4320
4321        # verify all records have been undeleted (recalled)
4322        self.assertEqual(len(active_records), len(table))
4323        self.assertEqual(len(deleted_records), 0)
4324        table.close()
4325
4326    def test_finding_ordering_searching(self):
4327        "finding, ordering, searching"
4328        table = self.dbf_table
4329        table.open(mode=READ_WRITE)
4330
4331        # find (brute force)
4332        unordered = []
4333        for record in table:
4334            unordered.append(record.name)
4335        for word in unordered:                                  # returns records
4336            # records = table.query("select * where name == %r" % word)
4337            # self.assertEqual(len(records), unordered.count(word))
4338            records = [rec for rec in table if rec.name == word]
4339            self.assertEqual(len(records), unordered.count(word))
4340
4341        # ordering by one field
4342        ordered = unordered[:]
4343        ordered.sort()
4344        name_index = table.create_index(lambda rec: rec.name)
4345        self.assertEqual(list(name_index[::-1]), list(reversed(name_index)))
4346        i = 0
4347        for record in name_index:
4348            self.assertEqual(record.name, ordered[i])
4349            i += 1
4350
4351        # search (BINARY)
4352        for word in unordered:
4353            records = name_index.search(match=word)
4354            self.assertEqual(len(records), unordered.count(word), "num records: %d\nnum words: %d\nfailure with %r" % (len(records), unordered.count(word), word))
4355            records = table.query("select * where name == %r" % word)
4356            self.assertEqual(len(records), unordered.count(word))
4357            records = dbf.pql(table, "select * where name == %r" % word)
4358            self.assertEqual(len(records), unordered.count(word))
4359
4360        # ordering by two fields
4361        ordered = unordered[:]
4362        ordered.sort()
4363        nd_index = table.create_index(lambda rec: (rec.name, rec.desc))
4364        self.assertEqual(list(nd_index[::-1]), list(reversed(nd_index)))
4365        i = 0
4366        for record in nd_index:
4367            self.assertEqual(record.name, ordered[i])
4368            i += 1
4369
4370        # search (BINARY)
4371        for word in unordered:
4372            records = nd_index.search(match=(word, ), partial=True)
4373            ucount = sum([1 for wrd in unordered if wrd.startswith(word)])
4374            self.assertEqual(len(records), ucount)
4375
4376        for record in table[::2]:
4377            dbf.write(record, qty=-record.qty)
4378        unordered = []
4379        for record in table:
4380            unordered.append(record.qty)
4381        ordered = unordered[:]
4382        ordered.sort()
4383        qty_index = table.create_index(lambda rec: rec.qty)
4384        self.assertEqual(list(qty_index[::-1]), list(reversed(qty_index)))
4385        i = 0
4386        for record in qty_index:
4387            self.assertEqual(record.qty, ordered[i])
4388            i += 1
4389        for number in unordered:
4390            records = qty_index.search(match=(number, ))
4391            self.assertEqual(len(records), unordered.count(number))
4392
4393        table.close()
4394
4395    def test_scatter_gather_new(self):
4396        "scattering and gathering fields, and new()"
4397        table = self.dbf_table
4398        table.open(mode=READ_WRITE)
4399        table2 = table.new(os.path.join(tempdir, 'temptable2'))
4400        table2.open(mode=READ_WRITE)
4401        for record in table:
4402            table2.append()
4403            newrecord = table2[-1]
4404            testdict = dbf.scatter(record)
4405            for key in field_names(testdict):
4406                self.assertEqual(testdict[key], record[key])
4407            dbf.gather(newrecord, dbf.scatter(record))
4408            for field in dbf.field_names(record):
4409                self.assertEqual(newrecord[field], record[field])
4410        table2.close()
4411        table2 = None
4412        table2 = Table(os.path.join(tempdir, 'temptable2'), dbf_type='db3')
4413        table2.open(mode=READ_WRITE)
4414        for i in range(len(table)):
4415            temp1 = dbf.scatter(table[i])
4416            temp2 = dbf.scatter(table2[i])
4417            for key in field_names(temp1):
4418                self.assertEqual(temp1[key], temp2[key])
4419            for key in field_names(temp2):
4420                self.assertEqual(temp1[key], temp2[key])
4421        table2.close()
4422        table3 = table.new(':memory:', on_disk=False)
4423        table3.open(mode=READ_WRITE)
4424        for record in table:
4425            table3.append(record)
4426        table4 = self.vfp_table
4427        table4.open(mode=READ_WRITE)
4428        table5 = table4.new(':memory:', on_disk=False)
4429        table5.open(mode=READ_WRITE)
4430        for record in table4:
4431            table5.append(record)
4432        table.close()
4433        table3.close()
4434        table4.close()
4435        table5.close()
4436
4437    def test_rename_contains_has_key(self):
4438        "renaming fields, __contains__, has_key"
4439        table = self.dbf_table
4440        table.open(mode=READ_WRITE)
4441        for field in table.field_names:
4442            oldfield = field
4443            table.rename_field(oldfield, 'newfield')
4444            self.assertEqual(oldfield in table.field_names, False)
4445            self.assertEqual('newfield' in table.field_names, True)
4446            table.close()
4447            table = Table(os.path.join(tempdir, 'temptable'), dbf_type='db3')
4448            table.open(mode=READ_WRITE)
4449            self.assertEqual(oldfield in table.field_names, False)
4450            self.assertEqual('newfield' in table.field_names, True)
4451            table.rename_field('newfield', oldfield)
4452            self.assertEqual(oldfield in table.field_names, True)
4453            self.assertEqual('newfield' in table.field_names, False)
4454        table.close()
4455
4456    def test_dbf_record_kamikaze(self):
4457        "kamikaze"
4458        table = self.dbf_table
4459        table.open(mode=READ_WRITE)
4460        table2 = table.new(os.path.join(tempdir, 'temptable2'))
4461        table2.open(mode=READ_WRITE)
4462        for record in table:
4463            table2.append(record)
4464            newrecord = table2[-1]
4465            for key in table.field_names:
4466                if key not in table.memo_types:
4467                    self.assertEqual(newrecord[key], record[key])
4468            for field in dbf.field_names(newrecord):
4469                if key not in table2.memo_types:
4470                    self.assertEqual(newrecord[field], record[field])
4471        table2.close()
4472        table2 = Table(os.path.join(tempdir, 'temptable2'), dbf_type='db3')
4473        table2.open(mode=READ_WRITE)
4474        for i in range(len(table)):
4475            dict1 = dbf.scatter(table[i], as_type=dict)
4476            dict2 = dbf.scatter(table2[i], as_type=dict)
4477            for key in dict1.keys():
4478                if key not in table.memo_types:
4479                    self.assertEqual(dict1[key], dict2[key])
4480            for key in dict2.keys():
4481                if key not in table2.memo_types:
4482                    self.assertEqual(dict1[key], dict2[key])
4483        for i in range(len(table)):
4484            template1 = dbf.scatter(table[i])
4485            template2 = dbf.scatter(table2[i])
4486            for key in dbf.field_names(template1):
4487                if key not in table.memo_types:
4488                    self.assertEqual(template1[key], template2[key])
4489            for key in dbf.field_names(template2):
4490                if key not in table2.memo_types:
4491                    self.assertEqual(template1[key], template2[key])
4492        table.close()
4493        table2.close()
4494
4495    def test_multiple_append(self):
4496        "multiple append"
4497        table = self.dbf_table
4498        table.open(mode=READ_WRITE)
4499        table2 = table.new(os.path.join(tempdir, 'temptable2'))
4500        table2.open(mode=READ_WRITE)
4501        record = table.next_record
4502        table2.append(dbf.scatter(record), multiple=100)
4503        for samerecord in table2:
4504            for field in dbf.field_names(record):
4505                self.assertEqual(record[field], samerecord[field])
4506        table2.close()
4507        table2 = Table(os.path.join(tempdir, 'temptable2'), dbf_type='db3')
4508        table2.open(mode=READ_WRITE)
4509        for samerecord in table2:
4510            for field in dbf.field_names(record):
4511                self.assertEqual(record[field], samerecord[field])
4512        table2.close()
4513        table3 = table.new(os.path.join(tempdir, 'temptable3'))
4514        table3.open(mode=READ_WRITE)
4515        record = table.next_record
4516        table3.append(record, multiple=100)
4517        for samerecord in table3:
4518            for field in dbf.field_names(record):
4519                self.assertEqual(record[field], samerecord[field])
4520        table3.close()
4521        table3 = Table(os.path.join(tempdir, 'temptable3'), dbf_type='db3')
4522        table3.open(mode=READ_WRITE)
4523        for samerecord in table3:
4524            for field in dbf.field_names(record):
4525                self.assertEqual(record[field], samerecord[field])
4526        table3.close()
4527        table.close()
4528
4529    def test_slices(self):
4530        "slices"
4531        table = self.dbf_table
4532        table.open(mode=READ_WRITE)
4533        slice1 = [table[0], table[1], table[2]]
4534        self.assertEqual(slice1, list(table[:3]))
4535        slice2 = [table[-3], table[-2], table[-1]]
4536        self.assertEqual(slice2, list(table[-3:]))
4537        slice3 = [record for record in table]
4538        self.assertEqual(slice3, list(table[:]))
4539        slice4 = [table[9]]
4540        self.assertEqual(slice4, list(table[9:10]))
4541        slice5 = [table[15], table[16], table[17], table[18]]
4542        self.assertEqual(slice5, list(table[15:19]))
4543        slice6 = [table[0], table[2], table[4], table[6], table[8]]
4544        self.assertEqual(slice6, list(table[:9:2]))
4545        slice7 = [table[-1], table[-2], table[-3]]
4546        self.assertEqual(slice7, list(table[-1:-4:-1]))
4547        table.close()
4548
4549    def test_record_reset(self):
4550        "reset record"
4551        table = self.dbf_table
4552        table.open(mode=READ_WRITE)
4553        for record in table:
4554            with record:
4555                self.assertTrue(record.qty)
4556                dbf.reset(record, keep_fields=['name'])
4557            self.assertFalse(record.qty)
4558            self.assertTrue(record.name)
4559        for record in table:
4560            dbf.reset(record)
4561        self.assertEqual(table[0].name, table[1].name)
4562        dbf.write(table[0], name='Python rocks!')
4563        self.assertNotEqual(table[0].name, table[1].name)
4564        table.close()
4565
4566    def test_adding_memos(self):
4567        "adding memos to existing records"
4568        table = Table(':memory:', 'name C(50); age N(3,0)', dbf_type='db3', on_disk=False)
4569        table.open(mode=READ_WRITE)
4570        table.append(('user', 0))
4571        table.add_fields('motto M')
4572        dbf.write(table[0], motto='Are we there yet??')
4573        self.assertEqual(table[0].motto, 'Are we there yet??')
4574        table.close()
4575        table = Table(os.path.join(tempdir, 'temptable4'), 'name C(50); age N(3,0)', dbf_type='db3')
4576        table.open(mode=READ_WRITE)
4577        table.append(('user', 0))
4578        table.close()
4579        table.open(mode=READ_WRITE)
4580        table.close()
4581        table = Table(os.path.join(tempdir, 'temptable4'), dbf_type='db3')
4582        table.open(mode=READ_WRITE)
4583        table.add_fields('motto M')
4584        dbf.write(table[0], motto='Are we there yet??')
4585        self.assertEqual(table[0].motto, 'Are we there yet??')
4586        table.close()
4587        table = Table(os.path.join(tempdir, 'temptable4'), dbf_type='db3')
4588        table.open(mode=READ_WRITE)
4589        self.assertEqual(table[0].motto, 'Are we there yet??')
4590        table.close()
4591        table = Table(os.path.join(tempdir, 'temptable4'), 'name C(50); age N(3,0)', dbf_type='vfp')
4592        table.open(mode=READ_WRITE)
4593        table.append(('user', 0))
4594        table.close()
4595        table.open(mode=READ_WRITE)
4596        table.close()
4597        table = Table(os.path.join(tempdir, 'temptable4'), dbf_type='vfp')
4598        table.open(mode=READ_WRITE)
4599        table.add_fields('motto M')
4600        dbf.write(table[0], motto='Are we there yet??')
4601        self.assertEqual(table[0].motto, 'Are we there yet??')
4602        table.close()
4603        table = Table(os.path.join(tempdir, 'temptable4'), dbf_type='vfp')
4604        table.open(mode=READ_WRITE)
4605        self.assertEqual(table[0].motto, 'Are we there yet??')
4606        table.close()
4607
4608    def test_from_csv(self):
4609        "from_csv"
4610        table = self.dbf_table
4611        table.open(mode=READ_WRITE)
4612        dbf.export(table, table.filename, header=False)
4613        csvtable = dbf.from_csv(os.path.join(tempdir, 'temptable.csv'))
4614        csvtable.open(mode=READ_WRITE)
4615        for i in index(table):
4616            for j in index(table.field_names):
4617                self.assertEqual(str(table[i][j]), csvtable[i][j])
4618        csvtable.close()
4619        csvtable = dbf.from_csv(os.path.join(tempdir, 'temptable.csv'), to_disk=True, filename=os.path.join(tempdir, 'temptable5'))
4620        csvtable.open(mode=READ_WRITE)
4621        for i in index(table):
4622            for j in index(table.field_names):
4623                self.assertEqual(str(table[i][j]).strip(), csvtable[i][j].strip())
4624        csvtable.close()
4625        csvtable = dbf.from_csv(os.path.join(tempdir, 'temptable.csv'), field_names=['field1','field2'])
4626        csvtable.open(mode=READ_WRITE)
4627        for i in index(table):
4628            for j in index(table.field_names):
4629                self.assertEqual(str(table[i][j]), csvtable[i][j])
4630        csvtable.close()
4631        csvtable = dbf.from_csv(os.path.join(tempdir, 'temptable.csv'), field_names=['field1','field2'], to_disk=True, filename=os.path.join(tempdir, 'temptable5'))
4632        csvtable.open(mode=READ_WRITE)
4633        for i in index(table):
4634            for j in index(table.field_names):
4635                self.assertEqual(str(table[i][j]).strip(), csvtable[i][j].strip())
4636        csvtable.close()
4637        csvtable = dbf.from_csv(os.path.join(tempdir, 'temptable.csv'), extra_fields=['count N(5,0)','id C(10)'])
4638        csvtable.open(mode=READ_WRITE)
4639        for i in index(table):
4640            for j in index(table.field_names):
4641                self.assertEqual(str(table[i][j]), csvtable[i][j])
4642        csvtable.close()
4643        csvtable = dbf.from_csv(os.path.join(tempdir, 'temptable.csv'), extra_fields=['count N(5,0)','id C(10)'], to_disk=True, filename=os.path.join(tempdir, 'temptable5'))
4644        csvtable.open(mode=READ_WRITE)
4645        for i in index(table):
4646            for j in index(table.field_names):
4647                self.assertEqual(str(table[i][j]).strip(), csvtable[i][j].strip())
4648        csvtable.close()
4649        csvtable = dbf.from_csv(os.path.join(tempdir, 'temptable.csv'), field_names=['name','qty','paid','desc'], extra_fields='test1 C(15);test2 L'.split(';'))
4650        csvtable.open(mode=READ_WRITE)
4651        for i in index(table):
4652            for j in index(table.field_names):
4653                self.assertEqual(str(table[i][j]), csvtable[i][j])
4654        csvtable.close()
4655        csvtable = dbf.from_csv(os.path.join(tempdir, 'temptable.csv'), field_names=['name','qty','paid','desc'], extra_fields='test1 C(15);test2 L'.split(';'), to_disk=True, filename=os.path.join(tempdir, 'temptable5'))
4656        csvtable.open(mode=READ_WRITE)
4657        for i in index(table):
4658            for j in index(table.field_names):
4659                self.assertEqual(str(table[i][j]).strip(), csvtable[i][j].strip())
4660        csvtable.close()
4661
4662    def test_resize_empty(self):
4663        "resize"
4664        table = self.empty_dbf_table
4665        table.open(mode=READ_WRITE)
4666        table.resize_field('name', 40)
4667        table.close()
4668
4669    def test_resize(self):
4670        "resize"
4671        table = self.dbf_table
4672        table.open(mode=READ_WRITE)
4673        test_record = dbf.scatter(table[5])
4674        test_record = dbf.scatter(table[5])
4675        table.resize_field('name', 40)
4676        new_record = dbf.scatter(table[5])
4677        self.assertEqual(test_record['orderdate'], new_record['orderdate'])
4678        table.close()
4679
4680    def test_memos_after_close(self):
4681        "memos available after close/open"
4682        table = dbf.Table('tempy', 'name C(20); desc M', dbf_type='db3', default_data_types=dict(C=Char))
4683        table.open(mode=READ_WRITE)
4684        table.append(('Author','dashing, debonair, delightful'))
4685        table.close()
4686        table.open(mode=READ_WRITE)
4687        self.assertEqual(tuple(table[0]), ('Author','dashing, debonair, delightful'))
4688        table.close()
4689        table2 = dbf.Table('tempy', 'name C(20); desc M', dbf_type='db3')
4690        table2.open(mode=READ_WRITE)
4691        table2.append(('Benedict', 'brilliant, bombastic, bothered'))
4692        table2.close()
4693        table.open(mode=READ_WRITE)
4694        self.assertEqual(table[0].name, 'Benedict')
4695        self.assertEqual(table[0].desc, 'brilliant, bombastic, bothered')
4696        table.close()
4697
4698    def test_field_type(self):
4699        "table.type(field) == ('C', Char)"
4700        table = dbf.Table('tempy', 'name C(20); desc M', dbf_type='db3', default_data_types=dict(C=Char))
4701        table.open(mode=READ_WRITE)
4702        field_info = table.field_info('name')
4703        self.assertEqual(field_info, (dbf.FieldType.CHAR, 20, 0, Char))
4704        self.assertEqual(field_info.field_type, dbf.FieldType.CHAR)
4705        self.assertEqual(field_info.length, 20)
4706        self.assertEqual(field_info.decimal, 0)
4707        self.assertEqual(field_info.py_type, Char)
4708        table.close()
4709
4710    def test_memo_after_backup(self):
4711        "memo fields accessible after .backup()"
4712        table = self.dbf_table
4713        table.open(mode=READ_WRITE)
4714        table.create_backup()
4715        backup = dbf.Table(table.backup)
4716        backup.open(mode=READ_WRITE)
4717        desclist = self.dbf_desclist
4718        for i in range(len(desclist)):
4719            self.assertEqual(desclist[i], backup[i].desc)
4720        backup.close()
4721        table.close()
4722
4723    def test_memo_file_size_before_backup(self):
4724        table = self.odd_memo_vfp_table
4725        self.assertEqual(48, table._meta.memo_size)
4726
4727    def test_memo_file_size_after_backup(self):
4728        table = self.odd_memo_vfp_table
4729        table.open(mode=READ_ONLY)
4730        table.create_backup()
4731        table.close()
4732        backup = dbf.Table(table.backup)
4733        self.assertEqual(backup._meta.memo_size, table._meta.memo_size)
4734
4735    def test_write_loop(self):
4736        "Process loop commits changes"
4737        table = self.dbf_table
4738        table.open(mode=READ_WRITE)
4739        for record in Process(table):
4740            record.name = '!BRAND NEW NAME!'
4741        for record in table:
4742            self.assertEqual(record.name, '!BRAND NEW NAME!         ')
4743        table.close()
4744
4745    def test_export(self):
4746        for table in self.dbf_table, self.vfp_table:
4747            table.open(mode=READ_WRITE)
4748            dbf.export(table, filename='test_export.csv')
4749
4750    def test_index_search(self):
4751        table = Table("unordered", "icao C(20)", default_data_types=dict(C=Char), on_disk=False).open(mode=READ_WRITE)
4752        icao = ("kilo charlie echo golf papa hotel delta tango india sierra juliet lima zulu mike "
4753                "bravo november alpha oscar quebec romeo uniform victor whiskey x-ray yankee foxtrot".split())
4754        for alpha in icao:
4755            table.append((alpha,))
4756        sorted = table.create_index(lambda rec: rec.icao)
4757        self.assertTrue(sorted.index_search('alpha'))
4758        self.assertTrue(sorted.index_search('bravo'))
4759        self.assertTrue(sorted.index_search('charlie'))
4760        self.assertTrue(sorted.index_search('delta'))
4761        self.assertTrue(sorted.index_search('echo'))
4762        self.assertTrue(sorted.index_search('foxtrot'))
4763        self.assertTrue(sorted.index_search('golf'))
4764        self.assertTrue(sorted.index_search('hotel'))
4765        self.assertTrue(sorted.index_search('india'))
4766        self.assertTrue(sorted.index_search('juliet'))
4767        self.assertTrue(sorted.index_search('kilo'))
4768        self.assertTrue(sorted.index_search('lima'))
4769        self.assertTrue(sorted.index_search('mike'))
4770        self.assertTrue(sorted.index_search('november'))
4771        self.assertTrue(sorted.index_search('oscar'))
4772        self.assertTrue(sorted.index_search('papa'))
4773        self.assertTrue(sorted.index_search('quebec'))
4774        self.assertTrue(sorted.index_search('romeo'))
4775        self.assertTrue(sorted.index_search('sierra'))
4776        self.assertTrue(sorted.index_search('tango'))
4777        self.assertTrue(sorted.index_search('uniform'))
4778        self.assertTrue(sorted.index_search('victor'))
4779        self.assertTrue(sorted.index_search('whiskey'))
4780        self.assertTrue(sorted.index_search('x-ray'))
4781        self.assertTrue(sorted.index_search('yankee'))
4782        self.assertTrue(sorted.index_search('zulu'))
4783        self.assertEqual(sorted.index_search('alpha'), 0)
4784        self.assertEqual(sorted.index_search('bravo'), 1)
4785        self.assertEqual(sorted.index_search('charlie'), 2)
4786        self.assertEqual(sorted.index_search('delta'), 3)
4787        self.assertEqual(sorted.index_search('echo'), 4)
4788        self.assertEqual(sorted.index_search('foxtrot'), 5)
4789        self.assertEqual(sorted.index_search('golf'), 6)
4790        self.assertEqual(sorted.index_search('hotel'), 7)
4791        self.assertEqual(sorted.index_search('india'), 8)
4792        self.assertEqual(sorted.index_search('juliet'), 9)
4793        self.assertEqual(sorted.index_search('kilo'), 10)
4794        self.assertEqual(sorted.index_search('lima'), 11)
4795        self.assertEqual(sorted.index_search('mike'), 12)
4796        self.assertEqual(sorted.index_search('november'), 13)
4797        self.assertEqual(sorted.index_search('oscar'), 14)
4798        self.assertEqual(sorted.index_search('papa'), 15)
4799        self.assertEqual(sorted.index_search('quebec'), 16)
4800        self.assertEqual(sorted.index_search('romeo'), 17)
4801        self.assertEqual(sorted.index_search('sierra'), 18)
4802        self.assertEqual(sorted.index_search('tango'), 19)
4803        self.assertEqual(sorted.index_search('uniform'), 20)
4804        self.assertEqual(sorted.index_search('victor'), 21)
4805        self.assertEqual(sorted.index_search('whiskey'), 22)
4806        self.assertEqual(sorted.index_search('x-ray'), 23)
4807        self.assertEqual(sorted.index_search('yankee'), 24)
4808        self.assertEqual(sorted.index_search('zulu'), 25)
4809        self.assertRaises(NotFoundError, sorted.index_search, 'john')
4810        self.assertRaises(NotFoundError, sorted.index_search, 'john', partial=True)
4811        self.assertEqual(sorted.index_search('able', nearest=True), 0)
4812        self.assertFalse(sorted.index_search('able', nearest=True))
4813        self.assertEqual(sorted.index_search('alp', partial=True), 0)
4814        self.assertTrue(sorted.index_search('alp', partial=True))
4815        self.assertEqual(sorted.index_search('john', nearest=True), 9)
4816        self.assertFalse(sorted.index_search('john', nearest=True))
4817        self.assertEqual(sorted.index_search('jul', partial=True), 9)
4818        self.assertTrue(sorted.index_search('jul', partial=True))
4819
4820
4821class TestDbfNavigation(TestCase):
4822
4823    def setUp(self):
4824        "create a dbf and vfp table"
4825        self.dbf_table = table = Table(
4826            os.path.join(tempdir, 'temptable'),
4827            'name C(25); paid L; qty N(11,5); orderdate D; desc M', dbf_type='db3'
4828            )
4829        table.open(mode=READ_WRITE)
4830        namelist = self.dbf_namelist = []
4831        paidlist = self.dbf_paidlist = []
4832        qtylist = self.dbf_qtylist = []
4833        orderlist = self.dbf_orderlist = []
4834        desclist = self.dbf_desclist = []
4835        for i in range(len(floats)):
4836            name = '%-25s' % words[i]
4837            paid = len(words[i]) % 3 == 0
4838            qty = floats[i]
4839            orderdate = datetime.date((numbers[i] + 1) * 2, (numbers[i] % 12) +1, (numbers[i] % 27) + 1)
4840            desc = ' '.join(words[i:i+50])
4841            namelist.append(name)
4842            paidlist.append(paid)
4843            qtylist.append(qty)
4844            orderlist.append(orderdate)
4845            desclist.append(desc)
4846            table.append({'name':name, 'paid':paid, 'qty':qty, 'orderdate':orderdate, 'desc':desc})
4847        table.close()
4848
4849        self.vfp_table = table = Table(
4850                os.path.join(tempdir, 'tempvfp'),
4851                'name C(25); paid L; qty N(11,5); orderdate D; desc M; mass B;'
4852                ' weight F(18,3); age I; meeting T; misc G; photo P',
4853                dbf_type='vfp',
4854                )
4855        table.open(mode=READ_WRITE)
4856        namelist = self.vfp_namelist = []
4857        paidlist = self.vfp_paidlist = []
4858        qtylist = self.vfp_qtylist = []
4859        orderlist = self.vfp_orderlist = []
4860        desclist = self.vfp_desclist = []
4861        masslist = self.vfp_masslist = []
4862        weightlist = self.vfp_weightlist = []
4863        agelist = self.vfp_agelist = []
4864        meetlist = self.vfp_meetlist = []
4865        misclist = self.vfp_misclist = []
4866        photolist = self.vfp_photolist = []
4867        for i in range(len(floats)):
4868            name = words[i]
4869            paid = len(words[i]) % 3 == 0
4870            qty = floats[i]
4871            orderdate = datetime.date((numbers[i] + 1) * 2, (numbers[i] % 12) +1, (numbers[i] % 27) + 1)
4872            desc = ' '.join(words[i:i+50])
4873            mass = floats[i] * floats[i] / 2.0
4874            weight = floats[i] * 3
4875            age = numbers[i]
4876            meeting = datetime.datetime((numbers[i] + 2000), (numbers[i] % 12)+1, (numbers[i] % 28)+1, \
4877                      (numbers[i] % 24), numbers[i] % 60, (numbers[i] * 3) % 60)
4878            misc = ' '.join(words[i:i+50:3]).encode('ascii')
4879            photo = ' '.join(words[i:i+50:7]).encode('ascii')
4880            namelist.append('%-25s' % name)
4881            paidlist.append(paid)
4882            qtylist.append(qty)
4883            orderlist.append(orderdate)
4884            desclist.append(desc)
4885            masslist.append(mass)
4886            weightlist.append(weight)
4887            agelist.append(age)
4888            meetlist.append(meeting)
4889            misclist.append(misc)
4890            photolist.append(photo)
4891            meeting = datetime.datetime((numbers[i] + 2000), (numbers[i] % 12)+1, (numbers[i] % 28)+1,
4892                      (numbers[i] % 24), numbers[i] % 60, (numbers[i] * 3) % 60)
4893            table.append({'name':name, 'paid':paid, 'qty':qty, 'orderdate':orderdate, 'desc':desc,
4894                    'mass':mass, 'weight':weight, 'age':age, 'meeting':meeting, 'misc':misc, 'photo':photo})
4895        table.close()
4896
4897    def tearDown(self):
4898        self.dbf_table.close()
4899        self.vfp_table.close()
4900
4901    def test_top(self):
4902        "top, current in Tables, Lists, and Indexes"
4903        table = self.dbf_table
4904        table.open(mode=READ_WRITE)
4905        list = List(table)
4906        index = Index(table, key=lambda rec: dbf.recno(rec))
4907        total = len(table)
4908        mid = total // 2
4909        table.goto(mid)
4910        list.goto(mid)
4911        index.goto(mid)
4912        self.assertTrue(table.current != -1)
4913        self.assertTrue(list.current != -1)
4914        self.assertTrue(index.current != -1)
4915        table.top()
4916        list.top()
4917        index.top()
4918        self.assertEqual(table.current, -1)
4919        self.assertEqual(list.current, -1)
4920        self.assertEqual(index.current, -1)
4921
4922    def test_bottom(self):
4923        "bottom, current in Tables, Lists, and Indexes"
4924        table = self.dbf_table
4925        table.open(mode=READ_WRITE)
4926        list = List(table)
4927        index = Index(table, key=lambda rec: dbf.recno(rec))
4928        total = len(table)
4929        mid = total // 2
4930        table.goto(mid)
4931        list.goto(mid)
4932        index.goto(mid)
4933        self.assertTrue(table.current != -1)
4934        self.assertTrue(list.current != -1)
4935        self.assertTrue(index.current != -1)
4936        table.bottom()
4937        list.bottom()
4938        index.bottom()
4939        self.assertEqual(table.current, total)
4940        self.assertEqual(list.current, total)
4941        self.assertEqual(index.current, total)
4942
4943    def test_goto(self):
4944        "goto, current in Tables, Lists, and Indexes"
4945        table = self.dbf_table
4946        table.open(mode=READ_WRITE)
4947        list = List(table)
4948        index = Index(table, key=lambda rec: dbf.recno(rec))
4949        total = len(table)
4950        mid = total // 2
4951        table.goto(mid)
4952        list.goto(mid)
4953        index.goto(mid)
4954        self.assertEqual(table.current, mid)
4955        self.assertEqual(list.current, mid)
4956        self.assertEqual(index.current, mid)
4957        table.goto('top')
4958        list.goto('top')
4959        index.goto('top')
4960        self.assertEqual(table.current, -1)
4961        self.assertEqual(list.current, -1)
4962        self.assertEqual(index.current, -1)
4963        table.goto('bottom')
4964        list.goto('bottom')
4965        index.goto('bottom')
4966        self.assertEqual(table.current, total)
4967        self.assertEqual(list.current, total)
4968        self.assertEqual(index.current, total)
4969        dbf.delete(table[10])
4970        self.assertTrue(dbf.is_deleted(list[10]))
4971        self.assertTrue(dbf.is_deleted(index[10]))
4972        table.goto(10)
4973        list.goto(10)
4974        index.goto(10)
4975        self.assertEqual(table.current, 10)
4976        self.assertEqual(list.current, 10)
4977        self.assertEqual(index.current, 10)
4978        table.close()
4979
4980    def test_skip(self):
4981        "skip, current in Tables, Lists, and Indexes"
4982        table = self.dbf_table
4983        table.open(mode=READ_WRITE)
4984        list = List(table)
4985        index = Index(table, key=lambda rec: dbf.recno(rec))
4986        total = len(table)
4987        self.assertEqual(table.current, -1)
4988        self.assertEqual(list.current, -1)
4989        self.assertEqual(index.current, -1)
4990        table.skip(1)
4991        list.skip(1)
4992        index.skip(1)
4993        self.assertEqual(table.current, 0)
4994        self.assertEqual(list.current, 0)
4995        self.assertEqual(index.current, 0)
4996        table.skip(10)
4997        list.skip(10)
4998        index.skip(10)
4999        self.assertEqual(table.current, 10)
5000        self.assertEqual(list.current, 10)
5001        self.assertEqual(index.current, 10)
5002        table.close()
5003
5004    def test_first_record(self):
5005        "first_record in Tables, Lists, and Indexes"
5006        table = self.dbf_table
5007        table.open(mode=READ_WRITE)
5008        list = List(table)
5009        index = Index(table, key=lambda rec: dbf.recno(rec))
5010        total = len(table)
5011        self.assertTrue(table[0] is list[0])
5012        self.assertTrue(table[0] is index[0])
5013        self.assertTrue(table.first_record is table[0])
5014        self.assertTrue(list.first_record is table[0])
5015        self.assertTrue(index.first_record is table[0])
5016        table.close()
5017
5018    def test_prev_record(self):
5019        "prev_record in Tables, Lists, and Indexes"
5020        table = self.dbf_table
5021        table.open(mode=READ_WRITE)
5022        list = List(table)
5023        index = Index(table, key=lambda rec: dbf.recno(rec))
5024        total = len(table)
5025        self.assertTrue(table[0] is list[0])
5026        self.assertTrue(table[0] is index[0])
5027        table.top()
5028        list.top()
5029        index.top()
5030        self.assertTrue(isinstance(table.prev_record, dbf.RecordVaporWare))
5031        self.assertTrue(isinstance(list.prev_record, dbf.RecordVaporWare))
5032        self.assertTrue(isinstance(index.prev_record, dbf.RecordVaporWare))
5033        table.skip()
5034        list.skip()
5035        index.skip()
5036        self.assertTrue(isinstance(table.prev_record, dbf.RecordVaporWare))
5037        self.assertTrue(isinstance(list.prev_record, dbf.RecordVaporWare))
5038        self.assertTrue(isinstance(index.prev_record, dbf.RecordVaporWare))
5039        table.skip()
5040        list.skip()
5041        index.skip()
5042        self.assertTrue(table.prev_record is table[0])
5043        self.assertTrue(list.prev_record is table[0])
5044        self.assertTrue(index.prev_record is table[0])
5045        table.close()
5046
5047    def test_current_record(self):
5048        "current_record in Tables, Lists, and Indexes"
5049        table = self.dbf_table
5050        table.open(mode=READ_WRITE)
5051        list = List(table)
5052        index = Index(table, key=lambda rec: dbf.recno(rec))
5053        total = len(table)
5054        mid = total // 2
5055        table.top()
5056        list.top()
5057        index.top()
5058        self.assertTrue(isinstance(table.current_record, dbf.RecordVaporWare))
5059        self.assertTrue(isinstance(list.current_record, dbf.RecordVaporWare))
5060        self.assertTrue(isinstance(index.current_record, dbf.RecordVaporWare))
5061        table.bottom()
5062        list.bottom()
5063        index.bottom()
5064        self.assertTrue(isinstance(table.current_record, dbf.RecordVaporWare))
5065        self.assertTrue(isinstance(list.current_record, dbf.RecordVaporWare))
5066        self.assertTrue(isinstance(index.current_record, dbf.RecordVaporWare))
5067        table.goto(mid)
5068        list.goto(mid)
5069        index.goto(mid)
5070        self.assertTrue(table.current_record is table[mid])
5071        self.assertTrue(list.current_record is table[mid])
5072        self.assertTrue(index.current_record is table[mid])
5073        table.close()
5074
5075    def test_next_record(self):
5076        "prev_record in Tables, Lists, and Indexes"
5077        table = self.dbf_table
5078        table.open(mode=READ_WRITE)
5079        list = List(table)
5080        index = Index(table, key=lambda rec: dbf.recno(rec))
5081        total = len(table)
5082        self.assertTrue(table[0] is list[0])
5083        self.assertTrue(table[0] is index[0])
5084        table.bottom()
5085        list.bottom()
5086        index.bottom()
5087        self.assertTrue(isinstance(table.next_record, dbf.RecordVaporWare))
5088        self.assertTrue(isinstance(list.next_record, dbf.RecordVaporWare))
5089        self.assertTrue(isinstance(index.next_record, dbf.RecordVaporWare))
5090        table.skip(-1)
5091        list.skip(-1)
5092        index.skip(-1)
5093        self.assertTrue(isinstance(table.next_record, dbf.RecordVaporWare))
5094        self.assertTrue(isinstance(list.next_record, dbf.RecordVaporWare))
5095        self.assertTrue(isinstance(index.next_record, dbf.RecordVaporWare))
5096        table.skip(-1)
5097        list.skip(-1)
5098        index.skip(-1)
5099        self.assertTrue(table.next_record is table[-1])
5100        self.assertTrue(list.next_record is table[-1])
5101        self.assertTrue(index.next_record is table[-1])
5102        table.close()
5103
5104    def test_last_record(self):
5105        "last_record in Tables, Lists, and Indexes"
5106        table = self.dbf_table
5107        table.open(mode=READ_WRITE)
5108        list = List(table)
5109        index = Index(table, key=lambda rec: dbf.recno(rec))
5110        total = len(table)
5111        self.assertTrue(table[-1] is list[-1])
5112        self.assertTrue(table[-1] is index[-1])
5113        self.assertTrue(table.last_record is table[-1])
5114        self.assertTrue(list.last_record is table[-1])
5115        self.assertTrue(index.last_record is table[-1])
5116        table.close()
5117
5118
5119class TestDbfLists(TestCase):
5120    "DbfList tests"
5121
5122    def setUp(self):
5123        "create a dbf table"
5124        self.dbf_table = table = Table(
5125            os.path.join(tempdir, 'temptable'),
5126            'name C(25); paid L; qty N(11,5); orderdate D; desc M', dbf_type='db3'
5127            )
5128        table.open(mode=READ_WRITE)
5129        records = []
5130        for i in range(len(floats)):
5131            name = words[i]
5132            paid = len(words[i]) % 3 == 0
5133            qty = round(floats[i], 5)
5134            orderdate = datetime.date((numbers[i] + 1) * 2, (numbers[i] % 12) +1, (numbers[i] % 27) + 1)
5135            desc = ' '.join(words[i:i+50])
5136            data = {'name':name, 'paid':paid, 'qty':qty, 'orderdate':orderdate, 'desc':desc}
5137            table.append(data)
5138            records.append(data)
5139        table.close()
5140        table.open(mode=READ_WRITE)
5141        for trec, drec in zip(table, records):
5142            self.assertEqual(trec.name.strip(), drec['name'])
5143            self.assertEqual(trec.paid, drec['paid'])
5144            self.assertEqual(trec.qty, drec['qty'])
5145            self.assertEqual(trec.orderdate, drec['orderdate'])
5146            self.assertEqual(trec.desc, drec['desc'])
5147        table.close()
5148
5149    def tearDown(self):
5150        self.dbf_table.close()
5151
5152    def test_exceptions(self):
5153        table = self.dbf_table
5154        table.open(mode=READ_WRITE)
5155        list = table[::5]
5156        record = table[5]
5157        dbf.delete(record)
5158        self.assertTrue(list[0] is table[0])
5159        self.assertTrue(record in list)
5160        self.assertRaises(TypeError, list.__contains__, 'some string')
5161        self.assertRaises(TypeError, list.__getitem__, 'some string')
5162        self.assertRaises(TypeError, list.__delitem__, 'some string')
5163        self.assertRaises(TypeError, list.remove, 'some string')
5164        self.assertRaises(TypeError, list.index, 'some string')
5165        self.assertRaises(IndexError, list.__getitem__, 100)
5166        self.assertRaises(IndexError, list.pop, 1000)
5167        self.assertRaises(IndexError, list.goto, 1000)
5168        list.top()
5169        self.assertRaises(Bof, list.skip, -1)
5170        list.bottom()
5171        self.assertRaises(Eof, list.skip)
5172        table.pack()
5173        self.assertRaises(DbfError, list.__contains__, record)
5174
5175        list = List()
5176        self.assertRaises(IndexError, list.goto, 0)
5177        self.assertRaises(Bof, list.skip, -1)
5178        self.assertRaises(Eof, list.skip)
5179        self.assertRaises(ValueError, list.remove, table[0])
5180        self.assertRaises(ValueError, list.index, table[1])
5181
5182    def test_add_subtract(self):
5183        "addition and subtraction"
5184        table1 = self.dbf_table
5185        table1.open(mode=READ_WRITE)
5186        list1 = table1[::2]
5187        list2 = table1[::3]
5188        list3 = table1[:] - list1 - list2
5189        self.assertEqual(100, len(table1))
5190        self.assertEqual(list1[0], list2[0])
5191        self.assertEqual(list1[3], list2[2])
5192        self.assertEqual(50, len(list1))
5193        self.assertEqual(34, len(list2))
5194        self.assertEqual(33, len(list3))
5195        self.assertEqual(117, len(list1) + len(list2) + len(list3))
5196        self.assertEqual(len(table1), len(list1 + list2 + list3))
5197        self.assertEqual(67, len(list1 + list2))
5198        self.assertEqual(33, len(list1 - list2))
5199        self.assertEqual(17, len(list2 - list1))
5200        table1.close()
5201
5202    def test_append_extend(self):
5203        "appending and extending"
5204        table1 = self.dbf_table
5205        table1.open(mode=READ_WRITE)
5206        list1 = table1[::2]
5207        list2 = table1[::3]
5208        list3 = table1[:] - list1 - list2
5209        list1.extend(list2)
5210        list2.append(table1[1])
5211        self.assertEqual(67, len(list1))
5212        self.assertEqual(35, len(list2))
5213        list1.append(table1[1])
5214        list2.extend(list3)
5215        self.assertEqual(68, len(list1))
5216        self.assertEqual(67, len(list2))
5217        table1.close()
5218
5219    def test_index(self):
5220        "indexing"
5221        table1 = self.dbf_table
5222        table1.open(mode=READ_WRITE)
5223        list1 = table1[::2]
5224        list2 = table1[::3]
5225        list3 = table1[:] - list1 - list2
5226        for i, rec in enumerate(list1):
5227            self.assertEqual(i, list1.index(rec))
5228        for rec in list3:
5229            self.assertRaises(ValueError, list1.index, rec )
5230        table1.close()
5231
5232    def test_sort(self):
5233        "sorting"
5234        table1 = self.dbf_table
5235        table1.open(mode=READ_WRITE)
5236        list1 = table1[::2]
5237        list2 = table1[::3]
5238        table1[:] - list1 - list2
5239        list4 = table1[:]
5240        index = table1.create_index(key = lambda rec: rec.name )
5241        list4.sort(key=lambda rec: rec.name)
5242        for trec, lrec in zip(index, list4):
5243            self.assertEqual(dbf.recno(trec), dbf.recno(lrec))
5244        table1.close()
5245
5246    def test_keys(self):
5247        "keys"
5248        table1 = self.dbf_table
5249        table1.open(mode=READ_WRITE)
5250        field = table1.field_names[0]
5251        list1 = List(table1, key=lambda rec: rec[field])
5252        unique = set()
5253        for rec in table1:
5254            if rec[field] not in unique:
5255                unique.add(rec[field])
5256            else:
5257                self.assertRaises(NotFoundError, list1.index, rec)
5258                self.assertFalse(rec in list1)
5259            self.assertTrue(rec[field] in unique)
5260        self.assertEqual(len(unique), len(list1))
5261        table1.close()
5262
5263    def test_contains(self):
5264        table = self.dbf_table
5265        table.open(mode=READ_WRITE)
5266        list = List(table)
5267        i = 0
5268        for record in list:
5269            self.assertEqual(record, list[i])
5270            self.assertTrue(record in list)
5271            self.assertTrue(tuple(record) in list)
5272            self.assertTrue(scatter(record) in list)
5273            self.assertTrue(create_template(record) in list)
5274            i += 1
5275        self.assertEqual(i, len(list))
5276        table.close()
5277
5278
5279class TestFieldnameLists(TestCase):
5280    "FieldnameList tests"
5281
5282    def test_exceptions(self):
5283        self.assertRaises(TypeError, FieldnameList, [1])
5284        self.assertRaises(TypeError, FieldnameList, ([u'1toy', int]))
5285        list1 = FieldnameList(unicodify(['lower', 'UPPER', 'MiXeD']))
5286        self.assertRaises(TypeError, list1.__add__, [7])
5287        self.assertRaises(TypeError, list1.__contains__, 7)
5288        self.assertRaises(TypeError, list1.__iadd__, [7])
5289        self.assertRaises(TypeError, list1.__radd__, [7])
5290        self.assertRaises(TypeError, list1.__setitem__, 0, 7)
5291        self.assertRaises(TypeError, list1.append, 7)
5292        self.assertRaises(TypeError, list1.count, 7)
5293        self.assertRaises(TypeError, list1.index, 7)
5294        self.assertRaises(TypeError, list1.insert, 7)
5295        self.assertRaises(TypeError, list1.remove, 7)
5296
5297
5298    def test_create(self):
5299        list1 = FieldnameList(['_this', 'that', 'somemore8'])
5300        list2 = list(list1)
5301        self.assertEqual(list2, unicodify(['_THIS', 'THAT', 'SOMEMORE8']))
5302        self.assertEqual(list1, list2)
5303
5304    def test_add(self):
5305        "addition"
5306        list1 = FieldnameList(unicodify(['lower', 'UPPER', 'MiXeD']))
5307        list2 = FieldnameList(['wah', u'a\xf1o'])
5308        list3 = FieldnameList(unicodify(['heh', 'hah']))
5309        #
5310        list4 = list1 + list2
5311        self.assertEqual(list1, ['Lower', 'uppeR', 'Mixed'])
5312        self.assertEqual(list2, unicodify(['wah', u'A\xf1o']))
5313        self.assertEqual(list4, unicodify(['loWer', 'UPpER', 'mixEd', 'wah', u'a\xf1O']))
5314        self.assertTrue(isinstance(list4, FieldnameList))
5315        #
5316        list4 += list3
5317        self.assertEqual(list3, unicodify(['heh', 'hah']))
5318        self.assertEqual(list4, unicodify(['LOWER', 'upper', 'MIxeD', 'wah', u'A\xf1O', 'heh', 'hah']))
5319        self.assertTrue(isinstance(list4, FieldnameList))
5320        #
5321        unicode_list = unicodify(['uhhuh', 'UhUh', 'zero'])
5322        self.assertEqual(unicode_list, [u'uhhuh', u'UhUh', u'zero'])
5323        list5 = unicode_list + list1
5324        self.assertEqual(list1, unicodify(['LoWeR', 'uPpEr', 'MixED']))
5325        self.assertEqual(list5, unicodify(['UhHuh', 'uHuH', 'zero', 'lowER', 'UPPer', 'miXeD']))
5326        self.assertTrue(isinstance(list5, FieldnameList))
5327
5328    def test_append_extend(self):
5329        "appending and extending"
5330        list1 = FieldnameList(unicodify(['lowER', 'UPPer', 'miXeD']))
5331        list2 = FieldnameList(['wah', u'a\xd1o'])
5332        list3 = FieldnameList(unicodify(['heh', 'hah']))
5333        #
5334        list1.append('ten')
5335        self.assertEqual(list1, ['LOWer', 'uppER', 'MIxEd', 'ten'])
5336        list2.extend(unicodify(['prime', 'Maybe']))
5337        self.assertEqual(list2, unicodify(['wah', u'A\xd1o', 'PRIME', 'maybe']))
5338        #
5339        list3.extend(list1)
5340        self.assertEqual(list1, unicodify(['lower', 'UPPER', 'miXEd', 'ten']))
5341        self.assertEqual(list3, unicodify(['heh', 'hah', 'Lower', 'uPPER', 'MiXEd', 'ten']))
5342
5343    def test_index(self):
5344        "indexing"
5345        list1 = FieldnameList(unicodify(['lOwEr', 'UpPeR', 'mIXed']))
5346        list2 = FieldnameList(['wah', u'a\xd1O'])
5347        list3 = FieldnameList(unicodify(['heh', 'hah']))
5348        #
5349        self.assertEqual(list1.index('lower'), 0)
5350        self.assertEqual(list2.index(u'A\xd1O'), 1)
5351        self.assertRaises(ValueError, list3.index, u'not there')
5352        self.assertRaises(ValueError, list3.index, 'not there')
5353        #
5354        slice1 = list1[:]
5355        slice2 = list2[:1]
5356        slice3 = list3[1:]
5357        self.assertTrue(isinstance(slice1, FieldnameList))
5358        self.assertTrue(isinstance(slice2, FieldnameList))
5359        self.assertTrue(isinstance(slice3, FieldnameList))
5360        self.assertEqual(slice1, ['LOWER', 'UPPER', 'MIXED'])
5361        self.assertEqual(slice2, unicodify(['WAH']))
5362        self.assertEqual(slice3, unicodify(['HAH']))
5363
5364    def test_sort(self):
5365        "sorting"
5366        list1 = FieldnameList(unicodify(['LoweR', 'uPPEr', 'MiXED']))
5367        list2 = FieldnameList(['wah', u'A\xd1O'])
5368        list3 = FieldnameList(unicodify(['heh', 'hah']))
5369        list1.sort()
5370        list2.sort()
5371        list3.sort()
5372        #
5373        self.assertEqual(list1, ['LOWER', 'MIXED', 'UPPER'])
5374        self.assertEqual(list2, unicodify([u'A\xD1O', 'WAH']))
5375        self.assertEqual(list3, unicodify(['HAH', 'HEH']))
5376        self.assertFalse(list3 != list3)
5377        self.assertFalse(list2 < list2)
5378        self.assertFalse(list1 > list1)
5379        #
5380        list4 = list2[:]
5381        list5 = list2[:] + ['bar']
5382        list6 = list2[:] + unicodify(['size'])
5383        list4.sort()
5384        list5.sort()
5385        list6.sort()
5386        #
5387        self.assertTrue(list2 < list1)
5388        self.assertTrue(list2 <= list1)
5389        self.assertFalse(list2 == list1)
5390        self.assertFalse(list2 >= list1)
5391        self.assertFalse(list2 > list1)
5392        self.assertTrue(list2 == list4)
5393        self.assertTrue(list4 > list5)
5394        self.assertTrue(list5 < list6)
5395        self.assertTrue(list5 <= list6)
5396        self.assertTrue(list5 != list6)
5397        self.assertFalse(list5 >= list6)
5398        self.assertFalse(list5 > list6)
5399        self.assertTrue(list6 > list5)
5400        self.assertTrue(list6 < list4)
5401
5402    def test_contains(self):
5403        list1 = FieldnameList(unicodify(['lower', 'UPPER', 'MiXeD']))
5404        list2 = FieldnameList(['wah', u'a\xf1o'])
5405        list3 = FieldnameList(unicodify(['heh', 'hah']))
5406        #
5407        self.assertTrue('Mixed' in list1)
5408        self.assertFalse(u'a\xf1o' in list1)
5409        self.assertTrue(u'A\xf1O' in list2)
5410        self.assertFalse('HEH' in list2)
5411        self.assertTrue(u'HEH' in list3)
5412        self.assertFalse(u'Mixed' in list3)
5413
5414
5415class TestReadWriteDefaultOpen(TestCase):
5416    "test __enter__/__exit__"
5417
5418    def setUp(self):
5419        "create a dbf table"
5420        self.dbf_table = table = Table(
5421            os.path.join(tempdir, 'temptable'),
5422            'name C(25); paid L; qty N(11,5); orderdate D; desc M', dbf_type='db3'
5423            )
5424        table.open(READ_WRITE)
5425        table.append(('Rose Petals', True, 115, Date(2018, 2, 14), 'lightly scented, pink & red'))
5426        table.close()
5427
5428    def tearDown(self):
5429        os.chmod(self.dbf_table.filename, stat.S_IWRITE|stat.S_IREAD)
5430        os.chmod(self.dbf_table._meta.memoname, stat.S_IWRITE|stat.S_IREAD)
5431        self.dbf_table.close()
5432
5433    def test_context_manager(self):
5434        with self.dbf_table as t:
5435            t.append(dict(name='Stoneleaf', paid=True, qty=1))
5436
5437    def test_delete_fields(self):
5438        dbf.delete_fields(self.dbf_table.filename, 'orderdate')
5439
5440    def test_add_fields(self):
5441        dbf.add_fields(self.dbf_table.filename, 'alias C(25)')
5442
5443    def test_processing(self):
5444        for rec in dbf.Process(self.dbf_table):
5445            rec.name = 'Carnations'
5446
5447    def test_read_only(self):
5448        table = self.dbf_table
5449        os.chmod(table.filename, stat.S_IREAD)
5450        os.chmod(table._meta.memoname, stat.S_IREAD)
5451        table.open(READ_ONLY)
5452        table.close()
5453        self.assertRaises((IOError, OSError), table.open, READ_WRITE)
5454
5455
5456class TestDBC(TestCase):
5457    "test DBC handling"
5458
5459
5460class TestVapor(TestCase):
5461    "test Vapor objects"
5462
5463    def test_falsey(self):
5464        self.assertFalse(dbf.Vapor)
5465
5466
5467class TestMisc(TestCase):
5468    "miscellaneous tests"
5469
5470    def setUp(self):
5471        self.table = Table(
5472                os.path.join(tempdir, 'dbf_table.'),
5473                'name C(25); paid L; qty N(11,5); orderdate D; desc M',
5474                dbf_type='db3',
5475                )
5476        self.table_dbf = Table(
5477                os.path.join(tempdir, 'dbf_table.dbf'),
5478                'name C(25); paid L; qty N(11,5); orderdate D; desc M',
5479                dbf_type='db3',
5480                )
5481        self.table_implicit = Table(
5482                os.path.join(tempdir, 'dbf_table'),
5483                'name C(25); paid L; qty N(11,5); orderdate D; desc M',
5484                dbf_type='db3',
5485                )
5486        self.table_wierd = Table(
5487                os.path.join(tempdir, 'dbf_table.blah'),
5488                'name C(25); paid L; qty N(11,5); orderdate D; desc M',
5489                dbf_type='db3',
5490                )
5491        self.table.close()
5492        self.table_dbf.close()
5493        self.table_implicit.close()
5494        self.table_wierd.close()
5495
5496    def test_table_type_with_dbf(self):
5497        dbf.table_type(self.table.filename)
5498        dbf.table_type(self.table_dbf.filename)
5499        dbf.table_type(self.table_implicit.filename)
5500        dbf.table_type(self.table_wierd.filename)
5501        dbf.Table(self.table.filename)
5502        dbf.Table(self.table_dbf.filename)
5503        dbf.Table(self.table_implicit.filename)
5504        dbf.Table(self.table_wierd.filename)
5505
5506
5507class TestWhatever(TestCase):
5508    "move tests here to run one at a time while debugging"
5509
5510    def setUp(self):
5511        "create a dbf and vfp table"
5512        self.dbf_table = table = Table(
5513            os.path.join(tempdir, 'temptable'),
5514            'name C(25); paid L; qty N(11,5); orderdate D; desc M', dbf_type='db3'
5515            )
5516        table.open(mode=READ_WRITE)
5517        namelist = self.dbf_namelist = []
5518        paidlist = self.dbf_paidlist = []
5519        qtylist = self.dbf_qtylist = []
5520        orderlist = self.dbf_orderlist = []
5521        desclist = self.dbf_desclist = []
5522        for i in range(len(floats)):
5523            name = '%-25s' % words[i]
5524            paid = len(words[i]) % 3 == 0
5525            qty = round(floats[i], 5)
5526            orderdate = datetime.date((numbers[i] + 1) * 2, (numbers[i] % 12) +1, (numbers[i] % 27) + 1)
5527            desc = ' '.join(words[i:i+50])
5528            namelist.append(name)
5529            paidlist.append(paid)
5530            qtylist.append(qty)
5531            orderlist.append(orderdate)
5532            desclist.append(desc)
5533            table.append({'name':name, 'paid':paid, 'qty':qty, 'orderdate':orderdate, 'desc':desc})
5534        table.close()
5535
5536        self.vfp_table = table = Table(
5537                os.path.join(tempdir, 'tempvfp'),
5538                'name C(25); paid L; qty N(11,5); orderdate D; desc M; mass B;'
5539                ' weight F(18,3); age I; meeting T; misc G; photo P',
5540                dbf_type='vfp',
5541                )
5542        table.open(mode=READ_WRITE)
5543        namelist = self.vfp_namelist = []
5544        paidlist = self.vfp_paidlist = []
5545        qtylist = self.vfp_qtylist = []
5546        orderlist = self.vfp_orderlist = []
5547        desclist = self.vfp_desclist = []
5548        masslist = self.vfp_masslist = []
5549        weightlist = self.vfp_weightlist = []
5550        agelist = self.vfp_agelist = []
5551        meetlist = self.vfp_meetlist = []
5552        misclist = self.vfp_misclist = []
5553        photolist = self.vfp_photolist = []
5554        for i in range(len(floats)):
5555            name = words[i]
5556            paid = len(words[i]) % 3 == 0
5557            qty = round(floats[i], 5)
5558            orderdate = datetime.date((numbers[i] + 1) * 2, (numbers[i] % 12) +1, (numbers[i] % 27) + 1)
5559            desc = ' '.join(words[i:i+50])
5560            mass = floats[i] * floats[i] / 2.0
5561            weight = round(floats[i] * 3, 3)
5562            age = numbers[i]
5563            meeting = datetime.datetime((numbers[i] + 2000), (numbers[i] % 12)+1, (numbers[i] % 28)+1, \
5564                      (numbers[i] % 24), numbers[i] % 60, (numbers[i] * 3) % 60)
5565            misc = ' '.join(words[i:i+50:3]).encode('ascii')
5566            photo = ' '.join(words[i:i+50:7]).encode('ascii')
5567            namelist.append('%-25s' % name)
5568            paidlist.append(paid)
5569            qtylist.append(qty)
5570            orderlist.append(orderdate)
5571            desclist.append(desc)
5572            masslist.append(mass)
5573            weightlist.append(weight)
5574            agelist.append(age)
5575            meetlist.append(meeting)
5576            misclist.append(misc)
5577            photolist.append(photo)
5578            meeting = datetime.datetime((numbers[i] + 2000), (numbers[i] % 12)+1, (numbers[i] % 28)+1,
5579                      (numbers[i] % 24), numbers[i] % 60, (numbers[i] * 3) % 60)
5580            table.append({'name':name, 'paid':paid, 'qty':qty, 'orderdate':orderdate, 'desc':desc,
5581                    'mass':mass, 'weight':weight, 'age':age, 'meeting':meeting, 'misc':misc, 'photo':photo})
5582        table.close()
5583
5584    def tearDown(self):
5585        self.dbf_table.close()
5586        self.vfp_table.close()
5587
5588
5589# main
5590if __name__ == '__main__':
5591    tempdir = tempfile.mkdtemp()
5592    try:
5593        unittest.main()
5594    finally:
5595        shutil.rmtree(tempdir, True)
5596