From 0b825adcf2a4608c8fb02a19cc56dc96ef1414a1 Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Tue, 31 Dec 2013 11:25:02 +0100 Subject: Renamed syndication tests To resolve the conflict between application names. --- tests/syndication/__init__.py | 0 tests/syndication/feeds.py | 175 -------- tests/syndication/fixtures/feeddata.json | 55 --- tests/syndication/models.py | 27 -- .../templates/syndication/description.html | 1 - .../templates/syndication/description_context.html | 1 - tests/syndication/templates/syndication/title.html | 1 - .../templates/syndication/title_context.html | 1 - tests/syndication/tests.py | 456 --------------------- tests/syndication/urls.py | 24 -- tests/syndication_tests/__init__.py | 0 tests/syndication_tests/feeds.py | 175 ++++++++ tests/syndication_tests/fixtures/feeddata.json | 55 +++ tests/syndication_tests/models.py | 27 ++ .../templates/syndication/description.html | 1 + .../templates/syndication/description_context.html | 1 + .../templates/syndication/title.html | 1 + .../templates/syndication/title_context.html | 1 + tests/syndication_tests/tests.py | 456 +++++++++++++++++++++ tests/syndication_tests/urls.py | 24 ++ 20 files changed, 741 insertions(+), 741 deletions(-) delete mode 100644 tests/syndication/__init__.py delete mode 100644 tests/syndication/feeds.py delete mode 100644 tests/syndication/fixtures/feeddata.json delete mode 100644 tests/syndication/models.py delete mode 100644 tests/syndication/templates/syndication/description.html delete mode 100644 tests/syndication/templates/syndication/description_context.html delete mode 100644 tests/syndication/templates/syndication/title.html delete mode 100644 tests/syndication/templates/syndication/title_context.html delete mode 100644 tests/syndication/tests.py delete mode 100644 tests/syndication/urls.py create mode 100644 tests/syndication_tests/__init__.py create mode 100644 tests/syndication_tests/feeds.py create mode 100644 tests/syndication_tests/fixtures/feeddata.json create mode 100644 tests/syndication_tests/models.py create mode 100644 tests/syndication_tests/templates/syndication/description.html create mode 100644 tests/syndication_tests/templates/syndication/description_context.html create mode 100644 tests/syndication_tests/templates/syndication/title.html create mode 100644 tests/syndication_tests/templates/syndication/title_context.html create mode 100644 tests/syndication_tests/tests.py create mode 100644 tests/syndication_tests/urls.py diff --git a/tests/syndication/__init__.py b/tests/syndication/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/syndication/feeds.py b/tests/syndication/feeds.py deleted file mode 100644 index 2097cb62ad..0000000000 --- a/tests/syndication/feeds.py +++ /dev/null @@ -1,175 +0,0 @@ -from __future__ import unicode_literals - -from django.contrib.syndication import views -from django.core.exceptions import ObjectDoesNotExist -from django.utils import feedgenerator -from django.utils.timezone import get_fixed_timezone - -from .models import Article, Entry - - -class ComplexFeed(views.Feed): - def get_object(self, request, foo=None): - if foo is not None: - raise ObjectDoesNotExist - return None - - -class TestRss2Feed(views.Feed): - title = 'My blog' - description = 'A more thorough description of my blog.' - link = '/blog/' - feed_guid = '/foo/bar/1234' - author_name = 'Sally Smith' - author_email = 'test@example.com' - author_link = 'http://www.example.com/' - categories = ('python', 'django') - feed_copyright = 'Copyright (c) 2007, Sally Smith' - ttl = 600 - - def items(self): - return Entry.objects.all() - - def item_description(self, item): - return "Overridden description: %s" % item - - def item_pubdate(self, item): - return item.published - - def item_updateddate(self, item): - return item.updated - - item_author_name = 'Sally Smith' - item_author_email = 'test@example.com' - item_author_link = 'http://www.example.com/' - item_categories = ('python', 'testing') - item_copyright = 'Copyright (c) 2007, Sally Smith' - - -class TestRss2FeedWithGuidIsPermaLinkTrue(TestRss2Feed): - def item_guid_is_permalink(self, item): - return True - - -class TestRss2FeedWithGuidIsPermaLinkFalse(TestRss2Feed): - def item_guid(self, item): - return str(item.pk) - - def item_guid_is_permalink(self, item): - return False - - -class TestRss091Feed(TestRss2Feed): - feed_type = feedgenerator.RssUserland091Feed - - -class TestNoPubdateFeed(views.Feed): - title = 'Test feed' - link = '/feed/' - - def items(self): - return Entry.objects.all() - - -class TestAtomFeed(TestRss2Feed): - feed_type = feedgenerator.Atom1Feed - subtitle = TestRss2Feed.description - - -class TestLatestFeed(TestRss2Feed): - """ - A feed where the latest entry date is an `updated` element. - """ - feed_type = feedgenerator.Atom1Feed - subtitle = TestRss2Feed.description - - def items(self): - return Entry.objects.exclude(pk=5) - - -class ArticlesFeed(TestRss2Feed): - """ - A feed to test no link being defined. Articles have no get_absolute_url() - method, and item_link() is not defined. - """ - def items(self): - return Article.objects.all() - - -class TestEnclosureFeed(TestRss2Feed): - pass - - -class TemplateFeed(TestRss2Feed): - """ - A feed to test defining item titles and descriptions with templates. - """ - title_template = 'syndication/title.html' - description_template = 'syndication/description.html' - - # Defining a template overrides any item_title definition - def item_title(self): - return "Not in a template" - - -class TemplateContextFeed(TestRss2Feed): - """ - A feed to test custom context data in templates for title or description. - """ - title_template = 'syndication/title_context.html' - description_template = 'syndication/description_context.html' - - def get_context_data(self, **kwargs): - context = super(TemplateContextFeed, self).get_context_data(**kwargs) - context['foo'] = 'bar' - return context - - -class NaiveDatesFeed(TestAtomFeed): - """ - A feed with naive (non-timezone-aware) dates. - """ - def item_pubdate(self, item): - return item.published - - -class TZAwareDatesFeed(TestAtomFeed): - """ - A feed with timezone-aware dates. - """ - def item_pubdate(self, item): - # Provide a weird offset so that the test can know it's getting this - # specific offset and not accidentally getting on from - # settings.TIME_ZONE. - return item.published.replace(tzinfo=get_fixed_timezone(42)) - - -class TestFeedUrlFeed(TestAtomFeed): - feed_url = 'http://example.com/customfeedurl/' - - -class MyCustomAtom1Feed(feedgenerator.Atom1Feed): - """ - Test of a custom feed generator class. - """ - def root_attributes(self): - attrs = super(MyCustomAtom1Feed, self).root_attributes() - attrs['django'] = 'rocks' - return attrs - - def add_root_elements(self, handler): - super(MyCustomAtom1Feed, self).add_root_elements(handler) - handler.addQuickElement('spam', 'eggs') - - def item_attributes(self, item): - attrs = super(MyCustomAtom1Feed, self).item_attributes(item) - attrs['bacon'] = 'yum' - return attrs - - def add_item_elements(self, handler, item): - super(MyCustomAtom1Feed, self).add_item_elements(handler, item) - handler.addQuickElement('ministry', 'silly walks') - - -class TestCustomFeed(TestAtomFeed): - feed_type = MyCustomAtom1Feed diff --git a/tests/syndication/fixtures/feeddata.json b/tests/syndication/fixtures/feeddata.json deleted file mode 100644 index 52e5028fcd..0000000000 --- a/tests/syndication/fixtures/feeddata.json +++ /dev/null @@ -1,55 +0,0 @@ -[ - { - "model": "syndication.entry", - "pk": 1, - "fields": { - "title": "My first entry", - "updated": "1850-01-01 12:30:00", - "published": "1066-09-25 20:15:00" - } - }, - { - "model": "syndication.entry", - "pk": 2, - "fields": { - "title": "My second entry", - "updated": "2008-01-02 12:30:00", - "published": "2006-03-17 18:00:00" - } - }, - { - "model": "syndication.entry", - "pk": 3, - "fields": { - "title": "My third entry", - "updated": "2008-01-02 13:30:00", - "published": "2005-06-14 10:45:00" - } - }, - { - "model": "syndication.entry", - "pk": 4, - "fields": { - "title": "A & B < C > D", - "updated": "2008-01-03 13:30:00", - "published": "2005-11-25 12:11:23" - } - }, - { - "model": "syndication.entry", - "pk": 5, - "fields": { - "title": "My last entry", - "updated": "2013-01-20 00:00:00", - "published": "2013-03-25 20:00:00" - } - }, - { - "model": "syndication.article", - "pk": 1, - "fields": { - "title": "My first article", - "entry": "1" - } - } -] diff --git a/tests/syndication/models.py b/tests/syndication/models.py deleted file mode 100644 index 166acd69ca..0000000000 --- a/tests/syndication/models.py +++ /dev/null @@ -1,27 +0,0 @@ -from django.db import models -from django.utils.encoding import python_2_unicode_compatible - - -@python_2_unicode_compatible -class Entry(models.Model): - title = models.CharField(max_length=200) - updated = models.DateTimeField() - published = models.DateTimeField() - - class Meta: - ordering = ('updated',) - - def __str__(self): - return self.title - - def get_absolute_url(self): - return "/blog/%s/" % self.pk - - -@python_2_unicode_compatible -class Article(models.Model): - title = models.CharField(max_length=200) - entry = models.ForeignKey(Entry) - - def __str__(self): - return self.title diff --git a/tests/syndication/templates/syndication/description.html b/tests/syndication/templates/syndication/description.html deleted file mode 100644 index 85ec82c8df..0000000000 --- a/tests/syndication/templates/syndication/description.html +++ /dev/null @@ -1 +0,0 @@ -Description in your templates: {{ obj }} \ No newline at end of file diff --git a/tests/syndication/templates/syndication/description_context.html b/tests/syndication/templates/syndication/description_context.html deleted file mode 100644 index 319d84b1b0..0000000000 --- a/tests/syndication/templates/syndication/description_context.html +++ /dev/null @@ -1 +0,0 @@ -{{ obj }} (foo is {{ foo }}) \ No newline at end of file diff --git a/tests/syndication/templates/syndication/title.html b/tests/syndication/templates/syndication/title.html deleted file mode 100644 index eb17969714..0000000000 --- a/tests/syndication/templates/syndication/title.html +++ /dev/null @@ -1 +0,0 @@ -Title in your templates: {{ obj }} \ No newline at end of file diff --git a/tests/syndication/templates/syndication/title_context.html b/tests/syndication/templates/syndication/title_context.html deleted file mode 100644 index 319d84b1b0..0000000000 --- a/tests/syndication/templates/syndication/title_context.html +++ /dev/null @@ -1 +0,0 @@ -{{ obj }} (foo is {{ foo }}) \ No newline at end of file diff --git a/tests/syndication/tests.py b/tests/syndication/tests.py deleted file mode 100644 index a3b75369be..0000000000 --- a/tests/syndication/tests.py +++ /dev/null @@ -1,456 +0,0 @@ -from __future__ import unicode_literals - -import datetime -from xml.dom import minidom - -try: - import pytz -except ImportError: - pytz = None - -from django.contrib.syndication import views -from django.core.exceptions import ImproperlyConfigured -from django.test import TestCase -from django.test.utils import requires_tz_support -from django.utils.feedgenerator import rfc2822_date, rfc3339_date -from django.utils import timezone - -from .models import Entry - - -TZ = timezone.get_default_timezone() - - -class FeedTestCase(TestCase): - fixtures = ['feeddata.json'] - - def setUp(self): - # Django cannot deal with very old dates when pytz isn't installed. - if pytz is None: - old_entry = Entry.objects.get(pk=1) - old_entry.updated = datetime.datetime(1980, 1, 1, 12, 30) - old_entry.published = datetime.datetime(1986, 9, 25, 20, 15, 00) - old_entry.save() - - def assertChildNodes(self, elem, expected): - actual = set(n.nodeName for n in elem.childNodes) - expected = set(expected) - self.assertEqual(actual, expected) - - def assertChildNodeContent(self, elem, expected): - for k, v in expected.items(): - self.assertEqual( - elem.getElementsByTagName(k)[0].firstChild.wholeText, v) - - def assertCategories(self, elem, expected): - self.assertEqual(set(i.firstChild.wholeText for i in elem.childNodes if i.nodeName == 'category'), set(expected)) - -###################################### -# Feed view -###################################### - - -class SyndicationFeedTest(FeedTestCase): - """ - Tests for the high-level syndication feed framework. - """ - urls = 'syndication.urls' - - def test_rss2_feed(self): - """ - Test the structure and content of feeds generated by Rss201rev2Feed. - """ - response = self.client.get('/syndication/rss2/') - doc = minidom.parseString(response.content) - - # Making sure there's only 1 `rss` element and that the correct - # RSS version was specified. - feed_elem = doc.getElementsByTagName('rss') - self.assertEqual(len(feed_elem), 1) - feed = feed_elem[0] - self.assertEqual(feed.getAttribute('version'), '2.0') - - # Making sure there's only one `channel` element w/in the - # `rss` element. - chan_elem = feed.getElementsByTagName('channel') - self.assertEqual(len(chan_elem), 1) - chan = chan_elem[0] - - # Find the last build date - d = Entry.objects.latest('published').published - last_build_date = rfc2822_date(timezone.make_aware(d, TZ)) - - self.assertChildNodes(chan, ['title', 'link', 'description', 'language', 'lastBuildDate', 'item', 'atom:link', 'ttl', 'copyright', 'category']) - self.assertChildNodeContent(chan, { - 'title': 'My blog', - 'description': 'A more thorough description of my blog.', - 'link': 'http://example.com/blog/', - 'language': 'en', - 'lastBuildDate': last_build_date, - #'atom:link': '', - 'ttl': '600', - 'copyright': 'Copyright (c) 2007, Sally Smith', - }) - self.assertCategories(chan, ['python', 'django']) - - # Ensure the content of the channel is correct - self.assertChildNodeContent(chan, { - 'title': 'My blog', - 'link': 'http://example.com/blog/', - }) - - # Check feed_url is passed - self.assertEqual( - chan.getElementsByTagName('atom:link')[0].getAttribute('href'), - 'http://example.com/syndication/rss2/' - ) - - # Find the pubdate of the first feed item - d = Entry.objects.get(pk=1).published - pub_date = rfc2822_date(timezone.make_aware(d, TZ)) - - items = chan.getElementsByTagName('item') - self.assertEqual(len(items), Entry.objects.count()) - self.assertChildNodeContent(items[0], { - 'title': 'My first entry', - 'description': 'Overridden description: My first entry', - 'link': 'http://example.com/blog/1/', - 'guid': 'http://example.com/blog/1/', - 'pubDate': pub_date, - 'author': 'test@example.com (Sally Smith)', - }) - self.assertCategories(items[0], ['python', 'testing']) - for item in items: - self.assertChildNodes(item, ['title', 'link', 'description', 'guid', 'category', 'pubDate', 'author']) - # Assert that does not have any 'isPermaLink' attribute - self.assertIsNone(item.getElementsByTagName( - 'guid')[0].attributes.get('isPermaLink')) - - def test_rss2_feed_guid_permalink_false(self): - """ - Test if the 'isPermaLink' attribute of element of an item - in the RSS feed is 'false'. - """ - response = self.client.get( - '/syndication/rss2/guid_ispermalink_false/') - doc = minidom.parseString(response.content) - chan = doc.getElementsByTagName( - 'rss')[0].getElementsByTagName('channel')[0] - items = chan.getElementsByTagName('item') - for item in items: - self.assertEqual( - item.getElementsByTagName('guid')[0].attributes.get( - 'isPermaLink').value, "false") - - def test_rss2_feed_guid_permalink_true(self): - """ - Test if the 'isPermaLink' attribute of element of an item - in the RSS feed is 'true'. - """ - response = self.client.get( - '/syndication/rss2/guid_ispermalink_true/') - doc = minidom.parseString(response.content) - chan = doc.getElementsByTagName( - 'rss')[0].getElementsByTagName('channel')[0] - items = chan.getElementsByTagName('item') - for item in items: - self.assertEqual( - item.getElementsByTagName('guid')[0].attributes.get( - 'isPermaLink').value, "true") - - def test_rss091_feed(self): - """ - Test the structure and content of feeds generated by RssUserland091Feed. - """ - response = self.client.get('/syndication/rss091/') - doc = minidom.parseString(response.content) - - # Making sure there's only 1 `rss` element and that the correct - # RSS version was specified. - feed_elem = doc.getElementsByTagName('rss') - self.assertEqual(len(feed_elem), 1) - feed = feed_elem[0] - self.assertEqual(feed.getAttribute('version'), '0.91') - - # Making sure there's only one `channel` element w/in the - # `rss` element. - chan_elem = feed.getElementsByTagName('channel') - self.assertEqual(len(chan_elem), 1) - chan = chan_elem[0] - self.assertChildNodes(chan, ['title', 'link', 'description', 'language', 'lastBuildDate', 'item', 'atom:link', 'ttl', 'copyright', 'category']) - - # Ensure the content of the channel is correct - self.assertChildNodeContent(chan, { - 'title': 'My blog', - 'link': 'http://example.com/blog/', - }) - self.assertCategories(chan, ['python', 'django']) - - # Check feed_url is passed - self.assertEqual( - chan.getElementsByTagName('atom:link')[0].getAttribute('href'), - 'http://example.com/syndication/rss091/' - ) - - items = chan.getElementsByTagName('item') - self.assertEqual(len(items), Entry.objects.count()) - self.assertChildNodeContent(items[0], { - 'title': 'My first entry', - 'description': 'Overridden description: My first entry', - 'link': 'http://example.com/blog/1/', - }) - for item in items: - self.assertChildNodes(item, ['title', 'link', 'description']) - self.assertCategories(item, []) - - def test_atom_feed(self): - """ - Test the structure and content of feeds generated by Atom1Feed. - """ - response = self.client.get('/syndication/atom/') - feed = minidom.parseString(response.content).firstChild - - self.assertEqual(feed.nodeName, 'feed') - self.assertEqual(feed.getAttribute('xmlns'), 'http://www.w3.org/2005/Atom') - self.assertChildNodes(feed, ['title', 'subtitle', 'link', 'id', 'updated', 'entry', 'rights', 'category', 'author']) - for link in feed.getElementsByTagName('link'): - if link.getAttribute('rel') == 'self': - self.assertEqual(link.getAttribute('href'), 'http://example.com/syndication/atom/') - - entries = feed.getElementsByTagName('entry') - self.assertEqual(len(entries), Entry.objects.count()) - for entry in entries: - self.assertChildNodes(entry, [ - 'title', - 'link', - 'id', - 'summary', - 'category', - 'updated', - 'published', - 'rights', - 'author', - ]) - summary = entry.getElementsByTagName('summary')[0] - self.assertEqual(summary.getAttribute('type'), 'html') - - def test_atom_feed_published_and_updated_elements(self): - """ - Test that the published and updated elements are not - the same and now adhere to RFC 4287. - """ - response = self.client.get('/syndication/atom/') - feed = minidom.parseString(response.content).firstChild - entries = feed.getElementsByTagName('entry') - - published = entries[0].getElementsByTagName('published')[0].firstChild.wholeText - updated = entries[0].getElementsByTagName('updated')[0].firstChild.wholeText - - self.assertNotEqual(published, updated) - - def test_latest_post_date(self): - """ - Test that both the published and updated dates are - considered when determining the latest post date. - """ - # this feed has a `published` element with the latest date - response = self.client.get('/syndication/atom/') - feed = minidom.parseString(response.content).firstChild - updated = feed.getElementsByTagName('updated')[0].firstChild.wholeText - - d = Entry.objects.latest('published').published - latest_published = rfc3339_date(timezone.make_aware(d, TZ)) - - self.assertEqual(updated, latest_published) - - # this feed has an `updated` element with the latest date - response = self.client.get('/syndication/latest/') - feed = minidom.parseString(response.content).firstChild - updated = feed.getElementsByTagName('updated')[0].firstChild.wholeText - - d = Entry.objects.exclude(pk=5).latest('updated').updated - latest_updated = rfc3339_date(timezone.make_aware(d, TZ)) - - self.assertEqual(updated, latest_updated) - - def test_custom_feed_generator(self): - response = self.client.get('/syndication/custom/') - feed = minidom.parseString(response.content).firstChild - - self.assertEqual(feed.nodeName, 'feed') - self.assertEqual(feed.getAttribute('django'), 'rocks') - self.assertChildNodes(feed, ['title', 'subtitle', 'link', 'id', 'updated', 'entry', 'spam', 'rights', 'category', 'author']) - - entries = feed.getElementsByTagName('entry') - self.assertEqual(len(entries), Entry.objects.count()) - for entry in entries: - self.assertEqual(entry.getAttribute('bacon'), 'yum') - self.assertChildNodes(entry, [ - 'title', - 'link', - 'id', - 'summary', - 'ministry', - 'rights', - 'author', - 'updated', - 'published', - 'category', - ]) - summary = entry.getElementsByTagName('summary')[0] - self.assertEqual(summary.getAttribute('type'), 'html') - - def test_title_escaping(self): - """ - Tests that titles are escaped correctly in RSS feeds. - """ - response = self.client.get('/syndication/rss2/') - doc = minidom.parseString(response.content) - for item in doc.getElementsByTagName('item'): - link = item.getElementsByTagName('link')[0] - if link.firstChild.wholeText == 'http://example.com/blog/4/': - title = item.getElementsByTagName('title')[0] - self.assertEqual(title.firstChild.wholeText, 'A & B < C > D') - - def test_naive_datetime_conversion(self): - """ - Test that datetimes are correctly converted to the local time zone. - """ - # Naive date times passed in get converted to the local time zone, so - # check the recived zone offset against the local offset. - response = self.client.get('/syndication/naive-dates/') - doc = minidom.parseString(response.content) - updated = doc.getElementsByTagName('updated')[0].firstChild.wholeText - - d = Entry.objects.latest('published').published - latest = rfc3339_date(timezone.make_aware(d, TZ)) - - self.assertEqual(updated, latest) - - def test_aware_datetime_conversion(self): - """ - Test that datetimes with timezones don't get trodden on. - """ - response = self.client.get('/syndication/aware-dates/') - doc = minidom.parseString(response.content) - published = doc.getElementsByTagName('published')[0].firstChild.wholeText - self.assertEqual(published[-6:], '+00:42') - - @requires_tz_support - def test_feed_last_modified_time_naive_date(self): - """ - Tests the Last-Modified header with naive publication dates. - """ - response = self.client.get('/syndication/naive-dates/') - self.assertEqual(response['Last-Modified'], 'Tue, 26 Mar 2013 01:00:00 GMT') - - def test_feed_last_modified_time(self): - """ - Tests the Last-Modified header with aware publication dates. - """ - response = self.client.get('/syndication/aware-dates/') - self.assertEqual(response['Last-Modified'], 'Mon, 25 Mar 2013 19:18:00 GMT') - - # No last-modified when feed has no item_pubdate - response = self.client.get('/syndication/no_pubdate/') - self.assertFalse(response.has_header('Last-Modified')) - - def test_feed_url(self): - """ - Test that the feed_url can be overridden. - """ - response = self.client.get('/syndication/feedurl/') - doc = minidom.parseString(response.content) - for link in doc.getElementsByTagName('link'): - if link.getAttribute('rel') == 'self': - self.assertEqual(link.getAttribute('href'), 'http://example.com/customfeedurl/') - - def test_secure_urls(self): - """ - Test URLs are prefixed with https:// when feed is requested over HTTPS. - """ - response = self.client.get('/syndication/rss2/', **{ - 'wsgi.url_scheme': 'https', - }) - doc = minidom.parseString(response.content) - chan = doc.getElementsByTagName('channel')[0] - self.assertEqual( - chan.getElementsByTagName('link')[0].firstChild.wholeText[0:5], - 'https' - ) - atom_link = chan.getElementsByTagName('atom:link')[0] - self.assertEqual(atom_link.getAttribute('href')[0:5], 'https') - for link in doc.getElementsByTagName('link'): - if link.getAttribute('rel') == 'self': - self.assertEqual(link.getAttribute('href')[0:5], 'https') - - def test_item_link_error(self): - """ - Test that a ImproperlyConfigured is raised if no link could be found - for the item(s). - """ - self.assertRaises(ImproperlyConfigured, - self.client.get, - '/syndication/articles/') - - def test_template_feed(self): - """ - Test that the item title and description can be overridden with - templates. - """ - response = self.client.get('/syndication/template/') - doc = minidom.parseString(response.content) - feed = doc.getElementsByTagName('rss')[0] - chan = feed.getElementsByTagName('channel')[0] - items = chan.getElementsByTagName('item') - - self.assertChildNodeContent(items[0], { - 'title': 'Title in your templates: My first entry', - 'description': 'Description in your templates: My first entry', - 'link': 'http://example.com/blog/1/', - }) - - def test_template_context_feed(self): - """ - Test that custom context data can be passed to templates for title - and description. - """ - response = self.client.get('/syndication/template_context/') - doc = minidom.parseString(response.content) - feed = doc.getElementsByTagName('rss')[0] - chan = feed.getElementsByTagName('channel')[0] - items = chan.getElementsByTagName('item') - - self.assertChildNodeContent(items[0], { - 'title': 'My first entry (foo is bar)', - 'description': 'My first entry (foo is bar)', - }) - - def test_add_domain(self): - """ - Test add_domain() prefixes domains onto the correct URLs. - """ - self.assertEqual( - views.add_domain('example.com', '/foo/?arg=value'), - 'http://example.com/foo/?arg=value' - ) - self.assertEqual( - views.add_domain('example.com', '/foo/?arg=value', True), - 'https://example.com/foo/?arg=value' - ) - self.assertEqual( - views.add_domain('example.com', 'http://djangoproject.com/doc/'), - 'http://djangoproject.com/doc/' - ) - self.assertEqual( - views.add_domain('example.com', 'https://djangoproject.com/doc/'), - 'https://djangoproject.com/doc/' - ) - self.assertEqual( - views.add_domain('example.com', 'mailto:uhoh@djangoproject.com'), - 'mailto:uhoh@djangoproject.com' - ) - self.assertEqual( - views.add_domain('example.com', '//example.com/foo/?arg=value'), - 'http://example.com/foo/?arg=value' - ) diff --git a/tests/syndication/urls.py b/tests/syndication/urls.py deleted file mode 100644 index 1b5d77f2e1..0000000000 --- a/tests/syndication/urls.py +++ /dev/null @@ -1,24 +0,0 @@ -from django.conf.urls import patterns - -from . import feeds - - -urlpatterns = patterns('django.contrib.syndication.views', - (r'^syndication/complex/(?P.*)/$', feeds.ComplexFeed()), - (r'^syndication/rss2/$', feeds.TestRss2Feed()), - (r'^syndication/rss2/guid_ispermalink_true/$', - feeds.TestRss2FeedWithGuidIsPermaLinkTrue()), - (r'^syndication/rss2/guid_ispermalink_false/$', - feeds.TestRss2FeedWithGuidIsPermaLinkFalse()), - (r'^syndication/rss091/$', feeds.TestRss091Feed()), - (r'^syndication/no_pubdate/$', feeds.TestNoPubdateFeed()), - (r'^syndication/atom/$', feeds.TestAtomFeed()), - (r'^syndication/latest/$', feeds.TestLatestFeed()), - (r'^syndication/custom/$', feeds.TestCustomFeed()), - (r'^syndication/naive-dates/$', feeds.NaiveDatesFeed()), - (r'^syndication/aware-dates/$', feeds.TZAwareDatesFeed()), - (r'^syndication/feedurl/$', feeds.TestFeedUrlFeed()), - (r'^syndication/articles/$', feeds.ArticlesFeed()), - (r'^syndication/template/$', feeds.TemplateFeed()), - (r'^syndication/template_context/$', feeds.TemplateContextFeed()), -) diff --git a/tests/syndication_tests/__init__.py b/tests/syndication_tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/syndication_tests/feeds.py b/tests/syndication_tests/feeds.py new file mode 100644 index 0000000000..2097cb62ad --- /dev/null +++ b/tests/syndication_tests/feeds.py @@ -0,0 +1,175 @@ +from __future__ import unicode_literals + +from django.contrib.syndication import views +from django.core.exceptions import ObjectDoesNotExist +from django.utils import feedgenerator +from django.utils.timezone import get_fixed_timezone + +from .models import Article, Entry + + +class ComplexFeed(views.Feed): + def get_object(self, request, foo=None): + if foo is not None: + raise ObjectDoesNotExist + return None + + +class TestRss2Feed(views.Feed): + title = 'My blog' + description = 'A more thorough description of my blog.' + link = '/blog/' + feed_guid = '/foo/bar/1234' + author_name = 'Sally Smith' + author_email = 'test@example.com' + author_link = 'http://www.example.com/' + categories = ('python', 'django') + feed_copyright = 'Copyright (c) 2007, Sally Smith' + ttl = 600 + + def items(self): + return Entry.objects.all() + + def item_description(self, item): + return "Overridden description: %s" % item + + def item_pubdate(self, item): + return item.published + + def item_updateddate(self, item): + return item.updated + + item_author_name = 'Sally Smith' + item_author_email = 'test@example.com' + item_author_link = 'http://www.example.com/' + item_categories = ('python', 'testing') + item_copyright = 'Copyright (c) 2007, Sally Smith' + + +class TestRss2FeedWithGuidIsPermaLinkTrue(TestRss2Feed): + def item_guid_is_permalink(self, item): + return True + + +class TestRss2FeedWithGuidIsPermaLinkFalse(TestRss2Feed): + def item_guid(self, item): + return str(item.pk) + + def item_guid_is_permalink(self, item): + return False + + +class TestRss091Feed(TestRss2Feed): + feed_type = feedgenerator.RssUserland091Feed + + +class TestNoPubdateFeed(views.Feed): + title = 'Test feed' + link = '/feed/' + + def items(self): + return Entry.objects.all() + + +class TestAtomFeed(TestRss2Feed): + feed_type = feedgenerator.Atom1Feed + subtitle = TestRss2Feed.description + + +class TestLatestFeed(TestRss2Feed): + """ + A feed where the latest entry date is an `updated` element. + """ + feed_type = feedgenerator.Atom1Feed + subtitle = TestRss2Feed.description + + def items(self): + return Entry.objects.exclude(pk=5) + + +class ArticlesFeed(TestRss2Feed): + """ + A feed to test no link being defined. Articles have no get_absolute_url() + method, and item_link() is not defined. + """ + def items(self): + return Article.objects.all() + + +class TestEnclosureFeed(TestRss2Feed): + pass + + +class TemplateFeed(TestRss2Feed): + """ + A feed to test defining item titles and descriptions with templates. + """ + title_template = 'syndication/title.html' + description_template = 'syndication/description.html' + + # Defining a template overrides any item_title definition + def item_title(self): + return "Not in a template" + + +class TemplateContextFeed(TestRss2Feed): + """ + A feed to test custom context data in templates for title or description. + """ + title_template = 'syndication/title_context.html' + description_template = 'syndication/description_context.html' + + def get_context_data(self, **kwargs): + context = super(TemplateContextFeed, self).get_context_data(**kwargs) + context['foo'] = 'bar' + return context + + +class NaiveDatesFeed(TestAtomFeed): + """ + A feed with naive (non-timezone-aware) dates. + """ + def item_pubdate(self, item): + return item.published + + +class TZAwareDatesFeed(TestAtomFeed): + """ + A feed with timezone-aware dates. + """ + def item_pubdate(self, item): + # Provide a weird offset so that the test can know it's getting this + # specific offset and not accidentally getting on from + # settings.TIME_ZONE. + return item.published.replace(tzinfo=get_fixed_timezone(42)) + + +class TestFeedUrlFeed(TestAtomFeed): + feed_url = 'http://example.com/customfeedurl/' + + +class MyCustomAtom1Feed(feedgenerator.Atom1Feed): + """ + Test of a custom feed generator class. + """ + def root_attributes(self): + attrs = super(MyCustomAtom1Feed, self).root_attributes() + attrs['django'] = 'rocks' + return attrs + + def add_root_elements(self, handler): + super(MyCustomAtom1Feed, self).add_root_elements(handler) + handler.addQuickElement('spam', 'eggs') + + def item_attributes(self, item): + attrs = super(MyCustomAtom1Feed, self).item_attributes(item) + attrs['bacon'] = 'yum' + return attrs + + def add_item_elements(self, handler, item): + super(MyCustomAtom1Feed, self).add_item_elements(handler, item) + handler.addQuickElement('ministry', 'silly walks') + + +class TestCustomFeed(TestAtomFeed): + feed_type = MyCustomAtom1Feed diff --git a/tests/syndication_tests/fixtures/feeddata.json b/tests/syndication_tests/fixtures/feeddata.json new file mode 100644 index 0000000000..52e5028fcd --- /dev/null +++ b/tests/syndication_tests/fixtures/feeddata.json @@ -0,0 +1,55 @@ +[ + { + "model": "syndication.entry", + "pk": 1, + "fields": { + "title": "My first entry", + "updated": "1850-01-01 12:30:00", + "published": "1066-09-25 20:15:00" + } + }, + { + "model": "syndication.entry", + "pk": 2, + "fields": { + "title": "My second entry", + "updated": "2008-01-02 12:30:00", + "published": "2006-03-17 18:00:00" + } + }, + { + "model": "syndication.entry", + "pk": 3, + "fields": { + "title": "My third entry", + "updated": "2008-01-02 13:30:00", + "published": "2005-06-14 10:45:00" + } + }, + { + "model": "syndication.entry", + "pk": 4, + "fields": { + "title": "A & B < C > D", + "updated": "2008-01-03 13:30:00", + "published": "2005-11-25 12:11:23" + } + }, + { + "model": "syndication.entry", + "pk": 5, + "fields": { + "title": "My last entry", + "updated": "2013-01-20 00:00:00", + "published": "2013-03-25 20:00:00" + } + }, + { + "model": "syndication.article", + "pk": 1, + "fields": { + "title": "My first article", + "entry": "1" + } + } +] diff --git a/tests/syndication_tests/models.py b/tests/syndication_tests/models.py new file mode 100644 index 0000000000..166acd69ca --- /dev/null +++ b/tests/syndication_tests/models.py @@ -0,0 +1,27 @@ +from django.db import models +from django.utils.encoding import python_2_unicode_compatible + + +@python_2_unicode_compatible +class Entry(models.Model): + title = models.CharField(max_length=200) + updated = models.DateTimeField() + published = models.DateTimeField() + + class Meta: + ordering = ('updated',) + + def __str__(self): + return self.title + + def get_absolute_url(self): + return "/blog/%s/" % self.pk + + +@python_2_unicode_compatible +class Article(models.Model): + title = models.CharField(max_length=200) + entry = models.ForeignKey(Entry) + + def __str__(self): + return self.title diff --git a/tests/syndication_tests/templates/syndication/description.html b/tests/syndication_tests/templates/syndication/description.html new file mode 100644 index 0000000000..85ec82c8df --- /dev/null +++ b/tests/syndication_tests/templates/syndication/description.html @@ -0,0 +1 @@ +Description in your templates: {{ obj }} \ No newline at end of file diff --git a/tests/syndication_tests/templates/syndication/description_context.html b/tests/syndication_tests/templates/syndication/description_context.html new file mode 100644 index 0000000000..319d84b1b0 --- /dev/null +++ b/tests/syndication_tests/templates/syndication/description_context.html @@ -0,0 +1 @@ +{{ obj }} (foo is {{ foo }}) \ No newline at end of file diff --git a/tests/syndication_tests/templates/syndication/title.html b/tests/syndication_tests/templates/syndication/title.html new file mode 100644 index 0000000000..eb17969714 --- /dev/null +++ b/tests/syndication_tests/templates/syndication/title.html @@ -0,0 +1 @@ +Title in your templates: {{ obj }} \ No newline at end of file diff --git a/tests/syndication_tests/templates/syndication/title_context.html b/tests/syndication_tests/templates/syndication/title_context.html new file mode 100644 index 0000000000..319d84b1b0 --- /dev/null +++ b/tests/syndication_tests/templates/syndication/title_context.html @@ -0,0 +1 @@ +{{ obj }} (foo is {{ foo }}) \ No newline at end of file diff --git a/tests/syndication_tests/tests.py b/tests/syndication_tests/tests.py new file mode 100644 index 0000000000..a3b75369be --- /dev/null +++ b/tests/syndication_tests/tests.py @@ -0,0 +1,456 @@ +from __future__ import unicode_literals + +import datetime +from xml.dom import minidom + +try: + import pytz +except ImportError: + pytz = None + +from django.contrib.syndication import views +from django.core.exceptions import ImproperlyConfigured +from django.test import TestCase +from django.test.utils import requires_tz_support +from django.utils.feedgenerator import rfc2822_date, rfc3339_date +from django.utils import timezone + +from .models import Entry + + +TZ = timezone.get_default_timezone() + + +class FeedTestCase(TestCase): + fixtures = ['feeddata.json'] + + def setUp(self): + # Django cannot deal with very old dates when pytz isn't installed. + if pytz is None: + old_entry = Entry.objects.get(pk=1) + old_entry.updated = datetime.datetime(1980, 1, 1, 12, 30) + old_entry.published = datetime.datetime(1986, 9, 25, 20, 15, 00) + old_entry.save() + + def assertChildNodes(self, elem, expected): + actual = set(n.nodeName for n in elem.childNodes) + expected = set(expected) + self.assertEqual(actual, expected) + + def assertChildNodeContent(self, elem, expected): + for k, v in expected.items(): + self.assertEqual( + elem.getElementsByTagName(k)[0].firstChild.wholeText, v) + + def assertCategories(self, elem, expected): + self.assertEqual(set(i.firstChild.wholeText for i in elem.childNodes if i.nodeName == 'category'), set(expected)) + +###################################### +# Feed view +###################################### + + +class SyndicationFeedTest(FeedTestCase): + """ + Tests for the high-level syndication feed framework. + """ + urls = 'syndication.urls' + + def test_rss2_feed(self): + """ + Test the structure and content of feeds generated by Rss201rev2Feed. + """ + response = self.client.get('/syndication/rss2/') + doc = minidom.parseString(response.content) + + # Making sure there's only 1 `rss` element and that the correct + # RSS version was specified. + feed_elem = doc.getElementsByTagName('rss') + self.assertEqual(len(feed_elem), 1) + feed = feed_elem[0] + self.assertEqual(feed.getAttribute('version'), '2.0') + + # Making sure there's only one `channel` element w/in the + # `rss` element. + chan_elem = feed.getElementsByTagName('channel') + self.assertEqual(len(chan_elem), 1) + chan = chan_elem[0] + + # Find the last build date + d = Entry.objects.latest('published').published + last_build_date = rfc2822_date(timezone.make_aware(d, TZ)) + + self.assertChildNodes(chan, ['title', 'link', 'description', 'language', 'lastBuildDate', 'item', 'atom:link', 'ttl', 'copyright', 'category']) + self.assertChildNodeContent(chan, { + 'title': 'My blog', + 'description': 'A more thorough description of my blog.', + 'link': 'http://example.com/blog/', + 'language': 'en', + 'lastBuildDate': last_build_date, + #'atom:link': '', + 'ttl': '600', + 'copyright': 'Copyright (c) 2007, Sally Smith', + }) + self.assertCategories(chan, ['python', 'django']) + + # Ensure the content of the channel is correct + self.assertChildNodeContent(chan, { + 'title': 'My blog', + 'link': 'http://example.com/blog/', + }) + + # Check feed_url is passed + self.assertEqual( + chan.getElementsByTagName('atom:link')[0].getAttribute('href'), + 'http://example.com/syndication/rss2/' + ) + + # Find the pubdate of the first feed item + d = Entry.objects.get(pk=1).published + pub_date = rfc2822_date(timezone.make_aware(d, TZ)) + + items = chan.getElementsByTagName('item') + self.assertEqual(len(items), Entry.objects.count()) + self.assertChildNodeContent(items[0], { + 'title': 'My first entry', + 'description': 'Overridden description: My first entry', + 'link': 'http://example.com/blog/1/', + 'guid': 'http://example.com/blog/1/', + 'pubDate': pub_date, + 'author': 'test@example.com (Sally Smith)', + }) + self.assertCategories(items[0], ['python', 'testing']) + for item in items: + self.assertChildNodes(item, ['title', 'link', 'description', 'guid', 'category', 'pubDate', 'author']) + # Assert that does not have any 'isPermaLink' attribute + self.assertIsNone(item.getElementsByTagName( + 'guid')[0].attributes.get('isPermaLink')) + + def test_rss2_feed_guid_permalink_false(self): + """ + Test if the 'isPermaLink' attribute of element of an item + in the RSS feed is 'false'. + """ + response = self.client.get( + '/syndication/rss2/guid_ispermalink_false/') + doc = minidom.parseString(response.content) + chan = doc.getElementsByTagName( + 'rss')[0].getElementsByTagName('channel')[0] + items = chan.getElementsByTagName('item') + for item in items: + self.assertEqual( + item.getElementsByTagName('guid')[0].attributes.get( + 'isPermaLink').value, "false") + + def test_rss2_feed_guid_permalink_true(self): + """ + Test if the 'isPermaLink' attribute of element of an item + in the RSS feed is 'true'. + """ + response = self.client.get( + '/syndication/rss2/guid_ispermalink_true/') + doc = minidom.parseString(response.content) + chan = doc.getElementsByTagName( + 'rss')[0].getElementsByTagName('channel')[0] + items = chan.getElementsByTagName('item') + for item in items: + self.assertEqual( + item.getElementsByTagName('guid')[0].attributes.get( + 'isPermaLink').value, "true") + + def test_rss091_feed(self): + """ + Test the structure and content of feeds generated by RssUserland091Feed. + """ + response = self.client.get('/syndication/rss091/') + doc = minidom.parseString(response.content) + + # Making sure there's only 1 `rss` element and that the correct + # RSS version was specified. + feed_elem = doc.getElementsByTagName('rss') + self.assertEqual(len(feed_elem), 1) + feed = feed_elem[0] + self.assertEqual(feed.getAttribute('version'), '0.91') + + # Making sure there's only one `channel` element w/in the + # `rss` element. + chan_elem = feed.getElementsByTagName('channel') + self.assertEqual(len(chan_elem), 1) + chan = chan_elem[0] + self.assertChildNodes(chan, ['title', 'link', 'description', 'language', 'lastBuildDate', 'item', 'atom:link', 'ttl', 'copyright', 'category']) + + # Ensure the content of the channel is correct + self.assertChildNodeContent(chan, { + 'title': 'My blog', + 'link': 'http://example.com/blog/', + }) + self.assertCategories(chan, ['python', 'django']) + + # Check feed_url is passed + self.assertEqual( + chan.getElementsByTagName('atom:link')[0].getAttribute('href'), + 'http://example.com/syndication/rss091/' + ) + + items = chan.getElementsByTagName('item') + self.assertEqual(len(items), Entry.objects.count()) + self.assertChildNodeContent(items[0], { + 'title': 'My first entry', + 'description': 'Overridden description: My first entry', + 'link': 'http://example.com/blog/1/', + }) + for item in items: + self.assertChildNodes(item, ['title', 'link', 'description']) + self.assertCategories(item, []) + + def test_atom_feed(self): + """ + Test the structure and content of feeds generated by Atom1Feed. + """ + response = self.client.get('/syndication/atom/') + feed = minidom.parseString(response.content).firstChild + + self.assertEqual(feed.nodeName, 'feed') + self.assertEqual(feed.getAttribute('xmlns'), 'http://www.w3.org/2005/Atom') + self.assertChildNodes(feed, ['title', 'subtitle', 'link', 'id', 'updated', 'entry', 'rights', 'category', 'author']) + for link in feed.getElementsByTagName('link'): + if link.getAttribute('rel') == 'self': + self.assertEqual(link.getAttribute('href'), 'http://example.com/syndication/atom/') + + entries = feed.getElementsByTagName('entry') + self.assertEqual(len(entries), Entry.objects.count()) + for entry in entries: + self.assertChildNodes(entry, [ + 'title', + 'link', + 'id', + 'summary', + 'category', + 'updated', + 'published', + 'rights', + 'author', + ]) + summary = entry.getElementsByTagName('summary')[0] + self.assertEqual(summary.getAttribute('type'), 'html') + + def test_atom_feed_published_and_updated_elements(self): + """ + Test that the published and updated elements are not + the same and now adhere to RFC 4287. + """ + response = self.client.get('/syndication/atom/') + feed = minidom.parseString(response.content).firstChild + entries = feed.getElementsByTagName('entry') + + published = entries[0].getElementsByTagName('published')[0].firstChild.wholeText + updated = entries[0].getElementsByTagName('updated')[0].firstChild.wholeText + + self.assertNotEqual(published, updated) + + def test_latest_post_date(self): + """ + Test that both the published and updated dates are + considered when determining the latest post date. + """ + # this feed has a `published` element with the latest date + response = self.client.get('/syndication/atom/') + feed = minidom.parseString(response.content).firstChild + updated = feed.getElementsByTagName('updated')[0].firstChild.wholeText + + d = Entry.objects.latest('published').published + latest_published = rfc3339_date(timezone.make_aware(d, TZ)) + + self.assertEqual(updated, latest_published) + + # this feed has an `updated` element with the latest date + response = self.client.get('/syndication/latest/') + feed = minidom.parseString(response.content).firstChild + updated = feed.getElementsByTagName('updated')[0].firstChild.wholeText + + d = Entry.objects.exclude(pk=5).latest('updated').updated + latest_updated = rfc3339_date(timezone.make_aware(d, TZ)) + + self.assertEqual(updated, latest_updated) + + def test_custom_feed_generator(self): + response = self.client.get('/syndication/custom/') + feed = minidom.parseString(response.content).firstChild + + self.assertEqual(feed.nodeName, 'feed') + self.assertEqual(feed.getAttribute('django'), 'rocks') + self.assertChildNodes(feed, ['title', 'subtitle', 'link', 'id', 'updated', 'entry', 'spam', 'rights', 'category', 'author']) + + entries = feed.getElementsByTagName('entry') + self.assertEqual(len(entries), Entry.objects.count()) + for entry in entries: + self.assertEqual(entry.getAttribute('bacon'), 'yum') + self.assertChildNodes(entry, [ + 'title', + 'link', + 'id', + 'summary', + 'ministry', + 'rights', + 'author', + 'updated', + 'published', + 'category', + ]) + summary = entry.getElementsByTagName('summary')[0] + self.assertEqual(summary.getAttribute('type'), 'html') + + def test_title_escaping(self): + """ + Tests that titles are escaped correctly in RSS feeds. + """ + response = self.client.get('/syndication/rss2/') + doc = minidom.parseString(response.content) + for item in doc.getElementsByTagName('item'): + link = item.getElementsByTagName('link')[0] + if link.firstChild.wholeText == 'http://example.com/blog/4/': + title = item.getElementsByTagName('title')[0] + self.assertEqual(title.firstChild.wholeText, 'A & B < C > D') + + def test_naive_datetime_conversion(self): + """ + Test that datetimes are correctly converted to the local time zone. + """ + # Naive date times passed in get converted to the local time zone, so + # check the recived zone offset against the local offset. + response = self.client.get('/syndication/naive-dates/') + doc = minidom.parseString(response.content) + updated = doc.getElementsByTagName('updated')[0].firstChild.wholeText + + d = Entry.objects.latest('published').published + latest = rfc3339_date(timezone.make_aware(d, TZ)) + + self.assertEqual(updated, latest) + + def test_aware_datetime_conversion(self): + """ + Test that datetimes with timezones don't get trodden on. + """ + response = self.client.get('/syndication/aware-dates/') + doc = minidom.parseString(response.content) + published = doc.getElementsByTagName('published')[0].firstChild.wholeText + self.assertEqual(published[-6:], '+00:42') + + @requires_tz_support + def test_feed_last_modified_time_naive_date(self): + """ + Tests the Last-Modified header with naive publication dates. + """ + response = self.client.get('/syndication/naive-dates/') + self.assertEqual(response['Last-Modified'], 'Tue, 26 Mar 2013 01:00:00 GMT') + + def test_feed_last_modified_time(self): + """ + Tests the Last-Modified header with aware publication dates. + """ + response = self.client.get('/syndication/aware-dates/') + self.assertEqual(response['Last-Modified'], 'Mon, 25 Mar 2013 19:18:00 GMT') + + # No last-modified when feed has no item_pubdate + response = self.client.get('/syndication/no_pubdate/') + self.assertFalse(response.has_header('Last-Modified')) + + def test_feed_url(self): + """ + Test that the feed_url can be overridden. + """ + response = self.client.get('/syndication/feedurl/') + doc = minidom.parseString(response.content) + for link in doc.getElementsByTagName('link'): + if link.getAttribute('rel') == 'self': + self.assertEqual(link.getAttribute('href'), 'http://example.com/customfeedurl/') + + def test_secure_urls(self): + """ + Test URLs are prefixed with https:// when feed is requested over HTTPS. + """ + response = self.client.get('/syndication/rss2/', **{ + 'wsgi.url_scheme': 'https', + }) + doc = minidom.parseString(response.content) + chan = doc.getElementsByTagName('channel')[0] + self.assertEqual( + chan.getElementsByTagName('link')[0].firstChild.wholeText[0:5], + 'https' + ) + atom_link = chan.getElementsByTagName('atom:link')[0] + self.assertEqual(atom_link.getAttribute('href')[0:5], 'https') + for link in doc.getElementsByTagName('link'): + if link.getAttribute('rel') == 'self': + self.assertEqual(link.getAttribute('href')[0:5], 'https') + + def test_item_link_error(self): + """ + Test that a ImproperlyConfigured is raised if no link could be found + for the item(s). + """ + self.assertRaises(ImproperlyConfigured, + self.client.get, + '/syndication/articles/') + + def test_template_feed(self): + """ + Test that the item title and description can be overridden with + templates. + """ + response = self.client.get('/syndication/template/') + doc = minidom.parseString(response.content) + feed = doc.getElementsByTagName('rss')[0] + chan = feed.getElementsByTagName('channel')[0] + items = chan.getElementsByTagName('item') + + self.assertChildNodeContent(items[0], { + 'title': 'Title in your templates: My first entry', + 'description': 'Description in your templates: My first entry', + 'link': 'http://example.com/blog/1/', + }) + + def test_template_context_feed(self): + """ + Test that custom context data can be passed to templates for title + and description. + """ + response = self.client.get('/syndication/template_context/') + doc = minidom.parseString(response.content) + feed = doc.getElementsByTagName('rss')[0] + chan = feed.getElementsByTagName('channel')[0] + items = chan.getElementsByTagName('item') + + self.assertChildNodeContent(items[0], { + 'title': 'My first entry (foo is bar)', + 'description': 'My first entry (foo is bar)', + }) + + def test_add_domain(self): + """ + Test add_domain() prefixes domains onto the correct URLs. + """ + self.assertEqual( + views.add_domain('example.com', '/foo/?arg=value'), + 'http://example.com/foo/?arg=value' + ) + self.assertEqual( + views.add_domain('example.com', '/foo/?arg=value', True), + 'https://example.com/foo/?arg=value' + ) + self.assertEqual( + views.add_domain('example.com', 'http://djangoproject.com/doc/'), + 'http://djangoproject.com/doc/' + ) + self.assertEqual( + views.add_domain('example.com', 'https://djangoproject.com/doc/'), + 'https://djangoproject.com/doc/' + ) + self.assertEqual( + views.add_domain('example.com', 'mailto:uhoh@djangoproject.com'), + 'mailto:uhoh@djangoproject.com' + ) + self.assertEqual( + views.add_domain('example.com', '//example.com/foo/?arg=value'), + 'http://example.com/foo/?arg=value' + ) diff --git a/tests/syndication_tests/urls.py b/tests/syndication_tests/urls.py new file mode 100644 index 0000000000..1b5d77f2e1 --- /dev/null +++ b/tests/syndication_tests/urls.py @@ -0,0 +1,24 @@ +from django.conf.urls import patterns + +from . import feeds + + +urlpatterns = patterns('django.contrib.syndication.views', + (r'^syndication/complex/(?P.*)/$', feeds.ComplexFeed()), + (r'^syndication/rss2/$', feeds.TestRss2Feed()), + (r'^syndication/rss2/guid_ispermalink_true/$', + feeds.TestRss2FeedWithGuidIsPermaLinkTrue()), + (r'^syndication/rss2/guid_ispermalink_false/$', + feeds.TestRss2FeedWithGuidIsPermaLinkFalse()), + (r'^syndication/rss091/$', feeds.TestRss091Feed()), + (r'^syndication/no_pubdate/$', feeds.TestNoPubdateFeed()), + (r'^syndication/atom/$', feeds.TestAtomFeed()), + (r'^syndication/latest/$', feeds.TestLatestFeed()), + (r'^syndication/custom/$', feeds.TestCustomFeed()), + (r'^syndication/naive-dates/$', feeds.NaiveDatesFeed()), + (r'^syndication/aware-dates/$', feeds.TZAwareDatesFeed()), + (r'^syndication/feedurl/$', feeds.TestFeedUrlFeed()), + (r'^syndication/articles/$', feeds.ArticlesFeed()), + (r'^syndication/template/$', feeds.TemplateFeed()), + (r'^syndication/template_context/$', feeds.TemplateContextFeed()), +) -- cgit v1.3