import sys import unittest from django.conf import settings from django.contrib import admin from django.contrib.admindocs import utils, views from django.contrib.admindocs.views import get_return_data_type, simplify_regex from django.contrib.sites.models import Site from django.db import models from django.db.models import fields from django.test import SimpleTestCase, modify_settings, override_settings from django.test.utils import captured_stderr from django.urls import include, path, reverse from django.utils.functional import SimpleLazyObject from .models import Company, Person from .tests import AdminDocsTestCase, TestDataMixin @unittest.skipUnless(utils.docutils_is_available, "no docutils installed.") class AdminDocViewTests(TestDataMixin, AdminDocsTestCase): def setUp(self): self.client.force_login(self.superuser) def test_index(self): response = self.client.get(reverse("django-admindocs-docroot")) self.assertContains(response, "
test:func
.")
self.assertContains(
response,
'admin_doc/template_detail.html
Please ask your administrators to install " 'docutils.
', html=True, ) self.assertContains( response, '', ) finally: utils.docutils_is_available = True @modify_settings(INSTALLED_APPS={"remove": "django.contrib.sites"}) @override_settings(SITE_ID=None) # will restore SITE_ID after the test def test_no_sites_framework(self): """ Without the sites framework, should not access SITE_ID or Site objects. Deleting settings is fine here as UserSettingsHolder is used. """ Site.objects.all().delete() del settings.SITE_ID response = self.client.get(reverse("django-admindocs-views-index")) self.assertContains(response, "View documentation") def test_callable_urlconf(self): """ Index view should correctly resolve view patterns when ROOT_URLCONF is not a string. """ def urlpatterns(): return ( path("admin/doc/", include("django.contrib.admindocs.urls")), path("admin/", admin.site.urls), ) with self.settings(ROOT_URLCONF=SimpleLazyObject(urlpatterns)): response = self.client.get(reverse("django-admindocs-views-index")) self.assertEqual(response.status_code, 200) @unittest.skipUnless(utils.docutils_is_available, "no docutils installed.") class AdminDocViewDefaultEngineOnly(TestDataMixin, AdminDocsTestCase): def setUp(self): self.client.force_login(self.superuser) def test_template_detail_path_traversal(self): cases = ["/etc/passwd", "../passwd"] for fpath in cases: with self.subTest(path=fpath): response = self.client.get( reverse("django-admindocs-templates", args=[fpath]), ) self.assertEqual(response.status_code, 400) @override_settings( TEMPLATES=[ { "NAME": "ONE", "BACKEND": "django.template.backends.django.DjangoTemplates", "APP_DIRS": True, }, { "NAME": "TWO", "BACKEND": "django.template.backends.django.DjangoTemplates", "APP_DIRS": True, }, ] ) @unittest.skipUnless(utils.docutils_is_available, "no docutils installed.") class AdminDocViewWithMultipleEngines(AdminDocViewTests): def test_templatefilter_index(self): # Overridden because non-trivial TEMPLATES settings aren't supported # but the page shouldn't crash (#24125). response = self.client.get(reverse("django-admindocs-filters")) self.assertContains(response, "Get the full name of the person
") link = '%s' markup = "the related %s object
" company_markup = markup % (link % ("admin_docs.company", "admin_docs.Company")) # foreign keys self.assertContains(self.response, company_markup) # foreign keys with help text self.assertContains(self.response, "%s\n - place of work" % company_markup) # many to many fields self.assertContains( self.response, "number of related %s objects" % (link % ("admin_docs.group", "admin_docs.Group")), ) self.assertContains( self.response, "all related %s objects" % (link % ("admin_docs.group", "admin_docs.Group")), ) # "raw" and "include" directives are disabled self.assertContains( self.response, ""raw" directive disabled.
", ) self.assertContains( self.response, ".. raw:: html\n :file: admin_docs/evilfile.txt" ) self.assertContains( self.response, ""include" directive disabled.
", ) self.assertContains(self.response, ".. include:: admin_docs/evilfile.txt") out = self.docutils_stderr.getvalue() self.assertIn('"raw" directive disabled', out) self.assertIn('"include" directive disabled', out) def test_model_with_many_to_one(self): link = '%s' response = self.client.get( reverse("django-admindocs-models-detail", args=["admin_docs", "company"]) ) self.assertContains( response, "number of related %s objects" % (link % ("admin_docs.person", "admin_docs.Person")), ) self.assertContains( response, "all related %s objects" % (link % ("admin_docs.person", "admin_docs.Person")), ) def test_model_with_no_backward_relations_render_only_relevant_fields(self): """ A model with ``related_name`` of `+` shouldn't show backward relationship links. """ response = self.client.get( reverse("django-admindocs-models-detail", args=["admin_docs", "family"]) ) fields = response.context_data.get("fields") self.assertEqual(len(fields), 2) def test_model_docstring_renders_correctly(self): summary = ( 'Stores information about a person, related to ' '' "myapp.Company.
" ) subheading = "Notes
" body = ( 'Use save_changes() when saving this ' "object.
" ) model_body = ( '