fortitude

Finished
1import json
2from typing import Dict, List, Optional, Any
3
14class RestAPI:
25 def __init__(self, database: dict | None = None):
3 pass
4
6 """
7 Initialize the REST API with a database of users.
8
9 Args:
10 database: A dictionary containing user data with IOUs
11 """
12 if database is None:
13 self.database = {"users": []}
14 else:
15 self.database = database
16
517 def get(self, url: str, payload: str | None = None) -> str:
6 pass
7
18 """
19 Handle GET requests to the API.
20
21 Args:
22 url: The endpoint URL
23 payload: Optional JSON payload
24
25 Returns:
26 JSON string response
27 """
28 if url == "/users":
29 if payload is None:
30 # Return all users sorted by name
31 users = sorted(self.database["users"], key=lambda x: x["name"])
32 return json.dumps({"users": users})
33 else:
34 # Return specific users
35 data = json.loads(payload)
36 user_names = data.get("users", [])
37
38 # Edge Case: Empty users list in payload
39 if not user_names:
40 return json.dumps({"users": []})
41
42 # Filter users by name
43 filtered_users = [user for user in self.database["users"] if user["name"] in user_names]
44 # Sort by name
45 filtered_users.sort(key=lambda x: x["name"])
46 return json.dumps({"users": filtered_users})
47
48 # Edge Case: Invalid URL
49 return json.dumps({"error": "Invalid URL"})
50
851 def post(self, url: str, payload: str | None = None) -> str:
9 pass
52 """
53 Handle POST requests to the API.
54
55 Args:
56 url: The endpoint URL
57 payload: JSON payload
58
59 Returns:
60 JSON string response
61 """
62 if payload is None:
63 # Edge Case: Missing payload
64 return json.dumps({"error": "Payload required"})
65
66 try:
67 data = json.loads(payload)
68 except json.JSONDecodeError:
69 # Edge Case: Invalid JSON payload
70 return json.dumps({"error": "Invalid JSON payload"})
71
72 if url == "/add":
73 user_name = data.get("user")
74
75 # Edge Case: Missing user name
76 if not user_name:
77 return json.dumps({"error": "User name required"})
78
79 # Edge Case: User already exists
80 for user in self.database["users"]:
81 if user["name"] == user_name:
82 return json.dumps({"error": "User already exists"})
83
84 # Create new user
85 new_user = {
86 "name": user_name,
87 "owes": {},
88 "owed_by": {},
89 "balance": 0.0
90 }
91
92 self.database["users"].append(new_user)
93 return json.dumps(new_user)
94
95 elif url == "/iou":
96 lender_name = data.get("lender")
97 borrower_name = data.get("borrower")
98 amount = data.get("amount")
99
100 # Edge Case: Missing required fields
101 if not lender_name or not borrower_name or amount is None:
102 return json.dumps({"error": "Lender, borrower, and amount required"})
103
104 # Edge Case: Invalid amount type
105 if not isinstance(amount, (int, float)):
106 return json.dumps({"error": "Amount must be a number"})
107
108 # Edge Case: Negative amount
109 if amount < 0:
110 return json.dumps({"error": "Amount must be positive"})
111
112 # Edge Case: Lender and borrower are the same
113 if lender_name == borrower_name:
114 return json.dumps({"error": "Lender and borrower cannot be the same"})
115
116 # Find lender and borrower
117 lender = None
118 borrower = None
119
120 for user in self.database["users"]:
121 if user["name"] == lender_name:
122 lender = user
123 elif user["name"] == borrower_name:
124 borrower = user
125
126 # Edge Case: Lender not found
127 if lender is None:
128 return json.dumps({"error": "Lender not found"})
129
130 # Edge Case: Borrower not found
131 if borrower is None:
132 return json.dumps({"error": "Borrower not found"})
133
134 # Update IOUs with proper debt handling
135 # Handle the case where lender already owes borrower
136 if borrower_name in lender["owes"]:
137 # Lender already owes borrower - add to existing debt
138 lender["owes"][borrower_name] += amount
139 borrower["owed_by"][lender_name] += amount
140 # Handle the case where borrower already owes lender
141 elif borrower_name in lender["owed_by"]:
142 # Borrower already owes lender - add to existing credit
143 lender["owed_by"][borrower_name] += amount
144 borrower["owes"][lender_name] += amount
145 else:
146 # No existing relationship between lender and borrower
147 # Update lender's owed_by
148 lender["owed_by"][borrower_name] = amount
149 # Update borrower's owes
150 borrower["owes"][lender_name] = amount
151
152 # Recalculate balances
153 lender_total_owed = sum(lender["owed_by"].values())
154 lender_total_owes = sum(lender["owes"].values())
155 lender["balance"] = lender_total_owed - lender_total_owes
156
157 borrower_total_owed = sum(borrower["owed_by"].values())
158 borrower_total_owes = sum(borrower["owes"].values())
159 borrower["balance"] = borrower_total_owed - borrower_total_owes
160
161 # Return updated users sorted by name
162 updated_users = [lender, borrower]
163 updated_users.sort(key=lambda x: x["name"])
164 return json.dumps({"users": updated_users})
165
166 # Edge Case: Invalid URL
167 return json.dumps({"error": "Invalid URL"})
168
169 # Handled Edge Cases: Invalid URL, Missing payload, Invalid JSON payload
170 # Handled Edge Cases: Missing user name, User already exists
171 # Handled Edge Cases: Missing required fields, Invalid amount type, Negative amount, Lender and borrower are the same
172 # Handled Edge Cases: Lender not found, Borrower not found
Test NameStatus
test_lender_owes_borrower
Fail
test_lender_owes_borrower_less_than_new_loan
Fail
test_lender_owes_borrower_same_as_new_loan
Fail
test_add_user
Pass
test_borrower_has_negative_balance
Pass
test_both_users_have_0_balance
Pass
test_get_single_user
Pass
test_lender_has_negative_balance
Pass
test_no_users
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.