File: test_phonenumber.py

package info (click to toggle)
python-sqlalchemy-utils 0.41.2-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 1,252 kB
  • sloc: python: 13,566; makefile: 141
file content (193 lines) | stat: -rw-r--r-- 6,246 bytes parent folder | download | duplicates (2)
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"