2022-08-12 20:31:55 +00:00
|
|
|
import string
|
2024-09-01 03:58:49 +00:00
|
|
|
import uuid
|
2022-08-12 20:31:55 +00:00
|
|
|
|
2024-09-01 03:58:49 +00:00
|
|
|
import pytest
|
|
|
|
|
from django.conf import settings as django_settings
|
2018-06-04 15:19:05 +00:00
|
|
|
from django.core.exceptions import ValidationError
|
2010-09-27 13:28:52 +00:00
|
|
|
from django.test import TestCase
|
2022-08-12 20:31:55 +00:00
|
|
|
from hypothesis import given, settings
|
2023-10-30 15:57:29 +00:00
|
|
|
from hypothesis import strategies as st
|
2024-09-01 03:58:49 +00:00
|
|
|
from hypothesis.extra import django
|
2022-08-12 21:24:47 +00:00
|
|
|
from hypothesis.strategies import just
|
2010-09-27 13:28:52 +00:00
|
|
|
|
|
|
|
|
import eav
|
2018-07-13 11:50:50 +00:00
|
|
|
from eav.exceptions import IllegalAssignmentException
|
2017-09-05 10:01:20 +00:00
|
|
|
from eav.models import Attribute, Value
|
2018-06-04 15:19:05 +00:00
|
|
|
from eav.registry import EavConfig
|
2021-10-22 22:36:17 +00:00
|
|
|
from test_project.models import Doctor, Encounter, Patient, RegisterTestModel
|
2010-09-27 13:28:52 +00:00
|
|
|
|
2023-10-30 15:57:29 +00:00
|
|
|
if django_settings.EAV2_PRIMARY_KEY_FIELD == "django.db.models.UUIDField":
|
|
|
|
|
auto_field_strategy = st.builds(uuid.uuid4, version=4, max_length=32)
|
|
|
|
|
elif django_settings.EAV2_PRIMARY_KEY_FIELD == "django.db.models.CharField":
|
|
|
|
|
auto_field_strategy = st.text(min_size=1, max_size=255)
|
|
|
|
|
else:
|
|
|
|
|
auto_field_strategy = st.integers(min_value=1, max_value=32)
|
|
|
|
|
|
|
|
|
|
|
2018-06-04 15:19:05 +00:00
|
|
|
class Attributes(TestCase):
|
2010-09-27 13:28:52 +00:00
|
|
|
def setUp(self):
|
|
|
|
|
class EncounterEavConfig(EavConfig):
|
2024-09-01 15:21:47 +00:00
|
|
|
manager_attr = "eav_objects"
|
|
|
|
|
eav_attr = "eav_field"
|
|
|
|
|
generic_relation_attr = "encounter_eav_values"
|
|
|
|
|
generic_relation_related_name = "encounters"
|
2010-09-27 13:28:52 +00:00
|
|
|
|
|
|
|
|
@classmethod
|
2020-10-22 20:53:34 +00:00
|
|
|
def get_attributes(cls, instance=None):
|
2024-09-01 15:21:47 +00:00
|
|
|
return Attribute.objects.filter(slug__contains="a")
|
2010-09-27 13:28:52 +00:00
|
|
|
|
|
|
|
|
eav.register(Encounter, EncounterEavConfig)
|
|
|
|
|
eav.register(Patient)
|
|
|
|
|
|
2024-09-01 15:21:47 +00:00
|
|
|
Attribute.objects.create(name="age", datatype=Attribute.TYPE_INT)
|
|
|
|
|
Attribute.objects.create(name="height", datatype=Attribute.TYPE_FLOAT)
|
|
|
|
|
Attribute.objects.create(name="weight", datatype=Attribute.TYPE_FLOAT)
|
|
|
|
|
Attribute.objects.create(name="color", datatype=Attribute.TYPE_TEXT)
|
2010-09-27 13:28:52 +00:00
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
|
eav.unregister(Encounter)
|
|
|
|
|
eav.unregister(Patient)
|
|
|
|
|
|
|
|
|
|
def test_get_attribute_querysets(self):
|
2018-06-04 15:19:05 +00:00
|
|
|
self.assertEqual(Patient._eav_config_cls.get_attributes().count(), 4)
|
|
|
|
|
self.assertEqual(Encounter._eav_config_cls.get_attributes().count(), 1)
|
|
|
|
|
|
|
|
|
|
def test_duplicate_attributs(self):
|
2024-09-01 15:21:47 +00:00
|
|
|
"""
|
2018-06-04 15:19:05 +00:00
|
|
|
Ensure that no two Attributes with the same slug can exist.
|
2024-09-01 15:21:47 +00:00
|
|
|
"""
|
2018-06-04 15:19:05 +00:00
|
|
|
with self.assertRaises(ValidationError):
|
2024-09-01 15:21:47 +00:00
|
|
|
Attribute.objects.create(name="height", datatype=Attribute.TYPE_FLOAT)
|
2010-09-27 13:28:52 +00:00
|
|
|
|
|
|
|
|
def test_setting_attributes(self):
|
2024-09-01 15:21:47 +00:00
|
|
|
p = Patient.objects.create(name="Jon")
|
2010-09-27 13:28:52 +00:00
|
|
|
e = Encounter.objects.create(patient=p, num=1)
|
2018-07-27 14:00:28 +00:00
|
|
|
|
2010-09-27 13:28:52 +00:00
|
|
|
p.eav.age = 3
|
|
|
|
|
p.eav.height = 2.3
|
|
|
|
|
p.save()
|
|
|
|
|
e.eav_field.age = 4
|
|
|
|
|
e.save()
|
|
|
|
|
self.assertEqual(Value.objects.count(), 3)
|
2018-07-27 14:00:28 +00:00
|
|
|
t = RegisterTestModel.objects.create(name="test")
|
|
|
|
|
t.eav.age = 6
|
|
|
|
|
t.eav.height = 10
|
|
|
|
|
t.save()
|
2024-09-01 15:21:47 +00:00
|
|
|
p = Patient.objects.get(name="Jon")
|
2010-09-27 13:28:52 +00:00
|
|
|
self.assertEqual(p.eav.age, 3)
|
|
|
|
|
self.assertEqual(p.eav.height, 2.3)
|
|
|
|
|
e = Encounter.objects.get(num=1)
|
|
|
|
|
self.assertEqual(e.eav_field.age, 4)
|
2018-07-27 14:00:28 +00:00
|
|
|
t = RegisterTestModel.objects.get(name="test")
|
|
|
|
|
self.assertEqual(t.eav.age, 6)
|
|
|
|
|
self.assertEqual(t.eav.height, 10)
|
2018-06-21 11:38:48 +00:00
|
|
|
|
2021-10-22 22:36:17 +00:00
|
|
|
# Validate repr of Value for an entity with an INT PK
|
|
|
|
|
v1 = Value.objects.filter(entity_id=p.pk).first()
|
|
|
|
|
assert isinstance(repr(v1), str)
|
|
|
|
|
assert isinstance(str(v1), str)
|
|
|
|
|
|
2018-06-21 11:38:48 +00:00
|
|
|
def test_illegal_assignemnt(self):
|
|
|
|
|
class EncounterEavConfig(EavConfig):
|
|
|
|
|
@classmethod
|
2020-10-22 20:53:34 +00:00
|
|
|
def get_attributes(cls, instance=None):
|
2018-06-21 11:38:48 +00:00
|
|
|
return Attribute.objects.filter(datatype=Attribute.TYPE_INT)
|
|
|
|
|
|
|
|
|
|
eav.unregister(Encounter)
|
|
|
|
|
eav.register(Encounter, EncounterEavConfig)
|
|
|
|
|
|
2024-09-01 15:21:47 +00:00
|
|
|
p = Patient.objects.create(name="Jon")
|
2018-06-21 11:38:48 +00:00
|
|
|
e = Encounter.objects.create(patient=p, num=1)
|
|
|
|
|
|
|
|
|
|
with self.assertRaises(IllegalAssignmentException):
|
2024-09-01 15:21:47 +00:00
|
|
|
e.eav.color = "red"
|
2018-06-21 11:38:48 +00:00
|
|
|
e.save()
|
2021-10-22 22:36:17 +00:00
|
|
|
|
|
|
|
|
def test_uuid_pk(self):
|
|
|
|
|
"""Tests for when model pk is UUID."""
|
2024-09-01 15:21:47 +00:00
|
|
|
expected_age = 10
|
|
|
|
|
d1 = Doctor.objects.create(name="Lu")
|
|
|
|
|
d1.eav.age = expected_age
|
2021-10-22 22:36:17 +00:00
|
|
|
d1.save()
|
|
|
|
|
|
2024-09-01 15:21:47 +00:00
|
|
|
assert d1.eav.age == expected_age
|
2021-10-22 22:36:17 +00:00
|
|
|
|
|
|
|
|
# Validate repr of Value for an entity with a UUID PK
|
|
|
|
|
v1 = Value.objects.filter(entity_uuid=d1.pk).first()
|
|
|
|
|
assert isinstance(repr(v1), str)
|
|
|
|
|
assert isinstance(str(v1), str)
|
2021-12-19 03:29:38 +00:00
|
|
|
|
|
|
|
|
def test_big_integer(self):
|
|
|
|
|
"""Tests an integer larger than 32-bit a value."""
|
|
|
|
|
big_num = 3147483647
|
2024-09-01 15:21:47 +00:00
|
|
|
patient = Patient.objects.create(name="Jon")
|
2021-12-19 03:29:38 +00:00
|
|
|
patient.eav.age = big_num
|
|
|
|
|
|
|
|
|
|
patient.save()
|
|
|
|
|
|
|
|
|
|
assert patient.eav.age == big_num
|
2022-08-12 20:31:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestAttributeModel(django.TestCase):
|
|
|
|
|
"""This is a property-based test that ensures model correctness."""
|
|
|
|
|
|
|
|
|
|
@given(
|
|
|
|
|
django.from_model(
|
|
|
|
|
Attribute,
|
2023-10-30 15:57:29 +00:00
|
|
|
id=auto_field_strategy,
|
2022-08-12 20:31:55 +00:00
|
|
|
datatype=just(Attribute.TYPE_TEXT),
|
|
|
|
|
enum_group=just(None),
|
2024-09-01 04:16:31 +00:00
|
|
|
slug=just(None), # Let Attribute.save() handle
|
2022-08-12 20:31:55 +00:00
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
@settings(deadline=None)
|
|
|
|
|
def test_model_properties(self, attribute: Attribute) -> None:
|
|
|
|
|
"""Tests that instance can be saved and has correct representation."""
|
|
|
|
|
attribute.full_clean()
|
|
|
|
|
attribute.save()
|
|
|
|
|
|
|
|
|
|
assert attribute
|
|
|
|
|
|
|
|
|
|
@given(
|
|
|
|
|
st.text(
|
|
|
|
|
alphabet=st.sampled_from(string.ascii_letters + string.digits),
|
|
|
|
|
min_size=50,
|
|
|
|
|
max_size=100,
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
def test_large_name_input(self, name_value) -> None:
|
2022-08-12 21:24:47 +00:00
|
|
|
"""Ensure proper slug is generated from large name fields."""
|
2022-08-12 20:31:55 +00:00
|
|
|
instance = Attribute.objects.create(
|
|
|
|
|
name=name_value,
|
|
|
|
|
datatype=Attribute.TYPE_TEXT,
|
|
|
|
|
enum_group=None,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert isinstance(instance, Attribute)
|
2024-09-01 03:58:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.django_db
|
2024-09-02 04:24:18 +00:00
|
|
|
def test_attribute_create_with_invalid_slug() -> None:
|
|
|
|
|
"""
|
|
|
|
|
Test that creating an Attribute with an invalid slug raises a UserWarning.
|
|
|
|
|
|
|
|
|
|
This test ensures that when an Attribute is created with a slug that is not
|
|
|
|
|
a valid Python identifier, a UserWarning is raised. The warning should
|
|
|
|
|
indicate that the slug is invalid and suggest updating it.
|
|
|
|
|
"""
|
|
|
|
|
with pytest.warns(UserWarning):
|
2024-09-01 03:58:49 +00:00
|
|
|
Attribute.objects.create(
|
2024-09-01 15:21:47 +00:00
|
|
|
name="Test Attribute",
|
|
|
|
|
slug="123-invalid",
|
|
|
|
|
datatype=Attribute.TYPE_TEXT,
|
2024-09-01 03:58:49 +00:00
|
|
|
)
|