1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
import pytest
import sqlalchemy as sa
import sqlalchemy.orm
from sqlalchemy_utils import ( # noqa
PhoneNumber,
PhoneNumberParseException,
PhoneNumberType,
types
)
from sqlalchemy_utils.compat import _select_args
VALID_PHONE_NUMBERS = (
"040 1234567",
"+358 401234567",
"09 2501234",
"+358 92501234",
"0800 939393",
"09 4243 0456",
"0600 900 500",
)
@pytest.fixture
def User(Base):
class User(Base):
__tablename__ = "user"
id = sa.Column(sa.Integer, autoincrement=True, primary_key=True)
name = sa.Column(sa.Unicode(255))
phone_number = sa.Column(PhoneNumberType())
return User
@pytest.fixture
def init_models(User):
pass
@pytest.fixture
def phone_number():
return PhoneNumber("040 1234567", "FI")
@pytest.fixture
def user(session, User, phone_number):
user = User()
user.name = "Someone"
user.phone_number = phone_number
session.add(user)
session.commit()
return user
@pytest.mark.skipif("types.phone_number.phonenumbers is None")
class TestPhoneNumber:
@pytest.mark.parametrize("raw_number", VALID_PHONE_NUMBERS)
def test_valid_phone_numbers(self, raw_number):
number = PhoneNumber(raw_number, "FI")
assert number.is_valid_number()
@pytest.mark.parametrize("raw_number", ("abc", "+040 1234567"))
def test_invalid_phone_numbers__constructor_fails(self, raw_number):
with pytest.raises(PhoneNumberParseException):
PhoneNumber(raw_number, "FI")
@pytest.mark.parametrize("raw_number", ("0111234567", "358"))
def test_invalid_phone_numbers__is_valid_number(self, raw_number):
number = PhoneNumber(raw_number, "FI")
assert not number.is_valid_number()
def test_invalid_phone_numbers_throw_dont_wrap_exception(self, session, User):
with pytest.raises(PhoneNumberParseException):
session.execute(
User.__table__.insert().values(name="Someone", phone_number="abc")
)
def test_phone_number_attributes(self):
number = PhoneNumber("+358401234567")
assert number.e164 == "+358401234567"
assert number.international == "+358 40 1234567"
assert number.national == "040 1234567"
def test_phone_number_attributes_for_short_code(self):
"""
For international and national shortcode remains the same, if we pass
short code to PhoneNumber library without giving check_region it will
raise exception
:return:
"""
number = PhoneNumber("72404", check_region=False)
assert number.e164 == "+072404"
assert number.international == "72404"
assert number.national == "72404"
def test_phone_number_str_repr(self):
number = PhoneNumber("+358401234567")
assert str(number) == number.national
def test_phone_number_hash(self):
number1 = PhoneNumber("+821023456789")
number2 = PhoneNumber("+82 10-2345-6789")
assert hash(number1) == hash(number2)
assert hash(number1) == hash(number1.e164)
assert {number1} == {number2}
@pytest.mark.skipif("types.phone_number.phonenumbers is None")
class TestPhoneNumberType:
def test_query_returns_phone_number_object(self, session, User, user, phone_number):
queried_user = session.query(User).first()
assert queried_user.phone_number == phone_number
def test_phone_number_is_stored_as_string(self, session, user):
result = session.execute(
sa.text('SELECT phone_number FROM "user" WHERE id=:param'),
{"param": user.id},
)
assert result.first()[0] == "+358401234567"
def test_phone_number_with_extension(self, session, User):
user = User(phone_number="555-555-5555 Ext. 555")
session.add(user)
session.commit()
session.refresh(user)
assert user.phone_number.extension == "555"
def test_empty_phone_number_is_equiv_to_none(self, session, User):
user = User(phone_number="")
session.add(user)
session.commit()
session.refresh(user)
assert user.phone_number is None
def test_uses_phonenumber_class_as_python_type(self):
assert PhoneNumberType().python_type is PhoneNumber
@pytest.mark.usefixtures("user")
def test_phone_number_is_none(self, session, User):
phone_number = None
user = User()
user.name = "Someone"
user.phone_number = phone_number
session.add(user)
session.commit()
queried_user = session.query(User)[1]
assert queried_user.phone_number is None
result = session.execute(
sa.text('SELECT phone_number FROM "user" WHERE id=:param'),
{"param": user.id},
)
assert result.first()[0] is None
def test_scalar_attributes_get_coerced_to_objects(self, User):
user = User(phone_number="050111222")
assert isinstance(user.phone_number, PhoneNumber)
def test_compilation(self, User, session):
query = sa.select(*_select_args(User.phone_number))
# the type should be cacheable and not throw exception
session.execute(query)
@pytest.mark.skipif("types.phone_number.phonenumbers is None")
class TestPhoneNumberComposite:
@pytest.fixture
def User(self, Base):
class User(Base):
__tablename__ = "user"
id = sa.Column(sa.Integer, autoincrement=True, primary_key=True)
name = sa.Column(sa.String(255))
_phone_number = sa.Column(sa.String(255))
country = sa.Column(sa.String(255))
phone_number = sa.orm.composite(PhoneNumber, _phone_number, country)
return User
@pytest.fixture
def user(self, session, User):
user = User()
user.name = "Someone"
user.phone_number = PhoneNumber("+35840111222", "FI")
session.add(user)
session.commit()
return user
def test_query_returns_phone_number_object(self, session, User, user):
queried_user = session.query(User).first()
assert queried_user.phone_number.national == "040 111222"
assert queried_user.phone_number.region == "FI"
|