mirror of
https://github.com/natelandau/obsidian-metadata.git
synced 2025-11-12 23:13:48 -05:00
* refactor(application): refactor questions to separate class * test(application): add tests for`Application` class
415 lines
14 KiB
Python
415 lines
14 KiB
Python
# type: ignore
|
|
"""Tests for the application module.
|
|
|
|
How mocking works in this test suite:
|
|
|
|
1. The main_app() method is mocked using a side effect iterable. This allows us to pass a value in the first run, and then a KeyError in the second run to exit the loop.
|
|
2. All questions are mocked using return_value. This allows us to pass in a value to the question and then the method will return that value. This is useful for testing questionary prompts without user input.
|
|
"""
|
|
|
|
import re
|
|
|
|
import pytest
|
|
|
|
from tests.helpers import Regex
|
|
|
|
|
|
def test_instantiate_application(test_application) -> None:
|
|
"""Test application."""
|
|
app = test_application
|
|
app.load_vault()
|
|
|
|
assert app.dry_run is False
|
|
assert app.config.name == "command_line_vault"
|
|
assert app.config.exclude_paths == [".git", ".obsidian"]
|
|
assert app.dry_run is False
|
|
assert app.vault.num_notes() == 13
|
|
|
|
|
|
def test_abort(test_application, mocker, capsys) -> None:
|
|
"""Test renaming a key."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
return_value="abort",
|
|
)
|
|
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert "Vault Info" in captured.out
|
|
assert "Done!" in captured.out
|
|
|
|
|
|
def test_list_notes(test_application, mocker, capsys) -> None:
|
|
"""Test renaming a key."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["list_notes", KeyError],
|
|
)
|
|
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert "04 no metadata/no_metadata_1.md" in captured.out
|
|
assert "02 inline/inline 2.md" in captured.out
|
|
assert "+inbox/Untitled.md" in captured.out
|
|
assert "00 meta/templates/data sample.md" in captured.out
|
|
|
|
|
|
def test_all_metadata(test_application, mocker, capsys) -> None:
|
|
"""Test renaming a key."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["all_metadata", KeyError],
|
|
)
|
|
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
expected = re.escape("┃ Keys ┃ Values")
|
|
assert captured.out == Regex(expected)
|
|
expected = re.escape("Inline Tags │ breakfast")
|
|
assert captured.out == Regex(expected)
|
|
|
|
|
|
def test_filter_notes(test_application, mocker, capsys) -> None:
|
|
"""Test renaming a key."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["filter_notes", "list_notes", KeyError],
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_filter_path",
|
|
return_value="inline",
|
|
)
|
|
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert "04 no metadata/no_metadata_1.md" not in captured.out
|
|
assert "02 inline/inline 1.md" in captured.out
|
|
assert "02 inline/inline 2.md" in captured.out
|
|
assert "+inbox/Untitled.md" not in captured.out
|
|
assert "00 meta/templates/data sample.md" not in captured.out
|
|
|
|
|
|
def test_rename_key_success(test_application, mocker, capsys) -> None:
|
|
"""Test renaming a key."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["rename_key", KeyError],
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_key",
|
|
return_value="tags",
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_new_key",
|
|
return_value="new_tags",
|
|
)
|
|
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert captured.out == Regex(r"Renamed.*tags.*to.*new_tags.*in.*\d+.*notes", re.DOTALL)
|
|
|
|
|
|
def test_rename_key_fail(test_application, mocker, capsys) -> None:
|
|
"""Test renaming a key."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["rename_key", KeyError],
|
|
)
|
|
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_key",
|
|
return_value="tag",
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_new_key",
|
|
return_value="new_tags",
|
|
)
|
|
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert "WARNING | No notes were changed" in captured.out
|
|
|
|
|
|
def test_rename_inline_tag_success(test_application, mocker, capsys) -> None:
|
|
"""Test renaming an inline tag."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["rename_inline_tag", KeyError],
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_inline_tag",
|
|
return_value="breakfast",
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_new_tag",
|
|
return_value="new_tag",
|
|
)
|
|
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert captured.out == Regex(r"Renamed.*breakfast.*to.*new_tag.*in.*\d+.*notes", re.DOTALL)
|
|
|
|
|
|
def test_rename_inline_tag_fail(test_application, mocker, capsys) -> None:
|
|
"""Test renaming an inline tag."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["rename_inline_tag", KeyError],
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_inline_tag",
|
|
return_value="not_a_tag",
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_new_tag",
|
|
return_value="new_tag",
|
|
)
|
|
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert captured.out == Regex(r"WARNING +\| No notes were changed", re.DOTALL)
|
|
|
|
|
|
def test_delete_inline_tag_success(test_application, mocker, capsys) -> None:
|
|
"""Test renaming an inline tag."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["delete_inline_tag", KeyError],
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_inline_tag",
|
|
return_value="breakfast",
|
|
)
|
|
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert captured.out == Regex(r"SUCCESS +\| Deleted.*\d+.*notes", re.DOTALL)
|
|
|
|
|
|
def test_delete_inline_tag_fail(test_application, mocker, capsys) -> None:
|
|
"""Test renaming an inline tag."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["delete_inline_tag", KeyError],
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_inline_tag",
|
|
return_value="not_a_tag_in_vault",
|
|
)
|
|
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert captured.out == Regex(r"WARNING +\| No notes were changed", re.DOTALL)
|
|
|
|
|
|
def test_delete_key_success(test_application, mocker, capsys) -> None:
|
|
"""Test renaming an inline tag."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["delete_key", KeyError],
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_keys_regex",
|
|
return_value=r"d\w+",
|
|
)
|
|
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert captured.out == Regex(
|
|
r"SUCCESS +\|.*Deleted.*keys.*matching:.*d\\w\+.*from.*10", re.DOTALL
|
|
)
|
|
|
|
|
|
def test_delete_key_fail(test_application, mocker, capsys) -> None:
|
|
"""Test renaming an inline tag."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["delete_key", KeyError],
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_keys_regex",
|
|
return_value=r"\d{7}",
|
|
)
|
|
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert captured.out == Regex(r"WARNING +\| No notes found with a.*key.*matching", re.DOTALL)
|
|
|
|
|
|
def test_rename_value_success(test_application, mocker, capsys) -> None:
|
|
"""Test renaming an inline tag."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["rename_value", KeyError],
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_key",
|
|
return_value="area",
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_value",
|
|
return_value="frontmatter",
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_new_value",
|
|
return_value="new_key",
|
|
)
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert captured.out == Regex(
|
|
r"SUCCESS | Renamed 'area:frontmatter' to 'area:new_key'", re.DOTALL
|
|
)
|
|
assert captured.out == Regex(r".*in.*\d+.*notes.*", re.DOTALL)
|
|
|
|
|
|
def test_rename_value_fail(test_application, mocker, capsys) -> None:
|
|
"""Test renaming an inline tag."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["rename_value", KeyError],
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_key",
|
|
return_value="area",
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_value",
|
|
return_value="not_exists",
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_new_value",
|
|
return_value="new_key",
|
|
)
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert captured.out == Regex(r"WARNING +\| No notes were changed", re.DOTALL)
|
|
|
|
|
|
def test_delete_value_success(test_application, mocker, capsys) -> None:
|
|
"""Test renaming an inline tag."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["delete_value", KeyError],
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_key",
|
|
return_value="area",
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_value_regex",
|
|
return_value=r"^front\w+$",
|
|
)
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert captured.out == Regex(
|
|
r"SUCCESS +\| Deleted value.*\^front\\w\+\$.*from.*key.*area.*in.*\d+.*notes", re.DOTALL
|
|
)
|
|
|
|
|
|
def test_delete_value_fail(test_application, mocker, capsys) -> None:
|
|
"""Test renaming an inline tag."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["delete_value", KeyError],
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_key",
|
|
return_value="area",
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_value_regex",
|
|
return_value=r"\d{7}",
|
|
)
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert captured.out == Regex(r"WARNING +\| No notes found matching:", re.DOTALL)
|
|
|
|
|
|
def test_review_no_changes(test_application, mocker, capsys) -> None:
|
|
"""Review changes when no changes to vault."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["review_changes", KeyError],
|
|
)
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert captured.out == Regex(r"INFO +\| No changes to review", re.DOTALL)
|
|
|
|
|
|
def test_review_changes(test_application, mocker, capsys) -> None:
|
|
"""Review changes when no changes to vault."""
|
|
app = test_application
|
|
app.load_vault()
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_main_application",
|
|
side_effect=["delete_key", "review_changes", KeyError],
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_existing_keys_regex",
|
|
return_value=r"d\w+",
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_confirm",
|
|
return_value=True,
|
|
)
|
|
mocker.patch(
|
|
"obsidian_metadata.models.application.Questions.ask_for_selection",
|
|
side_effect=[1, "return"],
|
|
)
|
|
with pytest.raises(KeyError):
|
|
app.main_app()
|
|
captured = capsys.readouterr()
|
|
assert captured.out == Regex(r".*Found.*\d+.*changed notes in the vault.*", re.DOTALL)
|
|
assert "- date_created: 2022-12-22" in captured.out
|
|
assert "+ - breakfast" in captured.out
|