Spaces:
Sleeping
Sleeping
File size: 9,027 Bytes
aaa634c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | import os
import sys
import io
import zipfile
from fastapi.testclient import TestClient
# Add workspace root to python path
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from main import app, get_supabase_client
# Define mock classes to intercept Supabase client interactions
class MockResponse:
def __init__(self, data):
self.data = data
class MockQueryBuilder:
def __init__(self, table_name, mock_client):
self.table_name = table_name
self.mock_client = mock_client
self.filters = {}
def select(self, columns):
return self
def eq(self, column, value):
self.filters[column] = value
return self
def insert(self, data):
if self.table_name == 'problems':
if not isinstance(data, list):
data = [data]
inserted = []
for item in data:
item_copy = item.copy()
if 'id' not in item_copy:
item_copy['id'] = f"mock-prob-id-{len(self.mock_client.problems) + 1}"
self.mock_client.problems.append(item_copy)
inserted.append(item_copy)
self.last_result = inserted
elif self.table_name == 'user_reviews':
if not isinstance(data, list):
data = [data]
inserted = []
for item in data:
item_copy = item.copy()
if 'id' not in item_copy:
item_copy['id'] = f"mock-rev-id-{len(self.mock_client.reviews) + 1}"
self.mock_client.reviews.append(item_copy)
inserted.append(item_copy)
self.last_result = inserted
return self
def update(self, data):
self.update_data = data
return self
def execute(self):
if hasattr(self, 'last_result'):
return MockResponse(self.last_result)
if self.table_name == 'problems':
name_filter = self.filters.get('name')
id_filter = self.filters.get('id')
# If update was called
if hasattr(self, 'update_data'):
updated = []
for p in self.mock_client.problems:
if id_filter and p.get('id') == id_filter:
p.update(self.update_data)
updated.append(p)
return MockResponse(updated)
matches = []
for p in self.mock_client.problems:
if name_filter and p.get('name') != name_filter:
continue
if id_filter and p.get('id') != id_filter:
continue
p_copy = p.copy()
p_reviews = [r for r in self.mock_client.reviews if r.get('problem_id') == p.get('id')]
p_copy['user_reviews'] = p_reviews
matches.append(p_copy)
return MockResponse(matches)
elif self.table_name == 'user_reviews':
return MockResponse(self.mock_client.reviews)
return MockResponse([])
class MockSupabaseClient:
def __init__(self):
self.problems = []
self.reviews = []
self.current_user_id = "mock_user_123"
self.auth = self
def get_user(self, token):
class MockUser:
id = "mock_user_123"
class MockUserRes:
user = MockUser()
return MockUserRes()
def table(self, table_name):
return MockQueryBuilder(table_name, self)
# Create a shared mock client state
shared_mock_client = MockSupabaseClient()
# Override FastAPI dependency
def mock_get_supabase_client():
return shared_mock_client
app.dependency_overrides[get_supabase_client] = mock_get_supabase_client
client = TestClient(app)
def test_explorer_endpoints():
print("=== Running Explorer REST API Tests ===")
headers = {"Authorization": "Bearer mock-token-123"}
# 1. Create Problem 1 (Two Sum)
print("\n1. Testing POST /api/explorer/problems/create (Two Sum)")
create_payload = {
"name": "Two Sum",
"pattern": "Two Pointers",
"difficulty": "Easy",
"reference_code": "def twoSum(nums, target):\n pass",
"description": "Find two numbers in the array that sum to target."
}
res = client.post("/api/explorer/problems/create", json=create_payload, headers=headers)
print("Response status:", res.status_code)
print("Response JSON:", res.json())
assert res.status_code == 200
assert res.json()["success"] is True
prob1_id = res.json()["problem_id"]
# Verify review was created
assert len(shared_mock_client.reviews) == 1
assert shared_mock_client.reviews[0]["problem_id"] == prob1_id
assert shared_mock_client.reviews[0]["box_level"] == 1
# 2. Try to create duplicate problem
print("\n2. Testing duplicate prevention")
res_dup = client.post("/api/explorer/problems/create", json=create_payload, headers=headers)
print("Response status:", res_dup.status_code)
print("Response JSON:", res_dup.json())
assert res_dup.status_code == 400
assert "already exists" in res_dup.json()["detail"]
# 3. Create Problem 2 (Three Sum)
print("\n3. Testing POST /api/explorer/problems/create (Three Sum)")
create_payload_2 = {
"name": "Three Sum",
"pattern": "Two Pointers",
"difficulty": "Medium",
"reference_code": "def threeSum(nums):\n pass",
"description": "Find all unique triplets that sum to zero."
}
res2 = client.post("/api/explorer/problems/create", json=create_payload_2, headers=headers)
assert res2.status_code == 200
prob2_id = res2.json()["problem_id"]
# 4. List Problems
print("\n4. Testing GET /api/explorer/problems")
res_list = client.get("/api/explorer/problems", headers=headers)
print("Response status:", res_list.status_code)
problems_list = res_list.json()
print("List count:", len(problems_list))
for p in problems_list:
print(f" - Problem: {p['name']}, Box: {p['box_level']}, Description: '{p['description']}', Code length: {len(p['reference_code'])}")
assert res_list.status_code == 200
assert len(problems_list) == 2
assert problems_list[0]["box_level"] == 1
assert problems_list[0]["description"] == "Find two numbers in the array that sum to target."
# 5. Update reference code for Two Sum
print("\n5. Testing PUT /api/explorer/problems/{id}")
new_code = "def twoSum(nums, target):\n # Optimized solution\n seen = {}\n for i, num in enumerate(nums):\n diff = target - num\n if diff in seen:\n return [seen[diff], i]\n seen[num] = i\n return []"
update_payload = {
"name": "Two Sum",
"pattern": "Two Pointers",
"difficulty": "Easy",
"reference_code": new_code,
"description": "Find two numbers in the array that sum to target (Optimized)."
}
res_update = client.put(f"/api/explorer/problems/{prob1_id}", json=update_payload, headers=headers)
print("Response status:", res_update.status_code)
print("Response JSON:", res_update.json())
assert res_update.status_code == 200
assert res_update.json()["success"] is True
# Verify update in listing
res_list2 = client.get("/api/explorer/problems", headers=headers)
problems_list2 = res_list2.json()
two_sum_updated = next(p for p in problems_list2 if p["id"] == prob1_id)
print("Updated Two Sum code length:", len(two_sum_updated["reference_code"]))
print("Updated Two Sum description:", two_sum_updated["description"])
assert "Optimized solution" in two_sum_updated["reference_code"]
assert "Optimized" in two_sum_updated["description"]
# 6. Export ZIP of solutions
print("\n6. Testing GET /api/explorer/export (ZIP download)")
res_export = client.get("/api/explorer/export", headers=headers)
print("Response status:", res_export.status_code)
print("Content-Type:", res_export.headers.get("content-type"))
assert res_export.status_code == 200
assert res_export.headers.get("content-type") == "application/zip"
# Validate Zip structure
zip_bytes = io.BytesIO(res_export.content)
with zipfile.ZipFile(zip_bytes, "r") as zf:
namelist = zf.namelist()
print("Files in ZIP:", namelist)
assert "Two_Sum.py" in namelist
assert "Three_Sum.py" in namelist
# Read content from ZIP
two_sum_zip_code = zf.read("Two_Sum.py").decode("utf-8")
print("Two_Sum.py contents in ZIP:")
print(two_sum_zip_code)
assert "Optimized solution" in two_sum_zip_code
assert "# Description:" in two_sum_zip_code
assert "Find two numbers in the array that sum to target" in two_sum_zip_code
print("\n=== ALL TESTS PASSED SUCCESSFULLY ===")
if __name__ == "__main__":
test_explorer_endpoints()
|