|
# retoor <retoor@molodetz.nl>
|
|
|
|
from datetime import date
|
|
|
|
import pytest
|
|
|
|
from devplacepy.database import (
|
|
AGE_BANDS,
|
|
MATURITY_TARGETS,
|
|
REPORTABLE_TARGETS,
|
|
REPORT_REASONS,
|
|
SOFT_DELETE_TABLES,
|
|
UNREPORTABLE_TABLES,
|
|
age_band_for,
|
|
years_between,
|
|
)
|
|
from devplacepy.database.moderation import MODERATION_TABLES
|
|
|
|
|
|
GUIDELINE_REASONS = (
|
|
"hate",
|
|
"violence",
|
|
"weapons",
|
|
"sexual",
|
|
"religious",
|
|
"misinformation",
|
|
"exploitative",
|
|
)
|
|
|
|
|
|
def test_every_visible_soft_delete_table_is_reportable():
|
|
reportable_tables = set(REPORTABLE_TARGETS.values())
|
|
excluded = set(UNREPORTABLE_TABLES) | set(MODERATION_TABLES)
|
|
unclassified = [
|
|
table
|
|
for table in SOFT_DELETE_TABLES
|
|
if table not in reportable_tables and table not in excluded
|
|
]
|
|
assert unclassified == []
|
|
|
|
|
|
def test_exclusion_list_only_names_real_soft_delete_tables():
|
|
unknown = [table for table in UNREPORTABLE_TABLES if table not in SOFT_DELETE_TABLES]
|
|
assert unknown == []
|
|
|
|
|
|
def test_registry_tables_are_unique_and_maturity_is_a_subset():
|
|
assert len(set(REPORTABLE_TARGETS.values())) == len(REPORTABLE_TARGETS)
|
|
assert MATURITY_TARGETS <= set(REPORTABLE_TARGETS)
|
|
|
|
|
|
def test_report_reasons_cover_every_guideline_category():
|
|
for reason in GUIDELINE_REASONS:
|
|
assert reason in REPORT_REASONS
|
|
assert REPORT_REASONS["intellectual_property"]
|
|
assert REPORT_REASONS["other"]
|
|
|
|
|
|
def test_every_registry_target_resolves_to_a_url(local_db):
|
|
from devplacepy.database import resolve_object_url
|
|
|
|
for target_type in REPORTABLE_TARGETS:
|
|
url = resolve_object_url(target_type, "missing-uid")
|
|
assert url.startswith("/")
|
|
|
|
|
|
def test_resolve_object_url_points_at_the_owning_surface(local_db):
|
|
from devplacepy.database import get_table, resolve_object_url
|
|
|
|
get_table("users").insert(
|
|
{"uid": "mod-user-1", "username": "mod_user_1", "deleted_at": None}
|
|
)
|
|
get_table("messages").insert(
|
|
{
|
|
"uid": "mod-msg-1",
|
|
"sender_uid": "mod-user-1",
|
|
"receiver_uid": "mod-user-2",
|
|
"content": "hello",
|
|
}
|
|
)
|
|
try:
|
|
assert resolve_object_url("user", "mod-user-1") == "/profile/mod_user_1"
|
|
assert (
|
|
resolve_object_url("message", "mod-msg-1")
|
|
== "/messages?with_uid=mod-user-1"
|
|
)
|
|
assert resolve_object_url("devii_output", "anything") == "/devii"
|
|
finally:
|
|
get_table("users").delete(uid="mod-user-1")
|
|
get_table("messages").delete(uid="mod-msg-1")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"age,expected",
|
|
[
|
|
(0, "under_min"),
|
|
(12, "under_min"),
|
|
(13, "13_15"),
|
|
(15, "13_15"),
|
|
(16, "16_17"),
|
|
(17, "16_17"),
|
|
(18, "adult"),
|
|
(120, "adult"),
|
|
],
|
|
)
|
|
def test_age_band_boundaries(age, expected):
|
|
assert age_band_for(age) == expected
|
|
|
|
|
|
def test_age_band_is_monotonic_across_the_whole_domain():
|
|
order = {band: index for index, band in enumerate(AGE_BANDS)}
|
|
previous = -1
|
|
for age in range(0, 150):
|
|
current = order[age_band_for(age)]
|
|
assert current >= previous
|
|
previous = current
|
|
|
|
|
|
def test_years_between_handles_leap_days_and_exact_boundaries():
|
|
assert years_between(date(2000, 2, 29), date(2018, 2, 28)) == 17
|
|
assert years_between(date(2000, 2, 29), date(2018, 3, 1)) == 18
|
|
assert years_between(date(2008, 1, 1), date(2026, 1, 1)) == 18
|
|
assert years_between(date(2008, 1, 2), date(2026, 1, 1)) == 17
|
|
|
|
|
|
def test_years_between_never_exceeds_the_calendar_difference():
|
|
born = date(2005, 6, 15)
|
|
for offset in range(0, 4000, 7):
|
|
today = date.fromordinal(born.toordinal() + offset)
|
|
years = years_between(born, today)
|
|
assert 0 <= years <= today.year - born.year
|