From 90ab565a4a358352c94e194362ac66ac640b3a8b Mon Sep 17 00:00:00 2001 From: snipem Date: Sun, 1 Jun 2014 00:27:35 +0200 Subject: [PATCH 1/6] Unit test for feed creation Tests feed object, atom and rss string --- feedgen/tests/test_feed.py | 116 +++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 feedgen/tests/test_feed.py diff --git a/feedgen/tests/test_feed.py b/feedgen/tests/test_feed.py new file mode 100644 index 0000000..071e2fd --- /dev/null +++ b/feedgen/tests/test_feed.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- + +""" +Tests for a basic feed + +These test cases contain test cases for a basic feed. A basic feed does not contain entries so far. +""" + +import unittest +from lxml import etree + +class TestSequenceFunctions(unittest.TestCase): + + def setUp(self): + from feedgen.feed import FeedGenerator + fg = FeedGenerator() + + self.feedId = 'http://lernfunk.de/media/654321' + self.title = 'Some Testfeed' + + self.authorName = 'John Doe' + self.authorMail = 'john@example.de' + self.author = {'name': self.authorName,'email': self.authorMail} + + self.linkHref = 'http://example.com' + self.linkRel = 'alternate' + + self.logo = 'http://ex.com/logo.jpg' + self.subtitle = 'This is a cool feed!' + + self.link2Href = 'http://larskiesow.de/test.atom' + self.link2Rel = 'self' + + self.language = 'en' + + fg.id(self.feedId) + fg.title(self.title) + fg.author(self.author) + fg.link( href=self.linkHref, rel=self.linkRel ) + fg.logo(self.logo) + fg.subtitle(self.subtitle) + fg.link( href=self.link2Href, rel=self.link2Rel ) + fg.language(self.language) + + self.fg = fg + + def test_baseFeed(self): + fg = self.fg + + assert fg.id() == self.feedId + assert fg.title() == self.title + + assert fg.author()[0]['name'] == self.authorName + assert fg.author()[0]['email'] == self.authorMail + + assert fg.link()[0]['href'] == self.linkHref + assert fg.link()[0]['rel'] == self.linkRel + + assert fg.logo() == self.logo + assert fg.subtitle() == self.subtitle + + assert fg.link()[1]['href'] == self.link2Href + assert fg.link()[1]['rel'] == self.link2Rel + + assert fg.language() == self.language + + def test_atomFeed(self): + fg = self.fg + + atomString = fg.atom_str(pretty=True) + feed = etree.fromstring(atomString) + + nsAtom = "http://www.w3.org/2005/Atom" + + assert feed.find("{%s}title" % nsAtom).text == self.title + assert feed.find("{%s}updated" % nsAtom).text != None + assert feed.find("{%s}id" % nsAtom).text == self.feedId + + assert feed.find("{%s}author" % nsAtom).find("{%s}name" % nsAtom).text == self.authorName + assert feed.find("{%s}author" % nsAtom).find("{%s}email" % nsAtom).text == self.authorMail + + assert feed.findall("{%s}link" % nsAtom)[0].get('href') == self.linkHref + assert feed.findall("{%s}link" % nsAtom)[0].get('rel') == self.linkRel + assert feed.findall("{%s}link" % nsAtom)[1].get('href') == self.link2Href + assert feed.findall("{%s}link" % nsAtom)[1].get('rel') == self.link2Rel + + assert feed.find("{%s}logo" % nsAtom).text == self.logo + assert feed.find("{%s}subtitle" % nsAtom).text == self.subtitle + + def test_rssFeed(self): + fg = self.fg + + rssString = fg.rss_str(pretty=True) + feed = etree.fromstring(rssString) + + nsAtom = "http://www.w3.org/2005/Atom" + nsRss = "http://purl.org/rss/1.0/modules/content/" + + channel = feed.find("channel") + assert channel != None + + assert channel.find("title").text == self.title + assert channel.find("description").text == self.subtitle + assert channel.find("lastBuildDate").text != None + assert channel.find("docs").text == "http://www.rssboard.org/rss-specification" + assert channel.find("generator").text == "python-feedgen" + + assert channel.findall("{%s}link" % nsAtom)[0].get('href') == self.link2Href + assert channel.findall("{%s}link" % nsAtom)[0].get('rel') == self.link2Rel + + assert channel.find("image").find("url").text == self.logo + assert channel.find("image").find("title").text == self.title + assert channel.find("image").find("link").text == self.link2Href + +if __name__ == '__main__': + unittest.main() \ No newline at end of file From d2bbc87f6c0dd5772bd74360e57530d9b0ab6847 Mon Sep 17 00:00:00 2001 From: snipem Date: Sun, 1 Jun 2014 13:39:37 +0200 Subject: [PATCH 2/6] Added test cases for all elements and travis support --- .gitignore | 4 ++ .travis.yml | 10 ++++ feedgen/tests/test_entry.py | 83 ++++++++++++++++++++++++++ feedgen/tests/test_feed.py | 115 ++++++++++++++++++++++++++++++++---- 4 files changed, 201 insertions(+), 11 deletions(-) create mode 100644 .travis.yml create mode 100644 feedgen/tests/test_entry.py diff --git a/.gitignore b/.gitignore index ce30c5f..acc4484 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ venv *.pyc *.pyo *.swp + +feedgen/tests/tmp_Atomfeed.xml + +feedgen/tests/tmp_Rssfeed.xml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..e3224ad --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: python +python: + - "2.6" + - "2.7" + - "3.2" + - "3.3" +# command to install dependencies +install: "pip install lxml" +# command to run tests +script: py.test \ No newline at end of file diff --git a/feedgen/tests/test_entry.py b/feedgen/tests/test_entry.py new file mode 100644 index 0000000..38023d3 --- /dev/null +++ b/feedgen/tests/test_entry.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- + +""" +Tests for a basic feed + +These test cases contain test cases for a basic feed. A basic feed does not contain entries so far. +""" + +import unittest +from lxml import etree +from feedgen.feed import FeedGenerator + + +class TestSequenceFunctions(unittest.TestCase): + + def setUp(self): + + fg = FeedGenerator() + self.feedId = 'http://example.com' + self.title = 'Some Testfeed' + + fg.id(self.feedId) + fg.title(self.title) + + fe = fg.add_entry() + fe.id('http://lernfunk.de/media/654321/1') + fe.title('The First Episode') + + #Use also the different name add_item + fe = fg.add_item() + fe.id('http://lernfunk.de/media/654321/1') + fe.title('The Second Episode') + + fe = fg.add_entry() + fe.id('http://lernfunk.de/media/654321/1') + fe.title('The Third Episode') + + self.fg = fg + + def test_checkEntryNumbers(self): + + fg = self.fg + assert len(fg.entry()) == 3 + + def test_checkItemNumbers(self): + + fg = self.fg + assert len(fg.item()) == 3 + + def test_checkEntryContent(self): + + fg = self.fg + assert len(fg.entry()) != None + + def test_removeEntryByIndex(self): + fg = FeedGenerator() + self.feedId = 'http://example.com' + self.title = 'Some Testfeed' + + fe = fg.add_entry() + fe.id('http://lernfunk.de/media/654321/1') + fe.title('The Third Episode') + assert len(fg.entry()) == 1 + fg.remove_entry(0) + assert len(fg.entry()) == 0 + + def test_removeEntryByEntry(self): + fg = FeedGenerator() + self.feedId = 'http://example.com' + self.title = 'Some Testfeed' + + fe = fg.add_entry() + fe.id('http://lernfunk.de/media/654321/1') + fe.title('The Third Episode') + + assert len(fg.entry()) == 1 + fg.remove_entry(fe) + assert len(fg.entry()) == 0 + + + + + diff --git a/feedgen/tests/test_feed.py b/feedgen/tests/test_feed.py index 071e2fd..12b51ee 100644 --- a/feedgen/tests/test_feed.py +++ b/feedgen/tests/test_feed.py @@ -15,6 +15,9 @@ class TestSequenceFunctions(unittest.TestCase): from feedgen.feed import FeedGenerator fg = FeedGenerator() + self.nsAtom = "http://www.w3.org/2005/Atom" + self.nsRss = "http://purl.org/rss/1.0/modules/content/" + self.feedId = 'http://lernfunk.de/media/654321' self.title = 'Some Testfeed' @@ -32,6 +35,34 @@ class TestSequenceFunctions(unittest.TestCase): self.link2Rel = 'self' self.language = 'en' + + self.categoryTerm = 'This category term' + self.categoryScheme = 'This category scheme' + self.categoryLabel = 'This category label' + + self.cloudDomain = 'example.com' + self.cloudPort = '4711' + self.cloudPath = '/ws/example' + self.cloudRegisterProcedure = 'registerProcedure' + self.cloudProtocol = 'SOAP 1.1' + + self.icon = "http://example.com/icon.png" + self.contributor = {'name':"Contributor Name", 'uri':"Contributor Uri", 'email': 'Contributor email'} + self.copyright = "The copyright notice" + self.docs = 'http://www.rssboard.org/rss-specification' + self.managingEditor = 'mail@example.com' + self.rating = '(PICS-1.1 "http://www.classify.org/safesurf/" 1 r (SS~~000 1))' + self.skipDays = 'Tuesday' + self.skipHours = 23 + + self.textInputTitle = "Text input title" + self.textInputDescription = "Text input description" + self.textInputName = "Text input name" + self.textInputLink = "Text input link" + + self.ttl = 900 + + self.webMaster = 'webmaster@example.com' fg.id(self.feedId) fg.title(self.title) @@ -41,9 +72,23 @@ class TestSequenceFunctions(unittest.TestCase): fg.subtitle(self.subtitle) fg.link( href=self.link2Href, rel=self.link2Rel ) fg.language(self.language) + fg.cloud(domain=self.cloudDomain, port=self.cloudPort, path=self.cloudPath, registerProcedure=self.cloudRegisterProcedure, protocol=self.cloudProtocol) + fg.icon(self.icon) + fg.category(term=self.categoryTerm, scheme=self.categoryScheme, label=self.categoryLabel) + fg.contributor(self.contributor) + fg.copyright(self.copyright) + fg.docs(docs=self.docs) + fg.managingEditor(self.managingEditor) + fg.rating(self.rating) + fg.skipDays(self.skipDays) + fg.skipHours(self.skipHours) + fg.textInput(title=self.textInputTitle, description=self.textInputDescription, name=self.textInputName, link=self.textInputLink) + fg.ttl(self.ttl) + fg.webMaster(self.webMaster) self.fg = fg + def test_baseFeed(self): fg = self.fg @@ -64,37 +109,73 @@ class TestSequenceFunctions(unittest.TestCase): assert fg.language() == self.language - def test_atomFeed(self): + def test_atomFeedFile(self): fg = self.fg + filename = 'tmp_Atomfeed.xml' + fg.atom_file(filename=filename, pretty=True) + + with open (filename, "r") as myfile: + atomString=myfile.read().replace('\n', '') + + self.checkAtomString(atomString) + def test_atomFeedString(self): + fg = self.fg + atomString = fg.atom_str(pretty=True) + self.checkAtomString(atomString) + + + def checkAtomString(self, atomString): + feed = etree.fromstring(atomString) - nsAtom = "http://www.w3.org/2005/Atom" + print (atomString) + nsAtom = self.nsAtom assert feed.find("{%s}title" % nsAtom).text == self.title assert feed.find("{%s}updated" % nsAtom).text != None assert feed.find("{%s}id" % nsAtom).text == self.feedId - + assert feed.find("{%s}category" % nsAtom).get('term') == self.categoryTerm + assert feed.find("{%s}category" % nsAtom).get('label') == self.categoryLabel assert feed.find("{%s}author" % nsAtom).find("{%s}name" % nsAtom).text == self.authorName assert feed.find("{%s}author" % nsAtom).find("{%s}email" % nsAtom).text == self.authorMail - assert feed.findall("{%s}link" % nsAtom)[0].get('href') == self.linkHref assert feed.findall("{%s}link" % nsAtom)[0].get('rel') == self.linkRel assert feed.findall("{%s}link" % nsAtom)[1].get('href') == self.link2Href assert feed.findall("{%s}link" % nsAtom)[1].get('rel') == self.link2Rel - assert feed.find("{%s}logo" % nsAtom).text == self.logo + assert feed.find("{%s}icon" % nsAtom).text == self.icon assert feed.find("{%s}subtitle" % nsAtom).text == self.subtitle + assert feed.find("{%s}contributor" % nsAtom).find("{%s}name" % nsAtom).text == self.contributor['name'] + assert feed.find("{%s}contributor" % nsAtom).find("{%s}email" % nsAtom).text == self.contributor['email'] + assert feed.find("{%s}contributor" % nsAtom).find("{%s}url" % nsAtom).text == self.contributor['uri'] + assert feed.find("{%s}rights" % nsAtom).text == self.copyright - def test_rssFeed(self): + def test_rssFeedFile(self): + fg = self.fg + filename = 'tmp_Rssfeed.xml' + fg.rss_file(filename=filename, pretty=True) + + with open (filename, "r") as myfile: + rssString=myfile.read().replace('\n', '') + + self.checkRssString(rssString) + + def test_rssFeedString(self): fg = self.fg rssString = fg.rss_str(pretty=True) - feed = etree.fromstring(rssString) + self.checkRssString(rssString) - nsAtom = "http://www.w3.org/2005/Atom" - nsRss = "http://purl.org/rss/1.0/modules/content/" + def test_loadExtension(self): + raise Exception('Not yet implemented') + + def checkRssString(self, rssString): + + feed = etree.fromstring(rssString) + nsAtom = self.nsAtom + nsRss = self.nsRss channel = feed.find("channel") assert channel != None @@ -104,13 +185,25 @@ class TestSequenceFunctions(unittest.TestCase): assert channel.find("lastBuildDate").text != None assert channel.find("docs").text == "http://www.rssboard.org/rss-specification" assert channel.find("generator").text == "python-feedgen" - assert channel.findall("{%s}link" % nsAtom)[0].get('href') == self.link2Href assert channel.findall("{%s}link" % nsAtom)[0].get('rel') == self.link2Rel - assert channel.find("image").find("url").text == self.logo assert channel.find("image").find("title").text == self.title assert channel.find("image").find("link").text == self.link2Href + assert channel.find("category").text == self.categoryLabel + assert channel.find("cloud").text == self.cloud + assert channel.find("copyright").text == self.copyright + assert channel.find("docs").text == self.docs + assert channel.find("managingEditor").text == self.managingEditor + assert channel.find("rating").text == self.rating + assert channel.find("skipDays").find("day").text == self.skipDays + assert int(channel.find("skipHours").find("hour").text) == self.skipHours + assert channel.find("textInput").get('title') == self.textInputTitle + assert channel.find("textInput").get('description') == self.textInputDescription + assert channel.find("textInput").get('name') == self.textInputName + assert channel.find("textInput").get('link') == self.textInputLink + assert channel.find("ttl").text == self.ttl + assert channel.find("webMaster").text == self.webMaster if __name__ == '__main__': unittest.main() \ No newline at end of file From da06835e8bd99a9c996719ad47efcf23b9b7e0e6 Mon Sep 17 00:00:00 2001 From: snipem Date: Mon, 2 Jun 2014 22:45:15 +0200 Subject: [PATCH 3/6] Added unit test cases for extension loading Also fixed bugs regarding the upcoming feed.py fix --- .gitignore | 4 ++++ feedgen/tests/__init__.py | 0 feedgen/tests/test_entry.py | 7 +++---- feedgen/tests/test_extension.py | 0 feedgen/tests/test_feed.py | 23 +++++++++++++++++------ 5 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 feedgen/tests/__init__.py create mode 100644 feedgen/tests/test_extension.py diff --git a/.gitignore b/.gitignore index acc4484..b6f6775 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,7 @@ venv feedgen/tests/tmp_Atomfeed.xml feedgen/tests/tmp_Rssfeed.xml + +tmp_Atomfeed.xml + +tmp_Rssfeed.xml diff --git a/feedgen/tests/__init__.py b/feedgen/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/feedgen/tests/test_entry.py b/feedgen/tests/test_entry.py index 38023d3..19186a5 100644 --- a/feedgen/tests/test_entry.py +++ b/feedgen/tests/test_entry.py @@ -1,15 +1,14 @@ # -*- coding: utf-8 -*- """ -Tests for a basic feed +Tests for a basic entry -These test cases contain test cases for a basic feed. A basic feed does not contain entries so far. +These test cases contain test cases for a basic entry. """ import unittest from lxml import etree -from feedgen.feed import FeedGenerator - +from ..feed import FeedGenerator class TestSequenceFunctions(unittest.TestCase): diff --git a/feedgen/tests/test_extension.py b/feedgen/tests/test_extension.py new file mode 100644 index 0000000..e69de29 diff --git a/feedgen/tests/test_feed.py b/feedgen/tests/test_feed.py index 12b51ee..79f144b 100644 --- a/feedgen/tests/test_feed.py +++ b/feedgen/tests/test_feed.py @@ -8,11 +8,12 @@ These test cases contain test cases for a basic feed. A basic feed does not cont import unittest from lxml import etree +from ..feed import FeedGenerator class TestSequenceFunctions(unittest.TestCase): def setUp(self): - from feedgen.feed import FeedGenerator + fg = FeedGenerator() self.nsAtom = "http://www.w3.org/2005/Atom" @@ -164,12 +165,16 @@ class TestSequenceFunctions(unittest.TestCase): def test_rssFeedString(self): fg = self.fg - rssString = fg.rss_str(pretty=True) self.checkRssString(rssString) - def test_loadExtension(self): - raise Exception('Not yet implemented') + def test_loadPodcastExtension(self): + fg = self.fg + fg.load_extension('podcast', atom=True, rss=True) + + def test_loadDcExtension(self): + fg = self.fg + fg.load_extension('dc', atom=True, rss=True) def checkRssString(self, rssString): @@ -177,6 +182,8 @@ class TestSequenceFunctions(unittest.TestCase): nsAtom = self.nsAtom nsRss = self.nsRss + print (rssString) + channel = feed.find("channel") assert channel != None @@ -191,7 +198,11 @@ class TestSequenceFunctions(unittest.TestCase): assert channel.find("image").find("title").text == self.title assert channel.find("image").find("link").text == self.link2Href assert channel.find("category").text == self.categoryLabel - assert channel.find("cloud").text == self.cloud + assert channel.find("cloud").get('domain') == self.cloudDomain + assert channel.find("cloud").get('port') == self.cloudPort + assert channel.find("cloud").get('path') == self.cloudPath + assert channel.find("cloud").get('registerProcedure') == self.cloudRegisterProcedure + assert channel.find("cloud").get('protocol') == self.cloudProtocol assert channel.find("copyright").text == self.copyright assert channel.find("docs").text == self.docs assert channel.find("managingEditor").text == self.managingEditor @@ -202,7 +213,7 @@ class TestSequenceFunctions(unittest.TestCase): assert channel.find("textInput").get('description') == self.textInputDescription assert channel.find("textInput").get('name') == self.textInputName assert channel.find("textInput").get('link') == self.textInputLink - assert channel.find("ttl").text == self.ttl + assert int(channel.find("ttl").text) == self.ttl assert channel.find("webMaster").text == self.webMaster if __name__ == '__main__': From 9213c3057e498b4abc8568165b287fa3e113ef80 Mon Sep 17 00:00:00 2001 From: snipem Date: Mon, 2 Jun 2014 22:47:45 +0200 Subject: [PATCH 4/6] Fix domain and ttl bugs for RSS generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the context of RSS cloud domain was spelled incorrectly as ‚donain‘ which resulted in an error while unit testing. Additionally, also in RSS ttl (Time to live) wasn’t transformed to a string. --- feedgen/feed.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feedgen/feed.py b/feedgen/feed.py index 315d109..e78e502 100644 --- a/feedgen/feed.py +++ b/feedgen/feed.py @@ -342,7 +342,7 @@ class FeedGenerator(object): textInput.attrib['link'] = self.__rss_textInput.get('link') if self.__rss_ttl: ttl = etree.SubElement(channel, 'ttl') - ttl.text = self.__rss_ttl + ttl.text = str(self.__rss_ttl) if self.__rss_webMaster: webMaster = etree.SubElement(channel, 'webMaster') webMaster.text = self.__rss_webMaster @@ -626,7 +626,7 @@ class FeedGenerator(object): :returns: Dictionary containing the cloud data. ''' if not domain is None: - self.__rss_cloud = {'donain':domain, 'port':port, 'path':path, + self.__rss_cloud = {'domain':domain, 'port':port, 'path':path, 'registerProcedure':registerProcedure, 'protocol':protocol} return self.__rss_cloud From a6300a13abb06e8a15bc69e083c8696ef23b4f93 Mon Sep 17 00:00:00 2001 From: snipem Date: Mon, 2 Jun 2014 22:55:25 +0200 Subject: [PATCH 5/6] Added dateutil requirement for travis python-dateutil was missing for a clean install of the module --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e3224ad..3d13151 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,6 @@ python: - "3.2" - "3.3" # command to install dependencies -install: "pip install lxml" +install: "pip install lxml python-dateutil" # command to run tests script: py.test \ No newline at end of file From 0907e993e4dc38f0f5e08c6b3555fd68e18caf4a Mon Sep 17 00:00:00 2001 From: snipem Date: Mon, 2 Jun 2014 23:08:50 +0200 Subject: [PATCH 6/6] Fix skipHours for Python 3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The xrange function isn’t available in Python 3. The range function however is doing the same job and is working for both Python 2 and Python 3. --- feedgen/feed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feedgen/feed.py b/feedgen/feed.py index e78e502..194ec5c 100644 --- a/feedgen/feed.py +++ b/feedgen/feed.py @@ -881,7 +881,7 @@ class FeedGenerator(object): if not (isinstance(hours, list) or isinstance(hours, set)): hours = [hours] for h in hours: - if not h in xrange(24): + if not h in range(24): raise ValueError('Invalid hour %s' % h) if replace or not self.__rss_skipHours: self.__rss_skipHours = set()