Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
268 changes: 137 additions & 131 deletions hw_4/api.py

Large diffs are not rendered by default.

Binary file modified hw_4/bank.db
Binary file not shown.
1 change: 0 additions & 1 deletion hw_4/db_con_decor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ def db_connection(func):
Returns:
function: Вложенная функция-обертка, которая обеспечивает соединение и закрытие.
"""
# не работает
@wraps(func)
def wrapper(*args, **kwargs):
"""
Expand Down
3 changes: 1 addition & 2 deletions hw_4/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def init_args():
def do_func_with_args(args):
# to be able to perform multiple functions
if args.add_path and args.table_name:
api.add_table_by_file(args.add_path, args.table_name)
api.add_generic_by_path(args.add_path, args.table_name)
if args.table_name and args.row_id and args.column and args.value:
api.update_row(args.table_name, args.row_id, args.column, args.value)
if args.clear_table:
Expand All @@ -58,7 +58,6 @@ def do_func_with_args(args):
if args.delete_incomplete:
print(api.delete_users_with_incomplete_info())


def main():
initial_db_setup.create_database()
do_func_with_args(init_args())
Expand Down
205 changes: 205 additions & 0 deletions hw_4/tests/unit/test_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
from unittest.mock import MagicMock, patch, call

currency_dict = {'AUD': 1.5087302415, 'BGN': 1.7944802113, 'BRL': 5.1709607454, 'CAD': 1.3662601591, 'CHF': 0.9142001532,
'CNY': 7.2410307379, 'CZK': 22.7015437907, 'DKK': 6.880361225, 'EUR': 0.9215801687, 'GBP': 0.7851001494,
'HKD': 7.8098112804, 'HRK': 6.6462708211, 'HUF': 353.9114355311, 'IDR': 15972.272064036, 'ILS': 3.657970377,
'INR': 82.9986356329, 'ISK': 138.25410507, 'JPY': 156.989784703, 'KRW': 1363.8085527748, 'MXN': 16.7282428767,
'MYR': 4.7111009312, 'NOK': 10.5840419142, 'NZD': 1.6331801746, 'PHP': 58.1784177311, 'PLN': 3.912080408,
'RON': 4.5850908988, 'RUB': 89.5966276992, 'SEK': 10.6642017923, 'SGD': 1.3488202508, 'THB': 36.635135533,
'TRY': 32.2610938602, 'USD': 1, 'ZAR': 18.4172320138}


def test_unpack_to_string():
from api import unpack_to_string
input_data = [(1, 2, 3), (4, 5), (6,)]
actual = unpack_to_string(input_data)
expected = '1,2,3,4,5,6'
assert actual == expected

def test_convert_currency():
from api import convert_currency
input_data_1 = currency_dict
input_data_2 = 'USD'
input_data_3 = 'EUR'
input_data_4 = 500
actual = convert_currency(input_data_1, input_data_2, input_data_3, input_data_4 )
expected = 460.79
assert actual == expected

def test_string_elements():
from api import format_data_string
data = [{'a': 23, 'b': 34, 'c': 90}, {'d': 90, 'f': 78, 'g': 54}]
expected = ('a, b, c', ':a, :b, :c')
actual = format_data_string(data)
assert actual == expected

def test_unpack_data():
from api import unpack_data
input_data = {'name': 'Alice', 'age': 30, 'city': 'Wonderland'}
expected_result = ['Alice', 30, 'Wonderland']
result = unpack_data(input_data)
assert list(result) == expected_result

@patch('api.insert_transaction')
@patch('api.update_row')
@patch('api.get_currency_data', return_value={'CNY': 7.2410307379,'USD': 1 })
@patch('api.get_data_by_id', return_value=['Bank1', 'Bank2',400,300,'USD','CNY'])
@patch('api.account_valid', return_value=[540.70, '2024-05-29 17:58:41.245018'])
def test_transfer_money(mock_f_1, mock_f_2, mock_f_3, mock_f_4, mock_f_5):
from api import transfer_money
sender_id = 1
receiver_id = 3
sent_amount = 900
result = transfer_money(sender_id, receiver_id, sent_amount)
expected_call_func_dict = {'get_currency_data': 1,
'get_data_by_id': 1,
'account_valid': 1,
'update_row': 2,
'insert_transaction': 1}
result_call_func_dict = {'get_currency_data': mock_f_1.call_count,
'get_data_by_id': mock_f_2.call_count,
'account_valid': mock_f_3.call_count,
'update_row': mock_f_4.call_count,
'insert_transaction': mock_f_5.call_count}
assert result == "success"
assert expected_call_func_dict == result_call_func_dict

def test_set_accounts():
from api import set_accounts
cursor = MagicMock()
data = [{'user_id': '1', 'type': 'credit', 'account_number': 'ID--dcd-123568744-',
'bank_id': '3', 'currency': 'USD', 'amount': '1000', 'status': 'gold'},
{'user_id': '3', 'type': 'debit', 'account_number': 'ID--xyz-987654-uvw',
'bank_id': '2', 'currency': 'USD', 'amount': '500', 'status': 'silver'}]
set_accounts(cursor, data)
result = cursor.mock_calls
expected = [call.execute('SELECT id FROM Account WHERE user_id = ?', ('1',)),
call.fetchall(),
call.fetchall().__iter__(),
call.execute('UPDATE User SET Accounts = ? WHERE id = ?', ('', '1')),
call.execute('SELECT id FROM Account WHERE user_id = ?', ('3',)),
call.fetchall(),
call.fetchall().__iter__(),
call.execute('UPDATE User SET Accounts = ? WHERE id = ?', ('', '3'))]
assert result == expected

@patch('validate.valid_currency_amount', return_value= True)
@patch('api.convert_currency', return_value= 450)
@patch('validate.add_transaction_time', return_value = '2024-05-29 17:58:41.245018')
def test_account_valid(mock_f_1, mock_f_2, mock_f_3):
from api import account_valid
result = account_valid(400,300,'USD','CNY',
{'CNY': 7.2410307379,'USD': 1 },'2023-05-11 12:33:12.245018')
expected = (450, '2024-05-29 17:58:41.245018')
expected_call_func_dict = {'valid_currency_amount': 1, 'convert_currency': 1, 'add_transaction_time': 1}
result_call_func_dict = {'valid_currency_amount': mock_f_1.call_count,
'convert_currency': mock_f_2.call_count, 'add_transaction_time': mock_f_3.call_count}

print(mock_f_1.call_count)
assert expected == result
assert expected_call_func_dict == result_call_func_dict

@patch('random.choice', return_value= 30)
@patch('random.sample', return_value= [(2,), (3,), (4,), (1,), (5,)])
@patch('api.select_id_from_user', return_value= [(4,), (1,), (3,), (5,), (2,)])
def test_select_random_users_with_discounts(mock_f_1, mock_f_2,mock_f_3):
from api import select_random_users_with_discounts
result = select_random_users_with_discounts()
expected = {2: 30, 3: 30, 4: 30, 1: 30, 5: 30}
expected_call_func_dict = {'api.select_id_from_use': 1,
'random.sample': 1,
'random.choice': 5}
result_call_func_dict = {'api.select_id_from_use': mock_f_1.call_count,
'random.sample': mock_f_2.call_count,
'random.choice': mock_f_3.call_count}
assert expected == result
assert expected_call_func_dict == result_call_func_dict

@patch('api.select_for_user_with_highest_amount', return_value= 6)
@patch('api.get_data_from_table', return_value= 'John')
def test_user_with_highest_amount(mock_f_1, mock_f_2):
from api import user_with_highest_amount
result = user_with_highest_amount()
expected = 'John'
expected_call_func_dict = {'api.get_data_from_table': 1,
'api.select_for_user_with_highest_amount': 1}
result_call_func_dict = {'api.get_data_from_table': mock_f_1.call_count,
'api.select_for_user_with_highest_amount': mock_f_2.call_count}
assert expected == result
assert expected_call_func_dict == result_call_func_dict

@patch('api.select_for_bank_with_biggest_capital', return_value= [(3, 'USD', 457.46), (2, 'USD', 500.0),
(5, 'EUR', 1342.54), (4, 'CAD', 1200.0),
(1, 'USD', 1500.0)])
@patch('api.get_currency_data', return_value= currency_dict)
def test_bank_with_biggest_capital(mock_f_1, mock_f_2):
from api import bank_with_biggest_capital
result = bank_with_biggest_capital()
expected = 1
expected_call_func_dict = {'api.select_for_bank_with_biggest_capital': 1,
'api.get_currency_data': 1}
result_call_func_dict = {'api.select_for_bank_with_biggest_capital': mock_f_1.call_count,
'api.get_currency_data': mock_f_2.call_count}
assert expected == result
assert expected_call_func_dict == result_call_func_dict


@patch('api.select_for_bank_serving_oldest_client', return_value= ([(1, '1990-05-05'), (2, '1985-10-15'),
(3, '1978-03-20'), (4, '1995-08-08'),
(5, '1982-12-30')], [(1, 3), (3, 2),
(2, 5), (2, 4), (4, 1)]))
def test_bank_serving_oldest_client(mock_f_1):
from api import bank_serving_oldest_client
result = bank_serving_oldest_client()
expected = 2
expected_call_func_dict = {'api.select_for_bank_with_biggest_capital': 1}
result_call_func_dict = {'api.select_for_bank_with_biggest_capital': mock_f_1.call_count}
assert expected == result
assert expected_call_func_dict == result_call_func_dict

@patch('api.select_for_bank_with_highest_unique_users', return_value= [('Chase Bank', 1), ('Citibank', 2),
('Citibank', 4), ('HSBC', 3)])
def test_bank_with_highest_unique_users(mock_f_1):
from api import bank_with_highest_unique_users
result = bank_with_highest_unique_users()
expected = 'Citibank'
expected_call_func_dict = {'api.select_for_bank_with_highest_unique_users': 1}
result_call_func_dict = {'api.select_for_bank_with_highest_unique_users': mock_f_1.call_count}
assert expected == result
assert expected_call_func_dict == result_call_func_dict


@patch('api.delete_user')
@patch('api.select_for_delete_users_with_incomplete_info', return_value= [(4,), (1,), (3,), (5,), (2,)])
def test_delete_users_with_incomplete_info(mock_f_1, mock_f_2):
from api import delete_users_with_incomplete_info
result = delete_users_with_incomplete_info()
print(result)
expected = "Deletion complete"
expected_call_func_dict = {'api.delete_user': 5}
result_call_func_dict = {'api.delete_user': mock_f_2.call_count}
assert expected == result
assert expected_call_func_dict == result_call_func_dict



'''
#sys.modules['db_con_decor'] = MagicMock()

def mock_db_connection(func):
@wraps(func)
def wrapper(*args, **kwargs):
c = MagicMock()
result = func(c, *args, **kwargs)

return wrapper

patch('db_con_deco.db_connection', mock_db_connection).start()

def test_update_row():
from api import update_row
cur = MagicMock()
res = update_row(cur, "User", 1, None, "BUIXGSCG")
assert res == "success"
#cur.mock_calls)
'''
102 changes: 102 additions & 0 deletions hw_4/tests/unit/test_validate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from unittest.mock import MagicMock, patch, call
import pytest

def test_validate_user_full_name():
from validate import validate_user_full_name
user_full_name = 'John1!! Doe'
actual = validate_user_full_name(user_full_name)
expected = ('John', 'Doe')
assert actual == expected

@pytest.mark.parametrize(
"field, value, allowed_values, strict, expected",
[
("test_field", "a", ["a", "b", "c"], True, True),
("test_field", "d", ["a", "b", "c"], True, pytest.raises(ValueError)),
("test_field", "a", ["a", "b", "c"], False, True),
("test_field", "d", ["a", "b", "c"], False, False),
]
)
def test_validate_field_value(field, value, allowed_values, strict, expected):
from validate import validate_field_value
if isinstance(expected, bool):
assert validate_field_value(field, value, allowed_values, strict) == expected
else:
with expected:
validate_field_value(field, value, allowed_values, strict)

@patch('validate.validate_field_value')
def test_valid_acc(mock_f_1):
from validate import valid_acc
data = [{"type": "credit", "status": "gold"},
{"type": "debit", "status": "platinum"},
{"type": "aaa", "status": "bbb"}]
valid_acc(data)
actual_call = {'validate_field_value': mock_f_1.call_count}
expected_call = {'validate_field_value': 6}
assert actual_call == expected_call


@pytest.mark.parametrize("account_number, expected", [
("ID--ABC-123444556-", "ID--ABC-123444556-"),
("ID--AC-1234445586-", "ID--AC-1234445586-"),
])
def test_valid_account_number(account_number, expected):
from validate import validate_account_number
actual = validate_account_number(account_number)
assert actual == expected


@pytest.mark.parametrize("account_number, expected_exception, expected_message", [
("ID--A-1234-", ValueError, "error: too little"),
("ID--ABC-12345678901234-", ValueError, "error: many chars"),
("XX--ABC-123444556-", ValueError, "error: wrong format"),
("ID--123-123456-", ValueError, "error: too little"),
])
def test_invalid_account_number(account_number, expected_exception, expected_message):
from validate import validate_account_number
with pytest.raises(expected_exception) as excinfo:
validate_account_number(account_number)
assert str(excinfo.value) == expected_message

@pytest.mark.parametrize("transact_time, expected", [(None, "time"), ("ttt", "ttt")])
def test_add_transaction_time(transact_time, expected):
with patch('validate.datetime') as mock_datetime:
mock_datetime.now.return_value = "time"
from validate import add_transaction_time
actual = add_transaction_time(transact_time)
assert actual == expected

@pytest.mark.parametrize("sender_amount, sent_amount, sender_currency, receiver_currency, expected", [
(100, 50, 'USD', 'USD', False),
(50, 100, 'USD', 'USD', ValueError),
(100, 50, 'USD', 'EUR', True),
])
def test_valid_currency_amount(sender_amount, sent_amount, sender_currency, receiver_currency, expected):
from validate import valid_currency_amount
if expected == ValueError:
with pytest.raises(ValueError):
valid_currency_amount(sender_amount, sent_amount, sender_currency, receiver_currency)
else:
actual = valid_currency_amount(sender_amount, sent_amount, sender_currency, receiver_currency)
assert actual == expected

@patch('validate.validate_field_value', return_value= True)
@patch('validate.validate_user_full_name', return_value= ("John", "Doe"))
def test_username_validate(mock_f_1,mock_f_2):
from validate import username_validate
data = [
{"user_name": "John1!! Doe"},
{"user_name": "Jane Smith"}
]
actual = username_validate(data)
expected = [{"name": "John", "surname": "Doe"},
{"name": "John", "surname": "Doe"}
]
actual_call = {'validate_field_value': mock_f_1.call_count,
'validate_user_full_name': mock_f_2.call_count}
expected_call = {'validate_field_value': 4,
'validate_user_full_name': 1}

assert actual == expected
assert actual_call == expected_call
2 changes: 1 addition & 1 deletion hw_4/user.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
user_name,birthday,accounts
user_name,birth_day,accounts
John1!! Doe,1990-05-05,0
Jane Smith,1985-10-15,0
Michael Johnson,1978-03-20,0
Expand Down
25 changes: 23 additions & 2 deletions hw_4/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ def validate_user_full_name(user_full_name):


# Validation of fields with a strict set of values
def validate_field_value(field, value, allowed_values):
def validate_field_value(field, value, allowed_values, strict = True):
if value not in allowed_values:
raise ValueError("error: not allowed value {} for field {}!".format(value, field))
if strict:
raise ValueError("error: not allowed value {} for field {}!".format(value, field))
return False
return True

def valid_acc(data):
type_values = ["credit", "debit"]
Expand Down Expand Up @@ -50,3 +53,21 @@ def add_transaction_time(transaction_time):
if not transaction_time:
transaction_time = datetime.now()
return transaction_time


def valid_currency_amount(sender_amount,sent_amount,sender_currency,receiver_currency ):
if sender_amount < sent_amount:
raise ValueError("not enough money in the account")
if receiver_currency != sender_currency:
return True
return False

def username_validate(data):
if not validate_field_value("user_name", "user_name", dict.keys(data[0]), False):
return data
for i in data:
i["name"] = validate_user_full_name(i["user_name"])[0]
i["surname"] = validate_user_full_name(i["user_name"])[1]
del i["user_name"]
return data