aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_rss_feeds.py
blob: 5b9b98194cb12e17c8b6eaa3d212cae2145d2d4a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# -*- coding: utf-8 -*-

from __future__ import unicode_literals
import unittest
import os
import re
from io import StringIO

import mock

from context import nikola
from lxml import etree


class RSSFeedTest(unittest.TestCase):
    def setUp(self):
        self.blog_url = "http://some.blog"

        with mock.patch('nikola.post.get_meta',
                        mock.Mock(return_value=({'title': 'post title',
                                                 'slug': 'awesome_article',
                                                 'date': '2012-10-01 22:41',
                                                 'tags': 'tags', 'link':
                                                 'link', 'description':
                                                 'description'}))):
            with mock.patch('nikola.nikola.utils.os.path.isdir',
                            mock.Mock(return_value=True)):
                with mock.patch('nikola.nikola.Post.text',
                                mock.Mock(return_value='some long text')):

                    example_post = nikola.nikola.Post('source.file',
                                                      'cache',
                                                      'blog_folder',
                                                      True,
                                                      {'en': ''},
                                                      'en',
                                                      self.blog_url,
                                                      'unused message.',
                                                      'post.tmpl')

                    opener_mock = mock.mock_open()

                    with mock.patch('nikola.nikola.utils.codecs.open', opener_mock, create=True):
                        nikola.nikola.utils.generic_rss_renderer('en',
                                                                 "blog_title",
                                                                 self.blog_url,
                                                                 "blog_description",
                                                                 [example_post,
                                                                  ],
                                                                 'testfeed.rss',
                                                                 True)

                    opener_mock.assert_called_once_with(
                        'testfeed.rss', 'wb+', 'utf-8')

                    # Python 3 / unicode strings workaround
                    # lxml will complain if the encoding is specified in the
                    # xml when running with unicode strings.
                    # We do not include this in our content.
                    open_handle = opener_mock()
                    file_content = [call[1][0]
                                    for call in open_handle.mock_calls[1:-1]][0]
                    splitted_content = file_content.split('\n')
                    self.encoding_declaration = splitted_content[0]
                    content_without_encoding_declaration = splitted_content[1:]
                    self.file_content = '\n'.join(
                        content_without_encoding_declaration)

    def tearDown(self):
        pass

    def test_feed_items_have_valid_URLs(self):
        '''The items in the feed need to have valid urls in link and guid.'''
        # This validation regex is taken from django.core.validators
        url_validation_regex = re.compile(r'^(?:http|ftp)s?://'  # http:// or https://
                                          r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'  # domain...
                                          r'localhost|'  # localhost...
                                          r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|'  # ...or ipv4
                                          r'\[?[A-F0-9]*:[A-F0-9:]+\]?)'  # ...or ipv6
                                          r'(?::\d+)?'  # optional port
                                          r'(?:/?|[/?]\S+)$', re.IGNORECASE)

        def is_valid_URL(url):
            return url_validation_regex.match(url) is not None

        et = etree.parse(StringIO(self.file_content))
        channel = et.find('channel')
        item = channel.find('item')
        guid = item.find('guid')
        link = item.find('link')

        # As stated by W3 FEED Validator: "link must be a full and valid URL"
        self.assertTrue(is_valid_URL(link.text),
                        'The following URL is not valid: %s' % link.text)
        self.assertTrue(self.blog_url in link.text)

        # "guid must be a full URL, unless isPermaLink attribute
        # is false: /weblog/posts/the-minimal-server.html "
        self.assertTrue(is_valid_URL(guid.text),
                        'The following URL is not valid: %s' %
                        guid.text)
        self.assertTrue(self.blog_url in guid.text)

    def test_feed_is_valid(self):
        '''
        A testcase to check if the generated feed is valid.

        Validation can be tested with W3 FEED Validator that can be found
        at http://feedvalidator.org
        '''
        rss_schema_filename = os.path.join(os.path.dirname(__file__),
                                           'rss-2_0.xsd')
        with open(rss_schema_filename, 'r') as rss_schema_file:
            xmlschema_doc = etree.parse(rss_schema_file)

        xmlschema = etree.XMLSchema(xmlschema_doc)
        document = etree.parse(StringIO(self.file_content))

        self.assertTrue(xmlschema.validate(document))

if __name__ == '__main__':
    unittest.main()