Skip to content

Commit

Permalink
Document mock class which enables extension and tests
Browse files Browse the repository at this point in the history
Inserted tests to the new extensions

- Load a custom validator
- Fails to load a custom validator
- Generate a sha for a given file if enabled
- If item_sha_required is not defined return None

Also included html files modified
  • Loading branch information
lbiaggi committed Jan 29, 2024
1 parent b2fd005 commit 29165c0
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 3 deletions.
66 changes: 66 additions & 0 deletions doorstop/cli/tests/files/settings_modified.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# SPDX-License-Identifier: LGPL-3.0-only

"""Settings for the Doorstop package."""

import logging
import os

# Logging settings
DEFAULT_LOGGING_FORMAT = "%(message)s"
LEVELED_LOGGING_FORMAT = "%(levelname)s: %(message)s"
VERBOSE_LOGGING_FORMAT = "[%(levelname)-8s] %(message)s"
VERBOSE2_LOGGING_FORMAT = "[%(levelname)-8s] (%(name)s @%(lineno)4d) %(message)s"
QUIET_LOGGING_LEVEL = logging.WARNING
TIMED_LOGGING_FORMAT = "%(asctime)s" + " " + VERBOSE_LOGGING_FORMAT
DEFAULT_LOGGING_LEVEL = logging.WARNING
VERBOSE_LOGGING_LEVEL = logging.INFO
VERBOSE2_LOGGING_LEVEL = logging.DEBUG
VERBOSE3_LOGGING_LEVEL = logging.DEBUG - 1

# Value constants
SEP_CHARS = "-_." # valid prefix/number separators
SKIP_EXTS = [".yml", ".csv", ".tsv"] # extensions skipped in reference search
RESERVED_WORDS = ["all"] # keywords that cannot be used for prefixes
PLACEHOLDER = "..." # placeholder for new item UIDs on export/import
PLACEHOLDER_COUNT = 1 # number of placeholders to include on export

# Formatting settings
MAX_LINE_LENGTH = 20 # line length to trigger multiline on extended attributes

# Validation settings
REFORMAT = True # reformat item files during validation
REORDER = False # reorder document levels during validation
CHECK_LEVELS = True # validate document levels during validation
CHECK_REF = True # validate external file references
CHECK_CHILD_LINKS = True # validate reverse links
# require child (reverse) links from every document
CHECK_CHILD_LINKS_STRICT = False
CHECK_SUSPECT_LINKS = True # check stamps on links
CHECK_REVIEW_STATUS = True # check stamps on items
WARN_ALL = False # display info-level issues as warnings
ERROR_ALL = False # display warning-level issues as errors

# Review settings
REVIEW_NEW_ITEMS = True # automatically review new items during validation

# Stamping settings
STAMP_NEW_LINKS = True # automatically stamp links upon creation

# Publishing settings
PUBLISH_CHILD_LINKS = True # include child links when publishing
PUBLISH_BODY_LEVELS = True # include levels on non-header items
PUBLISH_HEADING_LEVELS = True # include levels on header items
ENABLE_HEADERS = True # use headers if defined
WRITE_LINESEPERATOR = os.linesep

# Version control settings
ADDREMOVE_FILES = True # automatically add/remove new/changed files

# Caching settings
CACHE_ITEMS = True # cache items in documents and trees
CACHE_DOCUMENTS = True # cache documents in trees
CACHE_PATHS = True # cache file/directory paths and contents

# Server settings
SERVER_HOST = None # '' = server not specified, None = no server in use
SERVER_PORT = 7867
11 changes: 10 additions & 1 deletion doorstop/cli/tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from doorstop import settings
from doorstop.cli import main
from doorstop.cli.tests import SettingsTestCase
from doorstop.cli.tests import FILES, SettingsTestCase


class TestMain(SettingsTestCase):
Expand Down Expand Up @@ -84,3 +84,12 @@ def test_main(self):
spec.loader.exec_module(runpy)
# Assert
self.assertIsNotNone(runpy)

@patch("doorstop.cli.commands.run", Mock())
def test_run_modified_settings_through_file(self):
"""Verify --settings has override settings."""
main.main(args=["--settings", f"{FILES}/settings_modified.py"])
self.assertEqual(settings.MAX_LINE_LENGTH, 20)
# rollback to the original value to not impact an item test
settings.MAX_LINE_LENGTH = 79
self.assertEqual(settings.MAX_LINE_LENGTH, 79)
9 changes: 9 additions & 0 deletions doorstop/core/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ def set_items(self, items):
self._items = items


class MockSimpleDocumentExtensions(MockSimpleDocument):
"""Mock Document class that enable extensions."""

def __init__(self, **kwargs):
super().__init__()
for k, v in kwargs.items():
self.extensions[k] = v


class MockDocumentSkip(MockDocument): # pylint: disable=W0223,R0902
"""Mock Document class that is always skipped in tree placement."""

Expand Down
2 changes: 1 addition & 1 deletion doorstop/core/tests/files/published.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion doorstop/core/tests/files/published2.html

Large diffs are not rendered by default.

93 changes: 93 additions & 0 deletions doorstop/core/tests/test_item_extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# SPDX-License-Identifier: LGPL-3.0-only
# pylint: disable=C0302

"""Unit tests for the doorstop.core.item module."""

import os
import unittest
from types import ModuleType
from unittest.mock import patch

from doorstop.common import import_path_as_module
from doorstop.core.tests import TESTS_ROOT, MockItem, MockSimpleDocumentExtensions


class TestItem(unittest.TestCase):
"""Unit tests for the Item class."""

# pylint: disable=protected-access,no-value-for-parameter

def setUp(self):
path = os.path.join("path", "to", "RQ001.yml")
self.item = MockItem(MockSimpleDocumentExtensions(item_sha_required=True), path)

@patch("doorstop.settings.CACHE_PATHS", False)
def test_find_references_and_get_sha(self):
"""Verify an item's references can be found."""
self.item.root = TESTS_ROOT

self.item.references = [
{"path": "files/REQ001.yml", "type": "file"},
{"path": "files/REQ002.yml", "type": "file"},
]
# Generate sha through review
self.item.review()
refs = self.item.references

self.assertIn("sha", refs[0])
self.assertIn("sha", refs[1])

@patch("doorstop.settings.CACHE_PATHS", False)
def test_load_custom_validator_per_folder(self):
"""Load a valid custom validator per folder."""
path = os.path.join("path", "to", "RQ001.yml")
self.item = MockItem(
MockSimpleDocumentExtensions(
item_validator=f"{TESTS_ROOT}/validators/validator_dummy.py"
),
path,
)
document = self.item.document
validator = import_path_as_module(document.extensions["item_validator"])

self.assertEqual(isinstance(validator, ModuleType), True)

@patch("doorstop.settings.CACHE_PATHS", False)
def test_load_custom_validator_per_folder_and_fails(self):
"""Load a invalid custom validator per folder and fails with FileNotFoundError."""
path = os.path.join("path", "to", "RQ001.yml")
self.item = MockItem(
MockSimpleDocumentExtensions(
item_validator=f"{TESTS_ROOT}/files/validator_dummy2.py"
),
path,
)
document = self.item.document
try:
validator = import_path_as_module(document.extensions["item_validator"])
except FileNotFoundError:
validator = FileNotFoundError

self.assertEqual(FileNotFoundError, validator)

@patch("doorstop.settings.CACHE_PATHS", False)
def test_no_sha_ref(self):
"""Verify sha is not obtained if extension is not enabled."""
path = os.path.join("path", "to", "RQ001.yml")
self.item = MockItem(
MockSimpleDocumentExtensions(),
path,
)

self.item.root = TESTS_ROOT

self.item.references = [
{"path": "files/REQ001.yml", "type": "file"},
{"path": "files/REQ002.yml", "type": "file"},
]
# without item_sha_required, sha must return None
self.item.review()
refs = self.item.references
sha = self.item._hash_reference(refs[0]["path"])
self.assertNotIn("sha", refs[0].keys())
self.assertIsNone(sha)
6 changes: 6 additions & 0 deletions doorstop/core/tests/validators/validator_dummy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from doorstop import DoorstopError, DoorstopInfo, DoorstopWarning


def item_validator(item):
if item:
yield DoorstopInfo("Loaded")

0 comments on commit 29165c0

Please sign in to comment.