import pytest import logging from fastapi.testclient import TestClient from hypothesis import given, strategies as st, settings from bson import ObjectId from pos_system.server import app from pos_system.database import get_db from datetime import datetime client = TestClient(app) logger = logging.getLogger(__name__) def clear_db(): db = get_db() db.orders.delete_many({}) db.items.delete_many({}) db.users.delete_many({}) @pytest.fixture(autouse=True) def run_around_tests(): clear_db() yield clear_db() def create_test_user(): user_data = { "username": "testuser", "email": "testuser@example.com", "password": "testpassword", "full_name": "Test User", "is_active": True, "is_superuser": False } response = client.post("/users/register", json=user_data) assert response.status_code == 200, f"Failed to create user: {response.text}" return response.json() def login_test_user(): login_data = { "username": "testuser", "password": "testpassword" } response = client.post("/token", data=login_data) assert response.status_code == 200 return response.json()["access_token"] def create_test_item(token): headers = {"Authorization": f"Bearer {token}"} response = client.post( "/items/", headers=headers, json={"name": "Test Item", "price": 10.99, "quantity": 100, "unit": "piece"} ) assert response.status_code == 200 return response.json()["_id"] @pytest.fixture def auth_headers(): create_test_user() token = login_test_user() return {"Authorization": f"Bearer {token}"} def test_create_order(auth_headers): logger.info("Testing create order") item_id = create_test_item(auth_headers["Authorization"].split()[1]) order_data = { "items": [{"item_id": item_id, "quantity": 2}], "total_amount": 21.98, "payment_method": "credit_card" } response = client.post("/orders/", json=order_data, headers=auth_headers) assert response.status_code == 200 assert "_id" in response.json() logger.info(f"Created order with ID: {response.json()['_id']}") def test_read_orders(auth_headers): logger.info("Testing read orders") item_id = create_test_item(auth_headers["Authorization"].split()[1]) order_data = { "items": [{"item_id": item_id, "quantity": 2}], "total_amount": 21.98, "payment_method": "credit_card" } client.post("/orders/", json=order_data, headers=auth_headers) response = client.get("/orders/", headers=auth_headers) assert response.status_code == 200 orders = response.json() assert len(orders) == 1 assert orders[0]["total_amount"] == 21.98 logger.info(f"Retrieved {len(orders)} orders") def test_read_order(auth_headers): logger.info("Testing read single order") item_id = create_test_item(auth_headers["Authorization"].split()[1]) order_data = { "items": [{"item_id": item_id, "quantity": 2}], "total_amount": 21.98, "payment_method": "credit_card" } create_response = client.post( "/orders/", json=order_data, headers=auth_headers) order_id = create_response.json()["_id"] response = client.get(f"/orders/{order_id}", headers=auth_headers) assert response.status_code == 200 assert response.json()["total_amount"] == 21.98 logger.info(f"Retrieved order with ID: {order_id}") def test_update_order(auth_headers): logger.info("Testing update order") item_id = create_test_item(auth_headers["Authorization"].split()[1]) order_data = { "items": [{"item_id": item_id, "quantity": 2}], "total_amount": 21.98, "payment_method": "credit_card" } create_response = client.post( "/orders/", json=order_data, headers=auth_headers) order_id = create_response.json()["_id"] update_data = { "items": [{"item_id": item_id, "quantity": 3}], "total_amount": 32.97, "payment_method": "cash" } response = client.put(f"/orders/{order_id}", json=update_data, headers=auth_headers) assert response.status_code == 200 assert response.json()["total_amount"] == 32.97 assert response.json()["payment_method"] == "cash" logger.info(f"Updated order with ID: {order_id}") def test_delete_order(auth_headers): logger.info("Testing delete order") item_id = create_test_item(auth_headers["Authorization"].split()[1]) order_data = { "items": [{"item_id": item_id, "quantity": 2}], "total_amount": 21.98, "payment_method": "credit_card" } create_response = client.post( "/orders/", json=order_data, headers=auth_headers) order_id = create_response.json()["_id"] response = client.delete(f"/orders/{order_id}", headers=auth_headers) assert response.status_code == 200 assert response.json()["message"] == "Order deleted successfully" get_response = client.get(f"/orders/{order_id}", headers=auth_headers) assert get_response.status_code == 404 logger.info(f"Deleted order with ID: {order_id}") @given( st.lists( st.fixed_dictionaries({ "quantity": st.integers(min_value=1, max_value=10) }), min_size=1, max_size=5 ), st.floats(min_value=0.01, max_value=1000, allow_nan=False, allow_infinity=False), st.sampled_from(["credit_card", "cash", "paypal"]) ) @settings(max_examples=50) def test_create_order_property(auth_headers, items, total_amount, payment_method): clear_db() create_test_user() token = login_test_user() auth_headers = {"Authorization": f"Bearer {token}"} item_id = create_test_item(token) for item in items: item["item_id"] = item_id # Use the same item_id for all items order_data = { "items": items, "total_amount": total_amount, "payment_method": payment_method } response = client.post("/orders/", json=order_data, headers=auth_headers) assert response.status_code == 200 assert "_id" in response.json() order_id = response.json()["_id"] get_response = client.get(f"/orders/{order_id}", headers=auth_headers) assert get_response.status_code == 200 retrieved_order = get_response.json() assert retrieved_order["total_amount"] == total_amount assert retrieved_order["payment_method"] == payment_method assert len(retrieved_order["items"]) == len(items) @given( st.lists( st.fixed_dictionaries({ "total_amount": st.floats(min_value=0.01, max_value=1000, allow_nan=False, allow_infinity=False), "payment_method": st.sampled_from(["credit_card", "cash", "paypal"]) }), min_size=1, max_size=10 ) ) @settings(max_examples=20) def test_read_orders_property(auth_headers, orders): clear_db() create_test_user() token = login_test_user() auth_headers = {"Authorization": f"Bearer {token}"} item_id = create_test_item(token) for order in orders: order_data = { "items": [{"item_id": item_id, "quantity": 1}], "total_amount": order["total_amount"], "payment_method": order["payment_method"] } client.post("/orders/", json=order_data, headers=auth_headers) response = client.get("/orders/", headers=auth_headers) assert response.status_code == 200 retrieved_orders = response.json() assert len(retrieved_orders) == len(orders) for retrieved_order in retrieved_orders: assert "total_amount" in retrieved_order assert "payment_method" in retrieved_order @pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(item, call): outcome = yield report = outcome.get_result() if report.when == "call" and report.failed: if "hypothesis" in item.keywords: logger.error(f"Property test failed: {item.name}") logger.error(f"Falsifying example: {call.excinfo.value}") if __name__ == "__main__": pytest.main([__file__])