mirror of
https://github.com/natelandau/obsidian-metadata.git
synced 2025-11-19 02:13:39 -05:00
feat: add new inline metadata (#15)
* feat: add new inline metadata to notes * fix: prepend note content after frontmatter * refactor: cleanup search patterns * feat(regex): find top of note * test: add headers * fix: insert to specified location * test: improve test coverage * docs: add inline metadata
This commit is contained in:
committed by
Nathaniel Landau
parent
13513b2a14
commit
17985615b3
@@ -69,6 +69,33 @@ def test_add_metadata_frontmatter_success(test_application, mocker, capsys) -> N
|
||||
assert captured.out == Regex(r"SUCCESS +\| Added metadata to.*\d+.*notes", re.DOTALL)
|
||||
|
||||
|
||||
def test_add_metadata_inline_success(test_application, mocker, capsys) -> None:
|
||||
"""Test adding new metadata to the vault."""
|
||||
app = test_application
|
||||
app._load_vault()
|
||||
mocker.patch(
|
||||
"obsidian_metadata.models.application.Questions.ask_application_main",
|
||||
side_effect=["add_metadata", KeyError],
|
||||
)
|
||||
mocker.patch(
|
||||
"obsidian_metadata.models.application.Questions.ask_area",
|
||||
return_value=MetadataType.INLINE,
|
||||
)
|
||||
mocker.patch(
|
||||
"obsidian_metadata.models.application.Questions.ask_new_key",
|
||||
return_value="new_key",
|
||||
)
|
||||
mocker.patch(
|
||||
"obsidian_metadata.models.application.Questions.ask_new_value",
|
||||
return_value="new_key_value",
|
||||
)
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
app.application_main()
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == Regex(r"SUCCESS +\| Added metadata to.*\d+.*notes", re.DOTALL)
|
||||
|
||||
|
||||
def test_delete_inline_tag(test_application, mocker, capsys) -> None:
|
||||
"""Test renaming an inline tag."""
|
||||
app = test_application
|
||||
|
||||
@@ -49,6 +49,7 @@ def test_multiple_vaults_okay() -> None:
|
||||
assert config.config == {
|
||||
"Sample Vault": {
|
||||
"exclude_paths": [".git", ".obsidian", "ignore_folder"],
|
||||
"insert_location": "top",
|
||||
"path": "tests/fixtures/sample_vault",
|
||||
},
|
||||
"Test Vault": {
|
||||
@@ -74,6 +75,7 @@ def test_single_vault() -> None:
|
||||
"Test Vault": {
|
||||
"exclude_paths": [".git", ".obsidian", "ignore_folder"],
|
||||
"path": "tests/fixtures/test_vault",
|
||||
"insert_location": "BOTTOM",
|
||||
}
|
||||
}
|
||||
assert len(config.vaults) == 1
|
||||
@@ -104,7 +106,14 @@ def test_no_config_no_vault(tmp_path, mocker) -> None:
|
||||
path = "{str(fake_vault)}"
|
||||
|
||||
# Folders within the vault to ignore when indexing metadata
|
||||
exclude_paths = [".git", ".obsidian"]"""
|
||||
exclude_paths = [".git", ".obsidian"]
|
||||
|
||||
# Location to add metadata. One of:
|
||||
# TOP: Directly after frontmatter.
|
||||
# AFTER_TITLE: After a header following frontmatter.
|
||||
# BOTTOM: The bottom of the note
|
||||
insert_location = "BOTTOM\"
|
||||
"""
|
||||
|
||||
assert config_file.exists() is True
|
||||
assert content == dedent(sample_config)
|
||||
@@ -114,5 +123,6 @@ def test_no_config_no_vault(tmp_path, mocker) -> None:
|
||||
"Vault 1": {
|
||||
"path": str(fake_vault),
|
||||
"exclude_paths": [".git", ".obsidian"],
|
||||
"insert_location": "BOTTOM",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,27 @@ def sample_note(tmp_path) -> Path:
|
||||
dest_file.unlink()
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def short_note(tmp_path) -> Path:
|
||||
"""Fixture which creates a temporary short note file."""
|
||||
source_file1: Path = Path("tests/fixtures/short_textfile.md")
|
||||
source_file2: Path = Path("tests/fixtures/no_metadata.md")
|
||||
if not source_file1.exists():
|
||||
raise FileNotFoundError(f"Original file not found: {source_file1}")
|
||||
if not source_file2.exists():
|
||||
raise FileNotFoundError(f"Original file not found: {source_file2}")
|
||||
|
||||
dest_file1: Path = Path(tmp_path / source_file1.name)
|
||||
dest_file2: Path = Path(tmp_path / source_file2.name)
|
||||
shutil.copy(source_file1, dest_file1)
|
||||
shutil.copy(source_file2, dest_file2)
|
||||
yield dest_file1, dest_file2
|
||||
|
||||
# after test - remove fixtures
|
||||
dest_file1.unlink()
|
||||
dest_file2.unlink()
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def sample_vault(tmp_path) -> Path:
|
||||
"""Fixture which creates a sample vault."""
|
||||
|
||||
5
tests/fixtures/multiple_vaults.toml
vendored
5
tests/fixtures/multiple_vaults.toml
vendored
@@ -1,6 +1,7 @@
|
||||
["Sample Vault"]
|
||||
exclude_paths = [".git", ".obsidian", "ignore_folder"]
|
||||
path = "tests/fixtures/sample_vault"
|
||||
exclude_paths = [".git", ".obsidian", "ignore_folder"]
|
||||
insert_location = "top"
|
||||
path = "tests/fixtures/sample_vault"
|
||||
["Test Vault"]
|
||||
exclude_paths = [".git", ".obsidian", "ignore_folder"]
|
||||
path = "tests/fixtures/test_vault"
|
||||
|
||||
1
tests/fixtures/no_metadata.md
vendored
Normal file
1
tests/fixtures/no_metadata.md
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Lorem ipsum dolor sit amet.
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
area:: frontmatter
|
||||
date_created:: 2022-12-22
|
||||
date_modified:: 2022-12-22
|
||||
@@ -11,9 +10,12 @@ on_one_note:: one
|
||||
#food/fruit/pear
|
||||
#dinner #lunch #breakfast
|
||||
|
||||
# note header
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
|
||||
|
||||
### header 3
|
||||
|
||||
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# Header 1
|
||||
|
||||
area:: frontmatter
|
||||
date_created:: 2022-12-22
|
||||
@@ -6,13 +7,16 @@ author:: John Doe
|
||||
status:: new
|
||||
type:: book
|
||||
type:: article
|
||||
#food/fruit/apple
|
||||
#food/fruit/pear
|
||||
#dinner #lunch #breakfast
|
||||
#food/fruit/apple
|
||||
#food/fruit/pear
|
||||
#dinner #lunch #breakfast
|
||||
|
||||
## Header 2
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
|
||||
|
||||
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
|
||||
### Header 3
|
||||
|
||||
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
|
||||
|
||||
25
tests/fixtures/sample_vault/03 mixed/mixed 1.md
vendored
25
tests/fixtures/sample_vault/03 mixed/mixed 1.md
vendored
@@ -1,18 +1,18 @@
|
||||
---
|
||||
date_created: 2022-12-22
|
||||
tags:
|
||||
- food/fruit/apple
|
||||
- dinner
|
||||
- breakfast
|
||||
- not_food
|
||||
- food/fruit/apple
|
||||
- dinner
|
||||
- breakfast
|
||||
- not_food
|
||||
author: John Doe
|
||||
nested_list:
|
||||
nested_list_one:
|
||||
- nested_list_one_a
|
||||
- nested_list_one_b
|
||||
nested_list_one:
|
||||
- nested_list_one_a
|
||||
- nested_list_one_b
|
||||
type:
|
||||
- article
|
||||
- note
|
||||
- article
|
||||
- note
|
||||
---
|
||||
|
||||
area:: mixed
|
||||
@@ -24,13 +24,16 @@ type:: [[article]]
|
||||
tags:: from_inline_metadata
|
||||
**bold_key**:: **bold** key value
|
||||
|
||||
|
||||
|
||||
# Note header
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
|
||||
## Header 2
|
||||
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, [in_text_key:: in-text value] eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? #inline_tag
|
||||
|
||||
### header 3
|
||||
|
||||
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, #inline_tag2 cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
|
||||
|
||||
#food/fruit/pear
|
||||
|
||||
7
tests/fixtures/short_textfile.md
vendored
Normal file
7
tests/fixtures/short_textfile.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
key: value
|
||||
---
|
||||
|
||||
# header 1
|
||||
|
||||
Lorem ipsum dolor sit amet.
|
||||
5
tests/fixtures/test_vault_config.toml
vendored
5
tests/fixtures/test_vault_config.toml
vendored
@@ -1,3 +1,4 @@
|
||||
["Test Vault"]
|
||||
exclude_paths = [".git", ".obsidian", "ignore_folder"]
|
||||
path = "tests/fixtures/test_vault"
|
||||
exclude_paths = [".git", ".obsidian", "ignore_folder"]
|
||||
insert_location = "BOTTOM"
|
||||
path = "tests/fixtures/test_vault"
|
||||
|
||||
@@ -517,6 +517,86 @@ def test_inline_contains() -> None:
|
||||
assert inline.contains("key", r"^\d_value", is_regex=True) is False
|
||||
|
||||
|
||||
def test_inline_add() -> None:
|
||||
"""Test inline add."""
|
||||
inline = InlineMetadata(INLINE_CONTENT)
|
||||
|
||||
assert inline.add("bold_key1") is False
|
||||
assert inline.add("bold_key1", "bold_key1_value") is False
|
||||
assert inline.add("added_key") is True
|
||||
assert inline.dict == {
|
||||
"added_key": [],
|
||||
"bold_key1": ["bold_key1_value"],
|
||||
"bold_key2": ["bold_key2_value"],
|
||||
"emoji_📅_key": ["emoji_📅_key_value"],
|
||||
"in_text_key1": ["in_text_key1_value"],
|
||||
"in_text_key2": ["in_text_key2_value"],
|
||||
"link_key": ["link_key_value"],
|
||||
"repeated_key": ["repeated_key_value1", "repeated_key_value2"],
|
||||
"tag_key": ["tag_key_value"],
|
||||
}
|
||||
|
||||
assert inline.add("added_key1", "added_value") is True
|
||||
assert inline.dict == {
|
||||
"added_key": [],
|
||||
"added_key1": ["added_value"],
|
||||
"bold_key1": ["bold_key1_value"],
|
||||
"bold_key2": ["bold_key2_value"],
|
||||
"emoji_📅_key": ["emoji_📅_key_value"],
|
||||
"in_text_key1": ["in_text_key1_value"],
|
||||
"in_text_key2": ["in_text_key2_value"],
|
||||
"link_key": ["link_key_value"],
|
||||
"repeated_key": ["repeated_key_value1", "repeated_key_value2"],
|
||||
"tag_key": ["tag_key_value"],
|
||||
}
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
assert inline.add("added_key1", "added_value_2") is True
|
||||
|
||||
assert inline.dict == {
|
||||
"added_key": [],
|
||||
"added_key1": ["added_value"],
|
||||
"bold_key1": ["bold_key1_value"],
|
||||
"bold_key2": ["bold_key2_value"],
|
||||
"emoji_📅_key": ["emoji_📅_key_value"],
|
||||
"in_text_key1": ["in_text_key1_value"],
|
||||
"in_text_key2": ["in_text_key2_value"],
|
||||
"link_key": ["link_key_value"],
|
||||
"repeated_key": ["repeated_key_value1", "repeated_key_value2"],
|
||||
"tag_key": ["tag_key_value"],
|
||||
}
|
||||
|
||||
assert inline.add("added_key2", ["added_value_1", "added_value_2"]) is True
|
||||
assert inline.dict == {
|
||||
"added_key": [],
|
||||
"added_key1": ["added_value"],
|
||||
"added_key2": ["added_value_1"],
|
||||
"bold_key1": ["bold_key1_value"],
|
||||
"bold_key2": ["bold_key2_value"],
|
||||
"emoji_📅_key": ["emoji_📅_key_value"],
|
||||
"in_text_key1": ["in_text_key1_value"],
|
||||
"in_text_key2": ["in_text_key2_value"],
|
||||
"link_key": ["link_key_value"],
|
||||
"repeated_key": ["repeated_key_value1", "repeated_key_value2"],
|
||||
"tag_key": ["tag_key_value"],
|
||||
}
|
||||
|
||||
assert inline.add("added_key", "added_value")
|
||||
assert inline.dict == {
|
||||
"added_key": ["added_value"],
|
||||
"added_key1": ["added_value"],
|
||||
"added_key2": ["added_value_1"],
|
||||
"bold_key1": ["bold_key1_value"],
|
||||
"bold_key2": ["bold_key2_value"],
|
||||
"emoji_📅_key": ["emoji_📅_key_value"],
|
||||
"in_text_key1": ["in_text_key1_value"],
|
||||
"in_text_key2": ["in_text_key2_value"],
|
||||
"link_key": ["link_key_value"],
|
||||
"repeated_key": ["repeated_key_value1", "repeated_key_value2"],
|
||||
"tag_key": ["tag_key_value"],
|
||||
}
|
||||
|
||||
|
||||
def test_inline_metadata_rename() -> None:
|
||||
"""Test inline metadata rename."""
|
||||
inline = InlineMetadata(INLINE_CONTENT)
|
||||
|
||||
@@ -7,7 +7,7 @@ from pathlib import Path
|
||||
import pytest
|
||||
import typer
|
||||
|
||||
from obsidian_metadata.models.enums import MetadataType
|
||||
from obsidian_metadata.models.enums import InsertLocation, MetadataType
|
||||
from obsidian_metadata.models.notes import Note
|
||||
from tests.helpers import Regex
|
||||
|
||||
@@ -74,36 +74,33 @@ def test_note_create(sample_note) -> None:
|
||||
assert note.original_file_content == content
|
||||
|
||||
|
||||
def test_append(sample_note) -> None:
|
||||
"""Test appending to note."""
|
||||
note = Note(note_path=sample_note)
|
||||
assert note.dry_run is False
|
||||
def test_add_metadata_inline(short_note) -> None:
|
||||
"""Test adding metadata."""
|
||||
path1, path2 = short_note
|
||||
note = Note(note_path=path1)
|
||||
|
||||
string = "This is a test string."
|
||||
string2 = "Lorem ipsum dolor sit"
|
||||
assert note.inline_metadata.dict == {}
|
||||
assert (
|
||||
note.add_metadata(MetadataType.INLINE, location=InsertLocation.BOTTOM, key="new_key1")
|
||||
is True
|
||||
)
|
||||
assert note.inline_metadata.dict == {"new_key1": []}
|
||||
assert "new_key1::" in note.file_content.strip()
|
||||
|
||||
note.append(string_to_append=string)
|
||||
assert string in note.file_content
|
||||
assert len(re.findall(re.escape(string), note.file_content)) == 1
|
||||
|
||||
note.append(string_to_append=string)
|
||||
assert string in note.file_content
|
||||
assert len(re.findall(re.escape(string), note.file_content)) == 1
|
||||
|
||||
note.append(string_to_append=string, allow_multiple=True)
|
||||
assert string in note.file_content
|
||||
assert len(re.findall(re.escape(string), note.file_content)) == 2
|
||||
|
||||
note.append(string_to_append=string2)
|
||||
assert string2 in note.file_content
|
||||
assert len(re.findall(re.escape(string2), note.file_content)) == 1
|
||||
|
||||
note.append(string_to_append=string2, allow_multiple=True)
|
||||
assert string2 in note.file_content
|
||||
assert len(re.findall(re.escape(string2), note.file_content)) == 2
|
||||
assert (
|
||||
note.add_metadata(MetadataType.INLINE, key="new_key1", location=InsertLocation.BOTTOM)
|
||||
is False
|
||||
)
|
||||
assert (
|
||||
note.add_metadata(
|
||||
MetadataType.INLINE, key="new_key2", value="new_value1", location=InsertLocation.TOP
|
||||
)
|
||||
is True
|
||||
)
|
||||
assert "new_key2:: new_value1" in note.file_content
|
||||
|
||||
|
||||
def test_add_metadata(sample_note) -> None:
|
||||
def test_add_metadata_frontmatter(sample_note) -> None:
|
||||
"""Test adding metadata."""
|
||||
note = Note(note_path=sample_note)
|
||||
assert note.add_metadata(MetadataType.FRONTMATTER, "frontmatter_Key1") is False
|
||||
@@ -240,7 +237,7 @@ def test_has_changes(sample_note) -> None:
|
||||
note = Note(note_path=sample_note)
|
||||
|
||||
assert note.has_changes() is False
|
||||
note.append("This is a test string.")
|
||||
note.insert("This is a test string.", location=InsertLocation.BOTTOM)
|
||||
assert note.has_changes() is True
|
||||
|
||||
note = Note(note_path=sample_note)
|
||||
@@ -259,6 +256,146 @@ def test_has_changes(sample_note) -> None:
|
||||
assert note.has_changes() is True
|
||||
|
||||
|
||||
def test_insert_bottom(short_note) -> None:
|
||||
"""Test inserting metadata to bottom of note."""
|
||||
path1, path2 = short_note
|
||||
note = Note(note_path=str(path1))
|
||||
note2 = Note(note_path=str(path2))
|
||||
|
||||
string1 = "This is a test string."
|
||||
string2 = "This is"
|
||||
|
||||
correct_content = """
|
||||
---
|
||||
key: value
|
||||
---
|
||||
|
||||
# header 1
|
||||
|
||||
Lorem ipsum dolor sit amet.
|
||||
|
||||
This is a test string.
|
||||
"""
|
||||
correct_content2 = """
|
||||
---
|
||||
key: value
|
||||
---
|
||||
|
||||
# header 1
|
||||
|
||||
Lorem ipsum dolor sit amet.
|
||||
|
||||
This is a test string.
|
||||
This is
|
||||
"""
|
||||
correct_content3 = """
|
||||
Lorem ipsum dolor sit amet.
|
||||
|
||||
This is a test string.
|
||||
"""
|
||||
note.insert(new_string=string1, location=InsertLocation.BOTTOM)
|
||||
assert note.file_content == correct_content.strip()
|
||||
|
||||
note.insert(new_string=string2, location=InsertLocation.BOTTOM)
|
||||
assert note.file_content == correct_content.strip()
|
||||
|
||||
note.insert(new_string=string2, allow_multiple=True, location=InsertLocation.BOTTOM)
|
||||
assert note.file_content == correct_content2.strip()
|
||||
|
||||
note2.insert(new_string=string1, location=InsertLocation.BOTTOM)
|
||||
assert note2.file_content == correct_content3.strip()
|
||||
|
||||
|
||||
def test_insert_after_frontmatter(short_note) -> None:
|
||||
"""Test inserting metadata to bottom of note."""
|
||||
path1, path2 = short_note
|
||||
note = Note(note_path=path1)
|
||||
note2 = Note(note_path=path2)
|
||||
|
||||
string1 = "This is a test string."
|
||||
string2 = "This is"
|
||||
correct_content = """
|
||||
---
|
||||
key: value
|
||||
---
|
||||
This is a test string.
|
||||
|
||||
# header 1
|
||||
|
||||
Lorem ipsum dolor sit amet.
|
||||
"""
|
||||
|
||||
correct_content2 = """
|
||||
---
|
||||
key: value
|
||||
---
|
||||
This is
|
||||
This is a test string.
|
||||
|
||||
# header 1
|
||||
|
||||
Lorem ipsum dolor sit amet.
|
||||
"""
|
||||
correct_content3 = """
|
||||
This is a test string.
|
||||
Lorem ipsum dolor sit amet.
|
||||
"""
|
||||
|
||||
note.insert(new_string=string1, location=InsertLocation.TOP)
|
||||
assert note.file_content.strip() == correct_content.strip()
|
||||
|
||||
note.insert(new_string=string2, allow_multiple=True, location=InsertLocation.TOP)
|
||||
assert note.file_content.strip() == correct_content2.strip()
|
||||
|
||||
note2.insert(new_string=string1, location=InsertLocation.TOP)
|
||||
assert note2.file_content.strip() == correct_content3.strip()
|
||||
|
||||
|
||||
def test_insert_after_title(short_note) -> None:
|
||||
"""Test inserting metadata to bottom of note."""
|
||||
path1, path2 = short_note
|
||||
note = Note(note_path=path1)
|
||||
note2 = Note(note_path=path2)
|
||||
|
||||
string1 = "This is a test string."
|
||||
string2 = "This is"
|
||||
correct_content = """
|
||||
---
|
||||
key: value
|
||||
---
|
||||
|
||||
# header 1
|
||||
This is a test string.
|
||||
|
||||
Lorem ipsum dolor sit amet.
|
||||
"""
|
||||
|
||||
correct_content2 = """
|
||||
---
|
||||
key: value
|
||||
---
|
||||
|
||||
# header 1
|
||||
This is
|
||||
This is a test string.
|
||||
|
||||
Lorem ipsum dolor sit amet.
|
||||
"""
|
||||
correct_content3 = """
|
||||
This is a test string.
|
||||
Lorem ipsum dolor sit amet.
|
||||
"""
|
||||
|
||||
note.insert(new_string=string1, location=InsertLocation.AFTER_TITLE)
|
||||
assert note.file_content.strip() == correct_content.strip()
|
||||
|
||||
note.insert(new_string=string2, allow_multiple=True, location=InsertLocation.AFTER_TITLE)
|
||||
assert note.file_content.strip() == correct_content2.strip()
|
||||
|
||||
note2.insert(new_string=string1, location=InsertLocation.AFTER_TITLE)
|
||||
assert note2.file_content.strip() == correct_content3.strip()
|
||||
|
||||
|
||||
def test_print_note(sample_note, capsys) -> None:
|
||||
"""Test printing note."""
|
||||
note = Note(note_path=sample_note)
|
||||
@@ -273,7 +410,7 @@ def test_print_diff(sample_note, capsys) -> None:
|
||||
"""Test printing diff."""
|
||||
note = Note(note_path=sample_note)
|
||||
|
||||
note.append("This is a test string.")
|
||||
note.insert("This is a test string.", location=InsertLocation.BOTTOM)
|
||||
note.print_diff()
|
||||
captured = capsys.readouterr()
|
||||
assert "+ This is a test string." in captured.out
|
||||
@@ -362,12 +499,12 @@ def test_rename_metadata(sample_note) -> None:
|
||||
assert note.file_content == Regex(r"new_key:: new_value")
|
||||
|
||||
|
||||
def test_replace_frontmatter(sample_note) -> None:
|
||||
def test_update_frontmatter(sample_note) -> None:
|
||||
"""Test replacing frontmatter."""
|
||||
note = Note(note_path=sample_note)
|
||||
|
||||
note.rename_metadata("frontmatter_Key1", "author name", "some_new_key_here")
|
||||
note.replace_frontmatter()
|
||||
note.update_frontmatter()
|
||||
new_frontmatter = """---
|
||||
date_created: '2022-12-22'
|
||||
tags:
|
||||
@@ -387,9 +524,9 @@ shared_key2: shared_key2_value1
|
||||
assert "```python" in note.file_content
|
||||
|
||||
note2 = Note(note_path="tests/fixtures/test_vault/no_metadata.md")
|
||||
note2.replace_frontmatter()
|
||||
note2.update_frontmatter()
|
||||
note2.frontmatter.dict = {"key1": "value1", "key2": "value2"}
|
||||
note2.replace_frontmatter()
|
||||
note2.update_frontmatter()
|
||||
new_frontmatter = """---
|
||||
key1: value1
|
||||
key2: value2
|
||||
|
||||
@@ -56,10 +56,69 @@ shared_key1: 'shared_key1_value'
|
||||
"""
|
||||
|
||||
|
||||
def test_regex():
|
||||
"""Test regexes."""
|
||||
def test_top_with_header():
|
||||
"""Test identifying the top of a note."""
|
||||
pattern = Patterns()
|
||||
|
||||
no_fm_or_header = """
|
||||
|
||||
|
||||
Lorem ipsum dolor sit amet.
|
||||
|
||||
# header 1
|
||||
---
|
||||
horizontal: rule
|
||||
---
|
||||
Lorem ipsum dolor sit amet.
|
||||
"""
|
||||
fm_and_header: str = """
|
||||
---
|
||||
tags:
|
||||
- tag_1
|
||||
- tag_2
|
||||
-
|
||||
- 📅/tag_3
|
||||
frontmatter_Key1: "frontmatter_Key1_value"
|
||||
frontmatter_Key2: ["note", "article"]
|
||||
shared_key1: 'shared_key1_value'
|
||||
---
|
||||
|
||||
# Header 1
|
||||
more content
|
||||
|
||||
---
|
||||
horizontal: rule
|
||||
---
|
||||
"""
|
||||
fm_and_header_result = """---
|
||||
tags:
|
||||
- tag_1
|
||||
- tag_2
|
||||
-
|
||||
- 📅/tag_3
|
||||
frontmatter_Key1: "frontmatter_Key1_value"
|
||||
frontmatter_Key2: ["note", "article"]
|
||||
shared_key1: 'shared_key1_value'
|
||||
---
|
||||
|
||||
# Header 1"""
|
||||
no_fm = """
|
||||
|
||||
### Header's number 3 [📅] "+$2.00" 🤷
|
||||
---
|
||||
horizontal: rule
|
||||
---
|
||||
"""
|
||||
no_fm_result = '### Header\'s number 3 [📅] "+$2.00" 🤷'
|
||||
|
||||
assert pattern.top_with_header.search(no_fm_or_header).group("top") == ""
|
||||
assert pattern.top_with_header.search(fm_and_header).group("top") == fm_and_header_result
|
||||
assert pattern.top_with_header.search(no_fm).group("top") == no_fm_result
|
||||
|
||||
|
||||
def test_find_inline_tags():
|
||||
"""Test find_inline_tags regex."""
|
||||
pattern = Patterns()
|
||||
assert pattern.find_inline_tags.findall(TAG_CONTENT) == [
|
||||
"1",
|
||||
"2",
|
||||
@@ -87,6 +146,11 @@ def test_regex():
|
||||
"📅/tag",
|
||||
]
|
||||
|
||||
|
||||
def test_find_inline_metadata():
|
||||
"""Test find_inline_metadata regex."""
|
||||
pattern = Patterns()
|
||||
|
||||
result = pattern.find_inline_metadata.findall(INLINE_METADATA)
|
||||
assert result == [
|
||||
("", "", "1", "1**"),
|
||||
@@ -99,14 +163,26 @@ def test_regex():
|
||||
("", "", "emoji_📅_key", "📅emoji_📅_key_value"),
|
||||
]
|
||||
|
||||
found = pattern.frontmatt_block_with_separators.search(FRONTMATTER_CONTENT).group("frontmatter")
|
||||
|
||||
def test_find_frontmatter():
|
||||
"""Test regexes."""
|
||||
pattern = Patterns()
|
||||
found = pattern.frontmatter_block.search(FRONTMATTER_CONTENT).group("frontmatter")
|
||||
assert found == CORRECT_FRONTMATTER_WITH_SEPARATORS
|
||||
|
||||
found = pattern.frontmatt_block_no_separators.search(FRONTMATTER_CONTENT).group("frontmatter")
|
||||
found = pattern.frontmatt_block_strip_separators.search(FRONTMATTER_CONTENT).group(
|
||||
"frontmatter"
|
||||
)
|
||||
assert found == CORRECT_FRONTMATTER_NO_SEPARATORS
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
pattern.frontmatt_block_no_separators.search(TAG_CONTENT).group("frontmatter")
|
||||
pattern.frontmatt_block_strip_separators.search(TAG_CONTENT).group("frontmatter")
|
||||
|
||||
|
||||
def test_validators():
|
||||
"""Test validators."""
|
||||
pattern = Patterns()
|
||||
|
||||
assert pattern.validate_tag_text.search("test_tag") is None
|
||||
assert pattern.validate_tag_text.search("#asdf").group(0) == "#"
|
||||
assert pattern.validate_tag_text.search("#asdf").group(0) == "#"
|
||||
|
||||
@@ -5,7 +5,7 @@ from pathlib import Path
|
||||
|
||||
from obsidian_metadata._config import Config
|
||||
from obsidian_metadata.models import Vault, VaultFilter
|
||||
from obsidian_metadata.models.enums import MetadataType
|
||||
from obsidian_metadata.models.enums import InsertLocation, MetadataType
|
||||
from tests.helpers import Regex
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ def test_vault_creation(test_vault):
|
||||
|
||||
assert vault.name == "vault"
|
||||
assert vault.vault_path == vault_path
|
||||
assert vault.insert_location == InsertLocation.BOTTOM
|
||||
assert vault.backup_path == Path(f"{vault_path}.bak")
|
||||
assert vault.dry_run is False
|
||||
assert str(vault.exclude_paths[0]) == Regex(r".*\.git")
|
||||
@@ -90,140 +91,6 @@ def test_vault_creation(test_vault):
|
||||
}
|
||||
|
||||
|
||||
def test_get_filtered_notes(sample_vault) -> None:
|
||||
"""Test filtering notes."""
|
||||
vault_path = sample_vault
|
||||
config = Config(config_path="tests/fixtures/sample_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
|
||||
filters = [VaultFilter(path_filter="front")]
|
||||
vault = Vault(config=vault_config, filters=filters)
|
||||
assert len(vault.all_notes) == 13
|
||||
assert len(vault.notes_in_scope) == 4
|
||||
|
||||
filters = [VaultFilter(path_filter="mixed")]
|
||||
vault = Vault(config=vault_config, filters=filters)
|
||||
assert len(vault.all_notes) == 13
|
||||
assert len(vault.notes_in_scope) == 1
|
||||
|
||||
filters = [VaultFilter(key_filter="on_one_note")]
|
||||
vault = Vault(config=vault_config, filters=filters)
|
||||
assert len(vault.all_notes) == 13
|
||||
assert len(vault.notes_in_scope) == 1
|
||||
|
||||
filters = [VaultFilter(key_filter="type", value_filter="book")]
|
||||
vault = Vault(config=vault_config, filters=filters)
|
||||
assert len(vault.all_notes) == 13
|
||||
assert len(vault.notes_in_scope) == 10
|
||||
|
||||
filters = [VaultFilter(tag_filter="brunch")]
|
||||
vault = Vault(config=vault_config, filters=filters)
|
||||
assert len(vault.all_notes) == 13
|
||||
assert len(vault.notes_in_scope) == 1
|
||||
|
||||
filters = [VaultFilter(tag_filter="brunch"), VaultFilter(path_filter="inbox")]
|
||||
vault = Vault(config=vault_config, filters=filters)
|
||||
assert len(vault.all_notes) == 13
|
||||
assert len(vault.notes_in_scope) == 0
|
||||
|
||||
|
||||
def test_backup(test_vault, capsys):
|
||||
"""Test backing up the vault."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config)
|
||||
|
||||
vault.backup()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert Path(f"{vault_path}.bak").exists() is True
|
||||
assert captured.out == Regex(r"SUCCESS +| backed up to")
|
||||
|
||||
vault.info()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == Regex(r"Backup path +\│[\s ]+/[\d\w]+")
|
||||
|
||||
|
||||
def test_backup_dryrun(test_vault, capsys):
|
||||
"""Test backing up the vault."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config, dry_run=True)
|
||||
|
||||
print(f"vault.dry_run: {vault.dry_run}")
|
||||
vault.backup()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert vault.backup_path.exists() is False
|
||||
assert captured.out == Regex(r"DRYRUN +| Backup up vault to")
|
||||
|
||||
|
||||
def test_delete_backup(test_vault, capsys):
|
||||
"""Test deleting the vault backup."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config)
|
||||
|
||||
vault.backup()
|
||||
vault.delete_backup()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == Regex(r"Backup deleted")
|
||||
assert vault.backup_path.exists() is False
|
||||
|
||||
vault.info()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == Regex(r"Backup +\│ None")
|
||||
|
||||
|
||||
def test_delete_backup_dryrun(test_vault, capsys):
|
||||
"""Test deleting the vault backup."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config, dry_run=True)
|
||||
|
||||
Path.mkdir(vault.backup_path)
|
||||
vault.delete_backup()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == Regex(r"DRYRUN +| Delete backup")
|
||||
assert vault.backup_path.exists() is True
|
||||
|
||||
|
||||
def test_info(test_vault, capsys):
|
||||
"""Test printing vault information."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config)
|
||||
|
||||
vault.info()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == Regex(r"Vault +\│ /[\d\w]+")
|
||||
assert captured.out == Regex(r"Notes in scope +\│ \d+")
|
||||
assert captured.out == Regex(r"Backup +\│ None")
|
||||
|
||||
|
||||
def test_list_editable_notes(test_vault, capsys) -> None:
|
||||
"""Test listing editable notes."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config)
|
||||
|
||||
vault.list_editable_notes()
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == Regex("Notes in current scope")
|
||||
assert captured.out == Regex(r"\d +test1\.md")
|
||||
|
||||
|
||||
def test_add_metadata(test_vault) -> None:
|
||||
"""Test adding metadata to the vault."""
|
||||
vault_path = test_vault
|
||||
@@ -327,6 +194,103 @@ def test_add_metadata(test_vault) -> None:
|
||||
}
|
||||
|
||||
|
||||
def test_backup(test_vault, capsys):
|
||||
"""Test backing up the vault."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config)
|
||||
|
||||
vault.backup()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert Path(f"{vault_path}.bak").exists() is True
|
||||
assert captured.out == Regex(r"SUCCESS +| backed up to")
|
||||
|
||||
vault.info()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == Regex(r"Backup path +\│[\s ]+/[\d\w]+")
|
||||
|
||||
|
||||
def test_commit(test_vault, tmp_path):
|
||||
"""Test committing changes to content in the vault."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config)
|
||||
content = Path(f"{tmp_path}/vault/test1.md").read_text()
|
||||
assert "new_key: new_key_value" not in content
|
||||
|
||||
vault.add_metadata(MetadataType.FRONTMATTER, "new_key", "new_key_value")
|
||||
vault.commit_changes()
|
||||
assert "new_key: new_key_value" not in content
|
||||
|
||||
|
||||
def test_commit_dry_run(test_vault, tmp_path):
|
||||
"""Test committing changes to content in the vault in dry run mode."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config, dry_run=True)
|
||||
content = Path(f"{tmp_path}/vault/test1.md").read_text()
|
||||
assert "new_key: new_key_value" not in content
|
||||
|
||||
vault.add_metadata(MetadataType.FRONTMATTER, "new_key", "new_key_value")
|
||||
vault.commit_changes()
|
||||
assert "new_key: new_key_value" not in content
|
||||
|
||||
|
||||
def test_backup_dryrun(test_vault, capsys):
|
||||
"""Test backing up the vault."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config, dry_run=True)
|
||||
|
||||
print(f"vault.dry_run: {vault.dry_run}")
|
||||
vault.backup()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert vault.backup_path.exists() is False
|
||||
assert captured.out == Regex(r"DRYRUN +| Backup up vault to")
|
||||
|
||||
|
||||
def test_delete_backup(test_vault, capsys):
|
||||
"""Test deleting the vault backup."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config)
|
||||
|
||||
vault.backup()
|
||||
vault.delete_backup()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == Regex(r"Backup deleted")
|
||||
assert vault.backup_path.exists() is False
|
||||
|
||||
vault.info()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == Regex(r"Backup +\│ None")
|
||||
|
||||
|
||||
def test_delete_backup_dryrun(test_vault, capsys):
|
||||
"""Test deleting the vault backup."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config, dry_run=True)
|
||||
|
||||
Path.mkdir(vault.backup_path)
|
||||
vault.delete_backup()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == Regex(r"DRYRUN +| Delete backup")
|
||||
assert vault.backup_path.exists() is True
|
||||
|
||||
|
||||
def test_delete_inline_tag(test_vault) -> None:
|
||||
"""Test deleting an inline tag."""
|
||||
vault_path = test_vault
|
||||
@@ -364,6 +328,97 @@ def test_delete_metadata(test_vault) -> None:
|
||||
assert "top_key2" not in vault.metadata.dict
|
||||
|
||||
|
||||
def test_export_csv(tmp_path, test_vault):
|
||||
"""Test exporting the vault to a CSV file."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config)
|
||||
export_file = Path(f"{tmp_path}/export.csv")
|
||||
|
||||
vault.export_metadata(path=export_file, format="csv")
|
||||
assert export_file.exists() is True
|
||||
assert "frontmatter,date_created,2022-12-22" in export_file.read_text()
|
||||
|
||||
|
||||
def test_export_json(tmp_path, test_vault):
|
||||
"""Test exporting the vault to a CSV file."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config)
|
||||
export_file = Path(f"{tmp_path}/export.json")
|
||||
|
||||
vault.export_metadata(path=export_file, format="json")
|
||||
assert export_file.exists() is True
|
||||
assert '"frontmatter": {' in export_file.read_text()
|
||||
|
||||
|
||||
def test_get_filtered_notes(sample_vault) -> None:
|
||||
"""Test filtering notes."""
|
||||
vault_path = sample_vault
|
||||
config = Config(config_path="tests/fixtures/sample_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
|
||||
filters = [VaultFilter(path_filter="front")]
|
||||
vault = Vault(config=vault_config, filters=filters)
|
||||
assert len(vault.all_notes) == 13
|
||||
assert len(vault.notes_in_scope) == 4
|
||||
|
||||
filters = [VaultFilter(path_filter="mixed")]
|
||||
vault = Vault(config=vault_config, filters=filters)
|
||||
assert len(vault.all_notes) == 13
|
||||
assert len(vault.notes_in_scope) == 1
|
||||
|
||||
filters = [VaultFilter(key_filter="on_one_note")]
|
||||
vault = Vault(config=vault_config, filters=filters)
|
||||
assert len(vault.all_notes) == 13
|
||||
assert len(vault.notes_in_scope) == 1
|
||||
|
||||
filters = [VaultFilter(key_filter="type", value_filter="book")]
|
||||
vault = Vault(config=vault_config, filters=filters)
|
||||
assert len(vault.all_notes) == 13
|
||||
assert len(vault.notes_in_scope) == 10
|
||||
|
||||
filters = [VaultFilter(tag_filter="brunch")]
|
||||
vault = Vault(config=vault_config, filters=filters)
|
||||
assert len(vault.all_notes) == 13
|
||||
assert len(vault.notes_in_scope) == 1
|
||||
|
||||
filters = [VaultFilter(tag_filter="brunch"), VaultFilter(path_filter="inbox")]
|
||||
vault = Vault(config=vault_config, filters=filters)
|
||||
assert len(vault.all_notes) == 13
|
||||
assert len(vault.notes_in_scope) == 0
|
||||
|
||||
|
||||
def test_info(test_vault, capsys):
|
||||
"""Test printing vault information."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config)
|
||||
|
||||
vault.info()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == Regex(r"Vault +\│ /[\d\w]+")
|
||||
assert captured.out == Regex(r"Notes in scope +\│ \d+")
|
||||
assert captured.out == Regex(r"Backup +\│ None")
|
||||
|
||||
|
||||
def test_list_editable_notes(test_vault, capsys) -> None:
|
||||
"""Test listing editable notes."""
|
||||
vault_path = test_vault
|
||||
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||
vault_config = config.vaults[0]
|
||||
vault = Vault(config=vault_config)
|
||||
|
||||
vault.list_editable_notes()
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == Regex("Notes in current scope")
|
||||
assert captured.out == Regex(r"\d +test1\.md")
|
||||
|
||||
|
||||
def test_rename_inline_tag(test_vault) -> None:
|
||||
"""Test renaming an inline tag."""
|
||||
vault_path = test_vault
|
||||
|
||||
Reference in New Issue
Block a user