PageRenderTime 97ms CodeModel.GetById 69ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/regressiontests/expressions_regress/tests.py

https://code.google.com/p/mango-py/
Python | 398 lines | 287 code | 68 blank | 43 comment | 49 complexity | 1f607b716bab7608faa6f7098368faa9 MD5 | raw file
  1"""
  2Spanning tests for all the operations that F() expressions can perform.
  3"""
  4import datetime
  5
  6from django.conf import settings
  7from django.db import models, connection
  8from django.db.models import F
  9from django.test import TestCase, Approximate, skipUnlessDBFeature
 10
 11from regressiontests.expressions_regress.models import Number, Experiment
 12
 13
 14class ExpressionsRegressTests(TestCase):
 15
 16    def setUp(self):
 17        Number(integer=-1).save()
 18        Number(integer=42).save()
 19        Number(integer=1337).save()
 20        self.assertEqual(Number.objects.update(float=F('integer')), 3)
 21
 22    def test_fill_with_value_from_same_object(self):
 23        """
 24        We can fill a value in all objects with an other value of the
 25        same object.
 26        """
 27        self.assertQuerysetEqual(
 28                Number.objects.all(),
 29                [
 30                    '<Number: -1, -1.000>',
 31                    '<Number: 42, 42.000>',
 32                    '<Number: 1337, 1337.000>'
 33                ]
 34        )
 35
 36    def test_increment_value(self):
 37        """
 38        We can increment a value of all objects in a query set.
 39        """
 40        self.assertEqual(
 41            Number.objects.filter(integer__gt=0)
 42                  .update(integer=F('integer') + 1),
 43            2)
 44
 45        self.assertQuerysetEqual(
 46                Number.objects.all(),
 47                [
 48                    '<Number: -1, -1.000>',
 49                    '<Number: 43, 42.000>',
 50                    '<Number: 1338, 1337.000>'
 51                ]
 52        )
 53
 54    def test_filter_not_equals_other_field(self):
 55        """
 56        We can filter for objects, where a value is not equals the value
 57        of an other field.
 58        """
 59        self.assertEqual(
 60            Number.objects.filter(integer__gt=0)
 61                  .update(integer=F('integer') + 1),
 62            2)
 63        self.assertQuerysetEqual(
 64                Number.objects.exclude(float=F('integer')),
 65                [
 66                    '<Number: 43, 42.000>',
 67                    '<Number: 1338, 1337.000>'
 68                ]
 69        )
 70
 71    def test_complex_expressions(self):
 72        """
 73        Complex expressions of different connection types are possible.
 74        """
 75        n = Number.objects.create(integer=10, float=123.45)
 76        self.assertEqual(Number.objects.filter(pk=n.pk)
 77                                .update(float=F('integer') + F('float') * 2),
 78                          1)
 79
 80        self.assertEqual(Number.objects.get(pk=n.pk).integer, 10)
 81        self.assertEqual(Number.objects.get(pk=n.pk).float, Approximate(256.900, places=3))
 82
 83class ExpressionOperatorTests(TestCase):
 84    def setUp(self):
 85        self.n = Number.objects.create(integer=42, float=15.5)
 86
 87    def test_lefthand_addition(self):
 88        # LH Addition of floats and integers
 89        Number.objects.filter(pk=self.n.pk).update(
 90            integer=F('integer') + 15,
 91            float=F('float') + 42.7
 92        )
 93
 94        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 57)
 95        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(58.200, places=3))
 96
 97    def test_lefthand_subtraction(self):
 98        # LH Subtraction of floats and integers
 99        Number.objects.filter(pk=self.n.pk).update(integer=F('integer') - 15,
100                                              float=F('float') - 42.7)
101
102        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 27)
103        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(-27.200, places=3))
104
105    def test_lefthand_multiplication(self):
106        # Multiplication of floats and integers
107        Number.objects.filter(pk=self.n.pk).update(integer=F('integer') * 15,
108                                              float=F('float') * 42.7)
109
110        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 630)
111        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(661.850, places=3))
112
113    def test_lefthand_division(self):
114        # LH Division of floats and integers
115        Number.objects.filter(pk=self.n.pk).update(integer=F('integer') / 2,
116                                              float=F('float') / 42.7)
117
118        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 21)
119        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(0.363, places=3))
120
121    def test_lefthand_modulo(self):
122        # LH Modulo arithmetic on integers
123        Number.objects.filter(pk=self.n.pk).update(integer=F('integer') % 20)
124
125        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 2)
126        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3))
127
128    def test_lefthand_bitwise_and(self):
129        # LH Bitwise ands on integers
130        Number.objects.filter(pk=self.n.pk).update(integer=F('integer') & 56)
131
132        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 40)
133        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3))
134
135    @skipUnlessDBFeature('supports_bitwise_or')
136    def test_lefthand_bitwise_or(self):
137        # LH Bitwise or on integers
138        Number.objects.filter(pk=self.n.pk).update(integer=F('integer') | 48)
139
140        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 58)
141        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3))
142
143    def test_right_hand_addition(self):
144        # Right hand operators
145        Number.objects.filter(pk=self.n.pk).update(integer=15 + F('integer'),
146                                              float=42.7 + F('float'))
147
148        # RH Addition of floats and integers
149        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 57)
150        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(58.200, places=3))
151
152    def test_right_hand_subtraction(self):
153        Number.objects.filter(pk=self.n.pk).update(integer=15 - F('integer'),
154                                              float=42.7 - F('float'))
155
156        # RH Subtraction of floats and integers
157        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, -27)
158        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(27.200, places=3))
159
160    def test_right_hand_multiplication(self):
161        # RH Multiplication of floats and integers
162        Number.objects.filter(pk=self.n.pk).update(integer=15 * F('integer'),
163                                              float=42.7 * F('float'))
164
165        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 630)
166        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(661.850, places=3))
167
168    def test_right_hand_division(self):
169        # RH Division of floats and integers
170        Number.objects.filter(pk=self.n.pk).update(integer=640 / F('integer'),
171                                              float=42.7 / F('float'))
172
173        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 15)
174        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(2.755, places=3))
175
176    def test_right_hand_modulo(self):
177        # RH Modulo arithmetic on integers
178        Number.objects.filter(pk=self.n.pk).update(integer=69 % F('integer'))
179
180        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 27)
181        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3))
182
183    def test_right_hand_bitwise_and(self):
184        # RH Bitwise ands on integers
185        Number.objects.filter(pk=self.n.pk).update(integer=15 & F('integer'))
186
187        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 10)
188        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3))
189
190    @skipUnlessDBFeature('supports_bitwise_or')
191    def test_right_hand_bitwise_or(self):
192        # RH Bitwise or on integers
193        Number.objects.filter(pk=self.n.pk).update(integer=15 | F('integer'))
194
195        self.assertEqual(Number.objects.get(pk=self.n.pk).integer, 47)
196        self.assertEqual(Number.objects.get(pk=self.n.pk).float, Approximate(15.500, places=3))
197
198class FTimeDeltaTests(TestCase):
199
200    def setUp(self):
201        sday = datetime.date(2010, 6, 25)
202        stime = datetime.datetime(2010, 6, 25, 12, 15, 30, 747000)
203        midnight = datetime.time(0)
204
205        delta0 = datetime.timedelta(0)
206        delta1 = datetime.timedelta(microseconds=253000)
207        delta2 = datetime.timedelta(seconds=44)
208        delta3 = datetime.timedelta(hours=21, minutes=8)
209        delta4 = datetime.timedelta(days=10)
210
211        # Test data is set so that deltas and delays will be
212        # strictly increasing.
213        self.deltas = []
214        self.delays = []
215        self.days_long = []
216
217        # e0: started same day as assigned, zero duration
218        end = stime+delta0
219        e0 = Experiment.objects.create(name='e0', assigned=sday, start=stime,
220            end=end, completed=end.date())
221        self.deltas.append(delta0)
222        self.delays.append(e0.start-
223            datetime.datetime.combine(e0.assigned, midnight))
224        self.days_long.append(e0.completed-e0.assigned)
225
226        # e1: started one day after assigned, tiny duration, data
227        # set so that end time has no fractional seconds, which
228        # tests an edge case on sqlite. This Experiment is only
229        # included in the test data when the DB supports microsecond
230        # precision.
231        if connection.features.supports_microsecond_precision:
232            delay = datetime.timedelta(1)
233            end = stime + delay + delta1
234            e1 = Experiment.objects.create(name='e1', assigned=sday,
235                start=stime+delay, end=end, completed=end.date())
236            self.deltas.append(delta1)
237            self.delays.append(e1.start-
238                datetime.datetime.combine(e1.assigned, midnight))
239            self.days_long.append(e1.completed-e1.assigned)
240
241        # e2: started three days after assigned, small duration
242        end = stime+delta2
243        e2 = Experiment.objects.create(name='e2',
244            assigned=sday-datetime.timedelta(3), start=stime, end=end, 
245            completed=end.date())
246        self.deltas.append(delta2)
247        self.delays.append(e2.start-
248            datetime.datetime.combine(e2.assigned, midnight))
249        self.days_long.append(e2.completed-e2.assigned)
250
251        # e3: started four days after assigned, medium duration
252        delay = datetime.timedelta(4)
253        end = stime + delay + delta3
254        e3 = Experiment.objects.create(name='e3',
255            assigned=sday, start=stime+delay, end=end, completed=end.date())
256        self.deltas.append(delta3)
257        self.delays.append(e3.start-
258            datetime.datetime.combine(e3.assigned, midnight))
259        self.days_long.append(e3.completed-e3.assigned)
260
261        # e4: started 10 days after assignment, long duration
262        end = stime + delta4
263        e4 = Experiment.objects.create(name='e4',
264            assigned=sday-datetime.timedelta(10), start=stime, end=end,
265            completed=end.date())
266        self.deltas.append(delta4)
267        self.delays.append(e4.start-
268            datetime.datetime.combine(e4.assigned, midnight))
269        self.days_long.append(e4.completed-e4.assigned)
270        self.expnames = [e.name for e in Experiment.objects.all()]
271
272    def test_delta_add(self):
273        for i in range(len(self.deltas)):
274            delta = self.deltas[i]
275            test_set = [e.name for e in
276                Experiment.objects.filter(end__lt=F('start')+delta)]
277            self.assertEqual(test_set, self.expnames[:i])
278
279            test_set = [e.name for e in
280                Experiment.objects.filter(end__lte=F('start')+delta)]
281            self.assertEqual(test_set, self.expnames[:i+1])
282
283    def test_delta_subtract(self):
284        for i in range(len(self.deltas)):
285            delta = self.deltas[i]
286            test_set = [e.name for e in
287                Experiment.objects.filter(start__gt=F('end')-delta)]
288            self.assertEqual(test_set, self.expnames[:i])
289
290            test_set = [e.name for e in
291                Experiment.objects.filter(start__gte=F('end')-delta)]
292            self.assertEqual(test_set, self.expnames[:i+1])
293
294    def test_exclude(self):
295        for i in range(len(self.deltas)):
296            delta = self.deltas[i]
297            test_set = [e.name for e in 
298                Experiment.objects.exclude(end__lt=F('start')+delta)]
299            self.assertEqual(test_set, self.expnames[i:])
300
301            test_set = [e.name for e in 
302                Experiment.objects.exclude(end__lte=F('start')+delta)]
303            self.assertEqual(test_set, self.expnames[i+1:])
304
305    def test_date_comparison(self):
306        for i in range(len(self.days_long)):
307            days = self.days_long[i]
308            test_set = [e.name for e in 
309                Experiment.objects.filter(completed__lt=F('assigned')+days)]
310            self.assertEqual(test_set, self.expnames[:i])
311
312            test_set = [e.name for e in 
313                Experiment.objects.filter(completed__lte=F('assigned')+days)]
314            self.assertEqual(test_set, self.expnames[:i+1])
315
316    @skipUnlessDBFeature("supports_mixed_date_datetime_comparisons")
317    def test_mixed_comparisons1(self):
318        for i in range(len(self.delays)):
319            delay = self.delays[i]
320            if not connection.features.supports_microsecond_precision:
321                delay = datetime.timedelta(delay.days, delay.seconds)
322            test_set = [e.name for e in
323                Experiment.objects.filter(assigned__gt=F('start')-delay)]
324            self.assertEqual(test_set, self.expnames[:i])
325
326            test_set = [e.name for e in
327                Experiment.objects.filter(assigned__gte=F('start')-delay)]
328            self.assertEqual(test_set, self.expnames[:i+1])
329
330    def test_mixed_comparisons2(self):
331        delays = [datetime.timedelta(delay.days) for delay in self.delays]
332        for i in range(len(delays)):
333            delay = delays[i]
334            test_set = [e.name for e in
335                Experiment.objects.filter(start__lt=F('assigned')+delay)]
336            self.assertEqual(test_set, self.expnames[:i])
337
338            test_set = [e.name for e in
339                Experiment.objects.filter(start__lte=F('assigned')+delay+
340                    datetime.timedelta(1))]
341            self.assertEqual(test_set, self.expnames[:i+1])
342
343    def test_delta_update(self):
344        for i in range(len(self.deltas)):
345            delta = self.deltas[i]
346            exps = Experiment.objects.all()
347            expected_durations = [e.duration() for e in exps]
348            expected_starts = [e.start+delta for e in exps]
349            expected_ends = [e.end+delta for e in exps]
350
351            Experiment.objects.update(start=F('start')+delta, end=F('end')+delta)
352            exps = Experiment.objects.all()
353            new_starts = [e.start for e in exps]
354            new_ends = [e.end for e in exps]
355            new_durations = [e.duration() for e in exps]
356            self.assertEqual(expected_starts, new_starts)
357            self.assertEqual(expected_ends, new_ends)
358            self.assertEqual(expected_durations, new_durations)
359
360    def test_delta_invalid_op_mult(self):
361        raised = False
362        try:
363            r = repr(Experiment.objects.filter(end__lt=F('start')*self.deltas[0]))
364        except TypeError:
365            raised = True
366        self.assertTrue(raised, "TypeError not raised on attempt to multiply datetime by timedelta.")
367
368    def test_delta_invalid_op_div(self):
369        raised = False
370        try:
371            r = repr(Experiment.objects.filter(end__lt=F('start')/self.deltas[0]))
372        except TypeError:
373            raised = True
374        self.assertTrue(raised, "TypeError not raised on attempt to divide datetime by timedelta.")
375
376    def test_delta_invalid_op_mod(self):
377        raised = False
378        try:
379            r = repr(Experiment.objects.filter(end__lt=F('start')%self.deltas[0]))
380        except TypeError:
381            raised = True
382        self.assertTrue(raised, "TypeError not raised on attempt to modulo divide datetime by timedelta.")
383
384    def test_delta_invalid_op_and(self):
385        raised = False
386        try:
387            r = repr(Experiment.objects.filter(end__lt=F('start')&self.deltas[0]))
388        except TypeError:
389            raised = True
390        self.assertTrue(raised, "TypeError not raised on attempt to binary and a datetime with a timedelta.")
391
392    def test_delta_invalid_op_or(self):
393        raised = False
394        try:
395            r = repr(Experiment.objects.filter(end__lt=F('start')|self.deltas[0]))
396        except TypeError:
397            raised = True
398        self.assertTrue(raised, "TypeError not raised on attempt to binary or a datetime with a timedelta.")