diff --git a/functions/level_1/two_date_parser.py b/functions/level_1/two_date_parser.py index 4979a02b..4aeeeb62 100644 --- a/functions/level_1/two_date_parser.py +++ b/functions/level_1/two_date_parser.py @@ -14,5 +14,3 @@ def compose_datetime_from(date_str: str, time_str: str) -> datetime.datetime: int(hour_str), int(minute_str), ) - - diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..87c2714f --- /dev/null +++ b/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +addopts = + -vv --diff-width=60 + -vv --diff-symbols \ No newline at end of file diff --git a/tests/level_1/test_five_title.py b/tests/level_1/test_five_title.py index fe767004..04306764 100644 --- a/tests/level_1/test_five_title.py +++ b/tests/level_1/test_five_title.py @@ -1,5 +1,38 @@ +import pytest + from functions.level_1.five_title import change_copy_item -def test_change_copy_item(): - pass +@pytest.mark.parametrize(('title', 'result'), [ + ('Title', 'Copy of Title'), + ('TitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitle6789', + 'Copy of TitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitle6789'), # Failed + ('TITLE', 'Copy of TITLE'), + ('TITLE ', 'Copy of TITLE '), + (' TITLE ', 'Copy of TITLE '), + ('Title /!@# $%^&*()_+=- 098765432 1]\};`', 'Copy of Title /!@# $%^&*()_+=- 098765432 1]\};`') +]) +def test_title_length_less_one_hundred(title, result): + assert change_copy_item(title) == result + + +@pytest.mark.parametrize(('title', 'result'), [ + ('TitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitle', + 'TitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitle'), + ('TitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitle1', + 'TitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitle1') + ]) +def test_title_length_more_or_equal_one_hundred(title, result): + assert change_copy_item(title) == result + + +@pytest.mark.parametrize(('title', 'result'), [ + ('Copy of Title', 'Copy of Title (2)'), + ('COPY OF Title', 'Copy of COPY OF Title'), + ('Copy of Title (2)', f'Copy of Title (3)'), + ('Copy Title', 'Copy of Copy Title'), + ('Copy of Title (0)', f'Copy of Title (1)'), + ('Copy of Title (-1)', f'Copy of Title (-1) (2)') + ]) +def test_title_contains_copy(title, result): + assert change_copy_item(title) == result diff --git a/tests/level_1/test_four_bank_parser.py b/tests/level_1/test_four_bank_parser.py index df6c1b41..37bb9422 100644 --- a/tests/level_1/test_four_bank_parser.py +++ b/tests/level_1/test_four_bank_parser.py @@ -1,5 +1,89 @@ +import datetime +import pytest +from decimal import Decimal from functions.level_1.four_bank_parser import BankCard, SmsMessage, Expense, parse_ineco_expense -def test_parse_ineco_expense(): - pass +def test_parse_ineco_expense_correct_data(): + assert (parse_ineco_expense( + SmsMessage( + text='7777.55 EUR, 8888 12.02.24 10:47 London authcode 123456', + author='Alice', sent_at=datetime.datetime(2024, 2, 22, 12, 34, 56)), + [BankCard(last_digits='8888', owner='John Doe')]) == + Expense(amount=Decimal('7777.55'), card=BankCard(last_digits='8888', owner='John Doe'), + spent_in='London', spent_at=datetime.datetime(2024, 2, 12, 10, 47))) + + + +def test_parse_ineco_expense_int_sms_money_amount(): + assert (parse_ineco_expense(SmsMessage( + text='777755 EUR, 8888 12.02.30 10:47 London authcode 123456', + author='Alice', sent_at=datetime.datetime(2024, 2, 22, 12, 34, 56)), + [BankCard(last_digits='8888', owner='John Doe')]) == + + Expense(amount=Decimal('777755'), card=BankCard(last_digits='8888', owner='John Doe'), + spent_in='London', spent_at=datetime.datetime(2030, 2, 12, 10, 47))) + + +def test_parse_ineco_expense_sms_no_currency(): + with pytest.raises(IndexError): + assert (parse_ineco_expense(SmsMessage( + text='7777.55, 8888 12.02.30 10:47 London authcode 123456', + author='Alice', sent_at=datetime.datetime(2024, 2, 22, 12, 34, 56)), + [BankCard(last_digits='8888', owner='John Doe')]) == + + Expense(amount=Decimal('7777.55'), card=BankCard(last_digits='8888', owner='John Doe'), + spent_in='London', spent_at=datetime.datetime(2030, 2, 12, 10, 47))) + + +def test_parse_ineco_expense_sms_no_auth_code(): + assert (parse_ineco_expense(SmsMessage( + text='7777.55 EUR, 8888 12.02.30 10:47 London', + author='Alice', sent_at=datetime.datetime(2024, 2, 22, 12, 34, 56)), + [BankCard(last_digits='8888', owner='John Doe')]) == + + Expense(amount=Decimal('7777.55'), card=BankCard(last_digits='8888', owner='John Doe'), + spent_in='London', spent_at=datetime.datetime(2030, 2, 12, 10, 47))) + + +def test_parse_ineco_expense_sms_no_card_last_digits(): + with pytest.raises(ValueError): + assert (parse_ineco_expense(SmsMessage( + text='7777.55 EUR, 12.02.30 10:47 London authcode 123456', + author='Alice', sent_at=datetime.datetime(2024, 2, 22, 12, 34, 56)), + [BankCard(last_digits='', owner='John Doe')]) == + + Expense(amount=Decimal('7777.55'), card=BankCard(last_digits='', owner='John Doe'), + spent_in='London', spent_at=datetime.datetime(2030, 2, 12, 10, 47))) + + +def test_parse_ineco_expense_sms_wrong_date(): + with pytest.raises(ValueError): + assert (parse_ineco_expense( + SmsMessage( + text='7777.55 EUR, 8888 40.02.24 10:47 London authcode 123456', + author='Alice', sent_at=datetime.datetime(2024, 2, 22, 12, 34, 56)), + [BankCard(last_digits='8888', owner='John Doe')]) == + Expense(amount=Decimal('7777.55'), card=BankCard(last_digits='8888', owner='John Doe'), + spent_in='London', spent_at=datetime.datetime(2024, 2, 40, 10, 47))) + + +def test_parse_ineco_expense_sms_wrong_time(): + with pytest.raises(ValueError): + assert (parse_ineco_expense( + SmsMessage( + text='7777.55 EUR, 8888 20.02.24 50:47 London authcode 123456', + author='Alice', sent_at=datetime.datetime(2024, 2, 22, 12, 34, 56)), + [BankCard(last_digits='8888', owner='John Doe')]) == + Expense(amount=Decimal('7777.55'), card=BankCard(last_digits='8888', owner='John Doe'), + spent_in='London', spent_at=datetime.datetime(2024, 2, 20, 50, 47))) + + +def test_parse_ineco_expense_sms_empty_owner(): + assert (parse_ineco_expense( + SmsMessage( + text='7777.55 EUR, 8888 20.02.24 10:47 London authcode 123456', + author='Alice', sent_at=datetime.datetime(2024, 2, 22, 12, 34, 56)), + [BankCard(last_digits='8888', owner='')]) == + Expense(amount=Decimal('7777.55'), card=BankCard(last_digits='8888', owner=''), + spent_in='London', spent_at=datetime.datetime(2024, 2, 20, 10, 47))) \ No newline at end of file diff --git a/tests/level_1/test_one_gender.py b/tests/level_1/test_one_gender.py index 31d0bc7f..0c1ae7b6 100644 --- a/tests/level_1/test_one_gender.py +++ b/tests/level_1/test_one_gender.py @@ -1,5 +1,26 @@ +import pytest + from functions.level_1.one_gender import genderalize -def test_genderalize(): - pass +@pytest.mark.parametrize(("gender", 'verb'), [ + ('male', 'he'), + ('male ', 'she'), + (' male ', 'she'), + ('ma le', 'she') +]) +def test_genderalize_male(gender, verb): + assert genderalize('he', 'she', gender) == verb + + +@pytest.mark.parametrize(("gender", 'verb'), [ + ('female', 'she'), + ('fem', 'she'), + ('female1', 'she'), + ('mal', 'she'), + ('male1', 'she'), + ('123', 'she'), + ('', 'she') +]) +def test_genderalize_not_male(gender, verb): + assert genderalize('he', 'she', gender) == verb diff --git a/tests/level_1/test_three_url_builder.py b/tests/level_1/test_three_url_builder.py index bb7b54d2..61837048 100644 --- a/tests/level_1/test_three_url_builder.py +++ b/tests/level_1/test_three_url_builder.py @@ -1,5 +1,24 @@ +import pytest + from functions.level_1.three_url_builder import build_url -def test_build_url(): - pass +@pytest.mark.parametrize(('host', 'relative_url', 'get_params', 'result'), [ + ('host', 'relative_url', {"key1": "param1", "key2": "param2"}, 'host/relative_url?key1=param1&key2=param2'), + ('https://example.com', 'relative_url', {"key1": "PARAM1", "key2": "PARAM2"}, 'https://example.com/relative_url?key1=PARAM1&key2=PARAM2'), + ('http://example.com', 'path/to/resource', {"key1": "param1", "key2": "param&2"}, 'http://example.com/path/to/resource?key1=param1&key2=param&2'), + ('!@#$%^&*()_+|}/*-+~`<>?', '!@#$%^&*()_+|}/*-+~`<>?', {"key1": "!@#$%^&*()_+|}/*-+~`<>?", "key2": "!@#$%^&*()_+|}/*-+~`<>?"}, '!@#$%^&*()_+|}/*-+~`<>?/!@#$%^&*()_+|}/*-+~`<>??key1=!@#$%^&*()_+|}/*-+~`<>?&key2=!@#$%^&*()_+|}/*-+~`<>?') +]) +def test_build_url(host, relative_url, get_params, result): + assert (build_url(host, relative_url, get_params) == result) + + +@pytest.mark.parametrize(('host', 'relative_url', 'get_params', 'result'), [ + ('http://example.com', '', {"key1": "param1", "key2": "param2"}, 'http://example.com/?key1=param1&key2=param2'), + ('', '', {"key1": "param1", "key2": "param2"}, '/?key1=param1&key2=param2'), + ('http://example.com', 'path/to/resource', {"key1": "", "key2": "param2"}, 'http://example.com/path/to/resource?key1=&key2=param2'), + ('http://example.com', 'path/to/resource', {"key1": "param1", "": "param2"}, 'http://example.com/path/to/resource?key1=param1&=param2'), + ('', '', {"": "", "": ""}, '/?=') +]) +def test_build_url_with_empty_data(host, relative_url, get_params, result): + assert (build_url(host, relative_url, get_params) == result) diff --git a/tests/level_1/test_two_date_parser.py b/tests/level_1/test_two_date_parser.py index b0247049..d37bb34e 100644 --- a/tests/level_1/test_two_date_parser.py +++ b/tests/level_1/test_two_date_parser.py @@ -1,5 +1,30 @@ +from datetime import datetime +import pytest + from functions.level_1.two_date_parser import compose_datetime_from -def test_compose_datetime_from(): - pass +@pytest.mark.parametrize('date_str', ['today', 'yesterday']) +def test_compose_datetime_today_or_yesterday(date_str): + assert compose_datetime_from(date_str, '11:22') == datetime(datetime.now().year, datetime.now().month, datetime.now().day, 11, 22) + + +def test_compose_datetime_tomorrow(): + assert compose_datetime_from('tomorrow', '11:22') == datetime(datetime.now().year, datetime.now().month, datetime.now().day+1, 11, 22) + + +@pytest.mark.parametrize('date_str', ['123', '', ' ']) +def test_compose_datetime_from_improper_date_value(date_str): + assert compose_datetime_from(date_str, '11:22') == datetime(datetime.now().year, datetime.now().month, datetime.now().day, 11, 22) + + +@pytest.mark.parametrize(('time_str', 'hour', 'minute'), [ + ('123', 1, 23), + ('', 0, 0), + ('12:77', 12, 77), + ('77:12', 77, 12), + (' : ', 0, 0) +]) +def test_compose_datetime_from_improper_time_value(time_str, hour, minute): + with pytest.raises(ValueError): + assert compose_datetime_from('today', time_str) == datetime(datetime.now().year, datetime.now().month, datetime.now().day, hour, minute) diff --git a/tests/level_2/test_five_replace_word.py b/tests/level_2/test_five_replace_word.py new file mode 100644 index 00000000..850337ac --- /dev/null +++ b/tests/level_2/test_five_replace_word.py @@ -0,0 +1,41 @@ +import pytest + +from functions.level_2.five_replace_word import replace_word + + +@pytest.mark.parametrize(('text', 'replace_from', 'replace_to'), [ + ('one two three four five six', 'seven', 'seven'), + ('one two three four five six', 'seven', 'one'), + ('one two three four five six', '', 'one'), + ('one two three four five six', '', ''), + ('one two three four five six', ' ', ' ') +]) +def test____five_replace_word____no_replacement_if_no_replace_from_in_the_text(text, replace_from, replace_to): + assert replace_word(text, replace_from, replace_to) == text + + +@pytest.mark.parametrize(('text', 'replace_from', 'replace_to'), [ + ('one two three four five six', 'one', 'seven'), + ('one two three four five six', 'one', 'two'), + ('one two three four five six', 'one', ''), + ('one two three four five six', 'one', ' ') +]) +def test__five_replace_word__replacement_if_replace_from_is_in_the_text(text, replace_from, replace_to): + removed_first_word = text.split(' ', 1)[1] + assert replace_word(text, replace_from, replace_to) == f"{replace_to} {removed_first_word}" + + +def test__five_replace_word__replacement_without_changes_if_the_same_words_in_all_parameters(): + assert replace_word('one two three four five six', 'one', 'one') == 'one two three four five six' + + +@pytest.mark.parametrize(('text', 'replace_from', 'replace_to'), [ + ('one two three four five six', 'ONE', 'seven'), + ('one two three four five six', 'one', 'TWO'), + ('one two three four five six', 'ONE', ''), + ('one two three four five six', 'ONE', ' '), + ('ONE two three four five six', 'one', 'seven'), +]) +def test__five_replace_word__replacement_if_replace_from_is_in_the_text_ignore_case(text, replace_from, replace_to): + removed_first_word = text.split(' ', 1)[1] + assert replace_word(text, replace_from, replace_to) == f"{replace_to} {removed_first_word}" \ No newline at end of file diff --git a/tests/level_2/test_four_sentiment.py b/tests/level_2/test_four_sentiment.py new file mode 100644 index 00000000..96112ee8 --- /dev/null +++ b/tests/level_2/test_four_sentiment.py @@ -0,0 +1,53 @@ +import pytest + +from functions.level_2.four_sentiment import check_tweet_sentiment + + +@pytest.mark.parametrize(('text', 'result'), [ + ('good news', 'GOOD'), + ('the best of the best news', 'GOOD'), + ('good fff best news', 'GOOD') +]) +def test__four_sentiment__return_good_if_good_words_more_than_bad(text, result): + assert check_tweet_sentiment(text, {'good', 'better', 'best'}, {'f', 'ff', 'fff'}) == result + + +@pytest.mark.parametrize(('text', 'result'), [ + ('ff news', 'BAD'), + ('f and fff news', 'BAD'), + ('good f ff news', 'BAD') +]) +def test__four_sentiment__return_bad_if_bad_words_more_than_good(text, result): + assert check_tweet_sentiment(text, {'good', 'better', 'best'}, {'f', 'ff', 'fff'}) == result + + +@pytest.mark.parametrize(('text', 'result'), [ + ('normal news', None), + ('good best f ff news', None) +]) +def test__four_sentiment__return_none_if_quantity_of_good_and_bad_words_is_equal(text, result): + assert check_tweet_sentiment(text, {'good', 'better', 'best'}, {'f', 'ff', 'fff'}) == result + + +@pytest.mark.parametrize(('text', 'result'), [ + ('', None), + (' ', None) +]) +def test__four_sentiment__return_none_if_no_words_in_text(text, result): + assert check_tweet_sentiment(text, {'good', 'better', 'best'}, {'f', 'ff', 'fff'}) == result + + +def test__four_sentiment__return_none_if_good_list_is_empty_and_no_bad_verbs_in_text(): + assert check_tweet_sentiment('good news', {}, {'f', 'ff', 'fff'}) == None + + +def test__four_sentiment__return_none_if_bad_list_is_empty_and_no_good_verbs_in_text(): + assert check_tweet_sentiment('ff news', {'good', 'better', 'best'}, {}) == None + + +def test__four_sentiment__return_bad_if_good_list_is_empty_and_some_bad_verbs_in_text(): + assert check_tweet_sentiment('ff news', {}, {'f', 'ff', 'fff'}) == 'BAD' + + +def test__four_sentiment__return_good_if_bad_list_is_empty_and_some_good_verbs_in_text(): + assert check_tweet_sentiment('good news', {'good', 'better', 'best'}, {}) == 'GOOD' \ No newline at end of file diff --git a/tests/level_2/test_one_pr_url.py b/tests/level_2/test_one_pr_url.py new file mode 100644 index 00000000..8c35c9e5 --- /dev/null +++ b/tests/level_2/test_one_pr_url.py @@ -0,0 +1,27 @@ +import pytest + +from functions.level_2.one_pr_url import is_github_pull_request_url + + +@pytest.mark.parametrize(('url', 'result'), [ + ('https://github.com/test/test/pull/1', True), + ('https://github.com/test/test/pull/', True) +]) +def test__one_pr_url__return_true_if_len_is_seven_github_on_third_and_pull_on_sixth_place_and_len_is_seven(url, result): + assert is_github_pull_request_url(url) == result + + +@pytest.mark.parametrize(('url', 'result'), [ + ('https://github.com/test/test/pull/1/test', False), + ('https://github.com/test/test/pull', False) +]) +def test__one_pr_url__return_false_if_len_is_not_seven(url, result): + assert is_github_pull_request_url(url) == result + + +@pytest.mark.parametrize(('url', 'result'), [ + ('https://git.com/test/test/pull/1', False), + ('https://github.com/test/test/no_pull/1', False) +]) +def test__one_pr_url__return_false_if_no_github_on_third_place_or_no_pul_on_sixth_place(url, result): + assert is_github_pull_request_url(url) == result diff --git a/tests/level_2/test_three_first.py b/tests/level_2/test_three_first.py new file mode 100644 index 00000000..1a418ab9 --- /dev/null +++ b/tests/level_2/test_three_first.py @@ -0,0 +1,19 @@ +import pytest + +from functions.level_2.three_first import first + + +@pytest.mark.parametrize(('items', 'default', 'expected'), [ + ([1, 2], 4, 1), + ([1, 2], None, 1), + ([1, 2], 'NOT_SET', 1), + ([], 5, 5), + ([], None, None) +]) +def test__three_first__with_return_value(items, default, expected): + assert first(items, default) == expected + + +def test__three_first__attribute_error_if_default_equals_not_set_and_no_items(): + with pytest.raises(AttributeError): + assert first([], 'NOT_SET') == 0 diff --git a/tests/level_2/test_two_square_equation.py b/tests/level_2/test_two_square_equation.py new file mode 100644 index 00000000..66b2be1f --- /dev/null +++ b/tests/level_2/test_two_square_equation.py @@ -0,0 +1,21 @@ +from functions.level_2.two_square_equation import solve_square_equation + + +def test__two_square_equation__descriminant_less_than_zero(): + assert solve_square_equation(1.0, 0.1, 0.1) == (None, None) + + +def test__two_square_equation__no_square_coefficient(): + assert solve_square_equation(0.0, 0.1, 0.1) == (-1.0, None) + + +def test__two_square_equation__no_square_coefficient_and_no_linear_coefficient(): + assert solve_square_equation(0.0, 0.0, 0.1) == (None, None) + + +def test__two_square_equation__no_square_coefficient_and_no(): + assert solve_square_equation(0.1, 5.1, 0.1) == (-50.980384612481814, -0.019615387518183702) + + +def test__two_square_equation__descriminant_is_zero(): # + assert solve_square_equation(2.0, 1.0, 1.0) == (None, None)