diff options
Diffstat (limited to 'tests/integration')
24 files changed, 1494 insertions, 0 deletions
diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py new file mode 100644 index 0000000..ee2f4ea --- /dev/null +++ b/tests/integration/__init__.py @@ -0,0 +1,12 @@ +""" +Various integration tests for the Nikola commands. + +Each test module provides a different build fixture that will create a +build in the desired way that then later can be checked in test +functions. +To avoid duplicating code many of the fixtures are shared between +modules. + +The build fixtures are scoped for module level in order to avoid +re-building the whole site for every test and to make these tests fast. +""" diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py new file mode 100644 index 0000000..a87cb07 --- /dev/null +++ b/tests/integration/conftest.py @@ -0,0 +1,74 @@ +import os +import sys + +import docutils +import pytest + +from nikola.utils import LocaleBorg +from ..helper import FakeSite + + +@pytest.fixture(scope="module") +def test_dir(): + """ + Absolute path to the directory with the tests. + """ + return os.path.abspath(os.path.dirname(__file__)) + + +@pytest.fixture(scope="session") +def other_locale() -> str: + return os.environ.get("NIKOLA_LOCALE_OTHER", "pl") + + +@pytest.fixture(scope="module") +def output_dir(target_dir): + return os.path.join(target_dir, "output") + + +@pytest.fixture(scope="module") +def target_dir(tmpdir_factory): + tdir = tmpdir_factory.mktemp("integration").join("target") + yield str(tdir) + + +@pytest.fixture(scope="module", autouse=True) +def remove_conf_module(): + """ + Remove the module `conf` from `sys.modules` after loading the config. + + Fixes issue #438 + """ + try: + yield + finally: + try: + del sys.modules["conf"] + except KeyError: + pass + + +@pytest.fixture(scope="module", autouse=True) +def localeborg_setup(default_locale): + """ + Reset the LocaleBorg before and after every test. + """ + LocaleBorg.reset() + LocaleBorg.initialize({}, default_locale) + try: + yield + finally: + LocaleBorg.reset() + + +@pytest.fixture(autouse=True, scope="module") +def fix_leaked_state(): + """Fix leaked state from integration tests""" + try: + yield + finally: + try: + func = docutils.parsers.rst.roles.role("doc", None, None, None)[0] + func.site = FakeSite() + except AttributeError: + pass diff --git a/tests/integration/helper.py b/tests/integration/helper.py new file mode 100644 index 0000000..c120721 --- /dev/null +++ b/tests/integration/helper.py @@ -0,0 +1,56 @@ +import io +import os +import shutil + +from ..helper import cd + +__all__ = ["add_post_without_text", "append_config", "cd", "create_simple_post", "patch_config"] + + +def add_post_without_text(directory): + """Add a post without text.""" + # File for Issue #374 (empty post text) + create_simple_post(directory, "empty.txt", "foobar") + + +def create_simple_post(directory, filename, title_slug, text='', date='2013-03-06 19:08:15'): + """Create a simple post in a given directory.""" + path = os.path.join(directory, filename) + text_processed = '\n' + text if text else '' + with io.open(path, "w+", encoding="utf8") as outf: + outf.write( + """ +.. title: {0} +.. slug: {0} +.. date: {1} +{2}""".format(title_slug, date, text_processed) + ) + + +def copy_example_post(destination_dir): + """Copy a modified version of the example post into the site.""" + test_dir = os.path.abspath(os.path.dirname(__file__)) + source_file = os.path.join(test_dir, "..", "data", "1-nolinks.rst") + destination = os.path.join(destination_dir, "1.rst") + shutil.copy(source_file, destination) + + +def append_config(config_dir, appendix): + """Append text to the config file.""" + config_path = os.path.join(config_dir, "conf.py") + with io.open(config_path, "a", encoding="utf8") as outf: + outf.write(appendix) + + +def patch_config(config_dir, *replacements): + """Patch the config file with new values (find and replace).""" + config_path = os.path.join(config_dir, "conf.py") + with io.open(config_path, "r", encoding="utf-8") as inf: + data = inf.read() + + for old, new in replacements: + data = data.replace(old, new) + + with io.open(config_path, "w+", encoding="utf8") as outf: + outf.write(data) + outf.flush() diff --git a/tests/integration/test_archive_full.py b/tests/integration/test_archive_full.py new file mode 100644 index 0000000..70d9504 --- /dev/null +++ b/tests/integration/test_archive_full.py @@ -0,0 +1,44 @@ +"""Check that full archives build and are correct.""" + +import os + +import pytest + +from nikola import __main__ + +from .helper import cd, patch_config +from .test_demo_build import prepare_demo_site +from .test_empty_build import ( # NOQA + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) + + +@pytest.mark.parametrize( + "path", + [ + pytest.param(["archive.html"], id="overall"), + pytest.param(["2012", "index.html"], id="year"), + pytest.param(["2012", "03", "index.html"], id="month"), + pytest.param(["2012", "03", "30", "index.html"], id="day"), + ], +) +def test_full_archive(build, output_dir, path): + """Check existance of archive pages""" + expected_path = os.path.join(output_dir, *path) + assert os.path.isfile(expected_path) + + +@pytest.fixture(scope="module") +def build(target_dir): + """Fill the site with demo content and build it.""" + prepare_demo_site(target_dir) + + patch_config( + target_dir, ("# CREATE_FULL_ARCHIVES = False", "CREATE_FULL_ARCHIVES = True") + ) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_archive_per_day.py b/tests/integration/test_archive_per_day.py new file mode 100644 index 0000000..52578a6 --- /dev/null +++ b/tests/integration/test_archive_per_day.py @@ -0,0 +1,36 @@ +"""Check that per-day archives build and are correct.""" + +import os + +import pytest + +from nikola import __main__ + +from .helper import cd, patch_config +from .test_demo_build import prepare_demo_site +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) + + +def test_day_archive(build, output_dir): + """See that it builds""" + archive = os.path.join(output_dir, "2012", "03", "30", "index.html") + assert os.path.isfile(archive) + + +@pytest.fixture(scope="module") +def build(target_dir): + """Fill the site with demo content and build it.""" + prepare_demo_site(target_dir) + + patch_config( + target_dir, ("# CREATE_DAILY_ARCHIVE = False", "CREATE_DAILY_ARCHIVE = True") + ) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_archive_per_month.py b/tests/integration/test_archive_per_month.py new file mode 100644 index 0000000..5f6c94b --- /dev/null +++ b/tests/integration/test_archive_per_month.py @@ -0,0 +1,36 @@ +"""Check that the monthly archives build and are correct.""" + +import os + +import pytest + +from nikola import __main__ + +from .helper import cd, patch_config +from .test_demo_build import prepare_demo_site +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) + + +def test_monthly_archive(build, output_dir): + """Check that the monthly archive is build.""" + assert os.path.isfile(os.path.join(output_dir, "2012", "03", "index.html")) + + +@pytest.fixture(scope="module") +def build(target_dir): + """Fill the site with demo content and build it.""" + prepare_demo_site(target_dir) + + patch_config( + target_dir, + ("# CREATE_MONTHLY_ARCHIVE = False", "CREATE_MONTHLY_ARCHIVE = True"), + ) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_building_in_subdir.py b/tests/integration/test_building_in_subdir.py new file mode 100644 index 0000000..37b2aae --- /dev/null +++ b/tests/integration/test_building_in_subdir.py @@ -0,0 +1,32 @@ +""" +Check that running nikola from subdir works. + +Check whether build works from posts/ +""" + +import os + +import pytest + +from nikola import __main__ + +from .helper import cd +from .test_demo_build import prepare_demo_site +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) + + +@pytest.fixture(scope="module") +def build(target_dir): + """Fill the site with demo content and build it.""" + prepare_demo_site(target_dir) + + build_dir = os.path.join(target_dir, "posts") + + with cd(build_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_category_destpath.py b/tests/integration/test_category_destpath.py new file mode 100644 index 0000000..9defcd3 --- /dev/null +++ b/tests/integration/test_category_destpath.py @@ -0,0 +1,88 @@ +"""Test if category destpath indexes avoid pages.""" + +import os + +import pytest + +import nikola.plugins.command.init +from nikola import __main__ +from nikola.utils import makedirs + +from .helper import append_config, cd, create_simple_post +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) + + +def test_destpath_with_avoidance(build, output_dir): + """Test destpath categories page generation and avoidance.""" + + def _make_output_path(dir, name): + """Make a file path to the output.""" + return os.path.join(dir, name + ".html") + + cat1 = os.path.join(output_dir, "posts", "cat1") + cat2 = os.path.join(output_dir, "posts", "cat2") + + index1 = _make_output_path(cat1, "index") + index2 = _make_output_path(cat2, "index") + + # Do all files exist? + assert os.path.isfile(index1) + assert os.path.isfile(index2) + + # Are their contents correct? + with open(index1, "r", encoding="utf-8") as fh: + page = fh.read() + + assert "Posts about cat1" in page + assert "test-destpath-p1" in page + assert "test-destpath-p2" in page + assert "test-destpath-p3" not in page + + with open(index2, "r", encoding="utf-8") as fh: + page = fh.read() + + assert "Posts about cat2" not in page + assert "This is a post that conflicts with cat2." in page + + +@pytest.fixture(scope="module") +def build(target_dir): + """ + Add subdirectories and create a post in category "cat1" and a page + with the same URL as the category index (created via destpaths). + """ + init_command = nikola.plugins.command.init.CommandInit() + init_command.create_empty_site(target_dir) + init_command.create_configuration(target_dir) + + posts = os.path.join(target_dir, "posts") + cat1 = os.path.join(posts, "cat1") + cat2 = os.path.join(posts, "cat2") + + makedirs(cat1) + makedirs(cat2) + + create_simple_post(cat1, "p1.txt", "test-destpath-p1", "This is a post in cat1.") + create_simple_post(cat1, "p2.txt", "test-destpath-p2", "This is a post in cat1.") + create_simple_post(cat2, "p3.txt", "test-destpath-p3", "This is a post in cat2.") + create_simple_post(posts, "cat2.txt", "cat2", "This is a post that conflicts with cat2.") + + append_config( + target_dir, + """ +PRETTY_URLS = True +CATEGORY_ALLOW_HIERARCHIES = True +CATEGORY_DESTPATH_AS_DEFAULT = True +CATEGORY_DESTPATH_TRIM_PREFIX = True +CATEGORY_PAGES_FOLLOW_DESTPATH = True +""", + ) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_check_absolute_subfolder.py b/tests/integration/test_check_absolute_subfolder.py new file mode 100644 index 0000000..86af065 --- /dev/null +++ b/tests/integration/test_check_absolute_subfolder.py @@ -0,0 +1,50 @@ +""" +Validate links in a site which is: + +* built in URL_TYPE="absolute" +* deployable to a subfolder (BASE_URL="https://example.com/foo/") +""" + +import io +import os + +import pytest + +from nikola import __main__ + +from .helper import cd, patch_config +from .test_demo_build import prepare_demo_site +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, +) + + +def test_index_in_sitemap(build, output_dir): + """ + Test that the correct path is in sitemap, and not the wrong one. + + The correct path ends in /foo/ because this is where we deploy to. + """ + sitemap_path = os.path.join(output_dir, "sitemap.xml") + with io.open(sitemap_path, "r", encoding="utf8") as inf: + sitemap_data = inf.read() + + assert "<loc>https://example.com/foo/</loc>" in sitemap_data + + +@pytest.fixture(scope="module") +def build(target_dir): + """Fill the site with demo content and build it.""" + prepare_demo_site(target_dir) + + patch_config( + target_dir, + ('SITE_URL = "https://example.com/"', 'SITE_URL = "https://example.com/foo/"'), + ("# URL_TYPE = 'rel_path'", "URL_TYPE = 'absolute'"), + ) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_check_failure.py b/tests/integration/test_check_failure.py new file mode 100644 index 0000000..08e9447 --- /dev/null +++ b/tests/integration/test_check_failure.py @@ -0,0 +1,47 @@ +""" +The demo build should pass 'nikola check' and fail with missing files. + +This tests the red path (failures) for the `check` command. +Green path tests (working as expected) can be found in `test_demo_build`. +""" + +import io +import os + +import pytest + +from nikola import __main__ + +from .helper import cd +from .test_demo_build import prepare_demo_site +from .test_empty_build import ( # NOQA + test_avoid_double_slash_in_rss, + test_index_in_sitemap, +) + + +def test_check_links_fail(build, output_dir, target_dir): + os.unlink(os.path.join(output_dir, "archive.html")) + + with cd(target_dir): + result = __main__.main(["check", "-l"]) + assert result != 0 + + +def test_check_files_fail(build, output_dir, target_dir): + manually_added_file = os.path.join(output_dir, "foobar") + with io.open(manually_added_file, "w+", encoding="utf8") as outf: + outf.write("foo") + + with cd(target_dir): + result = __main__.main(["check", "-f"]) + assert result != 0 + + +@pytest.fixture(scope="module") +def build(target_dir): + """Fill the site with demo content and build it.""" + prepare_demo_site(target_dir) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_check_full_path_subfolder.py b/tests/integration/test_check_full_path_subfolder.py new file mode 100644 index 0000000..e678016 --- /dev/null +++ b/tests/integration/test_check_full_path_subfolder.py @@ -0,0 +1,35 @@ +""" +Validate links in a site which is: + +* built in URL_TYPE="full_path" +* deployable to a subfolder (BASE_URL="https://example.com/foo/") +""" + +import pytest + +from nikola import __main__ + +from .helper import cd, patch_config +from .test_check_absolute_subfolder import test_index_in_sitemap # NOQA +from .test_demo_build import prepare_demo_site +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, +) + + +@pytest.fixture(scope="module") +def build(target_dir): + """Fill the site with demo content and build it.""" + prepare_demo_site(target_dir) + + patch_config( + target_dir, + ('SITE_URL = "https://example.com/"', 'SITE_URL = "https://example.com/foo/"'), + ("# URL_TYPE = 'rel_path'", "URL_TYPE = 'full_path'"), + ) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_demo_build.py b/tests/integration/test_demo_build.py new file mode 100644 index 0000000..57a1807 --- /dev/null +++ b/tests/integration/test_demo_build.py @@ -0,0 +1,43 @@ +""" +Test that a default build of a new site based on the demo site works. + +This module also is one place where green path tests (working as +expected) for the `check` command are tested. +In this case these are tested against the demo site with default +settings. +""" + +import os + +import pytest + +import nikola.plugins.command.init +from nikola import __main__ + +from .helper import add_post_without_text, cd, copy_example_post +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) + + +@pytest.fixture(scope="module") +def build(target_dir): + """Fill the site with demo content and build it.""" + prepare_demo_site(target_dir) + + with cd(target_dir): + __main__.main(["build"]) + + +def prepare_demo_site(target_dir): + init_command = nikola.plugins.command.init.CommandInit() + init_command.copy_sample_site(target_dir) + init_command.create_configuration(target_dir) + + posts_dir = os.path.join(target_dir, "posts") + copy_example_post(posts_dir) + add_post_without_text(posts_dir) diff --git a/tests/integration/test_empty_build.py b/tests/integration/test_empty_build.py new file mode 100644 index 0000000..a21bf73 --- /dev/null +++ b/tests/integration/test_empty_build.py @@ -0,0 +1,54 @@ +"""Performaning the build of an empty site.""" + +import io +import os + +import pytest + +import nikola.plugins.command.init +from nikola import __main__ + +from .helper import cd + + +def test_check_links(build, target_dir): + with cd(target_dir): + assert __main__.main(["check", "-l"]) is None + + +def test_check_files(build, target_dir): + with cd(target_dir): + assert __main__.main(["check", "-f"]) is None + + +def test_index_in_sitemap(build, output_dir): + sitemap_path = os.path.join(output_dir, "sitemap.xml") + with io.open(sitemap_path, "r", encoding="utf8") as inf: + sitemap_data = inf.read() + + assert "<loc>https://example.com/</loc>" in sitemap_data + + +def test_avoid_double_slash_in_rss(build, output_dir): + rss_path = os.path.join(output_dir, "rss.xml") + with io.open(rss_path, "r", encoding="utf8") as inf: + rss_data = inf.read() + + assert "https://example.com//" not in rss_data + + +def test_archive_exists(build, output_dir): + """Ensure the build did something.""" + index_path = os.path.join(output_dir, "archive.html") + assert os.path.isfile(index_path) + + +@pytest.fixture(scope="module") +def build(target_dir): + """Build the site.""" + init_command = nikola.plugins.command.init.CommandInit() + init_command.create_empty_site(target_dir) + init_command.create_configuration(target_dir) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_future_post.py b/tests/integration/test_future_post.py new file mode 100644 index 0000000..4645464 --- /dev/null +++ b/tests/integration/test_future_post.py @@ -0,0 +1,109 @@ +"""Test a site with future posts.""" + +import io +import os +from datetime import timedelta + +import pytest + +import nikola +import nikola.plugins.command.init +from nikola.utils import current_time +from nikola import __main__ + +from .helper import append_config, cd +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) + + +def test_future_post_deployment(build, output_dir, target_dir): + """ Ensure that the future post is deleted upon deploying. """ + index_path = os.path.join(output_dir, "index.html") + post_in_past = os.path.join(output_dir, "posts", "foo", "index.html") + post_in_future = os.path.join(output_dir, "posts", "bar", "index.html") + + assert os.path.isfile(index_path) + assert os.path.isfile(post_in_past) + assert os.path.isfile(post_in_future) + + # Run deploy command to see if future post is deleted + with cd(target_dir): + __main__.main(["deploy"]) + + assert os.path.isfile(index_path) + assert os.path.isfile(post_in_past) + assert not os.path.isfile(post_in_future) + + +@pytest.mark.parametrize("filename", ["index.html", "sitemap.xml"]) +def test_future_post_not_in_indexes(build, output_dir, filename): + """ Ensure that the future post is not present in the index and sitemap.""" + filepath = os.path.join(output_dir, filename) + assert os.path.isfile(filepath) + + with io.open(filepath, "r", encoding="utf8") as inf: + content = inf.read() + assert "foo/" in content + assert "bar/" not in content + assert "baz" not in content + + +@pytest.fixture(scope="module") +def build(target_dir): + """Build the site.""" + init_command = nikola.plugins.command.init.CommandInit() + init_command.create_empty_site(target_dir) + init_command.create_configuration(target_dir) + + # Change COMMENT_SYSTEM_ID to not wait for 5 seconds + append_config(target_dir, '\nCOMMENT_SYSTEM_ID = "nikolatest"\n') + + def format_datetime(datetime): + return datetime.strftime("%Y-%m-%d %H:%M:%S") + + past_datetime = format_datetime(current_time() + timedelta(days=-1)) + with io.open( + os.path.join(target_dir, "posts", "empty1.txt"), "w+", encoding="utf8" + ) as past_post: + past_post.write( + """\ +.. title: foo +.. slug: foo +.. date: %s +""" + % past_datetime + ) + + future_datetime = format_datetime(current_time() + timedelta(days=1)) + with io.open( + os.path.join(target_dir, "posts", "empty2.txt"), "w+", encoding="utf8" + ) as future_post: + future_post.write( + """\ +.. title: bar +.. slug: bar +.. date: %s +""" + % future_datetime + ) + + with io.open( + os.path.join(target_dir, "posts", "empty3.txt"), "w+", encoding="utf8" + ) as future_post: + future_post.write( + """\ +.. title: baz +.. slug: baz +.. date: %s +.. pretty_url: false +""" + % future_datetime + ) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_page_index_normal_urls.py b/tests/integration/test_page_index_normal_urls.py new file mode 100644 index 0000000..4dbedfd --- /dev/null +++ b/tests/integration/test_page_index_normal_urls.py @@ -0,0 +1,238 @@ +"""Test if PAGE_INDEX works, with different PRETTY_URLS=False settings.""" + +import io +import os + +import pytest + +import nikola.plugins.command.init +from nikola import __main__ +from nikola.utils import makedirs + +from .helper import append_config, cd +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) + + +def get_last_folder_as_id(value): + """Use the last part of the directories as test identifier.""" + if isinstance(value, (tuple,)): + return value[-1] + + return value + + +@pytest.mark.parametrize( + "dirs, expected_file", + [ + (("pages",), "page0"), + (("pages", "subdir1"), "page1"), + (("pages", "subdir1"), "page2"), + (("pages", "subdir2"), "page3"), + (("pages", "subdir3"), "page4"), + ], + ids=get_last_folder_as_id, +) +def test_page_index(build, output_dir, dirs, expected_file, output_path_func): + """Test PAGE_INDEX - Do all files exist?""" + path_func = output_path_func + + checkdir = os.path.join(output_dir, *dirs) + + assert os.path.isfile(path_func(checkdir, expected_file)) + + +@pytest.mark.parametrize( + "dirs, expected_index_file", + [ + (("pages",), "index.html"), + (("pages", "subdir1"), "index.html"), + (("pages", "subdir2"), "index.html"), + (("pages", "subdir3"), "index.php"), + ], + ids=get_last_folder_as_id, +) +def test_page_index_in_subdir(build, output_dir, dirs, expected_index_file): + """Test PAGE_INDEX - Do index files in subdir exist?""" + checkdir = os.path.join(output_dir, *dirs) + + assert os.path.isfile(os.path.join(checkdir, expected_index_file)) + if expected_index_file == "index.php": + assert not os.path.isfile(os.path.join(checkdir, "index.html")) + + +@pytest.fixture(scope="module") +def output_path_func(): + def output_path(dir, name): + """Make a file path to the output.""" + return os.path.join(dir, name + ".html") + + return output_path + + +def test_page_index_content_in_pages(build, output_dir): + """Do the indexes only contain the pages the should?""" + pages = os.path.join(output_dir, "pages") + + with io.open(os.path.join(pages, "index.html"), "r", encoding="utf-8") as fh: + pages_index = fh.read() + + assert "Page 0" in pages_index + assert "Page 1" not in pages_index + assert "Page 2" not in pages_index + assert "Page 3" not in pages_index + assert "Page 4" not in pages_index + assert "This is not the page index" not in pages_index + + +def test_page_index_content_in_subdir1(build, output_dir): + """Do the indexes only contain the pages the should?""" + subdir1 = os.path.join(output_dir, "pages", "subdir1") + + with io.open(os.path.join(subdir1, "index.html"), "r", encoding="utf-8") as fh: + subdir1_index = fh.read() + + assert "Page 0" not in subdir1_index + assert "Page 1" in subdir1_index + assert "Page 2" in subdir1_index + assert "Page 3" not in subdir1_index + assert "Page 4" not in subdir1_index + assert "This is not the page index" not in subdir1_index + + +def test_page_index_content_in_subdir2(build, output_dir): + """Do the indexes only contain the pages the should?""" + subdir2 = os.path.join(output_dir, "pages", "subdir2") + + with io.open(os.path.join(subdir2, "index.html"), "r", encoding="utf-8") as fh: + subdir2_index = fh.read() + + assert "Page 0" not in subdir2_index + assert "Page 1" not in subdir2_index + assert "Page 2" not in subdir2_index + assert "Page 3" not in subdir2_index + assert "Page 4" not in subdir2_index + assert "This is not the page index." in subdir2_index + + +def test_page_index_content_in_subdir3(build, output_dir): + """Do the indexes only contain the pages the should?""" + subdir3 = os.path.join(output_dir, "pages", "subdir3") + + with io.open(os.path.join(subdir3, "index.php"), "r", encoding="utf-8") as fh: + subdir3_index = fh.read() + + assert "Page 0" not in subdir3_index + assert "Page 1" not in subdir3_index + assert "Page 2" not in subdir3_index + assert "Page 3" not in subdir3_index + assert "Page 4" not in subdir3_index + assert "This is not the page index either." in subdir3_index + + +@pytest.fixture(scope="module") +def build(target_dir): + """Build the site.""" + init_command = nikola.plugins.command.init.CommandInit() + init_command.create_empty_site(target_dir) + init_command.create_configuration(target_dir) + + create_pages(target_dir) + + append_config( + target_dir, + """ +PAGE_INDEX = True +PRETTY_URLS = False +PAGES = PAGES + (('pages/*.php', 'pages', 'page.tmpl'),) +""", + ) + + with cd(target_dir): + __main__.main(["build"]) + + +def create_pages(target_dir): + pages = os.path.join(target_dir, "pages") + subdir1 = os.path.join(target_dir, "pages", "subdir1") + subdir2 = os.path.join(target_dir, "pages", "subdir2") + subdir3 = os.path.join(target_dir, "pages", "subdir3") + + makedirs(subdir1) + makedirs(subdir2) + makedirs(subdir3) + + with io.open(os.path.join(pages, "page0.txt"), "w+", encoding="utf8") as outf: + outf.write( + """\ +.. title: Page 0 +.. slug: page0 + +This is page 0. +""" + ) + + with io.open(os.path.join(subdir1, "page1.txt"), "w+", encoding="utf8") as outf: + outf.write( + """\ +.. title: Page 1 +.. slug: page1 + +This is page 1. +""" + ) + + with io.open(os.path.join(subdir1, "page2.txt"), "w+", encoding="utf8") as outf: + outf.write( + """\ +.. title: Page 2 +.. slug: page2 + +This is page 2. +""" + ) + + with io.open(os.path.join(subdir2, "page3.txt"), "w+", encoding="utf8") as outf: + outf.write( + """\ +.. title: Page 3 +.. slug: page3 + +This is page 3. +""" + ) + + with io.open(os.path.join(subdir2, "foo.txt"), "w+", encoding="utf8") as outf: + outf.write( + """\ +.. title: Not the page index +.. slug: index + +This is not the page index. +""" + ) + + with io.open(os.path.join(subdir3, "page4.txt"), "w+", encoding="utf8") as outf: + outf.write( + """\ +.. title: Page 4 +.. slug: page4 + +This is page 4. +""" + ) + + with io.open(os.path.join(subdir3, "bar.php"), "w+", encoding="utf8") as outf: + outf.write( + """\ +.. title: Still not the page index +.. slug: index + +This is not the page index either. +""" + ) diff --git a/tests/integration/test_page_index_pretty_urls.py b/tests/integration/test_page_index_pretty_urls.py new file mode 100644 index 0000000..b31680f --- /dev/null +++ b/tests/integration/test_page_index_pretty_urls.py @@ -0,0 +1,57 @@ +"""Test if PAGE_INDEX works, with different PRETTY_URLS=True.""" + +import os + +import pytest + +import nikola.plugins.command.init +from nikola import __main__ + +from .helper import append_config, cd +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) +from .test_page_index_normal_urls import create_pages +from .test_page_index_normal_urls import ( # NOQA + test_page_index, + test_page_index_in_subdir, + test_page_index_content_in_pages, + test_page_index_content_in_subdir1, + test_page_index_content_in_subdir2, + test_page_index_content_in_subdir3, +) + + +@pytest.fixture(scope="module") +def output_path_func(): + def output_path(dir, name): + """Make a file path to the output.""" + return os.path.join(dir, name + "/index.html") + + return output_path + + +@pytest.fixture(scope="module") +def build(target_dir): + """Build the site.""" + init_command = nikola.plugins.command.init.CommandInit() + init_command.create_empty_site(target_dir) + init_command.create_configuration(target_dir) + + create_pages(target_dir) + + append_config( + target_dir, + """ +PAGE_INDEX = True +PRETTY_URLS = True +PAGES = PAGES + (('pages/*.php', 'pages', 'page.tmpl'),) +""", + ) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_redirection.py b/tests/integration/test_redirection.py new file mode 100644 index 0000000..323740d --- /dev/null +++ b/tests/integration/test_redirection.py @@ -0,0 +1,106 @@ +""" +Check REDIRECTIONS. + +This module tests absolute, external and relative redirects. +Each of the different redirect types is specified in the config and +then tested by at least one test.""" + +import io +import os + +import pytest + +import nikola.plugins.command.init +from nikola import __main__ + +from .helper import append_config, cd +from .test_demo_build import prepare_demo_site +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) + + +def test_absolute_redirection(build, output_dir): + abs_source = os.path.join(output_dir, "redirects", "absolute_source.html") + assert os.path.exists(abs_source) + + abs_destination = os.path.join(output_dir, "posts", "absolute.html") + assert os.path.exists(abs_destination) + + with open(abs_destination) as abs_destination_fd: + abs_destination_content = abs_destination_fd.read() + + redirect_tag = '<meta http-equiv="refresh" content="0; url=/redirects/absolute_source.html">' + assert redirect_tag in abs_destination_content + + with open(abs_source) as abs_source_fd: + absolute_source_content = abs_source_fd.read() + + assert absolute_source_content == "absolute" + + +def test_external_redirection(build, output_dir): + ext_link = os.path.join(output_dir, "external.html") + + assert os.path.exists(ext_link) + with open(ext_link) as ext_link_fd: + ext_link_content = ext_link_fd.read() + + redirect_tag = '<meta http-equiv="refresh" content="0; url=http://www.example.com/">' + assert redirect_tag in ext_link_content + + +def test_relative_redirection(build, output_dir): + rel_destination = os.path.join(output_dir, "relative.html") + assert os.path.exists(rel_destination) + rel_source = os.path.join(output_dir, "redirects", "rel_src.html") + assert os.path.exists(rel_source) + + with open(rel_destination) as rel_destination_fd: + rel_destination_content = rel_destination_fd.read() + + redirect_tag = '<meta http-equiv="refresh" content="0; url=redirects/rel_src.html">' + assert redirect_tag in rel_destination_content + + with open(rel_source) as rel_source_fd: + rel_source_content = rel_source_fd.read() + + assert rel_source_content == "relative" + + +@pytest.fixture(scope="module") +def build(target_dir): + """Fill the site with demo content and build it.""" + prepare_demo_site(target_dir) + + redirects_dir = os.path.join(target_dir, "files", "redirects") + nikola.utils.makedirs(redirects_dir) + + # Source file for absolute redirect + target_path = os.path.join(redirects_dir, "absolute_source.html") + with io.open(target_path, "w+", encoding="utf8") as outf: + outf.write("absolute") + + # Source file for relative redirect + target_path = os.path.join(redirects_dir, "rel_src.html") + with io.open(target_path, "w+", encoding="utf8") as outf: + outf.write("relative") + + # Configure usage of specific redirects + append_config( + target_dir, + """ +REDIRECTIONS = [ + ("posts/absolute.html", "/redirects/absolute_source.html"), + ("external.html", "http://www.example.com/"), + ("relative.html", "redirects/rel_src.html"), +] +""", + ) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_relative_links.py b/tests/integration/test_relative_links.py new file mode 100644 index 0000000..3b158cf --- /dev/null +++ b/tests/integration/test_relative_links.py @@ -0,0 +1,60 @@ +"""Check that SITE_URL with a path doesn't break links.""" + +import io +import os + +import lxml +import pytest + +from nikola import __main__ + +from .helper import cd, patch_config +from .test_demo_build import prepare_demo_site +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, +) + + +def test_relative_links(build, output_dir): + """Check that the links in output/index.html are correct""" + test_path = os.path.join(output_dir, "index.html") + + with io.open(test_path, "rb") as inf: + data = inf.read() + + assert not any( + url.startswith("..") + for _, _, url, _ in lxml.html.iterlinks(data) + if url.endswith("css") + ) + + +def test_index_in_sitemap(build, output_dir): + """Test that the correct path is in sitemap, and not the wrong one.""" + sitemap_path = os.path.join(output_dir, "sitemap.xml") + with io.open(sitemap_path, "r", encoding="utf8") as inf: + sitemap_data = inf.read() + + assert "<loc>https://example.com/</loc>" not in sitemap_data + assert "<loc>https://example.com/foo/bar/</loc>" in sitemap_data + + +@pytest.fixture(scope="module") +def build(target_dir): + """Fill the site with demo content and build it.""" + prepare_demo_site(target_dir) + + # Set the SITE_URL to have a path with subfolder + patch_config( + target_dir, + ( + 'SITE_URL = "https://example.com/"', + 'SITE_URL = "https://example.com/foo/bar/"', + ), + ) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_relative_links_with_pages_in_root.py b/tests/integration/test_relative_links_with_pages_in_root.py new file mode 100644 index 0000000..16f9d6f --- /dev/null +++ b/tests/integration/test_relative_links_with_pages_in_root.py @@ -0,0 +1,65 @@ +"""Check that dropping pages to the root doesn't break links.""" + +import io +import os + +import lxml +import pytest + +from nikola import __main__ + +from .helper import append_config, cd, patch_config +from .test_demo_build import prepare_demo_site +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, +) + + +def test_relative_links(build, output_dir): + """Check that the links in a page are correct""" + test_path = os.path.join(output_dir, "about-nikola.html") + + with io.open(test_path, "rb") as inf: + data = inf.read() + + assert not any( + url.startswith("..") + for _, _, url, _ in lxml.html.iterlinks(data) + if url.endswith("css") + ) + + +def test_index_in_sitemap(build, output_dir): + """Test that the correct path is in sitemap, and not the wrong one.""" + sitemap_path = os.path.join(output_dir, "sitemap.xml") + with io.open(sitemap_path, "r", encoding="utf8") as inf: + sitemap_data = inf.read() + + assert "<loc>https://example.com/</loc>" not in sitemap_data + assert "<loc>https://example.com/blog/index.html</loc>" in sitemap_data + + +@pytest.fixture(scope="module") +def build(target_dir): + """Fill the site with demo content and build it.""" + prepare_demo_site(target_dir) + + # Configure our pages to reside in the root + patch_config( + target_dir, + ('("pages/*.txt", "pages", "page.tmpl"),', '("pages/*.txt", "", "page.tmpl"),'), + ('("pages/*.rst", "pages", "page.tmpl"),', '("pages/*.rst", "", "page.tmpl"),'), + ('# INDEX_PATH = ""', 'INDEX_PATH = "blog"'), + ) + append_config( + target_dir, + """ +PRETTY_URLS = False +STRIP_INDEXES = False +""", + ) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_repeated_posts_setting.py b/tests/integration/test_repeated_posts_setting.py new file mode 100644 index 0000000..2a03338 --- /dev/null +++ b/tests/integration/test_repeated_posts_setting.py @@ -0,0 +1,36 @@ +""" +Duplicate POSTS in settings. + +Should not read each post twice, which causes conflicts. +""" + +import pytest + +from nikola import __main__ + +from .helper import append_config, cd +from .test_demo_build import prepare_demo_site +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) + + +@pytest.fixture(scope="module") +def build(target_dir): + """Fill the site with demo content and build it.""" + prepare_demo_site(target_dir) + + append_config( + target_dir, + """ +POSTS = (("posts/*.txt", "posts", "post.tmpl"), + ("posts/*.txt", "posts", "post.tmpl")) +""", + ) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_translated_content.py b/tests/integration/test_translated_content.py new file mode 100644 index 0000000..9d1338f --- /dev/null +++ b/tests/integration/test_translated_content.py @@ -0,0 +1,62 @@ +""" +Test a site with translated content. + +Do not test titles as we remove the translation. +""" + +import io +import os +import shutil + +import lxml.html +import pytest + +import nikola.plugins.command.init +from nikola import __main__ + +from .helper import cd +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) + + +def test_translated_titles(build, output_dir, other_locale): + """Check that translated title is picked up.""" + normal_file = os.path.join(output_dir, "pages", "1", "index.html") + translated_file = os.path.join(output_dir, other_locale, "pages", "1", "index.html") + + # Files should be created + assert os.path.isfile(normal_file) + assert os.path.isfile(translated_file) + + # And now let's check the titles + with io.open(normal_file, "r", encoding="utf8") as inf: + doc = lxml.html.parse(inf) + assert doc.find("//title").text == "Foo | Demo Site" + + with io.open(translated_file, "r", encoding="utf8") as inf: + doc = lxml.html.parse(inf) + assert doc.find("//title").text == "Bar | Demo Site" + + +@pytest.fixture(scope="module") +def build(target_dir, test_dir): + """Build the site.""" + init_command = nikola.plugins.command.init.CommandInit() + init_command.create_empty_site(target_dir) + init_command.create_configuration(target_dir) + + src = os.path.join(test_dir, "..", "data", "translated_titles") + 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(target_dir, rel_dir, src_name) + src_file = os.path.join(root, src_name) + shutil.copy2(src_file, dst_file) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_translated_content_secondary_language.py b/tests/integration/test_translated_content_secondary_language.py new file mode 100644 index 0000000..f826d1d --- /dev/null +++ b/tests/integration/test_translated_content_secondary_language.py @@ -0,0 +1,40 @@ +"""Make sure posts only in secondary languages work.""" + +import os +import shutil + +import pytest + +import nikola.plugins.command.init +from nikola import __main__ + +from .helper import cd +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) + + +@pytest.fixture(scope="module") +def build(target_dir, test_dir): + """Build the site.""" + init_command = nikola.plugins.command.init.CommandInit() + init_command.create_empty_site(target_dir) + init_command.create_configuration(target_dir) + + src = os.path.join(test_dir, "..", "data", "translated_titles") + for root, dirs, files in os.walk(src): + for src_name in files: + if src_name == "1.txt": # English post + continue + + rel_dir = os.path.relpath(root, src) + dst_file = os.path.join(target_dir, rel_dir, src_name) + src_file = os.path.join(root, src_name) + shutil.copy2(src_file, dst_file) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_translation_patterns.py b/tests/integration/test_translation_patterns.py new file mode 100644 index 0000000..6f77960 --- /dev/null +++ b/tests/integration/test_translation_patterns.py @@ -0,0 +1,55 @@ +"""Check that the path.lang.ext TRANSLATIONS_PATTERN works too""" + +import os +import shutil + +import pytest + +import nikola.plugins.command.init +from nikola import __main__ + +from .helper import cd, patch_config +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, + test_check_links, + test_index_in_sitemap, +) +from .test_translated_content import test_translated_titles # NOQA + + +@pytest.fixture(scope="module") +def build(target_dir, test_dir, other_locale): + """ + Build the site. + + Set the TRANSLATIONS_PATTERN to the old v6 default. + """ + init_command = nikola.plugins.command.init.CommandInit() + init_command.create_empty_site(target_dir) + init_command.create_configuration(target_dir) + + src = os.path.join(test_dir, "..", "data", "translated_titles") + 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(target_dir, rel_dir, src_name) + src_file = os.path.join(root, src_name) + shutil.copy2(src_file, dst_file) + + os.rename( + os.path.join(target_dir, "pages", "1.%s.txt" % other_locale), + os.path.join(target_dir, "pages", "1.txt.%s" % other_locale), + ) + + patch_config( + target_dir, + ( + 'TRANSLATIONS_PATTERN = "{path}.{lang}.{ext}"', + 'TRANSLATIONS_PATTERN = "{path}.{ext}.{lang}"', + ), + ) + + with cd(target_dir): + __main__.main(["build"]) diff --git a/tests/integration/test_wordpress_import.py b/tests/integration/test_wordpress_import.py new file mode 100644 index 0000000..6d3bfb8 --- /dev/null +++ b/tests/integration/test_wordpress_import.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +""" +Testing the wordpress import. + +It will do create a new site with the import_wordpress command +and use that newly created site to make a build. +""" + +import os.path +from glob import glob + +import pytest + +from nikola import __main__ + +from .helper import cd +from .test_empty_build import ( # NOQA + test_archive_exists, + test_avoid_double_slash_in_rss, + test_check_files, +) + + +def test_import_created_files(build, target_dir): + assert os.path.exists(target_dir) + assert os.path.exists(os.path.join(target_dir, "conf.py")) + + +@pytest.mark.parametrize("dirname", ["pages", "posts"]) +def test_filled_directories(build, target_dir, dirname): + folder = os.path.join(target_dir, dirname) + assert os.path.isdir(folder) + content = glob(os.path.join(folder, "**"), recursive=True) + assert any(os.path.isfile(element) for element in content) + + +@pytest.fixture(scope="module") +def build(target_dir, import_file): + __main__.main( + [ + "import_wordpress", + "--no-downloads", + "--output-folder", + target_dir, + import_file, + ] + ) + + with cd(target_dir): + result = __main__.main(["build"]) + assert not result + + +@pytest.fixture(scope="module") +def import_file(test_dir): + """Path to the Wordpress export file.""" + return os.path.join( + test_dir, "..", "data", "wordpress_import", "wordpress_export_example.xml" + ) |
