Skip to content

Commit

Permalink
Move fake content under a subdirectory
Browse files Browse the repository at this point in the history
Relying on tmp is not portable. Populating the true temporary directory
is redundant and may cause more problems because of nested directories.
  • Loading branch information
MarkKoz committed Jun 4, 2021
1 parent 4575bff commit 9d59fd5
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 58 deletions.
65 changes: 30 additions & 35 deletions pydis_site/apps/content/tests/helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import tempfile
from pathlib import Path

from pyfakefs import fake_filesystem_unittest


# Set the module constant within Patcher to use the fake filesystem
# https://jmcgeheeiv.github.io/pyfakefs/master/usage.html#modules-to-reload
with fake_filesystem_unittest.Patcher() as _:
BASE_PATH = Path("res")

from pyfakefs.fake_filesystem_unittest import TestCase

# Valid markdown content with YAML metadata
MARKDOWN_WITH_METADATA = """
Expand Down Expand Up @@ -43,11 +50,11 @@
PARSED_CATEGORY_INFO = {"title": "Category Name", "description": "Description"}


class MockPagesTestCase(TestCase):
class MockPagesTestCase(fake_filesystem_unittest.TestCase):
"""
TestCase with a fake filesystem for testing.
Structure:
Structure (relative to BASE_PATH):
├── _info.yml
├── root.md
├── root_without_metadata.md
Expand All @@ -70,39 +77,27 @@ def setUp(self):
"""Create the fake filesystem."""
self.setUpPyfakefs()

self.fs.create_file("_info.yml", contents=CATEGORY_INFO)
self.fs.create_file("root.md", contents=MARKDOWN_WITH_METADATA)
self.fs.create_file("root_without_metadata.md", contents=MARKDOWN_WITHOUT_METADATA)
self.fs.create_file("not_a_page.md/_info.yml", contents=CATEGORY_INFO)
self.fs.create_file("category/_info.yml", contents=CATEGORY_INFO)
self.fs.create_file("category/with_metadata.md", contents=MARKDOWN_WITH_METADATA)
self.fs.create_file("category/subcategory/_info.yml", contents=CATEGORY_INFO)
self.fs.create_file(f"{BASE_PATH}/_info.yml", contents=CATEGORY_INFO)
self.fs.create_file(f"{BASE_PATH}/root.md", contents=MARKDOWN_WITH_METADATA)
self.fs.create_file(
f"{BASE_PATH}/root_without_metadata.md", contents=MARKDOWN_WITHOUT_METADATA
)
self.fs.create_file(f"{BASE_PATH}/not_a_page.md/_info.yml", contents=CATEGORY_INFO)
self.fs.create_file(f"{BASE_PATH}/category/_info.yml", contents=CATEGORY_INFO)
self.fs.create_file(
f"{BASE_PATH}/category/with_metadata.md", contents=MARKDOWN_WITH_METADATA
)
self.fs.create_file(f"{BASE_PATH}/category/subcategory/_info.yml", contents=CATEGORY_INFO)
self.fs.create_file(
"category/subcategory/with_metadata.md", contents=MARKDOWN_WITH_METADATA
f"{BASE_PATH}/category/subcategory/with_metadata.md", contents=MARKDOWN_WITH_METADATA
)
self.fs.create_file(
"category/subcategory/without_metadata.md", contents=MARKDOWN_WITHOUT_METADATA
f"{BASE_PATH}/category/subcategory/without_metadata.md",
contents=MARKDOWN_WITHOUT_METADATA
)

# There is always a `tmp` directory in the filesystem, so make it a category
# for testing purposes.
# See: https://jmcgeheeiv.github.io/pyfakefs/release/usage.html#os-temporary-directories
self.populate_tempdir('tmp')

# Some systems do not use `/tmp` as their temporary directory, such as macOS,
# which means that we will have an additional folder in the root directory
# to deal with. To prevent this from causing any errors during tests, we
# also populate the platform-specific temp directory. It is populated in
# addition to `/tmp`, as some files are tested in `/tmp`.
_, tmpname, *_rest = tempfile.gettempdir().split('/')
if tmpname != 'tmp': # pragma: no cover - platform-specific
self.populate_tempdir(tmpname)

self.os_tmpname = tmpname

def populate_tempdir(self, name: str) -> None:
"""Populate contents of the OS temp directory."""
self.fs.create_file(f"{name}/_info.yml", contents=CATEGORY_INFO)
self.fs.create_file(f"{name}.md", contents=MARKDOWN_WITH_METADATA)
self.fs.create_file(f"{name}/category/_info.yml", contents=CATEGORY_INFO)
self.fs.create_dir(f"{name}/category/subcategory_without_info")
temp = f"{BASE_PATH}/tmp" # noqa: S108
self.fs.create_file(f"{temp}/_info.yml", contents=CATEGORY_INFO)
self.fs.create_file(f"{temp}.md", contents=MARKDOWN_WITH_METADATA)
self.fs.create_file(f"{temp}/category/_info.yml", contents=CATEGORY_INFO)
self.fs.create_dir(f"{temp}/category/subcategory_without_info")
26 changes: 12 additions & 14 deletions pydis_site/apps/content/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,54 @@

from pydis_site.apps.content import utils
from pydis_site.apps.content.tests.helpers import (
MockPagesTestCase, PARSED_CATEGORY_INFO, PARSED_HTML, PARSED_METADATA
BASE_PATH, MockPagesTestCase, PARSED_CATEGORY_INFO, PARSED_HTML, PARSED_METADATA
)


class GetCategoryTests(MockPagesTestCase):
"""Tests for the get_category function."""

def test_get_valid_category(self):
result = utils.get_category(Path("category"))
result = utils.get_category(Path(BASE_PATH, "category"))

self.assertEqual(result, {"title": "Category Name", "description": "Description"})

def test_get_nonexistent_category(self):
with self.assertRaises(Http404):
utils.get_category(Path("invalid"))
utils.get_category(Path(BASE_PATH, "invalid"))

def test_get_category_with_path_to_file(self):
# Valid categories are directories, not files
with self.assertRaises(Http404):
utils.get_category(Path("root.md"))
utils.get_category(Path(BASE_PATH, "root.md"))

def test_get_category_without_info_yml(self):
# Categories should provide an _info.yml file
with self.assertRaises(FileNotFoundError):
utils.get_category(Path("tmp/category/subcategory_without_info"))
utils.get_category(Path(BASE_PATH, "tmp/category/subcategory_without_info"))


class GetCategoriesTests(MockPagesTestCase):
"""Tests for the get_categories function."""

def test_get_root_categories(self):
result = utils.get_categories(Path("."))
result = utils.get_categories(BASE_PATH)

info = PARSED_CATEGORY_INFO
categories = {
"category": info,
"tmp": info,
# "tmp" on Linux, "var" on macOS.
self.os_tmpname: info,
"not_a_page.md": info,
}
self.assertEqual(result, categories)

def test_get_categories_with_subcategories(self):
result = utils.get_categories(Path("category"))
result = utils.get_categories(Path(BASE_PATH, "category"))

self.assertEqual(result, {"subcategory": PARSED_CATEGORY_INFO})

def test_get_categories_without_subcategories(self):
result = utils.get_categories(Path("category/subcategory"))
result = utils.get_categories(Path(BASE_PATH, "category/subcategory"))

self.assertEqual(result, {})

Expand All @@ -63,14 +61,14 @@ class GetCategoryPagesTests(MockPagesTestCase):

def test_get_pages_in_root_category_successfully(self):
"""The method should successfully retrieve page metadata."""
root_category_pages = utils.get_category_pages(Path("."))
root_category_pages = utils.get_category_pages(BASE_PATH)
self.assertEqual(
root_category_pages, {"root": PARSED_METADATA, "root_without_metadata": {}}
)

def test_get_pages_in_subcategories_successfully(self):
"""The method should successfully retrieve page metadata."""
category_pages = utils.get_category_pages(Path("category"))
category_pages = utils.get_category_pages(Path(BASE_PATH, "category"))

# Page metadata is properly retrieved
self.assertEqual(category_pages, {"with_metadata": PARSED_METADATA})
Expand All @@ -91,10 +89,10 @@ def test_get_page(self):

for msg, page_path, expected_html, expected_metadata in cases:
with self.subTest(msg=msg):
html, metadata = utils.get_page(Path(page_path))
html, metadata = utils.get_page(Path(BASE_PATH, page_path))
self.assertEqual(html, expected_html)
self.assertEqual(metadata, expected_metadata)

def test_get_nonexistent_page_returns_404(self):
with self.assertRaises(Http404):
utils.get_page(Path("invalid"))
utils.get_page(Path(BASE_PATH, "invalid"))
11 changes: 2 additions & 9 deletions pydis_site/apps/content/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,20 @@

from django.http import Http404
from django.test import RequestFactory, SimpleTestCase, override_settings
from pyfakefs import fake_filesystem_unittest

from pydis_site.apps.content.tests.helpers import (
MockPagesTestCase, PARSED_CATEGORY_INFO, PARSED_HTML, PARSED_METADATA
BASE_PATH, MockPagesTestCase, PARSED_CATEGORY_INFO, PARSED_HTML, PARSED_METADATA
)
from pydis_site.apps.content.views import PageOrCategoryView


# Set the module constant within Patcher to use the fake filesystem
# https://jmcgeheeiv.github.io/pyfakefs/master/usage.html#modules-to-reload
with fake_filesystem_unittest.Patcher() as _:
BASE_PATH = Path(".")


def patch_dispatch_attributes(view: PageOrCategoryView, location: str) -> None:
"""
Set the attributes set in the `dispatch` method manually.
This is necessary because it is never automatically called during tests.
"""
view.location = Path(location)
view.location = Path(BASE_PATH, location)

# URL location on the filesystem
view.full_location = view.location
Expand Down

0 comments on commit 9d59fd5

Please sign in to comment.