170 lines
5.5 KiB
Python
170 lines
5.5 KiB
Python
"""
|
|
قرارداد URLها و ویوها پس از تقسیم `views.py` به پکیج `views/`.
|
|
|
|
نگهبان حذف تصادفی مسیر/ویو: مجموعهی نامهای URL با یک snapshot ثابت مقایسه میشود
|
|
و هر نام باید با ``reverse()`` قابل بازیابی باشد.
|
|
"""
|
|
from django.test import SimpleTestCase
|
|
from django.urls import reverse
|
|
|
|
# snapshot قطعی نامهای مسیرهای اپ admin_panel (۶۲ مسیر)
|
|
EXPECTED_URL_NAMES = {
|
|
'index',
|
|
'p_login',
|
|
'p_logout',
|
|
'bedehi',
|
|
'report',
|
|
'inventory_movements_report',
|
|
'financial_dashboard',
|
|
'report_debtors_no_vosol',
|
|
'rezayat_dashboard',
|
|
'hesabdari',
|
|
'hesabdari_residnashone',
|
|
'hesabdari_check_pass',
|
|
'hesabdari_check_pass_fail',
|
|
'bedehiKhadamat',
|
|
'bedehiNasb',
|
|
'customers',
|
|
'customersSearch',
|
|
'customersAdd',
|
|
'customer',
|
|
'api_check_status_inquiry',
|
|
'api_check_sabt_inquiry',
|
|
'customer2',
|
|
'customerNew',
|
|
'customerAction',
|
|
'customerNazar',
|
|
'customerNewAction',
|
|
'customerEditAction',
|
|
'customerDel',
|
|
'customerFactors',
|
|
'customerFactor',
|
|
'FactorDel',
|
|
'newFactor',
|
|
'newFactor2',
|
|
'customerHesabdari',
|
|
'customerSarresidh',
|
|
'customerHesabdariAdd',
|
|
'stores',
|
|
'productsJson',
|
|
'ActionJson',
|
|
'CustomerJson',
|
|
'productMojodi',
|
|
'store',
|
|
'operations',
|
|
'operationProduct',
|
|
'newOperation',
|
|
'newStore',
|
|
'store_transfers',
|
|
'process_transfer_action',
|
|
'productAdd',
|
|
'productEdit',
|
|
'operation',
|
|
'productDel',
|
|
'customerEdit',
|
|
'rezayat',
|
|
'rezayatEdit',
|
|
'entezar',
|
|
'ActionList',
|
|
'ActionListToday',
|
|
'ActionListUserToday',
|
|
'ActionListAll',
|
|
'passCheck',
|
|
'update_check_info',
|
|
'addSarresid',
|
|
'pardakhtNesiye',
|
|
}
|
|
|
|
# مسیرهایی که آرگومان میگیرند: نام -> kwargs نمونه
|
|
PARAMETERIZED = {
|
|
'customersSearch': {'searchVal': 'ali', 'searchOn': 'name'},
|
|
'customer': {'c_id': 1},
|
|
'customer2': {'c_id': 1},
|
|
'customerNew': {'c_id': 1},
|
|
'customerAction': {'c_id': 1},
|
|
'customerNazar': {'c_id': 1},
|
|
'customerNewAction': {'c_id': 1},
|
|
'customerEditAction': {'c_id': 1, 'action_id': 1},
|
|
'customerDel': {'c_id': 1},
|
|
'customerFactors': {'c_id': 1},
|
|
'customerFactor': {'c_id': 1, 'f_id': 1},
|
|
'FactorDel': {'c_id': 1, 'f_id': 1},
|
|
'newFactor': {'c_id': 1},
|
|
'newFactor2': {'c_id': 1},
|
|
'customerHesabdari': {'c_id': 1},
|
|
'customerSarresidh': {'c_id': 1},
|
|
'customerHesabdariAdd': {'c_id': 1},
|
|
'ActionJson': {'action_id': 1},
|
|
'CustomerJson': {'c_id': 1},
|
|
'productMojodi': {'p_id': 1},
|
|
'store': {'s_id': 1},
|
|
'operations': {'s_id': 1},
|
|
'operationProduct': {'s_id': 1, 'p_id': 1},
|
|
'newOperation': {'s_id': 1, 'p_id': 1},
|
|
'store_transfers': {'s_id': 1},
|
|
'process_transfer_action': {'transfer_id': 1},
|
|
'productDel': {'p_id': 1, 's_id': 1},
|
|
'customerEdit': {'c_id': 1},
|
|
'rezayatEdit': {'ac_id': 1},
|
|
'ActionListUserToday': {'u_id': 1},
|
|
'passCheck': {'articl_id': 1},
|
|
'update_check_info': {'sarresid_id': 1},
|
|
'addSarresid': {'cs_id': 1},
|
|
'pardakhtNesiye': {'cs_id': 1},
|
|
}
|
|
|
|
|
|
class UrlContractTests(SimpleTestCase):
|
|
|
|
def _all_names(self):
|
|
from admin_panel.urls import urlpatterns
|
|
return {p.name for p in urlpatterns if p.name}
|
|
|
|
def test_url_name_snapshot_unchanged(self):
|
|
names = self._all_names()
|
|
missing = EXPECTED_URL_NAMES - names
|
|
added = names - EXPECTED_URL_NAMES
|
|
self.assertEqual(
|
|
missing, set(),
|
|
msg=f"این نامهای URL پس از refactor گم شدهاند: {sorted(missing)}",
|
|
)
|
|
self.assertEqual(
|
|
added, set(),
|
|
msg=f"نامهای URL جدید و پیشبینینشده اضافه شدهاند: {sorted(added)}",
|
|
)
|
|
|
|
def test_every_url_reverses(self):
|
|
for name in sorted(EXPECTED_URL_NAMES):
|
|
kwargs = PARAMETERIZED.get(name, {})
|
|
with self.subTest(url=name):
|
|
try:
|
|
reverse(f'admin_panel:{name}', kwargs=kwargs)
|
|
except Exception as exc: # noqa: BLE001 - هدف: گزارش دقیق نام مشکلدار
|
|
self.fail(f"reverse('admin_panel:{name}') شکست خورد: {exc}")
|
|
|
|
def test_all_view_callables_are_importable(self):
|
|
"""هر `views.X` در urls.py باید در پکیج views موجود و قابل فراخوانی باشد."""
|
|
from admin_panel import views
|
|
from admin_panel.urls import urlpatterns
|
|
|
|
for pattern in urlpatterns:
|
|
if pattern.name not in EXPECTED_URL_NAMES:
|
|
# مسیرهای سرو استاتیک (از static()) ویوی اپ نیستند
|
|
continue
|
|
callback = getattr(pattern, 'callback', None)
|
|
if callback is None:
|
|
continue
|
|
self.assertTrue(
|
|
callable(callback),
|
|
msg=f"ویو مسیر «{pattern.name}» قابل فراخوانی نیست.",
|
|
)
|
|
self.assertTrue(
|
|
callback.__module__.startswith('admin_panel.views'),
|
|
msg=(
|
|
f"ویو مسیر «{pattern.name}» بجای پکیج admin_panel.views از "
|
|
f"ماژول {callback.__module__} میآید."
|
|
),
|
|
)
|
|
# اطمینان از اینکه از دسترسپذیری نامها استفاده میکنیم
|
|
self.assertTrue(hasattr(views, 'p_login'))
|