Skip to content
This repository was archived by the owner on Jun 13, 2025. It is now read-only.
Closed
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
115 changes: 115 additions & 0 deletions api/gen_ai/tests/test_bank.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import unittest
from datetime import datetime
Comment on lines +1 to +2
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding tests for race conditions and thread safety, especially for operations that modify account balances. This is crucial for a banking system.

Suggested change
import unittest
from datetime import datetime
import threading
import unittest
from datetime import datetime
from unittest.mock import patch
class TestBankAccountManagerConcurrency(unittest.TestCase):
def test_concurrent_deposits(self):
"""Test concurrent deposits to the same account."""
manager = BankAccountManager()
account_id = manager.create_account("Test User")
def deposit_amount():
manager.deposit(account_id, 100.0)
threads = [threading.Thread(target=deposit_amount) for _ in range(10)]
for t in threads:
t.start()
for t in threads:
t.join()
self.assertEqual(manager.get_balance(account_id), 1000.0)

from unittest.mock import patch

from api.gen_ai.bank import BankAccountManager


class TestBankAccountManager(unittest.TestCase):
Comment on lines +7 to +8
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding test class docstring to describe the purpose and scope of these tests. This helps other developers understand what's being tested and any specific setup requirements.

Suggested change
class TestBankAccountManager(unittest.TestCase):
class TestBankAccountManager(unittest.TestCase):
"""Test suite for BankAccountManager class.
Tests account creation, monetary operations (deposit, withdraw, transfer),
and account management functionality.
"""

Comment on lines +7 to +8
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test suite should include performance tests for large numbers of transactions and accounts. Consider using pytest-benchmark or similar tools for this purpose.

Suggested change
class TestBankAccountManager(unittest.TestCase):
@pytest.mark.benchmark
def test_account_performance(self, benchmark):
"""Test performance of account operations."""
def create_and_operate():
manager = BankAccountManager()
account_id = manager.create_account("Test User")
for _ in range(1000):
manager.deposit(account_id, 100.0)
manager.withdraw(account_id, 50.0)
benchmark(create_and_operate)

def setUp(self):
self.manager = BankAccountManager()
self.account_id = self.manager.create_account("Test User")
Comment on lines +8 to +11
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The setUp method should handle potential exceptions during account creation. Also, consider adding a tearDown method to clean up any resources or state between tests.

Suggested change
class TestBankAccountManager(unittest.TestCase):
def setUp(self):
self.manager = BankAccountManager()
self.account_id = self.manager.create_account("Test User")
def setUp(self):
try:
self.manager = BankAccountManager()
self.account_id = self.manager.create_account("Test User")
except Exception as e:
self.fail(f"Failed to set up test case: {str(e)}")
def tearDown(self):
# Clean up any test accounts
if hasattr(self, 'account_id'):
self.manager.delete_account(self.account_id)


def test_create_account(self):
"""Test that an account can be created with correct initial values."""
account = self.manager.accounts[self.account_id]
self.assertEqual(account['owner'], "Test User")
self.assertEqual(account['balance'], 0.0)
self.assertIsInstance(account['transactions'], list)
self.assertEqual(len(account['transactions']), 0)
self.assertIsInstance(account['created_at'], datetime)

@patch('uuid.uuid4')
def test_create_account_id(self, mock_uuid):
"""Test that an account ID is created correctly using UUID."""
mock_uuid.return_value = "mock-uuid-123"
manager = BankAccountManager()
account_id = manager.create_account("Test User")
self.assertEqual(account_id, "mock-uuid-123")

def test_deposit_valid_amount(self):
"""Test depositing a valid amount into an account."""
new_balance = self.manager.deposit(self.account_id, 100.0)
self.assertEqual(new_balance, 100.0)
self.assertEqual(self.manager.accounts[self.account_id]['balance'], 100.0)

# Verify transaction was recorded
transactions = self.manager.accounts[self.account_id]['transactions']
self.assertEqual(len(transactions), 1)
self.assertEqual(transactions[0]['type'], 'deposit')
self.assertEqual(transactions[0]['amount'], 100.0)
self.assertIsInstance(transactions[0]['timestamp'], datetime)

def test_deposit_multiple_amounts(self):
"""Test multiple deposits into an account."""
self.manager.deposit(self.account_id, 100.0)
new_balance = self.manager.deposit(self.account_id, 50.0)
self.assertEqual(new_balance, 150.0)
self.assertEqual(len(self.manager.accounts[self.account_id]['transactions']), 2)
Comment on lines +29 to +48
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deposit tests should include additional edge cases such as floating-point precision issues and very large numbers. Also consider testing type validation for non-numeric inputs.

Suggested change
def test_deposit_valid_amount(self):
"""Test depositing a valid amount into an account."""
new_balance = self.manager.deposit(self.account_id, 100.0)
self.assertEqual(new_balance, 100.0)
self.assertEqual(self.manager.accounts[self.account_id]['balance'], 100.0)
# Verify transaction was recorded
transactions = self.manager.accounts[self.account_id]['transactions']
self.assertEqual(len(transactions), 1)
self.assertEqual(transactions[0]['type'], 'deposit')
self.assertEqual(transactions[0]['amount'], 100.0)
self.assertIsInstance(transactions[0]['timestamp'], datetime)
def test_deposit_multiple_amounts(self):
"""Test multiple deposits into an account."""
self.manager.deposit(self.account_id, 100.0)
new_balance = self.manager.deposit(self.account_id, 50.0)
self.assertEqual(new_balance, 150.0)
self.assertEqual(len(self.manager.accounts[self.account_id]['transactions']), 2)
def test_deposit_edge_cases(self):
"""Test edge cases for deposit functionality."""
# Test floating point precision
balance = self.manager.deposit(self.account_id, 0.1 + 0.2)
self.assertAlmostEqual(balance, 0.3, places=7)
# Test very large numbers
large_amount = 1e15
balance = self.manager.deposit(self.account_id, large_amount)
self.assertEqual(balance, large_amount)
# Test non-numeric input
with self.assertRaises(TypeError):
self.manager.deposit(self.account_id, "100")


def test_deposit_invalid_amount(self):
"""Test that depositing zero or negative amount raises ValueError."""
with self.assertRaises(ValueError) as context:
self.manager.deposit(self.account_id, 0)
self.assertIn("Deposit amount must be positive", str(context.exception))

with self.assertRaises(ValueError) as context:
self.manager.deposit(self.account_id, -50)
self.assertIn("Deposit amount must be positive", str(context.exception))

def test_withdraw_valid_amount(self):
"""Test withdrawing a valid amount from an account."""
self.manager.deposit(self.account_id, 100.0)
new_balance = self.manager.withdraw(self.account_id, 50.0)
self.assertEqual(new_balance, 50.0)

# Verify transaction was recorded
transactions = self.manager.accounts[self.account_id]['transactions']
self.assertEqual(len(transactions), 2)
self.assertEqual(transactions[1]['type'], 'withdrawal')
self.assertEqual(transactions[1]['amount'], 50.0)

def test_withdraw_insufficient_funds(self):
"""Test that withdrawing more than balance raises ValueError."""
self.manager.deposit(self.account_id, 50.0)
with self.assertRaises(ValueError) as context:
self.manager.withdraw(self.account_id, 100.0)
self.assertIn("Insufficient funds", str(context.exception))

def test_withdraw_invalid_amount(self):
"""Test that withdrawing zero or negative amount raises ValueError."""
with self.assertRaises(ValueError) as context:
self.manager.withdraw(self.account_id, 0)
self.assertIn("Withdrawal amount must be positive", str(context.exception))

def test_transfer_between_accounts(self):
"""Test transferring money between two accounts."""
second_account_id = self.manager.create_account("Second User")
self.manager.deposit(self.account_id, 100.0)

result = self.manager.transfer(self.account_id, second_account_id, 50.0)
self.assertTrue(result)
Comment on lines +83 to +91
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The transfer_between_accounts test should verify the transaction history of both accounts and ensure the transfer is atomic. Also add tests for concurrent transfers.

Suggested change
self.assertIn("Withdrawal amount must be positive", str(context.exception))
def test_transfer_between_accounts(self):
"""Test transferring money between two accounts."""
second_account_id = self.manager.create_account("Second User")
self.manager.deposit(self.account_id, 100.0)
result = self.manager.transfer(self.account_id, second_account_id, 50.0)
self.assertTrue(result)
def test_transfer_between_accounts(self):
"""Test transferring money between two accounts."""
second_account_id = self.manager.create_account("Second User")
self.manager.deposit(self.account_id, 100.0)
result = self.manager.transfer(self.account_id, second_account_id, 50.0)
self.assertTrue(result)
# Verify balances
self.assertEqual(self.manager.get_balance(self.account_id), 50.0)
self.assertEqual(self.manager.get_balance(second_account_id), 50.0)
# Verify transaction history
source_history = self.manager.get_transaction_history(self.account_id)
dest_history = self.manager.get_transaction_history(second_account_id)
self.assertEqual(source_history[-1]['type'], 'transfer_out')
self.assertEqual(dest_history[-1]['type'], 'transfer_in')
self.assertEqual(source_history[-1]['amount'], 50.0)
self.assertEqual(dest_history[-1]['amount'], 50.0)

self.assertEqual(self.manager.get_balance(self.account_id), 50.0)
self.assertEqual(self.manager.get_balance(second_account_id), 50.0)

def test_transfer_to_same_account(self):
"""Test that transferring to the same account raises ValueError."""
with self.assertRaises(ValueError) as context:
self.manager.transfer(self.account_id, self.account_id, 50.0)
self.assertIn("Cannot transfer to the same account", str(context.exception))

def test_get_transaction_history(self):
"""Test retrieving transaction history for an account."""
self.manager.deposit(self.account_id, 100.0)
self.manager.withdraw(self.account_id, 50.0)

history = self.manager.get_transaction_history(self.account_id)
self.assertEqual(len(history), 2)
Comment on lines +97 to +107
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add tests for transaction timestamp ordering and integrity. Ensure that timestamps are monotonically increasing and accurate.

Suggested change
with self.assertRaises(ValueError) as context:
self.manager.transfer(self.account_id, self.account_id, 50.0)
self.assertIn("Cannot transfer to the same account", str(context.exception))
def test_get_transaction_history(self):
"""Test retrieving transaction history for an account."""
self.manager.deposit(self.account_id, 100.0)
self.manager.withdraw(self.account_id, 50.0)
history = self.manager.get_transaction_history(self.account_id)
self.assertEqual(len(history), 2)
def test_transaction_timestamp_ordering(self):
"""Test that transaction timestamps are ordered correctly."""
self.manager.deposit(self.account_id, 100.0)
self.manager.withdraw(self.account_id, 50.0)
history = self.manager.get_transaction_history(self.account_id)
self.assertTrue(history[0]['timestamp'] < history[1]['timestamp'])
# Verify timestamp is recent
now = datetime.now()
self.assertLess((now - history[-1]['timestamp']).total_seconds(), 1)

self.assertEqual(history[0]['type'], 'deposit')
self.assertEqual(history[1]['type'], 'withdrawal')

def test_delete_account(self):
"""Test that an account can be deleted."""
result = self.manager.delete_account(self.account_id)
self.assertTrue(result)
self.assertNotIn(self.account_id, self.manager.accounts)
Comment on lines +108 to +115
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add tests for account ID validation to ensure the system handles non-existent or invalid account IDs appropriately.

Suggested change
self.assertEqual(history[0]['type'], 'deposit')
self.assertEqual(history[1]['type'], 'withdrawal')
def test_delete_account(self):
"""Test that an account can be deleted."""
result = self.manager.delete_account(self.account_id)
self.assertTrue(result)
self.assertNotIn(self.account_id, self.manager.accounts)
def test_invalid_account_operations(self):
"""Test operations with invalid or non-existent account IDs."""
non_existent_id = "invalid-uuid"
with self.assertRaises(ValueError) as context:
self.manager.get_balance(non_existent_id)
self.assertIn("Account not found", str(context.exception))
with self.assertRaises(ValueError) as context:
self.manager.deposit(non_existent_id, 100.0)
self.assertIn("Account not found", str(context.exception))

Loading