Finished
1import json
2
13class RestAPI:
24 def __init__(self, database: dict | None = None):
3 pass
4
5 # Edge Case: Handle None database by initializing empty users list
6 self.database = database if database is not None else {"users": []}
7 # Ensure all users have required fields
8 for user in self.database["users"]:
9 if "owes" not in user:
10 user["owes"] = {}
11 if "owed_by" not in user:
12 user["owed_by"] = {}
13 if "balance" not in user:
14 user["balance"] = 0.0
15
516 def get(self, url: str, payload: str | None = None) -> str:
6 pass
7
17 # Edge Case: Handle invalid URL
18 if url != "/users":
19 return json.dumps({"error": "Invalid URL"})
20
21 # Edge Case: Handle malformed payload
22 if payload is not None:
23 try:
24 payload_data = json.loads(payload)
25 except json.JSONDecodeError:
26 return json.dumps({"error": "Invalid payload"})
27 else:
28 payload_data = None
29
30 users = self.database["users"]
31
32 # Calculate balances for all users
33 for user in users:
34 owed_to_user = sum(user.get("owed_by", {}).values())
35 owed_by_user = sum(user.get("owes", {}).values())
36 user["balance"] = round(owed_to_user - owed_by_user, 2)
37
38 # If no payload, return all users
39 if payload_data is None:
40 # Sort users by name
41 sorted_users = sorted(users, key=lambda x: x["name"])
42 return json.dumps({"users": sorted_users})
43
44 # Edge Case: Handle missing 'users' key in payload
45 if "users" not in payload_data:
46 return json.dumps({"error": "Missing users key in payload"})
47
48 # Filter users by the provided list
49 requested_names = payload_data["users"]
50
51 # Edge Case: Handle non-list users value
52 if not isinstance(requested_names, list):
53 return json.dumps({"error": "Users must be a list"})
54
55 filtered_users = [user for user in users if user["name"] in requested_names]
56
57 # Edge Case: Handle request for non-existent users (they're simply not included)
58 # Sort by name
59 sorted_users = sorted(filtered_users, key=lambda x: x["name"])
60
61 return json.dumps({"users": sorted_users})
62
863 def post(self, url: str, payload: str | None = None) -> str:
9 pass
64 # Edge Case: Handle invalid URL
65 if url not in ["/add", "/iou"]:
66 return json.dumps({"error": "Invalid URL"})
67
68 # Edge Case: Handle missing payload
69 if payload is None:
70 return json.dumps({"error": "Payload required"})
71
72 # Edge Case: Handle malformed payload
73 try:
74 payload_data = json.loads(payload)
75 except json.JSONDecodeError:
76 return json.dumps({"error": "Invalid payload"})
77
78 users = self.database["users"]
79
80 if url == "/add":
81 # Edge Case: Handle missing 'user' key
82 if "user" not in payload_data:
83 return json.dumps({"error": "Missing user key"})
84
85 new_user_name = payload_data["user"]
86
87 # Edge Case: Handle non-string user name
88 if not isinstance(new_user_name, str):
89 return json.dumps({"error": "User name must be a string"})
90
91 # Edge Case: Handle duplicate user
92 if any(user["name"] == new_user_name for user in users):
93 return json.dumps({"error": "User already exists"})
94
95 # Create new user
96 new_user = {
97 "name": new_user_name,
98 "owes": {},
99 "owed_by": {},
100 "balance": 0.0
101 }
102 users.append(new_user)
103 return json.dumps(new_user)
104
105 elif url == "/iou":
106 # Edge Case: Handle missing required keys
107 required_keys = ["lender", "borrower", "amount"]
108 for key in required_keys:
109 if key not in payload_data:
110 return json.dumps({"error": f"Missing {key} key"})
111
112 lender_name = payload_data["lender"]
113 borrower_name = payload_data["borrower"]
114 amount = payload_data["amount"]
115
116 # Edge Case: Handle non-string lender/borrower
117 if not isinstance(lender_name, str) or not isinstance(borrower_name, str):
118 return json.dumps({"error": "Lender and borrower must be strings"})
119
120 # Edge Case: Handle non-numeric amount
121 if not isinstance(amount, (int, float)):
122 return json.dumps({"error": "Amount must be a number"})
123
124 # Edge Case: Handle negative amount
125 if amount < 0:
126 return json.dumps({"error": "Amount must be positive"})
127
128 # Find users
129 lender = next((user for user in users if user["name"] == lender_name), None)
130 borrower = next((user for user in users if user["name"] == borrower_name), None)
131
132 # Edge Case: Handle lender equals borrower - return user unchanged
133 if lender_name == borrower_name:
134 # Recalculate balance for the user
135 owed_to_user = sum(lender.get("owed_by", {}).values())
136 owed_by_user = sum(lender.get("owes", {}).values())
137 lender["balance"] = round(owed_to_user - owed_by_user, 2)
138 return json.dumps({"users": [lender]})
139
140 # Edge Case: Handle non-existent lender or borrower
141 if lender is None or borrower is None:
142 return json.dumps({"error": "Both lender and borrower must exist"})
143
144 # Update IOUs
145 # Update lender's owed_by
146 if borrower_name in lender["owed_by"]:
147 lender["owed_by"][borrower_name] += amount
148 else:
149 lender["owed_by"][borrower_name] = amount
150
151 # Update borrower's owes
152 if lender_name in borrower["owes"]:
153 borrower["owes"][lender_name] += amount
154 else:
155 borrower["owes"][lender_name] = amount
156
157 # Recalculate balances
158 for user in [lender, borrower]:
159 owed_to_user = sum(user.get("owed_by", {}).values())
160 owed_by_user = sum(user.get("owes", {}).values())
161 user["balance"] = round(owed_to_user - owed_by_user, 2)
162
163 # Return updated users, sorted by name
164 result_users = sorted([lender, borrower], key=lambda x: x["name"])
165 return json.dumps({"users": result_users})
166 # Handled Edge Cases: None database, invalid URLs, malformed payloads, missing keys, non-list users value, non-existent users, duplicate user, non-string user name, non-string lender/borrower, non-numeric amount, negative amount, lender equals borrower, non-existent lender or borrower
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.