From 8b14a1e5b2ca574fdd4fd2377567ec98a110d4b6 Mon Sep 17 00:00:00 2001 From: Agustin Henze Date: Wed, 13 Mar 2013 20:58:39 -0300 Subject: Imported Upstream version 5.4.2 --- tests/data/translated_titles/conf.py | 397 ++++++++++++++++++++++++++ tests/data/translated_titles/stories/1.txt | 5 + tests/data/translated_titles/stories/1.txt.es | 4 + tests/test_command_import_wordpress.py | 142 +++++++-- tests/test_command_init.py | 15 +- tests/test_integration.py | 157 ++++++++-- tests/test_rss_feeds.py | 12 +- tests/test_utils.py | 121 ++++---- tests/wordpress_export_example.xml | 52 ++++ 9 files changed, 779 insertions(+), 126 deletions(-) create mode 100644 tests/data/translated_titles/conf.py create mode 100644 tests/data/translated_titles/stories/1.txt create mode 100644 tests/data/translated_titles/stories/1.txt.es (limited to 'tests') diff --git a/tests/data/translated_titles/conf.py b/tests/data/translated_titles/conf.py new file mode 100644 index 0000000..69c7bc7 --- /dev/null +++ b/tests/data/translated_titles/conf.py @@ -0,0 +1,397 @@ + +# -*- coding: utf-8 -*- +from __future__ import unicode_literals +import time + +############################################## +# Configuration, please edit +############################################## + + +# Data about this site +BLOG_AUTHOR = "Your Name" +BLOG_TITLE = "Demo Site" +# This is the main URL for your site. It will be used +# in a prominent link +SITE_URL = "http://nikola.ralsina.com.ar" +# This is the URL where nikola's output will be deployed. +# If not set, defaults to SITE_URL +# BASE_URL = "http://nikola.ralsina.com.ar +BLOG_EMAIL = "joe@demo.site" +BLOG_DESCRIPTION = "This is a demo site for Nikola." + +# Nikola is multilingual! +# +# Currently supported languages are: +# English -> en +# Greek -> gr +# German -> de +# French -> fr +# Polish -> pl +# Russian -> ru +# Spanish -> es +# Italian -> it +# Simplified Chinese -> zh-cn +# +# If you want to use Nikola with a non-supported language you have to provide +# a module containing the necessary translations +# (p.e. look at the modules at: ./nikola/data/themes/default/messages/fr.py). +# If a specific post is not translated to a language, then the version +# in the default language will be shown instead. + +# What is the default language? +DEFAULT_LANG = "en" + +# What other languages do you have? +# The format is {"translationcode" : "path/to/translation" } +# the path will be used as a prefix for the generated pages location +TRANSLATIONS = { + "en": "", + # Example for another language: + "es": "./es", +} + +# Links for the sidebar / navigation bar. +# You should provide a key-value pair for each used language. +SIDEBAR_LINKS = { + DEFAULT_LANG: ( + ('/archive.html', 'Archives'), + ('/categories/index.html', 'Tags'), + ), + "es": () +} + + +############################################## +# Below this point, everything is optional +############################################## + + +# post_pages contains (wildcard, destination, template, use_in_feed) tuples. +# +# The wildcard is used to generate a list of reSt source files +# (whatever/thing.txt). +# That fragment must have an associated metadata file (whatever/thing.meta), +# and opcionally translated files (example for spanish, with code "es"): +# whatever/thing.txt.es and whatever/thing.meta.es +# +# From those files, a set of HTML fragment files will be generated: +# cache/whatever/thing.html (and maybe cache/whatever/thing.html.es) +# +# These files are combinated with the template to produce rendered +# pages, which will be placed at +# output / TRANSLATIONS[lang] / destination / pagename.html +# +# where "pagename" is specified in the metadata file. +# +# if use_in_feed is True, then those posts will be added to the site's +# rss feeds. +# + +post_pages = ( + ("posts/*.txt", "posts", "post.tmpl", True), + ("stories/*.txt", "stories", "story.tmpl", False), +) + +# One or more folders containing files to be copied as-is into the output. +# The format is a dictionary of "source" "relative destination". +# Default is: +# FILES_FOLDERS = {'files': '' } +# Which means copy 'files' into 'output' + +# A mapping of languages to file-extensions that represent that language. +# Feel free to add or delete extensions to any list, but don't add any new +# compilers unless you write the interface for it yourself. +# +# 'rest' is reStructuredText +# 'markdown' is MarkDown +# 'html' assumes the file is html and just copies it +post_compilers = { + "rest": ('.txt', '.rst'), + "markdown": ('.md', '.mdown', '.markdown'), + "textile": ('.textile',), + "txt2tags": ('.t2t',), + "bbcode": ('.bb',), + "wiki": ('.wiki',), + "ipynb": ('.ipynb',), + "html": ('.html', '.htm') +} + +# Create by default posts in one file format? +# Set to False for two-file posts, with separate metadata. +# ONE_FILE_POSTS = True + +# Paths for different autogenerated bits. These are combined with the +# translation paths. + +# Final locations are: +# output / TRANSLATION[lang] / TAG_PATH / index.html (list of tags) +# output / TRANSLATION[lang] / TAG_PATH / tag.html (list of posts for a tag) +# output / TRANSLATION[lang] / TAG_PATH / tag.xml (RSS feed for a tag) +# TAG_PATH = "categories" + +# If TAG_PAGES_ARE_INDEXES is set to True, each tag's page will contain +# the posts themselves. If set to False, it will be just a list of links. +# TAG_PAGES_ARE_INDEXES = True + +# Final location is output / TRANSLATION[lang] / INDEX_PATH / index-*.html +# INDEX_PATH = "" +# Final locations for the archives are: +# output / TRANSLATION[lang] / ARCHIVE_PATH / ARCHIVE_FILENAME +# output / TRANSLATION[lang] / ARCHIVE_PATH / YEAR / index.html +# ARCHIVE_PATH = "" +# ARCHIVE_FILENAME = "archive.html" +# Final locations are: +# output / TRANSLATION[lang] / RSS_PATH / rss.xml +# RSS_PATH = "" + +# Slug the Tag URL easier for users to type, special characters are +# often removed or replaced as well. +# SLUG_TAG_PATH = True + +# A list of redirection tuples, [("foo/from.html", "/bar/to.html")]. +# +# A HTML file will be created in output/foo/from.html that redirects +# to the "/bar/to.html" URL. notice that the "from" side MUST be a +# relative URL. +# +# If you don't need any of these, just set to [] +# REDIRECTIONS = [] + +# Commands to execute to deploy. Can be anything, for example, +# you may use rsync: +# "rsync -rav output/* joe@my.site:/srv/www/site" +# And then do a backup, or ping pingomatic. +# To do manual deployment, set it to [] +# DEPLOY_COMMANDS = [] + +# Where the output site should be located +# If you don't use an absolute path, it will be considered as relative +# to the location of conf.py +# OUTPUT_FOLDER = 'output' + +# where the "cache" of partial generated content should be located +# default: 'cache' +# CACHE_FOLDER = 'cache' + +# Filters to apply to the output. +# A directory where the keys are either: a file extensions, or +# a tuple of file extensions. +# +# And the value is a list of commands to be applied in order. +# +# Each command must be either: +# +# A string containing a '%s' which will +# be replaced with a filename. The command *must* produce output +# in place. +# +# Or: +# +# A python callable, which will be called with the filename as +# argument. +# +# By default, there are no filters. +# FILTERS = { +# ".jpg": ["jpegoptim --strip-all -m75 -v %s"], +# } + +# Create a gzipped copy of each generated file. Cheap server-side optimization. +# GZIP_FILES = False +# File extensions that will be compressed +# GZIP_EXTENSIONS = ('.txt', '.htm', '.html', '.css', '.js', '.json') + +# ############################################################################# +# Image Gallery Options +# ############################################################################# + +# Galleries are folders in galleries/ +# Final location of galleries will be output / GALLERY_PATH / gallery_name +# GALLERY_PATH = "galleries" +# THUMBNAIL_SIZE = 180 +# MAX_IMAGE_SIZE = 1280 +# USE_FILENAME_AS_TITLE = True + +# ############################################################################# +# HTML fragments and diverse things that are used by the templates +# ############################################################################# + +# Data about post-per-page indexes +# INDEXES_TITLE = "" # If this is empty, the default is BLOG_TITLE +# INDEXES_PAGES = "" # If this is empty, the default is 'old posts page %d' translated + +# Name of the theme to use. Themes are located in themes/theme_name +# THEME = 'site' + +# If you use 'site-reveal' theme you can select several subthemes +# THEME_REVEAL_CONGIF_SUBTHEME = 'sky' # You can also use: beige/serif/simple/night/default + +# Again, if you use 'site-reveal' theme you can select several transitions between the slides +# THEME_REVEAL_CONGIF_TRANSITION = 'cube' # You can also use: page/concave/linear/none/default + +# date format used to display post dates. (str used by datetime.datetime.strftime) +# DATE_FORMAT = '%Y-%m-%d %H:%M' + +# FAVICONS contains (name, file, size) tuples. +# Used for create favicon link like this: +# +# about favicons, see: http://www.netmagazine.com/features/create-perfect-favicon +# FAVICONS = { +# ("icon", "/favicon.ico", "16x16"), +# ("icon", "/icon_128x128.png", "128x128"), +# } + +# Show only teasers in the index pages? Defaults to False. +# INDEX_TEASERS = False + +# A HTML fragment describing the license, for the sidebar. Default is "". +# I recommend using the Creative Commons' wizard: +# http://creativecommons.org/choose/ +# LICENSE = """ +# +# Creative Commons License BY-NC-SA""" + +# A small copyright notice for the page footer (in HTML). +# Default is '' +CONTENT_FOOTER = 'Contents © {date} {author} - Powered by Nikola' +CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL, + author=BLOG_AUTHOR, + date=time.gmtime().tm_year) + +# To enable comments via Disqus, you need to create a forum at +# http://disqus.com, and set DISQUS_FORUM to the short name you selected. +# If you want to disable comments, set it to False. +# Default is "nikolademo", used by the demo sites +# DISQUS_FORUM = "nikolademo" + +# Create index.html for story folders? +# STORY_INDEX = False +# Enable comments on story pages? +# COMMENTS_IN_STORIES = False +# Enable comments on picture gallery pages? +# COMMENTS_IN_GALLERIES = False + +# Do you want a add a Mathjax config file? +# MATHJAX_CONFIG = "" + +# If you are using the compile-ipynb plugin, just add this one: +#MATHJAX_CONFIG = """ +# +#""" + +# Enable Addthis social buttons? +# Defaults to true +# ADD_THIS_BUTTONS = True + +# Modify the number of Post per Index Page +# Defaults to 10 +# INDEX_DISPLAY_POST_COUNT = 10 + +# RSS_LINK is a HTML fragment to link the RSS or Atom feeds. If set to None, +# the base.tmpl will use the feed Nikola generates. However, you may want to +# change it for a feedburner feed or something else. +# RSS_LINK = None + +# Show only teasers in the RSS feed? Default to True +# RSS_TEASERS = True + +# A search form to search this site, for the sidebar. You can use a google +# custom search (http://www.google.com/cse/) +# Or a duckduckgo search: https://duckduckgo.com/search_box.html +# Default is no search form. +# SEARCH_FORM = "" +# +# This search form works for any site and looks good in the "site" theme where it +# appears on the navigation bar +#SEARCH_FORM = """ +# +# +# +#""" % BLOG_URL +# +# Also, there is a local search plugin you can use. + +# Use content distribution networks for jquery and twitter-bootstrap css and js +# If this is True, jquery is served from the Google CDN and twitter-bootstrap +# is served from the NetDNA CDN +# Set this to False if you want to host your site without requiring access to +# external resources. +# USE_CDN = False + +# Google analytics or whatever else you use. Added to the bottom of +# in the default template (base.tmpl). +# ANALYTICS = "" + +# The possibility to extract metadata from the filename by using a +# regular expression. +# To make it work you need to name parts of your regular expression. +# The following names will be used to extract metadata: +# - title +# - slug +# - date +# - tags +# - link +# - description +# +# An example re is the following: +# '(?P\d{4}-\d{2}-\d{2})-(?P.*)-(?P.*)\.md' +# FILE_METADATA_REGEXP = None + +# Nikola supports Twitter Card summaries / Open Graph. +# Twitter cards make it possible for you to attach media to Tweets +# that link to your content. +# +# IMPORTANT: +# Please note, that you need to opt-in for using Twitter Cards! +# To do this please visit https://dev.twitter.com/form/participate-twitter-cards +# +# Uncomment and modify to following lines to match your accounts. +# Specifying the id for either 'site' or 'creator' will be preferred +# over the cleartext username. Specifying an ID is not necessary. +# Displaying images is currently not supported. +# TWITTER_CARD = { +# # 'use_twitter_cards': True, # enable Twitter Cards / Open Graph +# # 'site': '@website', # twitter nick for the website +# # 'site:id': 123456, # Same as site, but the website's Twitter user ID instead. +# # 'creator': '@username', # Username for the content creator / author. +# # 'creator:id': 654321, # Same as creator, but the Twitter user's ID. +# } + + +# If you want to use formatted post time in W3C-DTF Format(ex. 2012-03-30T23:00:00+02:00), +# set timzone if you want a localized posted date. +# +# TIMEZONE = 'Europe/Zurich' + +# If webassets is installed, bundle JS and CSS to make site loading faster +# USE_BUNDLES = True + +# Plugins you don't want to use. Be careful :-) +# DISABLED_PLUGINS = ["render_galleries"] + +# Put in global_context things you want available on all your templates. +# It can be anything, data, functions, modules, etc. + +GLOBAL_CONTEXT = {} diff --git a/tests/data/translated_titles/stories/1.txt b/tests/data/translated_titles/stories/1.txt new file mode 100644 index 0000000..45fb214 --- /dev/null +++ b/tests/data/translated_titles/stories/1.txt @@ -0,0 +1,5 @@ +.. title: Foo +.. slug: 1 +.. date: 2001/01/01 00:00:00 + +Foo diff --git a/tests/data/translated_titles/stories/1.txt.es b/tests/data/translated_titles/stories/1.txt.es new file mode 100644 index 0000000..a888c1f --- /dev/null +++ b/tests/data/translated_titles/stories/1.txt.es @@ -0,0 +1,4 @@ +.. title: Bar +.. slug: 1 + +Bar diff --git a/tests/test_command_import_wordpress.py b/tests/test_command_import_wordpress.py index bda9b49..3be2ad9 100644 --- a/tests/test_command_import_wordpress.py +++ b/tests/test_command_import_wordpress.py @@ -9,17 +9,38 @@ import mock class BasicCommandImportWordpress(unittest.TestCase): def setUp(self): - self.import_command = nikola.plugins.command_import_wordpress.CommandImportWordpress( - ) - self.import_filename = os.path.abspath( - os.path.join(os.path.dirname(__file__), - 'wordpress_export_example.xml')) + self.import_command = nikola.plugins.command_import_wordpress.CommandImportWordpress() + self.import_filename = os.path.abspath(os.path.join( + os.path.dirname(__file__), 'wordpress_export_example.xml')) def tearDown(self): del self.import_command del self.import_filename +class TestXMLGlueing(BasicCommandImportWordpress): + def test_making_correct_newlines(self): + xml = [b"Some information about how to (un)subscripe to a google group with a normal mail client.\n", + b"<ul>\n", + b" <li>to post: <strong>groupname@googlegroups.com</strong></li>\n", + b" <li>to <em>subscribe</em>: <strong>groupname+subscribe@googlegroups.com</strong></li>\n", + b" <li>to <em>unsubscribe</em>: <strong>groupname+unsubscribe@googlegroups.com</strong></li>\n", + b"</ul>\n", + b"Easy.\n"] + + expected_xml = b"""Some information about how to (un)subscripe to a google group with a normal mail client. + +<ul> + <li>to post: <strong>groupname@googlegroups.com</strong></li> + <li>to <em>subscribe</em>: <strong>groupname+subscribe@googlegroups.com</strong></li> + <li>to <em>unsubscribe</em>: <strong>groupname+unsubscribe@googlegroups.com</strong></li> +</ul> + +Easy. +""" + self.assertEqual(expected_xml, self.import_command._glue_xml_lines(xml)) + + class CommandImportWordpressRunTest(BasicCommandImportWordpress): def setUp(self): super(self.__class__, self).setUp() @@ -28,8 +49,7 @@ class CommandImportWordpressRunTest(BasicCommandImportWordpress): self.write_urlmap = mock.MagicMock() self.write_configuration = mock.MagicMock() - site_generation_patch = mock.patch( - 'nikola.plugins.command_import_wordpress.CommandImportWordpress.generate_base_site', self.site_generation) + site_generation_patch = mock.patch('os.system', self.site_generation) data_import_patch = mock.patch( 'nikola.plugins.command_import_wordpress.CommandImportWordpress.import_posts', self.data_import) write_urlmap_patch = mock.patch( @@ -56,14 +76,14 @@ class CommandImportWordpressRunTest(BasicCommandImportWordpress): def test_create_import(self): valid_import_arguments = ( - ['--filename', self.import_filename], - ['-f', self.import_filename, '-o', 'some_folder'], - [self.import_filename], - [self.import_filename, 'folder_argument'], + dict(options={'output_folder': 'some_folder'}, + args=[self.import_filename]), + dict(args=[self.import_filename]), + dict(args=[self.import_filename, 'folder_argument']), ) for arguments in valid_import_arguments: - self.import_command.run(*arguments) + self.import_command.execute(**arguments) self.assertTrue(self.site_generation.called) self.assertTrue(self.data_import.called) @@ -73,29 +93,24 @@ class CommandImportWordpressRunTest(BasicCommandImportWordpress): def test_ignoring_drafts(self): valid_import_arguments = ( - ['--filename', self.import_filename, '--no-drafts'], - ['-f', self.import_filename, '-o', 'some_folder', '-d'], + dict(options={'exclude_drafts': True}, args=[ + self.import_filename]), + dict( + options={'exclude_drafts': True, + 'output_folder': 'some_folder'}, + args=[self.import_filename]), ) for arguments in valid_import_arguments: - self.import_command.run(*arguments) + self.import_command.execute(**arguments) self.assertTrue(self.import_command.exclude_drafts) - def test_getting_help(self): - for arguments in (['-h'], ['--help']): - self.assertRaises(SystemExit, self.import_command.run, *arguments) - - self.assertFalse(self.site_generation.called) - self.assertFalse(self.data_import.called) - self.assertFalse(self.write_urlmap.called) - self.assertFalse(self.write_configuration.called) - class CommandImportWordpressTest(BasicCommandImportWordpress): def test_create_import_work_without_argument(self): # Running this without an argument must not fail. # It should show the proper usage of the command. - self.import_command.run() + self.import_command.execute() def test_populate_context(self): channel = self.import_command.get_channel_from_file( @@ -109,7 +124,7 @@ class CommandImportWordpressTest(BasicCommandImportWordpress): self.assertEqual('Wordpress blog title', context['BLOG_TITLE']) self.assertEqual('Nikola test blog ;) - with moré Ümläüts', context['BLOG_DESCRIPTION']) - self.assertEqual('http://some.blog', context['BLOG_URL']) + self.assertEqual('http://some.blog', context['SITE_URL']) self.assertEqual('mail@some.blog', context['BLOG_EMAIL']) self.assertEqual('Niko', context['BLOG_AUTHOR']) @@ -120,6 +135,8 @@ class CommandImportWordpressTest(BasicCommandImportWordpress): channel) self.import_command.url_map = {} # For testing we use an empty one. self.import_command.output_folder = 'new_site' + self.import_command.squash_newlines = True + self.import_command.no_downloads = False write_metadata = mock.MagicMock() write_content = mock.MagicMock() @@ -142,11 +159,42 @@ class CommandImportWordpressTest(BasicCommandImportWordpress): 'kontakt', '2009-07-16 20:20:32', None, []) self.assertTrue(write_content.called) - write_content.assert_any_call('new_site/posts/200704hoert.wp', 'An image.\n\n\n\n<img class="size-full wp-image-16" title="caption test" src="http://some.blog/wp-content/uploads/2009/07/caption_test.jpg" alt="caption test" width="739" height="517" />\n\n\n\nSome source code.\n\n\n\n\n~~~~~~~~~~~~{.Python}\n\n\nimport sys\n\nprint sys.version\n\n\n~~~~~~~~~~~~\n\n\n\n\nThe end.\n\n') + write_content.assert_any_call('new_site/posts/200704hoert.wp', + """An image. + +<img class="size-full wp-image-16" title="caption test" src="http://some.blog/wp-content/uploads/2009/07/caption_test.jpg" alt="caption test" width="739" height="517" /> + +Some source code. + +~~~~~~~~~~~~{.Python} + +import sys + +print sys.version + +~~~~~~~~~~~~ + +The end. + +""") + write_content.assert_any_call( - 'new_site/posts/200807arzt-und-pfusch-s-i-c-k.wp', '<img class="size-full wp-image-10 alignright" title="Arzt+Pfusch - S.I.C.K." src="http://some.blog/wp-content/uploads/2008/07/arzt_und_pfusch-sick-cover.png" alt="Arzt+Pfusch - S.I.C.K." width="210" height="209" />Arzt+Pfusch - S.I.C.K.Gerade bin ich \xfcber das Album <em>S.I.C.K</em> von <a title="Arzt+Pfusch" href="http://www.arztpfusch.com/" target="_blank">Arzt+Pfusch</a> gestolpert, welches Arzt+Pfusch zum Download f\xfcr lau anbieten. Das Album steht unter einer Creative Commons <a href="http://creativecommons.org/licenses/by-nc-nd/3.0/de/">BY-NC-ND</a>-Lizenz.\n\nDie Ladung <em>noisebmstupidevildustrial</em> gibts als MP3s mit <a href="http://www.archive.org/download/dmp005/dmp005_64kb_mp3.zip">64kbps</a> und <a href="http://www.archive.org/download/dmp005/dmp005_vbr_mp3.zip">VBR</a>, als Ogg Vorbis und als FLAC (letztere <a href="http://www.archive.org/details/dmp005">hier</a>). <a href="http://www.archive.org/download/dmp005/dmp005-artwork.zip">Artwork</a> und <a href="http://www.archive.org/download/dmp005/dmp005-lyrics.txt">Lyrics</a> gibts nochmal einzeln zum Download.') + 'new_site/posts/200807arzt-und-pfusch-s-i-c-k.wp', + '''<img class="size-full wp-image-10 alignright" title="Arzt+Pfusch - S.I.C.K." src="http://some.blog/wp-content/uploads/2008/07/arzt_und_pfusch-sick-cover.png" alt="Arzt+Pfusch - S.I.C.K." width="210" height="209" />Arzt+Pfusch - S.I.C.K.Gerade bin ich \xfcber das Album <em>S.I.C.K</em> von <a title="Arzt+Pfusch" href="http://www.arztpfusch.com/" target="_blank">Arzt+Pfusch</a> gestolpert, welches Arzt+Pfusch zum Download f\xfcr lau anbieten. Das Album steht unter einer Creative Commons <a href="http://creativecommons.org/licenses/by-nc-nd/3.0/de/">BY-NC-ND</a>-Lizenz. +Die Ladung <em>noisebmstupidevildustrial</em> gibts als MP3s mit <a href="http://www.archive.org/download/dmp005/dmp005_64kb_mp3.zip">64kbps</a> und <a href="http://www.archive.org/download/dmp005/dmp005_vbr_mp3.zip">VBR</a>, als Ogg Vorbis und als FLAC (letztere <a href="http://www.archive.org/details/dmp005">hier</a>). <a href="http://www.archive.org/download/dmp005/dmp005-artwork.zip">Artwork</a> und <a href="http://www.archive.org/download/dmp005/dmp005-lyrics.txt">Lyrics</a> gibts nochmal einzeln zum Download.''') write_content.assert_any_call( - 'new_site/stories/kontakt.wp', '<h1>Datenschutz</h1>\n\nIch erhebe und speichere automatisch in meine Server Log Files Informationen, die dein Browser an mich \xfcbermittelt. Dies sind:\n\n<ul>\n\n <li>Browsertyp und -version</li>\n\n <li>verwendetes Betriebssystem</li>\n\n <li>Referrer URL (die zuvor besuchte Seite)</li>\n\n <li>IP Adresse des zugreifenden Rechners</li>\n\n <li>Uhrzeit der Serveranfrage.</li>\n\n</ul>\n\nDiese Daten sind f\xfcr mich nicht bestimmten Personen zuordenbar. Eine Zusammenf\xfchrung dieser Daten mit anderen Datenquellen wird nicht vorgenommen, die Daten werden einzig zu statistischen Zwecken erhoben.') + 'new_site/stories/kontakt.wp', """<h1>Datenschutz</h1> +Ich erhebe und speichere automatisch in meine Server Log Files Informationen, die dein Browser an mich \xfcbermittelt. Dies sind: + +<ul> + <li>Browsertyp und -version</li> + <li>verwendetes Betriebssystem</li> + <li>Referrer URL (die zuvor besuchte Seite)</li> + <li>IP Adresse des zugreifenden Rechners</li> + <li>Uhrzeit der Serveranfrage.</li> +</ul> + +Diese Daten sind f\xfcr mich nicht bestimmten Personen zuordenbar. Eine Zusammenf\xfchrung dieser Daten mit anderen Datenquellen wird nicht vorgenommen, die Daten werden einzig zu statistischen Zwecken erhoben.""") self.assertTrue(len(self.import_command.url_map) > 0) @@ -165,13 +213,16 @@ class CommandImportWordpressTest(BasicCommandImportWordpress): """Applying markup conversions to content.""" transform_sourcecode = mock.MagicMock() transform_caption = mock.MagicMock() + transform_newlines = mock.MagicMock() with mock.patch('nikola.plugins.command_import_wordpress.CommandImportWordpress.transform_sourcecode', transform_sourcecode): with mock.patch('nikola.plugins.command_import_wordpress.CommandImportWordpress.transform_caption', transform_caption): - self.import_command.transform_content("random content") + with mock.patch('nikola.plugins.command_import_wordpress.CommandImportWordpress.transform_multiple_newlines', transform_newlines): + self.import_command.transform_content("random content") self.assertTrue(transform_sourcecode.called) self.assertTrue(transform_caption.called) + self.assertTrue(transform_newlines.called) def test_transforming_source_code(self): """ @@ -226,6 +277,37 @@ asdasdas""" self.assertEqual( expected_content, self.import_command.transform_caption(content)) + def test_transform_multiple_newlines(self): + content = """This + + +has + + + +way to many + +newlines. + + +""" + expected_content = """This + +has + +way to many + +newlines. + +""" + self.import_command.squash_newlines = False + self.assertEqual(content, + self.import_command.transform_multiple_newlines(content)) + + self.import_command.squash_newlines = True + self.assertEqual(expected_content, + self.import_command.transform_multiple_newlines(content)) + def test_transform_caption_with_link_inside(self): content = """[caption caption="Fehlermeldung"]<a href="http://some.blog/openttd-missing_sound.png"><img class="size-thumbnail wp-image-551" title="openttd-missing_sound" src="http://some.blog/openttd-missing_sound-150x150.png" alt="Fehlermeldung" /></a>[/caption]""" transformed_content = self.import_command.transform_caption(content) diff --git a/tests/test_command_init.py b/tests/test_command_init.py index 32ce345..1904fa1 100644 --- a/tests/test_command_init.py +++ b/tests/test_command_init.py @@ -35,27 +35,26 @@ class CommandInitCallTest(unittest.TestCase): del self.create_empty_site def test_init_default(self): - for arguments in (('destination', '--demo'),): - self.init_commad.run(*arguments) + for arguments in (dict(options={'demo': True}, args=['destination']), {}): + self.init_commad.execute(**arguments) self.assertTrue(self.create_configuration.called) self.assertTrue(self.copy_sample_site.called) self.assertFalse(self.create_empty_site.called) def test_init_called_without_target(self): - self.init_commad.run() + self.init_commad.execute() self.assertFalse(self.create_configuration.called) self.assertFalse(self.copy_sample_site.called) self.assertFalse(self.create_empty_site.called) def test_init_empty_dir(self): - for arguments in (('destination', ), ('destination', '--empty')): - self.init_commad.run(*arguments) + self.init_commad.execute(args=['destination']) - self.assertTrue(self.create_configuration.called) - self.assertFalse(self.copy_sample_site.called) - self.assertTrue(self.create_empty_site.called) + self.assertTrue(self.create_configuration.called) + self.assertFalse(self.copy_sample_site.called) + self.assertTrue(self.create_empty_site.called) if __name__ == '__main__': diff --git a/tests/test_integration.py b/tests/test_integration.py index 947a832..c940a07 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -1,13 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals, print_function +import codecs from contextlib import contextmanager import os import shutil import tempfile import unittest +import lxml.html + from context import nikola +from nikola import main @contextmanager @@ -18,56 +22,147 @@ def cd(path): os.chdir(old_dir) -class IntegrationTest(unittest.TestCase): +class EmptyBuildTest(unittest.TestCase): """Basic integration testcase.""" - def setUp(self): + + dataname = None + + @classmethod + def setUpClass(self): """Setup a demo site.""" self.tmpdir = tempfile.mkdtemp() self.target_dir = os.path.join(self.tmpdir, "target") - self.build_command = nikola.plugins.command_build.CommandBuild() self.init_command = nikola.plugins.command_init.CommandInit() - self.init_command.copy_sample_site(self.target_dir) - self.init_command.create_configuration(self.target_dir) + self.fill_site() self.patch_site() self.build() + @classmethod + def fill_site(self): + """Add any needed initial content.""" + self.init_command.create_empty_site(self.target_dir) + self.init_command.create_configuration(self.target_dir) + + if self.dataname: + src = os.path.join(os.path.dirname(__file__), 'data', + self.dataname) + for root, dirs, files in os.walk(src): + for src_name in files: + rel_dir = os.path.relpath(root, src) + dst_file = os.path.join(self.target_dir, rel_dir, src_name) + src_file = os.path.join(root, src_name) + shutil.copy2(src_file, dst_file) + + @classmethod def patch_site(self): """Make any modifications you need to the site.""" - pass + @classmethod def build(self): """Build the site.""" with cd(self.target_dir): - self.build_command.run() + main.main(["build"]) - def tearDown(self): - """Reove the demo site.""" - shutil.rmtree(self.tmpdir) + @classmethod + def tearDownClass(self): + """Remove the demo site.""" + def test_build(self): + """Ensure the build did something.""" + index_path = os.path.join( + self.target_dir, "output", "archive.html") + self.assertTrue(os.path.isfile(index_path)) -class EmptytBuild(IntegrationTest): - """Basic integration testcase.""" - def setUp(self): - """Setup a demo site.""" - self.tmpdir = tempfile.mkdtemp() - self.target_dir = os.path.join(self.tmpdir, "target") - self.build_command = nikola.plugins.command_build.CommandBuild() - self.init_command = nikola.plugins.command_init.CommandInit() - self.init_command.create_empty_site(self.target_dir) + +class DemoBuildTest(EmptyBuildTest): + """Test that a default build of --demo works.""" + + @classmethod + def fill_site(self): + """Fill the site with demo content.""" + self.init_command.copy_sample_site(self.target_dir) self.init_command.create_configuration(self.target_dir) - self.patch_site() - self.build() - def test_deleted_dodo(self): - """Test that a default build of --demo works.""" - # Ensure the temprary dodo file is deleted (Issue #302) - self.assertFalse(os.path.isfile(self.build_command.dodo.name)) +class TranslatedBuildTest(EmptyBuildTest): + """Test a site with translated content.""" -class DefaultBuild(IntegrationTest): - """Test that a default build of --demo works.""" + dataname = "translated_titles" + + def test_translated_titles(self): + """Check that translated title is picked up.""" + en_file = os.path.join(self.target_dir, "output", "stories", "1.html") + es_file = os.path.join(self.target_dir, "output", "es", "stories", "1.html") + # Files should be created + self.assertTrue(os.path.isfile(en_file)) + self.assertTrue(os.path.isfile(es_file)) + # And now let's check the titles + with codecs.open(en_file, 'r', 'utf8') as inf: + doc = lxml.html.parse(inf) + self.assertEqual(doc.find('//title').text, 'Foo | Demo Site') + with codecs.open(es_file, 'r', 'utf8') as inf: + doc = lxml.html.parse(inf) + self.assertEqual(doc.find('//title').text, 'Bar | Demo Site') + + +class RelativeLinkTest(DemoBuildTest): + """Check that SITE_URL with a path doesn't break links.""" + + @classmethod + def patch_site(self): + """Set the SITE_URL to have a path""" + conf_path = os.path.join(self.target_dir, "conf.py") + with codecs.open(conf_path, "rb", "utf-8") as inf: + data = inf.read() + data = data.replace('SITE_URL = "http://nikola.ralsina.com.ar"', + 'SITE_URL = "http://nikola.ralsina.com.ar/foo/bar/"') + with codecs.open(conf_path, "wb+", "utf8") as outf: + outf.write(data) + + def test_relative_links(self): + """Check that the links in output/index.html are correct""" + test_path = os.path.join(self.target_dir, "output", "index.html") + flag = False + with open(test_path, "rb") as inf: + data = inf.read() + for _, _, url, _ in lxml.html.iterlinks(data): + # Just need to be sure this one is ok + if url.endswith("css"): + self.assertFalse(url.startswith("..")) + flag = True + # But I also need to be sure it is there! + self.assertTrue(flag) + + +class RelativeLinkTest2(DemoBuildTest): + """Check that dropping stories to the root doesn't break links.""" + + @classmethod + def patch_site(self): + """Set the SITE_URL to have a path""" + conf_path = os.path.join(self.target_dir, "conf.py") + with codecs.open(conf_path, "rb", "utf-8") as inf: + data = inf.read() + data = data.replace('("stories/*.txt", "stories", "story.tmpl", False),', + '("stories/*.txt", "", "story.tmpl", False),') + data = data.replace('# INDEX_PATH = ""', + 'INDEX_PATH = "blog"') + with codecs.open(conf_path, "wb+", "utf8") as outf: + outf.write(data) + outf.flush() - def test_deleted_dodo(self): - """Test that a default build of --demo works.""" - # Ensure the temprary dodo file is deleted (Issue #302) - self.assertFalse(os.path.isfile(self.build_command.dodo.name)) + def test_relative_links(self): + """Check that the links in a story are correct""" + conf_path = os.path.join(self.target_dir, "conf.py") + data = open(conf_path).read() + test_path = os.path.join(self.target_dir, "output", "about-nikola.html") + flag = False + with open(test_path, "rb") as inf: + data = inf.read() + for _, _, url, _ in lxml.html.iterlinks(data): + # Just need to be sure this one is ok + if url.endswith("css"): + self.assertFalse(url.startswith("..")) + flag = True + # But I also need to be sure it is there! + self.assertTrue(flag) diff --git a/tests/test_rss_feeds.py b/tests/test_rss_feeds.py index ae1cd41..5b9b981 100644 --- a/tests/test_rss_feeds.py +++ b/tests/test_rss_feeds.py @@ -16,11 +16,13 @@ class RSSFeedTest(unittest.TestCase): def setUp(self): self.blog_url = "http://some.blog" - with mock.patch('nikola.nikola.utils.get_meta', - mock.Mock(return_value=('post title', - 'awesome_article', - '2012-10-01 22:41', 'tags', - 'link', 'description'))): + 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', diff --git a/tests/test_utils.py b/tests/test_utils.py index 2cb36a8..4f3fd72 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,9 +1,13 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from context import nikola import unittest import mock +from nikola.post import get_meta + + +class dummy(object): + pass class GetMetaTest(unittest.TestCase): @@ -19,16 +23,19 @@ class GetMetaTest(unittest.TestCase): opener_mock = mock.mock_open(read_data=file_metadata) opener_mock.return_value.readlines.return_value = file_metadata - with mock.patch('nikola.utils.codecs.open', opener_mock, create=True): - (title, slug, date, tags, link, - description) = nikola.utils.get_meta('file_with_metadata') + post = dummy() + post.source_path = 'file_with_metadata' + post.metadata_path = 'file_with_metadata.meta' - self.assertEqual('Nikola needs more tests!', title) - self.assertEqual('write-tests-now', slug) - self.assertEqual('2012/09/15 19:52:05', date) - self.assertEqual('', tags) - self.assertEqual('', link) - self.assertEqual('', description) + with mock.patch('nikola.post.codecs.open', opener_mock, create=True): + meta = get_meta(post) + + self.assertEqual('Nikola needs more tests!', meta['title']) + self.assertEqual('write-tests-now', meta['slug']) + self.assertEqual('2012/09/15 19:52:05', meta['date']) + self.assertFalse('tags' in meta) + self.assertFalse('link' in meta) + self.assertFalse('description' in meta) def test_get_title_from_rest(self): file_metadata = [".. slug: write-tests-now\n", @@ -42,16 +49,19 @@ class GetMetaTest(unittest.TestCase): opener_mock = mock.mock_open(read_data=file_metadata) opener_mock.return_value.readlines.return_value = file_metadata - with mock.patch('nikola.utils.codecs.open', opener_mock, create=True): - (title, slug, date, tags, link, - description) = nikola.utils.get_meta('file_with_metadata') + post = dummy() + post.source_path = 'file_with_metadata' + post.metadata_path = 'file_with_metadata.meta' + + with mock.patch('nikola.post.codecs.open', opener_mock, create=True): + meta = get_meta(post) - self.assertEqual('Post Title', title) - self.assertEqual('write-tests-now', slug) - self.assertEqual('2012/09/15 19:52:05', date) - self.assertEqual('', tags) - self.assertEqual('', link) - self.assertEqual('', description) + self.assertEqual('Post Title', meta['title']) + self.assertEqual('write-tests-now', meta['slug']) + self.assertEqual('2012/09/15 19:52:05', meta['date']) + self.assertFalse('tags' in meta) + self.assertFalse('link' in meta) + self.assertFalse('description' in meta) def test_get_title_from_fname(self): file_metadata = [".. slug: write-tests-now\n", @@ -63,16 +73,19 @@ class GetMetaTest(unittest.TestCase): opener_mock = mock.mock_open(read_data=file_metadata) opener_mock.return_value.readlines.return_value = file_metadata - with mock.patch('nikola.utils.codecs.open', opener_mock, create=True): - (title, slug, date, tags, link, - description) = nikola.utils.get_meta('file_with_metadata') + post = dummy() + post.source_path = 'file_with_metadata' + post.metadata_path = 'file_with_metadata.meta' - self.assertEqual('file_with_metadata', title) - self.assertEqual('write-tests-now', slug) - self.assertEqual('2012/09/15 19:52:05', date) - self.assertEqual('', tags) - self.assertEqual('', link) - self.assertEqual('', description) + with mock.patch('nikola.post.codecs.open', opener_mock, create=True): + meta = get_meta(post, 'file_with_metadata') + + self.assertEqual('file_with_metadata', meta['title']) + self.assertEqual('write-tests-now', meta['slug']) + self.assertEqual('2012/09/15 19:52:05', meta['date']) + self.assertFalse('tags' in meta) + self.assertFalse('link' in meta) + self.assertFalse('description' in meta) def test_use_filename_as_slug_fallback(self): file_metadata = [".. title: Nikola needs more tests!\n", @@ -85,36 +98,40 @@ class GetMetaTest(unittest.TestCase): opener_mock = mock.mock_open(read_data=file_metadata) opener_mock.return_value.readlines.return_value = file_metadata - with mock.patch('nikola.utils.codecs.open', opener_mock, create=True): - (title, slug, date, tags, link, - description) = nikola.utils.get_meta('Slugify this') + post = dummy() + post.source_path = 'Slugify this' + post.metadata_path = 'Slugify this.meta' + + with mock.patch('nikola.post.codecs.open', opener_mock, create=True): + meta = get_meta(post, 'Slugify this') - self.assertEqual('Nikola needs more tests!', title) - self.assertEqual('slugify-this', slug) - self.assertEqual('2012/09/15 19:52:05', date) - self.assertEqual('', tags) - self.assertEqual('', link) - self.assertEqual('', description) + self.assertEqual('Nikola needs more tests!', meta['title']) + self.assertEqual('slugify-this', meta['slug']) + self.assertEqual('2012/09/15 19:52:05', meta['date']) + self.assertFalse('tags' in meta) + self.assertFalse('link' in meta) + self.assertFalse('description' in meta) def test_extracting_metadata_from_filename(self): - with mock.patch('nikola.utils.codecs.open', create=True): - ( - title, slug, date, tags, link, description) = nikola.utils.get_meta('2013-01-23-the_slug-dubdubtitle.md', - '(?P<date>\d{4}-\d{2}-\d{2})-(?P<slug>.*)-(?P<title>.*)\.md') - - self.assertEqual('dubdubtitle', title) - self.assertEqual('the_slug', slug) - self.assertEqual('2013-01-23', date) - self.assertEqual('', tags) - self.assertEqual('', link) - self.assertEqual('', description) + post = dummy() + post.source_path = '2013-01-23-the_slug-dubdubtitle.md' + post.metadata_path = '2013-01-23-the_slug-dubdubtitle.meta' + with mock.patch('nikola.post.codecs.open', create=True): + meta = get_meta(post, + '(?P<date>\d{4}-\d{2}-\d{2})-(?P<slug>.*)-(?P<title>.*)\.md') + + self.assertEqual('dubdubtitle', meta['title']) + self.assertEqual('the_slug', meta['slug']) + self.assertEqual('2013-01-23', meta['date']) def test_get_meta_slug_only_from_filename(self): - with mock.patch('nikola.utils.codecs.open', create=True): - (title, slug, date, tags, link, - description) = nikola.utils.get_meta('some/path/the_slug.md') + post = dummy() + post.source_path = 'some/path/the_slug.md' + post.metadata_path = 'some/path/the_slug.meta' + with mock.patch('nikola.post.codecs.open', create=True): + meta = get_meta(post) - self.assertEqual('the_slug', slug) + self.assertEqual('the_slug', meta['slug']) if __name__ == '__main__': unittest.main() diff --git a/tests/wordpress_export_example.xml b/tests/wordpress_export_example.xml index 8ef1325..e697a5b 100644 --- a/tests/wordpress_export_example.xml +++ b/tests/wordpress_export_example.xml @@ -177,6 +177,58 @@ Diese Daten sind für mich nicht bestimmten Personen zuordenbar. Eine Zusammenf <wp:meta_value><![CDATA[default]]></wp:meta_value> </wp:postmeta> </item> + <item> + <title>Indentation Test + http://some.blog/2012/04/indentation_test/ + Sun, 15 Apr 2012 11:44:59 +0000 + Niko + http://some.blog/?p=2077 + + class Borg: + _state = {} + def __init__(self): + self.__dict__ = self._state +  + +Here is a listing made with HTML that should display without the HTML being visible to the visitor. +
    +
  • to post: groupname@googlegroups.com
  • +
  • to subscribe: groupname+subscribe@googlegroups.com
  • +
  • to unsubscribe: groupname+unsubscribe@googlegroups.com
  • +
+ +A listing with another listing inside. +
    +
  • foo +
      +
    • bar +
    +
+]]>
+ + 2077 + 2012-04-15 12:44:59 + 2012-04-15 11:44:59 + open + open + python-borg-pattern + publish + 0 + 0 + post + + 0 + + + + + _edit_last + + + -- cgit v1.2.3