algospaced-dsa / scratch /test_explorer_upgrades.py
iamfebin's picture
Configure AlgoSpaced for Hugging Face Spaces deployment
aaa634c
Raw
History Blame Contribute Delete
9.03 kB
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()