""" Integration tests for the Links feature. Links are managed via Django template views, tested through the Django test client. """ import pytest from links.models import Link @pytest.mark.django_db class TestLinksUI: def test_list_page_returns_200(self, client): response = client.get("/", follow=True) assert response.status_code == 200 def test_create_link(self, client): response = client.post( "/create/", { "alias": "testlink", "original_url": "https://example.com", "link_type": Link.LinkType.LINK, "description": "", "text": "", }, follow=True, ) assert response.status_code == 200 assert Link.objects.filter(alias="testlink").exists() def test_redirect_follows_alias(self, client): Link.objects.create(alias="gh", original_url="https://github.com") response = client.get("/gh/") assert response.status_code == 302 assert response["Location"] == "https://github.com" def test_redirect_unknown_alias_goes_to_create(self, client): response = client.get("/definitely-not-a-real-alias/") assert response.status_code == 302 assert "create" in response["Location"] def test_delete_link(self, client): link = Link.objects.create(alias="del-me", original_url="https://example.com") response = client.post(f"/delete/{link.pk}/") assert response.status_code in (200, 302) assert not Link.objects.filter(pk=link.pk).exists() def test_link_with_template_url(self, client): Link.objects.create( alias="gosearch", original_url="https://google.com/search?q={query,default=hello}", ) response = client.get("/gosearch/") assert response.status_code == 302 assert "q=hello" in response["Location"] def test_link_with_template_param_override(self, client): Link.objects.create( alias="wiki", original_url="https://en.wikipedia.org/wiki/{topic,default=Python}", ) response = client.get("/wiki/Django/") assert response.status_code == 302 assert "Django" in response["Location"] @pytest.mark.django_db class TestTemplateLinkFormValidation: """Tests for template URL validation in LinkForm, including static Unicode text.""" def test_create_link_with_unicode_prefix_in_template_url(self, client): """Static Chinese text before a template param should be accepted.""" original_url = 'https://chatgpt.com/?q=翻译下面的段落为中文: {query,default=Cool beans}' response = client.post( "/create/", { "alias": "chatgpt-translate", "original_url": original_url, "link_type": Link.LinkType.LINK, "description": "", "text": "", }, follow=True, ) assert response.status_code == 200 link = Link.objects.get(alias="chatgpt-translate") assert link.original_url == original_url def test_create_link_with_unicode_suffix_in_template_url(self, client): """Static Chinese text after a template param should be accepted.""" original_url = 'https://chatgpt.com/?q={query,default=Cool beans},保证真实性' response = client.post( "/create/", { "alias": "chatgpt-verify", "original_url": original_url, "link_type": Link.LinkType.LINK, "description": "", "text": "", }, follow=True, ) assert response.status_code == 200 link = Link.objects.get(alias="chatgpt-verify") assert link.original_url == original_url def test_create_link_with_unicode_around_template_param(self, client): """Static Unicode text both before and after a template param should be accepted.""" original_url = 'https://chatgpt.com/?q=翻译: {query,default=hello} 保证真实性' response = client.post( "/create/", { "alias": "chatgpt-both", "original_url": original_url, "link_type": Link.LinkType.LINK, "description": "", "text": "", }, follow=True, ) assert response.status_code == 200 link = Link.objects.get(alias="chatgpt-both") assert link.original_url == original_url def test_create_link_with_invalid_url_still_rejected(self, client): """A completely invalid URL (no scheme/host) must still be rejected.""" response = client.post( "/create/", { "alias": "bad-url", "original_url": "not-a-url-at-all", "link_type": Link.LinkType.LINK, "description": "", "text": "", }, follow=True, ) assert not Link.objects.filter(alias="bad-url").exists()