Skip to content

Commit

Permalink
tests: Use direct values instead of raw SQL
Browse files Browse the repository at this point in the history
Supersedes #11.

In order to prevent (-1) from being masked by BitField.get_prep_value
and converted to 15 (0xf), the test code uses a direct SQL statement.
Its implementation has a few peculiarities that may be undesirable:

- It uses an Django internal API, the Field.column attribute.  Granted,
  this package already uses a lot of internal APIs, and Field.column
  is highly unlikely to change.  However, in general using less internal
  APIs is better for future compatibility.

- Using low-level API misses a lot of code paths that could have been
  tested.

- Neither db_table nor db_column is escaped.  In case we later
  incorporate tests involving pathological SQL object identifiers, we
  have to further use quote_name, which is not exactly public API
  either.

Instead, we use models.Value() with an explicit output_field, which
still avoids BitField.get_prep_value and inserts the value directly.

Further, directly assign to __dict__ so that the BitFieldCreator
descriptor's __set__ method is bypassed and the value is assigned
unchanged.
  • Loading branch information
iamahuman committed Jan 18, 2021
1 parent e2b295c commit e5be396
Showing 1 changed file with 7 additions and 6 deletions.
13 changes: 7 additions & 6 deletions bitfield/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pickle

from django.db import connection, models
from django.db import models
from django.db.models import F
from django.test import TestCase

Expand Down Expand Up @@ -155,11 +155,12 @@ def test_regression_1425(self):
self.assertTrue(instance.flags.FLAG_2)
self.assertTrue(instance.flags.FLAG_3)

cursor = connection.cursor()
flags_field = BitFieldTestModel._meta.get_field('flags')
flags_db_column = flags_field.db_column or flags_field.name
cursor.execute("INSERT INTO %s (%s) VALUES (-1)" % (BitFieldTestModel._meta.db_table, flags_db_column))
# There should only be the one row we inserted through the cursor.
# Bypass BitField.to_python and insert (-1) directly.
instance = BitFieldTestModel()
instance.__dict__['flags'] = models.Value(-1, output_field=models.IntegerField())
instance.save()

# There should only be the one row we inserted with a direct value.
instance = BitFieldTestModel.objects.get(flags=-1)
self.assertTrue(instance.flags.FLAG_0)
self.assertTrue(instance.flags.FLAG_1)
Expand Down

0 comments on commit e5be396

Please sign in to comment.