Skip to content

Commit

Permalink
Test Suite Housekeeping (Part 3) (#1167)
Browse files Browse the repository at this point in the history
* Add test fixtures exclusive for tests.providers

* Pytestify tests.sphinx

* Pytestify and improve user agent provider tests

* Pytestify barcode provider tests

* Fix flake8 bare except issue

* Pytestify, reorganize, and improve Generator class tests

* Pytestify, reorganize, and improve Faker class tests

* Fix test failure

* Pytestify currency provider tests

* Pytestify isbn provider tests

* Pytestify, reorganize, and improve internet provider tests

* Pytestify, reorganize, and improve base provider tests

* Fix CI errors
  • Loading branch information
malefice authored May 19, 2020
1 parent 262a5bb commit fca4fe9
Show file tree
Hide file tree
Showing 13 changed files with 1,000 additions and 1,136 deletions.
244 changes: 210 additions & 34 deletions tests/providers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,53 +1,229 @@
import unittest
import re
import string

from faker import Faker
from collections import OrderedDict

import pytest

class BaseProviderTestCase(unittest.TestCase):
def setUp(self):
self.fake = Faker('en_US')
Faker.seed(0)
from faker.providers import BaseProvider

def test_random_digit_or_empty(self):
ret = self.fake.random_digit_or_empty()
assert isinstance(ret, int)
assert 0 <= ret <= 9

Faker.seed(1)
assert self.fake.random_digit_or_empty() == ''
class TestBaseProvider:
"""Test base provider methods"""

def test_random_digit_not_null_or_empty(self):
ret = self.fake.random_digit_not_null_or_empty()
assert isinstance(ret, int)
assert 0 <= ret <= 9
def test_locale(self, faker, num_samples):
locales = [
'{}_{}'.format(language, region)
for language, regions in BaseProvider.language_locale_codes.items()
for region in regions
]
for _ in range(num_samples):
locale = faker.locale()
assert locale in locales

Faker.seed(1)
assert self.fake.random_digit_not_null_or_empty() == ''
def test_language_code(self, faker, num_samples):
language_codes = list(BaseProvider.language_locale_codes)
for _ in range(num_samples):
language_code = faker.language_code()
assert language_code in language_codes

def test_randomize_nb_elements(self):
assert self.fake.randomize_nb_elements(number=1, le=True, ge=True) == 1
def test_random_digit(self, faker, num_samples):
samples = [faker.random_digit() for _ in range(num_samples * 10)]
assert set(samples) == set(range(10))

assert self.fake.randomize_nb_elements(le=True, ge=True) == 10
def test_random_digit_not_null(self, faker, num_samples):
samples = [faker.random_digit_not_null() for _ in range(num_samples * 10)]
assert set(samples) == set(range(1, 10))

assert self.fake.randomize_nb_elements(min=42) == 42
assert self.fake.randomize_nb_elements(max=1) == 1
def test_random_digit_or_empty(self, faker, num_samples):
expected = set(range(10))
expected.add('')
samples = [faker.random_digit_or_empty() for _ in range(num_samples * 10)]
assert set(samples) == expected

def test_random_digit_not_null_or_empty(self, faker, num_samples):
expected = set(range(1, 10))
expected.add('')
samples = [faker.random_digit_not_null_or_empty() for _ in range(num_samples * 10)]
assert set(samples) == expected

def test_random_number(self, faker):
number = faker.random_number(10, True)
assert len(str(number)) == 10

# Digits parameter < 0
with pytest.raises(ValueError):
number = faker.random_number(-1, True)

# Digits parameter < 1 with fix_len=True
with pytest.raises(ValueError):
number = faker.random_number(0, True)

@pytest.mark.parametrize('text,pattern', [
('', r''),
('abcd', r'abcd'),
('#' * 100, r'[0-9]{100}'),
('%' * 100, r'[1-9]{100}'),
('!' * 100, r'[0-9]{,100}'),
('@' * 100, r'[0-9]{,100}'),
('##!abc %%@def##!' * 100, r'(?:[0-9]{2,3}abc [1-9]{2,3}def[0-9]{2,3}){100}'),
('#@@#^?あ5漢!!%%@' * 100, r'(?:\d[1-9]{,2}\d\^\?あ5漢\d{,2}[1-9]{2}[1-9]*){100}'),
], ids=[
'empty_string',
'no_valid_placeholders',
'only_number_signs',
'only_percent_signs',
'only_exclamation_marks',
'only_at_symbols',
'with_ascii_characters',
'with_other_symbols_and_non_ascii',
])
def test_numerify(self, faker, num_samples, text, pattern):
for _ in range(num_samples):
numerified = faker.numerify(text)
assert re.fullmatch(pattern, numerified)

@pytest.mark.parametrize('text,letters,pattern', [
('', string.ascii_letters, r''),
('abcd', string.ascii_letters, r'abcd'),
('???', string.ascii_letters, r'[0-9a-zA-Z]{3}'),
('???', 'aBcDeFgHiJ12345', r'[1-5aBcDeFgHiJ]{3}'),
('??Xr^#7p??', 'AbCdخあ5漢7Я', r'[AbCdخあ5漢7Я]{2}Xr\^#7p[AbCdخあ5漢7Я]{2}'),
], ids=[
'empty_string',
'no_valid_placeholders',
'letters_using_whole_ascii',
'letters_using_ascii_subset',
'pattern_with_other_symbols_and_letters_using_non_ascii',
])
def test_lexify(self, faker, num_samples, text, letters, pattern):
for _ in range(num_samples):
lexified = faker.lexify(text, letters=letters)
assert re.fullmatch(pattern, lexified)

@pytest.mark.parametrize('text,letters,pattern', [
('', string.ascii_letters, r''),
('abcd', string.ascii_letters, r'abcd'),
('???', string.ascii_letters, r'[0-9a-zA-Z]{3}'),
('???', 'aBcDeFgHiJ12345', r'[1-5aBcDeFgHiJ]{3}'),
('#%!@???', string.ascii_letters, r'\d[1-9]\d*[1-9]*[0-9a-zA-Z]{3}'),
('#%!@???', 'aBcDeFgHiJ12345', r'\d[1-9]\d*[1-9]*[1-5aBcDeFgHiJ]{3}'),
('#%!@??Xr7p??', 'AbCdخあ5漢7Я', r'\d[1-9]\d*[1-9]*[AbCdخあ5漢7Я]{2}Xr7p[AbCdخあ5漢7Я]{2}'),
], ids=[
'empty_string',
'no_valid_placeholders',
'simple_pattern_and_letters_using_whole_ascii',
'simple_pattern_and_letters_using_ascii_subset',
'more_complex_pattern_and_letters_using_whole_ascii',
'more_complex_pattern_and_letters_using_ascii_subset',
'more_complex_pattern_with_other_symbols_and_letters_using_non_ascii',
])
def test_bothify(self, faker, num_samples, text, letters, pattern):
for _ in range(num_samples):
bothified = faker.bothify(text, letters=letters)
assert re.fullmatch(pattern, bothified)

@pytest.mark.parametrize('text,upper,pattern', [
('', False, r''),
('', True, r''),
('abcd', False, r'abcd'),
('abcd', True, r'abcd'),
('^^^^', False, r'[0-9a-f]{4}'),
('^^^^', True, r'[0-9A-F]{4}'),
('Abc ^^^ %^^^?あ5漢!#^^', False, r'Abc [0-9a-f]{3} %[0-9a-f]{3}\?あ5漢!#[0-9a-f]{2}'),
('Abc ^^^ %^^^?あ5漢!#^^', True, r'Abc [0-9A-F]{3} %[0-9A-F]{3}\?あ5漢!#[0-9A-F]{2}'),
], ids=[
'empty_string_lowercase',
'empty_string_uppercase',
'no_circumflex_lowercase',
'no_circumflex_uppercase',
'simple_pattern_lowercase',
'simple_pattern_uppercase',
'complex_pattern_lowercase',
'complex_pattern_uppercase',
])
def test_hexify(self, faker, num_samples, text, upper, pattern):
for _ in range(num_samples):
hexified = faker.hexify(text, upper=upper)
assert re.fullmatch(pattern, hexified)

def test_random_letter(self, faker, num_samples):
for _ in range(num_samples):
letter = faker.random_letter()
assert letter.isalpha()

def test_random_lowercase_letter(self, faker, num_samples):
for _ in range(num_samples):
letter = faker.random_lowercase_letter()
assert letter.isalpha() and letter.lower() == letter

def test_random_uppercase_letter(self, faker, num_samples):
for _ in range(num_samples):
letter = faker.random_uppercase_letter()
assert letter.isalpha() and letter.upper() == letter

def test_random_element(self, faker, num_samples):
# dicts not allowed because they introduce dependency on PYTHONHASHSEED
with pytest.raises(ValueError):
faker.random_element({})

choices = ('a', 'b', 'c', 'd')
for _ in range(num_samples):
assert faker.random_element(choices) in choices

choices = OrderedDict([('a', 5), ('b', 2), ('c', 2), ('d', 1)])
for _ in range(num_samples):
assert faker.random_element(choices) in choices

choices = OrderedDict([('a', 0.5), ('b', 0.2), ('c', 0.2), ('d', 0.1)])
for _ in range(num_samples):
assert faker.random_element(choices) in choices

def test_random_sample(self, faker):
# Too many items requested
with pytest.raises(ValueError):
faker.random_sample('abcde', 6)

# Same length
sample = faker.random_sample('abcd', 4)
assert sorted(sample) == list('abcd')

sample = faker.random_sample('abcde', 5)
assert sorted(sample) == list('abcde')

# Length = 3
sample = faker.random_sample('abcde', 3)
assert len(sample) == 3
assert set(sample).issubset(set('abcde'))

# Length = 1
sample = faker.random_sample('abcde', 1)
assert len(sample) == 1
assert set(sample).issubset(set('abcde'))

# Length = 0
sample = faker.random_sample('abcde', 0)
assert sample == []

def test_randomize_nb_elements(self, faker, num_samples):
assert faker.randomize_nb_elements(number=1, le=True, ge=True) == 1
assert faker.randomize_nb_elements(le=True, ge=True) == 10
assert faker.randomize_nb_elements(min=42) == 42
assert faker.randomize_nb_elements(max=1) == 1

number = 9999
random_times = 100
lower_bound = int(number * 0.6)
upper_bound = int(number * 1.4)

for _ in range(random_times):
res = self.fake.randomize_nb_elements(number=number, le=True)
for _ in range(num_samples):
res = faker.randomize_nb_elements(number=number, le=True)
assert res >= lower_bound
assert res <= number, "'{}' is not <= than '{}'".format(res, number)

for _ in range(random_times):
res = self.fake.randomize_nb_elements(number=number, ge=True)
assert res >= number
assert res <= upper_bound
for _ in range(num_samples):
res = faker.randomize_nb_elements(number=number, ge=True)
assert number <= res <= upper_bound

for _ in range(random_times):
res = self.fake.randomize_nb_elements(number=number)
assert res >= lower_bound
assert res <= upper_bound
for _ in range(num_samples):
res = faker.randomize_nb_elements(number=number)
assert lower_bound <= res <= upper_bound
41 changes: 41 additions & 0 deletions tests/providers/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import locale as pylocale
import re

import pytest

from faker import Faker
from faker.contrib.pytest.plugin import DEFAULT_SEED

LOCALE_TEST_CLASS_NAME_REGEX = re.compile(
r'^Test(?P<language>[A-Z][a-z]{1,2})(?P<region>[A-Z][a-z])$',
)


@pytest.fixture(scope='class', autouse=True)
def _class_locale_faker(request):
if not request.cls:
return None
class_name = request.cls.__name__
match = LOCALE_TEST_CLASS_NAME_REGEX.fullmatch(class_name)
if not match:
return None
locale = '{language}_{region}'.format(**match.groupdict())
locale = pylocale.normalize(locale).split('.')[0]
return Faker(locale=locale)


@pytest.fixture(autouse=True)
def faker(_class_locale_faker, faker):
if not _class_locale_faker:
return faker
_class_locale_faker.seed_instance(DEFAULT_SEED)
return _class_locale_faker


@pytest.fixture(scope='class', autouse=True)
def num_samples(request):
try:
num = int(request.cls.num_samples)
except AttributeError:
num = 100
return num
Loading

0 comments on commit fca4fe9

Please sign in to comment.