213 lines
6.3 KiB
Python
213 lines
6.3 KiB
Python
|
|
# retoor <retoor@molodetz.nl>
|
||
|
|
|
||
|
|
from datetime import datetime, timezone
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from devplacepy.db_client import get_table
|
||
|
|
from devplacepy.utils import generate_uid
|
||
|
|
|
||
|
|
|
||
|
|
def _now():
|
||
|
|
return datetime.now(timezone.utc).isoformat()
|
||
|
|
|
||
|
|
|
||
|
|
def _make_user(local_db, **overrides):
|
||
|
|
uid = generate_uid()
|
||
|
|
row = {
|
||
|
|
"uid": uid,
|
||
|
|
"username": f"cpd_{uid[:8]}",
|
||
|
|
"email": f"cpd_{uid[:8]}@t.dev",
|
||
|
|
"api_key": generate_uid(),
|
||
|
|
"role": "Member",
|
||
|
|
"is_active": True,
|
||
|
|
"created_at": _now(),
|
||
|
|
"bio": "",
|
||
|
|
}
|
||
|
|
row.update(overrides)
|
||
|
|
get_table("users").insert(row)
|
||
|
|
return row
|
||
|
|
|
||
|
|
|
||
|
|
def _make_post(local_db, user, **overrides):
|
||
|
|
from devplacepy.utils import make_combined_slug
|
||
|
|
|
||
|
|
uid = generate_uid()
|
||
|
|
row = {
|
||
|
|
"uid": uid,
|
||
|
|
"user_uid": user["uid"],
|
||
|
|
"title": "Compound test post",
|
||
|
|
"content": "Body of the compound test post.",
|
||
|
|
"topic": "devlog",
|
||
|
|
"slug": make_combined_slug("Compound test post", uid),
|
||
|
|
"stars": 0,
|
||
|
|
"created_at": _now(),
|
||
|
|
"deleted_at": None,
|
||
|
|
"deleted_by": None,
|
||
|
|
}
|
||
|
|
row.update(overrides)
|
||
|
|
get_table("posts").insert(row)
|
||
|
|
return row
|
||
|
|
|
||
|
|
|
||
|
|
def _make_project(local_db, user, **overrides):
|
||
|
|
from devplacepy.utils import make_combined_slug
|
||
|
|
|
||
|
|
uid = generate_uid()
|
||
|
|
row = {
|
||
|
|
"uid": uid,
|
||
|
|
"user_uid": user["uid"],
|
||
|
|
"title": "Compound test project",
|
||
|
|
"description": "",
|
||
|
|
"slug": make_combined_slug("Compound test project", uid),
|
||
|
|
"stars": 0,
|
||
|
|
"is_private": 0,
|
||
|
|
"created_at": _now(),
|
||
|
|
"deleted_at": None,
|
||
|
|
"deleted_by": None,
|
||
|
|
}
|
||
|
|
row.update(overrides)
|
||
|
|
get_table("projects").insert(row)
|
||
|
|
return row
|
||
|
|
|
||
|
|
|
||
|
|
def _make_gist(local_db, user, **overrides):
|
||
|
|
from devplacepy.utils import make_combined_slug
|
||
|
|
|
||
|
|
uid = generate_uid()
|
||
|
|
row = {
|
||
|
|
"uid": uid,
|
||
|
|
"user_uid": user["uid"],
|
||
|
|
"title": "Compound test gist",
|
||
|
|
"description": "",
|
||
|
|
"source_code": "print('hi')",
|
||
|
|
"language": "python",
|
||
|
|
"slug": make_combined_slug("Compound test gist", uid),
|
||
|
|
"stars": 0,
|
||
|
|
"created_at": _now(),
|
||
|
|
"deleted_at": None,
|
||
|
|
"deleted_by": None,
|
||
|
|
}
|
||
|
|
row.update(overrides)
|
||
|
|
get_table("gists").insert(row)
|
||
|
|
return row
|
||
|
|
|
||
|
|
|
||
|
|
# Section 5.3 page compounds actually wired to a caller (db_client.build_*)
|
||
|
|
# and consumed by a real web route. Each assertion checks the template
|
||
|
|
# context keys the corresponding route/schema depends on.
|
||
|
|
|
||
|
|
|
||
|
|
def test_build_feed_page_shape(local_db):
|
||
|
|
from devplacepy_services.database.compounds_page import build_feed_page
|
||
|
|
|
||
|
|
user = _make_user(local_db)
|
||
|
|
post = _make_post(local_db, user)
|
||
|
|
|
||
|
|
result = build_feed_page(user=user)
|
||
|
|
|
||
|
|
for key in ("posts", "next_cursor", "stats", "top_authors", "daily_topic", "current_tab"):
|
||
|
|
assert key in result
|
||
|
|
uids = [item["post"]["uid"] for item in result["posts"]]
|
||
|
|
assert post["uid"] in uids
|
||
|
|
item = next(i for i in result["posts"] if i["post"]["uid"] == post["uid"])
|
||
|
|
for key in ("attachments", "recent_comments", "reactions", "bookmarked", "poll"):
|
||
|
|
assert key in item
|
||
|
|
|
||
|
|
|
||
|
|
def test_build_post_detail_shape(local_db):
|
||
|
|
from devplacepy_services.database.compounds_page import build_post_detail
|
||
|
|
|
||
|
|
user = _make_user(local_db)
|
||
|
|
post = _make_post(local_db, user)
|
||
|
|
|
||
|
|
result = build_post_detail(post["uid"], user=user)
|
||
|
|
|
||
|
|
assert result["post"]["uid"] == post["uid"]
|
||
|
|
assert result["author"]["uid"] == user["uid"]
|
||
|
|
assert isinstance(result["comments"], list)
|
||
|
|
assert isinstance(result["attachments"], list)
|
||
|
|
|
||
|
|
|
||
|
|
def test_build_post_detail_missing_post(local_db):
|
||
|
|
from devplacepy_services.database.compounds_page import build_post_detail
|
||
|
|
|
||
|
|
result = build_post_detail("does-not-exist")
|
||
|
|
assert result["post"] is None
|
||
|
|
|
||
|
|
|
||
|
|
def test_build_profile_bundle_shape(local_db):
|
||
|
|
from devplacepy_services.database.compounds_page import build_profile_bundle
|
||
|
|
|
||
|
|
user = _make_user(local_db)
|
||
|
|
|
||
|
|
result = build_profile_bundle(user["uid"])
|
||
|
|
|
||
|
|
assert result["user"]["uid"] == user["uid"]
|
||
|
|
assert "followers" in result["follow_counts"]
|
||
|
|
assert "following" in result["follow_counts"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_build_leaderboard_page_shape(local_db):
|
||
|
|
from devplacepy_services.database.compounds_page import build_leaderboard_page
|
||
|
|
|
||
|
|
user = _make_user(local_db)
|
||
|
|
|
||
|
|
result = build_leaderboard_page(viewer_uid=user["uid"])
|
||
|
|
|
||
|
|
assert "leaderboard" in result
|
||
|
|
assert isinstance(result["leaderboard"], list)
|
||
|
|
|
||
|
|
|
||
|
|
def test_build_project_detail_shape(local_db):
|
||
|
|
from devplacepy_services.database.compounds_page import build_project_detail
|
||
|
|
|
||
|
|
user = _make_user(local_db)
|
||
|
|
project = _make_project(local_db, user)
|
||
|
|
|
||
|
|
result = build_project_detail(project["uid"])
|
||
|
|
|
||
|
|
assert result["project"]["uid"] == project["uid"]
|
||
|
|
assert result["owner"]["uid"] == user["uid"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_build_gist_detail_shape(local_db):
|
||
|
|
from devplacepy_services.database.compounds_page import build_gist_detail
|
||
|
|
|
||
|
|
user = _make_user(local_db)
|
||
|
|
gist = _make_gist(local_db, user)
|
||
|
|
|
||
|
|
result = build_gist_detail(gist["uid"], user=user)
|
||
|
|
|
||
|
|
assert result["gist"]["uid"] == gist["uid"]
|
||
|
|
assert result["author"]["uid"] == user["uid"]
|
||
|
|
assert isinstance(result["comments"], list)
|
||
|
|
|
||
|
|
|
||
|
|
# Section 5.3 rows registered as HTTP endpoints (devplacepy_services/database/routes.py)
|
||
|
|
# but not yet called by any web route (routers/messages.py, notifications.py,
|
||
|
|
# game/, admin/index.py all still do their own direct db_client calls) - these
|
||
|
|
# four builders are unfinished stubs, tracked here so a real implementation
|
||
|
|
# lands as a visible test change rather than silently.
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize(
|
||
|
|
"fn_name,expected_keys",
|
||
|
|
[
|
||
|
|
("build_messages_page", {"threads", "unread", "partners"}),
|
||
|
|
("build_notifications_page", {"notifications", "actors", "unread_count"}),
|
||
|
|
("build_game_state", {"store", "leaderboard"}),
|
||
|
|
("build_admin_dashboard", {"stats", "service_states"}),
|
||
|
|
],
|
||
|
|
)
|
||
|
|
def test_stub_compounds_documented(local_db, fn_name, expected_keys):
|
||
|
|
import devplacepy_services.database.compounds_page as compounds_page
|
||
|
|
|
||
|
|
fn = getattr(compounds_page, fn_name)
|
||
|
|
result = fn() if fn_name != "build_admin_dashboard" else fn()
|
||
|
|
assert set(result.keys()) == expected_keys, (
|
||
|
|
f"{fn_name} shape changed - if this is a real implementation now, "
|
||
|
|
"replace this stub-tracking test with a real assertion and update "
|
||
|
|
"splitup.md Section 17.2"
|
||
|
|
)
|