feat: initial application release

This commit is contained in:
Nathaniel Landau
2022-12-23 04:10:08 +00:00
parent 35717e0760
commit b7bcf74926
78 changed files with 15508 additions and 0 deletions

1
tests/__init__.py Normal file
View File

@@ -0,0 +1 @@
"""obsidian-metadata test suite."""

155
tests/alerts_test.py Normal file
View File

@@ -0,0 +1,155 @@
# type: ignore
"""Test alerts and logging."""
import re
import pytest
from obsidian_metadata._utils import alerts
from obsidian_metadata._utils.alerts import logger as log
from tests.helpers import Regex
def test_dryrun(capsys):
"""Test dry run."""
alerts.dryrun("This prints in dry run")
captured = capsys.readouterr()
assert captured.out == "DRYRUN | This prints in dry run\n"
def test_success(capsys):
"""Test success."""
alerts.success("This prints in success")
captured = capsys.readouterr()
assert captured.out == "SUCCESS | This prints in success\n"
def test_error(capsys):
"""Test success."""
alerts.error("This prints in error")
captured = capsys.readouterr()
assert captured.out == "ERROR | This prints in error\n"
def test_warning(capsys):
"""Test warning."""
alerts.warning("This prints in warning")
captured = capsys.readouterr()
assert captured.out == "WARNING | This prints in warning\n"
def test_notice(capsys):
"""Test notice."""
alerts.notice("This prints in notice")
captured = capsys.readouterr()
assert captured.out == "NOTICE | This prints in notice\n"
def test_info(capsys):
"""Test info."""
alerts.info("This prints in info")
captured = capsys.readouterr()
assert captured.out == "INFO | This prints in info\n"
def test_dim(capsys):
"""Test info."""
alerts.dim("This prints in dim")
captured = capsys.readouterr()
assert captured.out == "This prints in dim\n"
@pytest.mark.parametrize(
("verbosity", "log_to_file"),
[(0, False), (1, False), (2, True), (3, True)],
)
def test_logging(capsys, tmp_path, verbosity, log_to_file) -> None:
"""Test logging."""
tmp_log = tmp_path / "tmp.log"
logging = alerts.LoggerManager(
log_file=tmp_log,
verbosity=verbosity,
log_to_file=log_to_file,
)
assert logging.verbosity == verbosity
if verbosity >= 3:
assert logging.is_trace() is True
captured = capsys.readouterr()
assert captured.out == ""
assert logging.is_trace("trace text") is True
captured = capsys.readouterr()
assert captured.out == "trace text\n"
log.trace("This is Trace logging")
captured = capsys.readouterr()
assert captured.err == Regex(r"^TRACE \| This is Trace logging \([\w\._:]+:\d+\)$")
else:
assert logging.is_trace("trace text") is False
captured = capsys.readouterr()
assert captured.out != "trace text\n"
log.trace("This is Trace logging")
captured = capsys.readouterr()
assert captured.err != Regex(r"^TRACE \| This is Trace logging \([\w\._:]+:\d+\)$")
if verbosity >= 2:
assert logging.is_debug() is True
captured = capsys.readouterr()
assert captured.out == ""
assert logging.is_debug("debug text") is True
captured = capsys.readouterr()
assert captured.out == "debug text\n"
log.debug("This is Debug logging")
captured = capsys.readouterr()
assert captured.err == Regex(r"^DEBUG \| This is Debug logging \([\w\._:]+:\d+\)$")
else:
assert logging.is_debug("debug text") is False
captured = capsys.readouterr()
assert captured.out != "debug text\n"
log.debug("This is Debug logging")
captured = capsys.readouterr()
assert captured.err != Regex(r"^DEBUG \| This is Debug logging \([\w\._:]+:\d+\)$")
if verbosity >= 1:
assert logging.is_info() is True
captured = capsys.readouterr()
assert captured.out == ""
assert logging.is_info("info text") is True
captured = capsys.readouterr()
assert captured.out == "info text\n"
log.info("This is Info logging")
captured = capsys.readouterr()
assert captured.err == "INFO | This is Info logging\n"
else:
assert logging.is_info("info text") is False
captured = capsys.readouterr()
assert captured.out != "info text\n"
log.info("This is Info logging")
captured = capsys.readouterr()
assert captured.out == ""
assert logging.is_default() is True
captured = capsys.readouterr()
assert captured.out == ""
assert logging.is_default("default text") is True
captured = capsys.readouterr()
assert captured.out == "default text\n"
if log_to_file:
assert tmp_log.exists() is True
log_file_content = tmp_log.read_text()
assert log_file_content == Regex(
r"^\d{4}-\d{2}-\d{2} \d+:\d+:\d+\.\d+ \| DEBUG \| [\w\.:]+:\d+ \- Logging to file:",
re.MULTILINE,
)
else:
assert tmp_log.exists() is False

16
tests/cli_test.py Normal file
View File

@@ -0,0 +1,16 @@
# type: ignore
"""Test obsidian-metadata CLI."""
from typer.testing import CliRunner
from obsidian_metadata.cli import app
from tests.helpers import Regex
runner = CliRunner()
def test_version() -> None:
"""Test printing version and then exiting."""
result = runner.invoke(app, ["--version"])
assert result.exit_code == 0
assert result.output == Regex(r"obsidian_metadata: v\d+\.\d+\.\d+$")

28
tests/config_test.py Normal file
View File

@@ -0,0 +1,28 @@
# type: ignore
"""Tests for the configuration module."""
import re
from pathlib import Path
from obsidian_metadata._config import Config
def test_first_run(tmp_path):
"""Test creating a config on first run."""
config_file = Path(tmp_path / "config.toml")
vault_path = Path(tmp_path / "vault/")
vault_path.mkdir()
config = Config(config_path=config_file, vault_path=vault_path)
assert config_file.exists() is True
config.write_config_value("vault", str(vault_path))
content = config_file.read_text()
assert config.vault_path == vault_path
assert re.search(str(vault_path), content) is not None
def test_parse_config():
"""Test parsing a config file."""
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=None)
assert config.vault_path == Path(Path.cwd() / "tests/fixtures/test_vault")

74
tests/conftest.py Normal file
View File

@@ -0,0 +1,74 @@
# type: ignore
"""Fixtures for tests."""
import shutil
from pathlib import Path
import pytest
def remove_all(root: Path):
"""Remove all files and directories in a directory."""
for path in root.iterdir():
if path.is_file():
print(f"Deleting the file: {path}")
path.unlink()
else:
remove_all(path)
print(f"Deleting the empty dir: {root}")
root.rmdir()
@pytest.fixture()
def sample_note(tmp_path) -> Path:
"""Fixture which creates a temporary note file."""
source_file: Path = Path("tests/fixtures/test_vault/test1.md")
if not source_file.exists():
raise FileNotFoundError(f"Original file not found: {source_file}")
dest_file: Path = Path(tmp_path / source_file.name)
shutil.copy(source_file, dest_file)
yield dest_file
# after test - remove fixtures
dest_file.unlink()
@pytest.fixture()
def sample_vault(tmp_path) -> Path:
"""Fixture which creates a sample vault."""
source_dir = Path(__file__).parent / "fixtures" / "sample_vault"
dest_dir = Path(tmp_path / "vault")
backup_dir = Path(f"{dest_dir}.bak")
if not source_dir.exists():
raise FileNotFoundError(f"Sample vault not found: {source_dir}")
shutil.copytree(source_dir, dest_dir)
yield dest_dir
# after test - remove fixtures
shutil.rmtree(dest_dir)
if backup_dir.exists():
shutil.rmtree(backup_dir)
@pytest.fixture()
def test_vault(tmp_path) -> Path:
"""Fixture which creates a sample vault."""
source_dir = Path(__file__).parent / "fixtures" / "test_vault"
dest_dir = Path(tmp_path / "vault")
backup_dir = Path(f"{dest_dir}.bak")
if not source_dir.exists():
raise FileNotFoundError(f"Sample vault not found: {source_dir}")
shutil.copytree(source_dir, dest_dir)
yield dest_dir
# after test - remove fixtures
shutil.rmtree(dest_dir)
if backup_dir.exists():
shutil.rmtree(backup_dir)

39
tests/fixtures/sample_note.md vendored Normal file
View File

@@ -0,0 +1,39 @@
---
date_created: 2022-12-22
tags:
- food/fruit/apple
- dinner
- breakfast
- not_food
author: John Doe
nested_list:
nested_list_one:
- nested_list_one_a
- nested_list_one_b
type:
- article
- note
---
area:: mixed
date_modified:: 2022-12-22
status:: new
type:: book
inline_key:: inline_key_value
type:: [[article]]
tags:: from_inline_metadata
**bold_key**:: **bold** key value
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, [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
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
#food/fruit/orange
#dinner #breakfast
#brunch

View File

@@ -0,0 +1,9 @@
---
type: note
tags:
- foo
- bar
- baz
- food/fruit/apple
---
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.

View File

@@ -0,0 +1,3 @@
{
"alwaysUpdateLinks": true
}

View File

@@ -0,0 +1,3 @@
{
"accentColor": ""
}

View File

@@ -0,0 +1,3 @@
[
"templater-obsidian"
]

View File

@@ -0,0 +1,29 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"starred": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": false
}

View File

@@ -0,0 +1,20 @@
[
"file-explorer",
"global-search",
"switcher",
"graph",
"backlink",
"canvas",
"outgoing-link",
"tag-pane",
"page-preview",
"daily-notes",
"templates",
"note-composer",
"command-palette",
"editor-status",
"starred",
"outline",
"word-count",
"file-recovery"
]

View File

@@ -0,0 +1 @@
{}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
{
"id": "templater-obsidian",
"name": "Templater",
"version": "1.16.0",
"description": "Create and use templates",
"minAppVersion": "0.11.13",
"author": "SilentVoid",
"authorUrl": "https://github.com/SilentVoid13",
"isDesktopOnly": false
}

View File

@@ -0,0 +1,281 @@
.templater_search {
width: calc(100% - 20px);
}
.templater_div {
border-top: 1px solid var(--background-modifier-border);
}
.templater_div > .setting-item {
border-top: none !important;
align-self: center;
}
.templater_div > .setting-item > .setting-item-control {
justify-content: space-around;
padding: 0;
width: 100%;
}
.templater_div
> .setting-item
> .setting-item-control
> .setting-editor-extra-setting-button {
align-self: center;
}
.templater_donating {
margin: 10px;
}
.templater_title {
margin: 0;
padding: 0;
margin-top: 5px;
text-align: center;
}
.templater_template {
align-self: center;
margin-left: 5px;
margin-right: 5px;
width: 70%;
}
.templater_cmd {
margin-left: 5px;
margin-right: 5px;
font-size: 14px;
width: 100%;
}
.templater_div2 > .setting-item {
align-content: center;
justify-content: center;
}
.templater-prompt-div {
display: flex;
}
.templater-prompt-form {
display: flex;
flex-grow: 1;
}
.templater-prompt-input {
flex-grow: 1;
}
.templater-button-div {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 1rem;
}
textarea.templater-prompt-input {
height: 10rem;
}
textarea.templater-prompt-input:focus {
border-color: var(--interactive-accent);
}
.cm-s-obsidian .templater-command-bg {
left: 0px;
right: 0px;
background-color: var(--background-primary-alt);
}
.cm-s-obsidian .cm-templater-command {
font-size: 0.85em;
font-family: var(--font-monospace);
line-height: 1.3;
}
.cm-s-obsidian .templater-inline .cm-templater-command {
background-color: var(--background-primary-alt);
}
.cm-s-obsidian .cm-templater-command.cm-templater-opening-tag {
font-weight: bold;
}
.cm-s-obsidian .cm-templater-command.cm-templater-closing-tag {
font-weight: bold;
}
.cm-s-obsidian .cm-templater-command.cm-templater-interpolation-tag {
color: #008bff;
}
.cm-s-obsidian .cm-templater-command.cm-templater-execution-tag {
color: #c0d700;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-keyword {
color: #00a7aa;
font-weight: normal;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-atom {
color: #f39b35;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-number {
color: #a06fca;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-type {
color: #a06fca;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-def {
color: #98e342;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-property {
color: #d4d4d4;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-variable {
color: #d4d4d4;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-variable-2 {
color: #da7dae;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-variable-3 {
color: #a06fca;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-type.cm-def {
color: #fc4384;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-property.cm-def {
color: #fc4384;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-callee {
color: #fc4384;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-operator {
color: #fc4384;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-qualifier {
color: #fc4384;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-tag {
color: #fc4384;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-tag.cm-bracket {
color: #d4d4d4;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-attribute {
color: #a06fca;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-comment {
color: #696d70;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-comment.cm-tag {
color: #fc4384;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-comment.cm-attribute {
color: #d4d4d4;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-string {
color: #e6db74;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-string-2 {
color: #f39b35;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-meta {
color: #d4d4d4;
background: inherit;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-builtin {
color: #fc4384;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-header {
color: #da7dae;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-hr {
color: #98e342;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-link {
color: #696d70;
}
.theme-dark .cm-s-obsidian .cm-templater-command.cm-error {
border-bottom: 1px solid #c42412;
}
.theme-dark .cm-s-obsidian pre.HyperMD-codeblock .cm-keyword {
font-weight: normal;
}
.theme-dark
.cm-s-obsidian
.cm-templater-command.CodeMirror-activeline-background {
background: #272727;
}
.theme-dark .cm-s-obsidian .cm-templater-command.CodeMirror-matchingbracket {
outline: 1px solid grey;
color: #d4d4d4 !important;
}
.CodeMirror-hints {
position: absolute;
z-index: 10;
overflow: hidden;
list-style: none;
margin: 0;
padding: 2px;
-webkit-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
border-radius: 3px;
border: 1px solid silver;
background: white;
font-size: 90%;
font-family: monospace;
max-height: 20em;
overflow-y: auto;
}
.CodeMirror-hint {
margin: 0;
padding: 0 4px;
border-radius: 2px;
white-space: pre;
color: black;
cursor: pointer;
}
li.CodeMirror-hint-active {
background: #08f;
color: white;
}

View File

@@ -0,0 +1,155 @@
{
"main": {
"id": "5f828621a37b21ab",
"type": "split",
"children": [
{
"id": "2f3322f01c16279b",
"type": "tabs",
"children": [
{
"id": "d16a705340a291b0",
"type": "leaf",
"state": {
"type": "empty",
"state": {}
}
}
]
}
],
"direction": "vertical"
},
"left": {
"id": "aeebc2581160842a",
"type": "split",
"children": [
{
"id": "cd71abd49c3ceb86",
"type": "tabs",
"children": [
{
"id": "fe51579e3e74af15",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical"
}
}
},
{
"id": "2a7187c7c8d51306",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": "",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
}
}
},
{
"id": "574f0713150d5067",
"type": "leaf",
"state": {
"type": "starred",
"state": {}
}
}
]
}
],
"direction": "horizontal",
"width": 300
},
"right": {
"id": "b20cf1cec7ad8379",
"type": "split",
"children": [
{
"id": "e4268aea52a4b751",
"type": "tabs",
"children": [
{
"id": "495261df1eda8469",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
}
}
},
{
"id": "a552a9e316c497c2",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"linksCollapsed": false,
"unlinkedCollapsed": true
}
}
},
{
"id": "49ac9a323fc7a3bb",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true
}
}
},
{
"id": "93bd91c8147876e4",
"type": "leaf",
"state": {
"type": "outline",
"state": {}
}
}
]
}
],
"direction": "horizontal",
"width": 300,
"collapsed": true
},
"left-ribbon": {
"hiddenItems": {
"switcher:Open quick switcher": false,
"graph:Open graph view": false,
"canvas:Create new canvas": false,
"daily-notes:Open today's daily note": false,
"templates:Insert template": false,
"command-palette:Open command palette": false,
"templater-obsidian:Templater": false
}
},
"active": "d16a705340a291b0",
"lastOpenFiles": [
"00 meta/templates/daily note.md",
"+inbox/Untitled.md",
"01 frontmatter/frontmatter 1.md",
"01 frontmatter/frontmatter 2.md",
"01 frontmatter/frontmatter 3.md",
"01 frontmatter/frontmatter 4.md",
"02 inline/inline 1.md",
"02 inline/inline 2.md",
"02 inline/inline 3.md",
"02 inline/inline 4.md"
]
}

View File

@@ -0,0 +1,19 @@
<%* let title = tp.file.title
if (title.startsWith("Untitled")) {
title = await tp.system.prompt("Title");
await tp.file.rename(title);
}
-%>
<%*
let result = title.replace(/-/g, ' ')
result = result.charAt(0).toUpperCase() + result.slice(1);
tR += "---"
%>
title: <%* tR += "\"" + result + "\"" %>
tags:
<% tp.file.cursor(1) %>
programming-languagues:
created: <% tp.date.now("YYYY-MM-DD") %>
---
# <%* tR += result %>
---

View File

@@ -0,0 +1,17 @@
---
area:
date_created: 2022-12-21
date_modified: 2022-12-20
tags:
- food/fruit/apple
- food/fruit/pear
- dinner
- lunch
- breakfast
author: John Doe
status: new
type:
- book
- article
- note
---

View File

@@ -0,0 +1,255 @@
---
area: frontmatter
date_created: 2022-12-22
date_modified: 2022-12-22
tags:
- food/fruit/apple
- food/fruit/pear
- dinner
- lunch
- breakfast
thoughts:
rating: 8
reviewable: false
levels:
level1:
- level1a
- level1b
level2:
- level2a
- level2b
author: John Doe
status: new
type: ["book", "article", "note", "one-off"]
---
# Page Title H1
# Headings
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
## Heading 2
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
### Heading 3
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
#### Heading 4
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
##### Heading 5
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
###### Heading 6
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
## Text styles
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 [[internal link]] exercitation ullamco laboris nisi ut [external link](https://google.com) aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. [[frontmatter 1]] Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum `inline code looks like this` 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?
```css
This is a code block
```
## Bold
**The quick brown fox jumps over the lazy dog.**
**The quick brown fox jumps over the lazy dog.**
<strong>The quick brown fox jumps over the lazy dog.</strong>
## Italic
_The quick brown fox jumps over the lazy dog._
_The quick brown fox jumps over the lazy dog._
<em>The quick brown fox jumps over the lazy dog.</em>
## Bold and Italic
**_The quick brown fox jumps over the lazy dog._**
<strong><em>The quick brown fox jumps over the lazy dog.</em></strong>
## Blockquotes
> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua
> The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
> **The quick brown fox** _jumps over the lazy dog._
## Monospaced
<samp>The quick brown fox jumps over the lazy dog.</samp>
## Underlined
<ins>The quick brown fox jumps over the lazy dog.</ins>
## Strike-through
~~The quick brown fox jumps over the lazy dog.~~
## sub and super
Subscript <sub>The quick brown fox jumps over the lazy dog.</sub>
Superscript <sup>The quick brown fox jumps over the lazy dog.</sup>
## Syntax Highlighting
A class method is an instance method of the class object. When a new class is created, an object of type `Class` is initialized and assigned to a global constant (Mobile in this case).
```
public static String monthNames[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
```
```java
public static String monthNames[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
```
```css
button.mod-cta a {
color: inherit;
text-decoration: none;
}
```
## Tables
| one | two | three |
| ---- | :--: | ----- |
| 9999 | 9999 | 9999 |
| 1 | 2 | 3 |
| 44 | 55 | 66 |
| Default | Left align | Center align | Right align |
| ---------- | :--------- | :----------: | ----------: |
| 9999999999 | 9999999999 | 9999999999 | 9999999999 |
| 999999999 | 999999999 | 999999999 | 999999999 |
| 99999999 | 99999999 | 99999999 | 99999999 |
| 9999999 | 9999999 | 9999999 | 9999999 |
| A | B | C |
| --- | --- | ----------------- |
| 1 | 2 | 3 <br/> 4 <br/> 5 |
## Links
[The-Ultimate-Markdown-Cheat-Sheet](https://github.com/lifeparticle/The-Ultimate-Markdown-Cheat-Sheet)
[The-Ultimate-Markdown-Cheat-Sheet][reference text]
[The-Ultimate-Markdown-Cheat-Sheet][1]
[Markdown-Cheat-Sheet]
[reference text]: https://github.com/lifeparticle/The-Ultimate-Markdown-Cheat-Sheet
[1]: https://github.com/lifeparticle/The-Ultimate-Markdown-Cheat-Sheet
[markdown-cheat-sheet]: https://github.com/lifeparticle/The-Ultimate-Markdown-Cheat-Sheet
[Example of a relative link](rl.md)
Visit https://github.com/
## Images
![alt text][image]
<img src="https://media.giphy.com/media/qLHzYjlA2FW8g/giphy.gif" />
<img src="https://img.shields.io/badge/theultimatemarkdowncheatsheet-brightgreen.svg" />
## Lists
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1. One
2. Two
3. Three
## Multi-level Lists
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1. First level
1. Second level
- Third level
- Fourth level
2. First level
1. Second level
3. First level
1. Second level
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
- 1
- 2
- 3
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
- First level
- Second level
- Third level
- Fourth level
- First level
- Second level
- First level
- Second level
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
- [x] Fix Bug 223 ✅ 2022-08-08
- [x] Add Feature 33 ✅ 2022-08-08
- [x] Add unit tests ✅ 2022-08-08
## Horizontal Rules
---
---
---
## Miscellaneous
<!--
Lorem ipsum dolor sit amet
-->
- Asterisk
\ Backslash
` Backtick
{} Curly braces
. Dot
! Exclamation mark
## Hash symbol
- Hyphen symbol
() Parentheses
* Plus symbol
[] Square brackets
\_ Underscore
\* Asterisk
\\ Backslash
\` Backtick
\{} Curly braces
\. Dot
\! Exclamation mark
\# Hash symbol
\- Hyphen symbol
\() Parentheses
\+ Plus symbol
\[] Square brackets
\_ Underscore
:octocat:
@lifeparticle
\#

View File

@@ -0,0 +1,255 @@
---
area: frontmatter
date_created: 2022-12-22
date_modified: 2022-11-14
tags:
- food/fruit/apple
- food/fruit/pear
- dinner
- lunch
- breakfast
thoughts:
rating: 8
reviewable: false
levels:
level1:
- level1a
- level1b
level2:
- level2a
- level2b
author: John Doe
status: new
type: ["book", "article", "note"]
---
# Page Title H1
# Headings
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
## Heading 2
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
### Heading 3
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
#### Heading 4
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
##### Heading 5
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
###### Heading 6
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
## Text styles
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 [[internal link]] exercitation ullamco laboris nisi ut [external link](https://google.com) aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. [[frontmatter 1]] Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum `inline code looks like this` 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?
```css
This is a code block
```
## Bold
**The quick brown fox jumps over the lazy dog.**
**The quick brown fox jumps over the lazy dog.**
<strong>The quick brown fox jumps over the lazy dog.</strong>
## Italic
_The quick brown fox jumps over the lazy dog._
_The quick brown fox jumps over the lazy dog._
<em>The quick brown fox jumps over the lazy dog.</em>
## Bold and Italic
**_The quick brown fox jumps over the lazy dog._**
<strong><em>The quick brown fox jumps over the lazy dog.</em></strong>
## Blockquotes
> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua
> The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
> **The quick brown fox** _jumps over the lazy dog._
## Monospaced
<samp>The quick brown fox jumps over the lazy dog.</samp>
## Underlined
<ins>The quick brown fox jumps over the lazy dog.</ins>
## Strike-through
~~The quick brown fox jumps over the lazy dog.~~
## sub and super
Subscript <sub>The quick brown fox jumps over the lazy dog.</sub>
Superscript <sup>The quick brown fox jumps over the lazy dog.</sup>
## Syntax Highlighting
A class method is an instance method of the class object. When a new class is created, an object of type `Class` is initialized and assigned to a global constant (Mobile in this case).
```
public static String monthNames[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
```
```java
public static String monthNames[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
```
```css
button.mod-cta a {
color: inherit;
text-decoration: none;
}
```
## Tables
| one | two | three |
| ---- | :--: | ----- |
| 9999 | 9999 | 9999 |
| 1 | 2 | 3 |
| 44 | 55 | 66 |
| Default | Left align | Center align | Right align |
| ---------- | :--------- | :----------: | ----------: |
| 9999999999 | 9999999999 | 9999999999 | 9999999999 |
| 999999999 | 999999999 | 999999999 | 999999999 |
| 99999999 | 99999999 | 99999999 | 99999999 |
| 9999999 | 9999999 | 9999999 | 9999999 |
| A | B | C |
| --- | --- | ----------------- |
| 1 | 2 | 3 <br/> 4 <br/> 5 |
## Links
[The-Ultimate-Markdown-Cheat-Sheet](https://github.com/lifeparticle/The-Ultimate-Markdown-Cheat-Sheet)
[The-Ultimate-Markdown-Cheat-Sheet][reference text]
[The-Ultimate-Markdown-Cheat-Sheet][1]
[Markdown-Cheat-Sheet]
[reference text]: https://github.com/lifeparticle/The-Ultimate-Markdown-Cheat-Sheet
[1]: https://github.com/lifeparticle/The-Ultimate-Markdown-Cheat-Sheet
[markdown-cheat-sheet]: https://github.com/lifeparticle/The-Ultimate-Markdown-Cheat-Sheet
[Example of a relative link](rl.md)
Visit https://github.com/
## Images
![alt text][image]
<img src="https://media.giphy.com/media/qLHzYjlA2FW8g/giphy.gif" />
<img src="https://img.shields.io/badge/theultimatemarkdowncheatsheet-brightgreen.svg" />
## Lists
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1. One
2. Two
3. Three
## Multi-level Lists
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1. First level
1. Second level
- Third level
- Fourth level
2. First level
1. Second level
3. First level
1. Second level
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
- 1
- 2
- 3
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
- First level
- Second level
- Third level
- Fourth level
- First level
- Second level
- First level
- Second level
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
- [x] Fix Bug 223 ✅ 2022-08-08
- [x] Add Feature 33 ✅ 2022-08-08
- [x] Add unit tests ✅ 2022-08-08
## Horizontal Rules
---
---
---
## Miscellaneous
<!--
Lorem ipsum dolor sit amet
-->
- Asterisk
\ Backslash
` Backtick
{} Curly braces
. Dot
! Exclamation mark
## Hash symbol
- Hyphen symbol
() Parentheses
* Plus symbol
[] Square brackets
\_ Underscore
\* Asterisk
\\ Backslash
\` Backtick
\{} Curly braces
\. Dot
\! Exclamation mark
\# Hash symbol
\- Hyphen symbol
\() Parentheses
\+ Plus symbol
\[] Square brackets
\_ Underscore
:octocat:
@lifeparticle
\#

View File

@@ -0,0 +1,255 @@
---
area: frontmatter
date_created: 2022-12-22
date_modified: 2022-10-01
tags:
- food/fruit/apple
- food/fruit/pear
- dinner
- lunch
- breakfast
thoughts:
rating: 8
reviewable: false
levels:
level1:
- level1a
- level1b
level2:
- level2a
- level2b
author: John Doe
status: new
type: ["book", "article", "note"]
---
# Page Title H1
# Headings
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
## Heading 2
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
### Heading 3
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
#### Heading 4
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
##### Heading 5
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
###### Heading 6
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
## Text styles
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 [[internal link]] exercitation ullamco laboris nisi ut [external link](https://google.com) aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. [[frontmatter 1]] Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum `inline code looks like this` 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?
```css
This is a code block
```
## Bold
**The quick brown fox jumps over the lazy dog.**
**The quick brown fox jumps over the lazy dog.**
<strong>The quick brown fox jumps over the lazy dog.</strong>
## Italic
_The quick brown fox jumps over the lazy dog._
_The quick brown fox jumps over the lazy dog._
<em>The quick brown fox jumps over the lazy dog.</em>
## Bold and Italic
**_The quick brown fox jumps over the lazy dog._**
<strong><em>The quick brown fox jumps over the lazy dog.</em></strong>
## Blockquotes
> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua
> The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
> **The quick brown fox** _jumps over the lazy dog._
## Monospaced
<samp>The quick brown fox jumps over the lazy dog.</samp>
## Underlined
<ins>The quick brown fox jumps over the lazy dog.</ins>
## Strike-through
~~The quick brown fox jumps over the lazy dog.~~
## sub and super
Subscript <sub>The quick brown fox jumps over the lazy dog.</sub>
Superscript <sup>The quick brown fox jumps over the lazy dog.</sup>
## Syntax Highlighting
A class method is an instance method of the class object. When a new class is created, an object of type `Class` is initialized and assigned to a global constant (Mobile in this case).
```
public static String monthNames[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
```
```java
public static String monthNames[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
```
```css
button.mod-cta a {
color: inherit;
text-decoration: none;
}
```
## Tables
| one | two | three |
| ---- | :--: | ----- |
| 9999 | 9999 | 9999 |
| 1 | 2 | 3 |
| 44 | 55 | 66 |
| Default | Left align | Center align | Right align |
| ---------- | :--------- | :----------: | ----------: |
| 9999999999 | 9999999999 | 9999999999 | 9999999999 |
| 999999999 | 999999999 | 999999999 | 999999999 |
| 99999999 | 99999999 | 99999999 | 99999999 |
| 9999999 | 9999999 | 9999999 | 9999999 |
| A | B | C |
| --- | --- | ----------------- |
| 1 | 2 | 3 <br/> 4 <br/> 5 |
## Links
[The-Ultimate-Markdown-Cheat-Sheet](https://github.com/lifeparticle/The-Ultimate-Markdown-Cheat-Sheet)
[The-Ultimate-Markdown-Cheat-Sheet][reference text]
[The-Ultimate-Markdown-Cheat-Sheet][1]
[Markdown-Cheat-Sheet]
[reference text]: https://github.com/lifeparticle/The-Ultimate-Markdown-Cheat-Sheet
[1]: https://github.com/lifeparticle/The-Ultimate-Markdown-Cheat-Sheet
[markdown-cheat-sheet]: https://github.com/lifeparticle/The-Ultimate-Markdown-Cheat-Sheet
[Example of a relative link](rl.md)
Visit https://github.com/
## Images
![alt text][image]
<img src="https://media.giphy.com/media/qLHzYjlA2FW8g/giphy.gif" />
<img src="https://img.shields.io/badge/theultimatemarkdowncheatsheet-brightgreen.svg" />
## Lists
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1. One
2. Two
3. Three
## Multi-level Lists
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1. First level
1. Second level
- Third level
- Fourth level
2. First level
1. Second level
3. First level
1. Second level
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
- 1
- 2
- 3
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
- First level
- Second level
- Third level
- Fourth level
- First level
- Second level
- First level
- Second level
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
- [x] Fix Bug 223 ✅ 2022-08-08
- [x] Add Feature 33 ✅ 2022-08-08
- [x] Add unit tests ✅ 2022-08-08
## Horizontal Rules
---
---
---
## Miscellaneous
<!--
Lorem ipsum dolor sit amet
-->
- Asterisk
\ Backslash
` Backtick
{} Curly braces
. Dot
! Exclamation mark
## Hash symbol
- Hyphen symbol
() Parentheses
* Plus symbol
[] Square brackets
\_ Underscore
\* Asterisk
\\ Backslash
\` Backtick
\{} Curly braces
\. Dot
\! Exclamation mark
\# Hash symbol
\- Hyphen symbol
\() Parentheses
\+ Plus symbol
\[] Square brackets
\_ Underscore
:octocat:
@lifeparticle
\#

View File

@@ -0,0 +1,29 @@
---
area: frontmatter
date_created: 2022-12-22
date_modified: 2022-12-22
tags:
- food/fruit/apple
- food/fruit/pear
- dinner
- lunch
- breakfast
thoughts:
rating: 8
reviewable: false
levels:
level1:
- level1a
- level1b
level2:
- level2a
- level2b
author: John Doe
status: new
type: ["book", "article", "note"]
something_new_here: I-am-new
---
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?

View File

@@ -0,0 +1,18 @@
area:: frontmatter
date_created:: 2022-12-22
date_modified:: 2022-12-22
author:: John Doe
status:: new
type:: book
type:: article
#food/fruit/apple
#food/fruit/pear
#dinner #lunch #breakfast
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.

View File

@@ -0,0 +1,18 @@
area:: frontmatter
date_created:: 2022-12-22
date_modified:: 2022-12-22
author:: John Doe
status:: new
type:: book
type:: article
#food/fruit/apple
#food/fruit/pear
#dinner #lunch #breakfast
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.

View File

@@ -0,0 +1,18 @@
area:: frontmatter
date_created:: 2022-12-22
date_modified:: 2022-12-22
author:: John Doe
status:: new
type:: book
type:: article
#food/fruit/apple
#food/fruit/pear
#dinner #lunch #breakfast
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.

View File

@@ -0,0 +1,18 @@
area:: frontmatter
date_created:: 2022-12-22
date_modified:: 2022-12-22
author:: John Doe
status:: new
type:: book
type:: article
#food/fruit/apple
#food/fruit/pear
#dinner #lunch #breakfast
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.

View File

@@ -0,0 +1,39 @@
---
date_created: 2022-12-22
tags:
- food/fruit/apple
- dinner
- breakfast
- not_food
author: John Doe
nested_list:
nested_list_one:
- nested_list_one_a
- nested_list_one_b
type:
- article
- note
---
area:: mixed
date_modified:: 2022-12-22
status:: new
type:: book
inline_key:: inline_key_value
type:: [[article]]
tags:: from_inline_metadata
**bold_key**:: **bold** key value
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, [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
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
#food/fruit/orange
#dinner #breakfast
#brunch

View File

@@ -0,0 +1,5 @@
.lLorem 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 repella

View File

@@ -0,0 +1,8 @@
vault = "tests/fixtures/sample_vault"
# folders to ignore when parsing content
exclude_paths = [".git", ".obsidian", "ignore_folder"]
[metadata]
metadata_location = "frontmatter" # "frontmatter", "top", "bottom"
tags_location = "top" # "frontmatter", "top", "bottom"

View File

@@ -0,0 +1,39 @@
---
date_created: 2022-12-22
tags:
- shared_tag
- frontmatter_tag1
- frontmatter_tag2
- frontmatter_tag3
- ignored_file_tag1
author: author name
type: ["article", "note"]
---
#inline_tag_top1 #inline_tag_top2
#ignored_file_tag2
top_key1:: top_key1_value
top_key2:: top_key2_value
# Heading 1
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. #intext_tag1 Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla (#intext_tag2) pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est lab
```python
#ffffff
# This is sample text with tags and metadata
#in_codeblock_tag1
#ffffff;
codeblock_key:: some text
The quick brown fox jumped over the #in_codeblock_tag2
```
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab `this is #inline_code_tag1` 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? `this is #inline_code_tag2` 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 pari
bottom_key1:: bottom_key1_value
bottom_key2:: bottom_key2_value
#inline_tag_bottom1
#inline_tag_bottom2
#shared_tag

View File

@@ -0,0 +1,3 @@
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 paria

44
tests/fixtures/test_vault/test1.md vendored Normal file
View File

@@ -0,0 +1,44 @@
---
date_created: 2022-12-22
tags:
- shared_tag
- frontmatter_tag1
- frontmatter_tag2
-
- 📅/frontmatter_tag3
frontmatter_Key1: author name
frontmatter_Key2: ["article", "note"]
shared_key1: shared_key1_value
shared_key2: shared_key2_value1
---
#inline_tag_top1 #inline_tag_top2
top_key1:: top_key1_value
**top_key2:: top_key2_value**
top_key3:: [[top_key3_value_as_link]]
shared_key1:: shared_key1_value
shared_key2:: shared_key2_value2
emoji_📅_key:: emoji_📅_key_value
# Heading 1
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. #intext_tag1 Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu [intext_key:: intext_value] fugiat nulla (#intext_tag2) pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est lab
```python
#ffffff
# This is sample text with tags and metadata
#in_codeblock_tag1
#ffffff;
codeblock_key:: some text
in_codeblock_key:: in_codeblock_value
The quick brown fox jumped over the #in_codeblock_tag2
```
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab `this is #inline_code_tag1` 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? `this is #inline_code_tag2` 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 pari
bottom_key1:: bottom_key1_value
bottom_key2:: bottom_key2_value
#inline_tag_bottom1
#inline_tag_bottom2
#shared_tag

8
tests/fixtures/test_vault_config.toml vendored Normal file
View File

@@ -0,0 +1,8 @@
vault = "tests/fixtures/test_vault"
# folders to ignore when parsing content
exclude_paths = [".git", ".obsidian", "ignore_folder"]
[metadata]
metadata_location = "frontmatter" # "frontmatter", "top", "bottom"
tags_location = "top" # "frontmatter", "top", "bottom"

32
tests/helpers.py Normal file
View File

@@ -0,0 +1,32 @@
# type: ignore
"""Helper functions for tests."""
import re
class Regex:
"""Assert that a given string meets some expectations.
Usage:
from tests.helpers import Regex
assert caplog.text == Regex(r"^.*$", re.I)
"""
def __init__(self, pattern, flags=0):
self._regex = re.compile(pattern, flags)
def __eq__(self, actual):
"""Define equality.
Args:
actual (str): String to be matched to the regex
Returns:
bool: True if the actual string matches the regex, False otherwise.
"""
return bool(self._regex.search(actual))
def __repr__(self):
"""Error printed on failed tests."""
return f"Regex: '{self._regex.pattern}'"

491
tests/metadata_test.py Normal file
View File

@@ -0,0 +1,491 @@
# type: ignore
"""Test metadata.py."""
from pathlib import Path
from obsidian_metadata.models.metadata import (
Frontmatter,
InlineMetadata,
InlineTags,
VaultMetadata,
)
from tests.helpers import Regex
FILE_CONTENT: str = Path("tests/fixtures/test_vault/test1.md").read_text()
METADATA: dict[str, list[str]] = {
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["note", "article"],
"shared_key1": ["shared_key1_value"],
"shared_key2": ["shared_key2_value"],
"tags": ["tag 2", "tag 1", "tag 3"],
"top_key1": ["top_key1_value"],
"top_key2": ["top_key2_value"],
"top_key3": ["top_key3_value"],
"intext_key": ["intext_key_value"],
}
FRONTMATTER_CONTENT: str = """
---
tags:
- tag_1
- tag_2
-
- 📅/tag_3
frontmatter_Key1: "frontmatter_Key1_value"
frontmatter_Key2: ["note", "article"]
shared_key1: "shared_key1_value"
---
more content
---
horizontal: rule
---
"""
INLINE_CONTENT = """\
repeated_key:: repeated_key_value1
#inline_tag_top1,#inline_tag_top2
**bold_key1**:: bold_key1_value
**bold_key2:: bold_key2_value**
link_key:: [[link_key_value]]
tag_key:: #tag_key_value
emoji_📅_key:: emoji_📅_key_value
**#bold_tag**
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. [in_text_key1:: in_text_key1_value] Ut enim ad minim veniam, quis nostrud exercitation [in_text_key2:: in_text_key2_value] ullamco laboris nisi ut aliquip ex ea commodo consequat. #in_text_tag 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.
```python
#ffffff
# This is sample text [no_key:: value]with tags and metadata
#in_codeblock_tag1
#ffffff;
in_codeblock_key:: in_codeblock_value
The quick brown fox jumped over the #in_codeblock_tag2
```
repeated_key:: repeated_key_value2
"""
def test_vault_metadata(capsys) -> None:
"""Test VaultMetadata class."""
vm = VaultMetadata()
assert vm.dict == {}
vm.add_metadata(METADATA)
assert vm.dict == {
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "note"],
"intext_key": ["intext_key_value"],
"shared_key1": ["shared_key1_value"],
"shared_key2": ["shared_key2_value"],
"tags": ["tag 1", "tag 2", "tag 3"],
"top_key1": ["top_key1_value"],
"top_key2": ["top_key2_value"],
"top_key3": ["top_key3_value"],
}
vm.print_keys()
captured = capsys.readouterr()
assert captured.out == Regex(r"frontmatter_Key1 +frontmatter_Key2 +intext_key")
vm.print_tags()
captured = capsys.readouterr()
assert captured.out == Regex(r"tag 1 +tag 2 +tag 3")
vm.print_metadata()
captured = capsys.readouterr()
assert captured.out == Regex(r"┃ Keys +┃ Values +┃")
assert captured.out == Regex(r"│ +│ tag 3 +│")
assert captured.out == Regex(r"│ frontmatter_Key1 +│ author name +│")
new_metadata = {"added_key": ["added_value"], "frontmatter_Key2": ["new_value"]}
vm.add_metadata(new_metadata)
assert vm.dict == {
"added_key": ["added_value"],
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "new_value", "note"],
"intext_key": ["intext_key_value"],
"shared_key1": ["shared_key1_value"],
"shared_key2": ["shared_key2_value"],
"tags": ["tag 1", "tag 2", "tag 3"],
"top_key1": ["top_key1_value"],
"top_key2": ["top_key2_value"],
"top_key3": ["top_key3_value"],
}
def test_vault_metadata_contains() -> None:
"""Test contains method."""
vm = VaultMetadata()
vm.add_metadata(METADATA)
assert vm.dict == {
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "note"],
"intext_key": ["intext_key_value"],
"shared_key1": ["shared_key1_value"],
"shared_key2": ["shared_key2_value"],
"tags": ["tag 1", "tag 2", "tag 3"],
"top_key1": ["top_key1_value"],
"top_key2": ["top_key2_value"],
"top_key3": ["top_key3_value"],
}
assert vm.contains("frontmatter_Key1") is True
assert vm.contains("frontmatter_Key2", "article") is True
assert vm.contains("frontmatter_Key3") is False
assert vm.contains("frontmatter_Key2", "no value") is False
assert vm.contains("1$", is_regex=True) is True
assert vm.contains("5$", is_regex=True) is False
assert vm.contains("tags", r"\d", is_regex=True) is True
assert vm.contains("tags", r"^\d", is_regex=True) is False
def test_vault_metadata_delete() -> None:
"""Test delete method."""
vm = VaultMetadata()
vm.add_metadata(METADATA)
assert vm.dict == {
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "note"],
"intext_key": ["intext_key_value"],
"shared_key1": ["shared_key1_value"],
"shared_key2": ["shared_key2_value"],
"tags": ["tag 1", "tag 2", "tag 3"],
"top_key1": ["top_key1_value"],
"top_key2": ["top_key2_value"],
"top_key3": ["top_key3_value"],
}
assert vm.delete("no key") is False
assert vm.delete("tags", "no value") is False
assert vm.delete("tags", "tag 2") is True
assert vm.dict["tags"] == ["tag 1", "tag 3"]
assert vm.delete("tags") is True
assert "tags" not in vm.dict
def test_vault_metadata_rename() -> None:
"""Test rename method."""
vm = VaultMetadata()
vm.add_metadata(METADATA)
assert vm.dict == {
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "note"],
"intext_key": ["intext_key_value"],
"shared_key1": ["shared_key1_value"],
"shared_key2": ["shared_key2_value"],
"tags": ["tag 1", "tag 2", "tag 3"],
"top_key1": ["top_key1_value"],
"top_key2": ["top_key2_value"],
"top_key3": ["top_key3_value"],
}
assert vm.rename("no key", "new key") is False
assert vm.rename("tags", "no tag", "new key") is False
assert vm.rename("tags", "tag 2", "new tag") is True
assert vm.dict["tags"] == ["new tag", "tag 1", "tag 3"]
assert vm.rename("tags", "old_tags") is True
assert vm.dict["old_tags"] == ["new tag", "tag 1", "tag 3"]
assert "tags" not in vm.dict
def test_frontmatter_create() -> None:
"""Test frontmatter creation."""
frontmatter = Frontmatter(INLINE_CONTENT)
assert frontmatter.dict == {}
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
assert frontmatter.dict == {
"frontmatter_Key1": ["frontmatter_Key1_value"],
"frontmatter_Key2": ["article", "note"],
"shared_key1": ["shared_key1_value"],
"tags": ["tag_1", "tag_2", "📅/tag_3"],
}
assert frontmatter.dict_original == {
"frontmatter_Key1": ["frontmatter_Key1_value"],
"frontmatter_Key2": ["article", "note"],
"shared_key1": ["shared_key1_value"],
"tags": ["tag_1", "tag_2", "📅/tag_3"],
}
def test_frontmatter_contains() -> None:
"""Test frontmatter contains."""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
assert frontmatter.contains("frontmatter_Key1") is True
assert frontmatter.contains("frontmatter_Key2", "article") is True
assert frontmatter.contains("frontmatter_Key3") is False
assert frontmatter.contains("frontmatter_Key2", "no value") is False
assert frontmatter.contains(r"\d$", is_regex=True) is True
assert frontmatter.contains(r"^\d", is_regex=True) is False
assert frontmatter.contains("key", r"_\d", is_regex=True) is False
assert frontmatter.contains("key", r"\w\d_", is_regex=True) is True
def test_frontmatter_rename() -> None:
"""Test frontmatter rename."""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
assert frontmatter.dict == {
"frontmatter_Key1": ["frontmatter_Key1_value"],
"frontmatter_Key2": ["article", "note"],
"shared_key1": ["shared_key1_value"],
"tags": ["tag_1", "tag_2", "📅/tag_3"],
}
assert frontmatter.rename("no key", "new key") is False
assert frontmatter.rename("tags", "no tag", "new key") is False
assert frontmatter.has_changes() is False
assert frontmatter.rename("tags", "tag_2", "new tag") is True
assert frontmatter.dict["tags"] == ["new tag", "tag_1", "📅/tag_3"]
assert frontmatter.rename("tags", "old_tags") is True
assert frontmatter.dict["old_tags"] == ["new tag", "tag_1", "📅/tag_3"]
assert "tags" not in frontmatter.dict
assert frontmatter.has_changes() is True
def test_frontmatter_delete() -> None:
"""Test Frontmatter delete method."""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
assert frontmatter.dict == {
"frontmatter_Key1": ["frontmatter_Key1_value"],
"frontmatter_Key2": ["article", "note"],
"shared_key1": ["shared_key1_value"],
"tags": ["tag_1", "tag_2", "📅/tag_3"],
}
assert frontmatter.delete("no key") is False
assert frontmatter.delete("tags", "no value") is False
assert frontmatter.delete(r"\d{3}") is False
assert frontmatter.has_changes() is False
assert frontmatter.delete("tags", "tag_2") is True
assert frontmatter.dict["tags"] == ["tag_1", "📅/tag_3"]
assert frontmatter.delete("tags") is True
assert "tags" not in frontmatter.dict
assert frontmatter.has_changes() is True
assert frontmatter.delete("shared_key1", r"\w+") is True
assert frontmatter.dict["shared_key1"] == []
assert frontmatter.delete(r"\w.tter") is True
assert frontmatter.dict == {"shared_key1": []}
def test_frontmatter_yaml_conversion():
"""Test Frontmatter to_yaml method."""
new_frontmatter: str = """\
tags:
- tag_1
- tag_2
- 📅/tag_3
frontmatter_Key1: frontmatter_Key1_value
frontmatter_Key2:
- article
- note
shared_key1: shared_key1_value
"""
new_frontmatter_sorted: str = """\
frontmatter_Key1: frontmatter_Key1_value
frontmatter_Key2:
- article
- note
shared_key1: shared_key1_value
tags:
- tag_1
- tag_2
- 📅/tag_3
"""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
assert frontmatter.to_yaml() == new_frontmatter
assert frontmatter.to_yaml(sort_keys=True) == new_frontmatter_sorted
def test_inline_metadata_create() -> None:
"""Test inline metadata creation."""
inline = InlineMetadata(FRONTMATTER_CONTENT)
assert inline.dict == {}
inline = InlineMetadata(INLINE_CONTENT)
assert inline.dict == {
"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.dict_original == {
"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_contains() -> None:
"""Test inline metadata contains method."""
inline = InlineMetadata(INLINE_CONTENT)
assert inline.contains("bold_key1") is True
assert inline.contains("bold_key2", "bold_key2_value") is True
assert inline.contains("bold_key3") is False
assert inline.contains("bold_key2", "no value") is False
assert inline.contains(r"\w{4}_key", is_regex=True) is True
assert inline.contains(r"^\d", is_regex=True) is False
assert inline.contains("1$", r"\d_value", is_regex=True) is True
assert inline.contains("key", r"^\d_value", is_regex=True) is False
def test_inline_metadata_rename() -> None:
"""Test inline metadata rename."""
inline = InlineMetadata(INLINE_CONTENT)
assert inline.dict == {
"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.rename("no key", "new key") is False
assert inline.rename("repeated_key", "no value", "new key") is False
assert inline.has_changes() is False
assert inline.rename("repeated_key", "repeated_key_value1", "new value") is True
assert inline.dict["repeated_key"] == ["new value", "repeated_key_value2"]
assert inline.rename("repeated_key", "old_key") is True
assert inline.dict["old_key"] == ["new value", "repeated_key_value2"]
assert "repeated_key" not in inline.dict
assert inline.has_changes() is True
def test_inline_metadata_delete() -> None:
"""Test inline metadata delete."""
inline = InlineMetadata(INLINE_CONTENT)
assert inline.dict == {
"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.delete("no key") is False
assert inline.delete("repeated_key", "no value") is False
assert inline.has_changes() is False
assert inline.delete("repeated_key", "repeated_key_value1") is True
assert inline.dict["repeated_key"] == ["repeated_key_value2"]
assert inline.delete("repeated_key") is True
assert "repeated_key" not in inline.dict
assert inline.has_changes() is True
assert inline.delete(r"\d{3}") is False
assert inline.delete(r"bold_key\d") is True
assert inline.dict == {
"emoji_📅_key": ["emoji_📅_key_value"],
"in_text_key1": ["in_text_key1_value"],
"in_text_key2": ["in_text_key2_value"],
"link_key": ["link_key_value"],
"tag_key": ["tag_key_value"],
}
assert inline.delete("emoji_📅_key", ".*📅.*") is True
assert inline.dict == {
"emoji_📅_key": [],
"in_text_key1": ["in_text_key1_value"],
"in_text_key2": ["in_text_key2_value"],
"link_key": ["link_key_value"],
"tag_key": ["tag_key_value"],
}
def test_inline_tags_create() -> None:
"""Test inline tags creation."""
tags = InlineTags(FRONTMATTER_CONTENT)
tags.metadata_key
assert tags.list == []
tags = InlineTags(INLINE_CONTENT)
assert tags.list == [
"bold_tag",
"in_text_tag",
"inline_tag_top1",
"inline_tag_top2",
"tag_key_value",
]
assert tags.list_original == [
"bold_tag",
"in_text_tag",
"inline_tag_top1",
"inline_tag_top2",
"tag_key_value",
]
def test_inline_tags_contains() -> None:
"""Test inline tags contains."""
tags = InlineTags(INLINE_CONTENT)
assert tags.contains("bold_tag") is True
assert tags.contains("no tag") is False
assert tags.contains(r"\w_\w", is_regex=True) is True
assert tags.contains(r"\d_\d", is_regex=True) is False
def test_inline_tags_rename() -> None:
"""Test inline tags rename."""
tags = InlineTags(INLINE_CONTENT)
assert tags.list == [
"bold_tag",
"in_text_tag",
"inline_tag_top1",
"inline_tag_top2",
"tag_key_value",
]
assert tags.rename("no tag", "new tag") is False
assert tags.has_changes() is False
assert tags.rename("bold_tag", "new tag") is True
assert tags.list == [
"in_text_tag",
"inline_tag_top1",
"inline_tag_top2",
"new tag",
"tag_key_value",
]
assert tags.has_changes() is True
def test_inline_tags_delete() -> None:
"""Test inline tags delete."""
tags = InlineTags(INLINE_CONTENT)
assert tags.list == [
"bold_tag",
"in_text_tag",
"inline_tag_top1",
"inline_tag_top2",
"tag_key_value",
]
assert tags.delete("no tag") is False
assert tags.has_changes() is False
assert tags.delete("bold_tag") is True
assert tags.list == [
"in_text_tag",
"inline_tag_top1",
"inline_tag_top2",
"tag_key_value",
]
assert tags.has_changes() is True
assert tags.delete(r"\d{3}") is False
assert tags.delete(r"inline_tag_top\d") is True
assert tags.list == ["in_text_tag", "tag_key_value"]

358
tests/notes_test.py Normal file
View File

@@ -0,0 +1,358 @@
# type: ignore
"""Test notes.py."""
import re
from pathlib import Path
import pytest
import typer
from obsidian_metadata.models.notes import Note
from tests.helpers import Regex
def test_note_not_exists() -> None:
"""Test target not found."""
with pytest.raises(typer.Exit):
note = Note(note_path="nonexistent_file.md")
assert note.note_path == "tests/test_data/test_note.md"
assert note.file_content == "This is a test note."
assert note.frontmatter == {}
assert note.inline_tags == []
assert note.inline_metadata == {}
assert note.dry_run is False
def test_note_create(sample_note) -> None:
"""Test creating note class."""
note = Note(note_path=sample_note, dry_run=True)
assert note.note_path == Path(sample_note)
assert note.dry_run is True
assert "Lorem ipsum dolor" in note.file_content
assert note.frontmatter.dict == {
"date_created": ["2022-12-22"],
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "note"],
"shared_key1": ["shared_key1_value"],
"shared_key2": ["shared_key2_value1"],
"tags": [
"frontmatter_tag1",
"frontmatter_tag2",
"shared_tag",
"📅/frontmatter_tag3",
],
}
assert note.inline_tags.list == [
"inline_tag_bottom1",
"inline_tag_bottom2",
"inline_tag_top1",
"inline_tag_top2",
"intext_tag1",
"intext_tag2",
"shared_tag",
]
assert note.inline_metadata.dict == {
"bottom_key1": ["bottom_key1_value"],
"bottom_key2": ["bottom_key2_value"],
"emoji_📅_key": ["emoji_📅_key_value"],
"intext_key": ["intext_value"],
"shared_key1": ["shared_key1_value"],
"shared_key2": ["shared_key2_value2"],
"top_key1": ["top_key1_value"],
"top_key2": ["top_key2_value"],
"top_key3": ["top_key3_value_as_link"],
}
with sample_note.open():
content = sample_note.read_text()
assert note.file_content == content
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
string = "This is a test string."
string2 = "Lorem ipsum dolor sit"
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
def test_contains_inline_tag(sample_note) -> None:
"""Test contains inline tag."""
note = Note(note_path=sample_note)
assert note.contains_inline_tag("intext_tag1") is True
assert note.contains_inline_tag("nonexistent_tag") is False
assert note.contains_inline_tag(r"\d$", is_regex=True) is True
assert note.contains_inline_tag(r"^\d", is_regex=True) is False
def test_contains_metadata(sample_note) -> None:
"""Test contains metadata."""
note = Note(note_path=sample_note)
assert note.contains_metadata("no key") is False
assert note.contains_metadata("frontmatter_Key2") is True
assert note.contains_metadata(r"^\d", is_regex=True) is False
assert note.contains_metadata(r"^[\w_]+\d", is_regex=True) is True
assert note.contains_metadata("frontmatter_Key2", "no value") is False
assert note.contains_metadata("frontmatter_Key2", "article") is True
assert note.contains_metadata("bottom_key1", "bottom_key1_value") is True
assert note.contains_metadata(r"bottom_key\d$", r"bottom_key\d_value", is_regex=True) is True
def test_delete_inline_metadata(sample_note) -> None:
"""Test deleting inline metadata."""
note = Note(note_path=sample_note)
note._delete_inline_metadata("nonexistent_key")
assert note.file_content == note.original_file_content
note._delete_inline_metadata("frontmatter_Key1")
assert note.file_content == note.original_file_content
note._delete_inline_metadata("intext_key")
assert note.file_content == Regex(r"dolore eu fugiat", re.DOTALL)
note._delete_inline_metadata("bottom_key2", "bottom_key2_value")
assert note.file_content != Regex(r"bottom_key2_value")
assert note.file_content == Regex(r"bottom_key2::")
note._delete_inline_metadata("bottom_key1")
assert note.file_content != Regex(r"bottom_key1::")
def test_delete_inline_tag(sample_note) -> None:
"""Test deleting inline tags."""
note = Note(note_path=sample_note)
assert note.delete_inline_tag("not_a_tag") is False
assert note.delete_inline_tag("intext_tag[1]") is True
assert "intext_tag1" not in note.inline_tags.list
assert note.file_content == Regex("consequat. Duis")
def test_delete_metadata(sample_note) -> Note:
"""Test deleting metadata."""
note = Note(note_path=sample_note)
assert note.delete_metadata("nonexistent_key") is False
assert note.delete_metadata("frontmatter_Key1", "no value") is False
assert note.delete_metadata("frontmatter_Key1") is True
assert "frontmatter_Key1" not in note.frontmatter.dict
assert note.delete_metadata("frontmatter_Key2", "article") is True
assert note.frontmatter.dict["frontmatter_Key2"] == ["note"]
assert note.delete_metadata("bottom_key1", "bottom_key1_value") is True
assert note.inline_metadata.dict["bottom_key1"] == []
assert note.file_content == Regex(r"bottom_key1::\n")
assert note.delete_metadata("bottom_key2") is True
assert "bottom_key2" not in note.inline_metadata.dict
assert note.file_content != Regex(r"bottom_key2")
def test_has_changes(sample_note) -> None:
"""Test has changes."""
note = Note(note_path=sample_note)
assert note.has_changes() is False
note.append("This is a test string.")
assert note.has_changes() is True
note = Note(note_path=sample_note)
assert note.has_changes() is False
note.delete_metadata("frontmatter_Key1")
assert note.has_changes() is True
note = Note(note_path=sample_note)
assert note.has_changes() is False
note.delete_metadata("bottom_key2")
assert note.has_changes() is True
note = Note(note_path=sample_note)
assert note.has_changes() is False
note.delete_inline_tag("intext_tag1")
assert note.has_changes() is True
def test_print_note(sample_note, capsys) -> None:
"""Test printing note."""
note = Note(note_path=sample_note)
note.print_note()
captured = capsys.readouterr()
assert "```python" in captured.out
assert "---" in captured.out
assert "#shared_tag" in captured.out
def test_print_diff(sample_note, capsys) -> None:
"""Test printing diff."""
note = Note(note_path=sample_note)
note.print_diff()
captured = capsys.readouterr()
assert captured.out == ""
note.append("This is a test string.")
note.print_diff()
captured = capsys.readouterr()
assert "+ This is a test string." in captured.out
note.sub("The quick brown fox", "The quick brown hedgehog")
note.print_diff()
captured = capsys.readouterr()
assert "- The quick brown fox" in captured.out
assert "+ The quick brown hedgehog" in captured.out
def test_sub(sample_note) -> None:
"""Test substituting text in a note."""
note = Note(note_path=sample_note)
note.sub("#shared_tag", "#unshared_tags", is_regex=True)
assert note.file_content != Regex(r"#shared_tag")
assert note.file_content == Regex(r"#unshared_tags")
note.sub(" ut ", "")
assert note.file_content != Regex(r" ut ")
assert note.file_content == Regex(r"laboriosam, nisialiquid ex ea")
def test_rename_inline_tag(sample_note) -> None:
"""Test renaming an inline tag."""
note = Note(note_path=sample_note)
assert note.rename_inline_tag("no_note_tag", "intext_tag2") is False
assert note.rename_inline_tag("intext_tag1", "intext_tag26") is True
assert note.inline_tags.list == [
"inline_tag_bottom1",
"inline_tag_bottom2",
"inline_tag_top1",
"inline_tag_top2",
"intext_tag2",
"intext_tag26",
"shared_tag",
]
assert note.file_content == Regex(r"#intext_tag26")
assert note.file_content != Regex(r"#intext_tag1")
def test_rename_inline_metadata(sample_note) -> None:
"""Test renaming inline metadata."""
note = Note(note_path=sample_note)
note._rename_inline_metadata("nonexistent_key", "new_key")
assert note.file_content == note.original_file_content
note._rename_inline_metadata("bottom_key1", "no_value", "new_value")
assert note.file_content == note.original_file_content
note._rename_inline_metadata("bottom_key1", "new_key")
assert note.file_content != Regex(r"bottom_key1::")
assert note.file_content == Regex(r"new_key::")
note._rename_inline_metadata("emoji_📅_key", "emoji_📅_key_value", "new_value")
assert note.file_content != Regex(r"emoji_📅_key:: ?emoji_📅_key_value")
assert note.file_content == Regex(r"emoji_📅_key:: ?new_value")
def test_rename_metadata(sample_note) -> None:
"""Test renaming metadata."""
note = Note(note_path=sample_note)
assert note.rename_metadata("nonexistent_key", "new_key") is False
assert note.rename_metadata("frontmatter_Key1", "nonexistent_value", "article") is False
assert note.rename_metadata("frontmatter_Key1", "new_key") is True
assert "frontmatter_Key1" not in note.frontmatter.dict
assert "new_key" in note.frontmatter.dict
assert note.frontmatter.dict["new_key"] == ["author name"]
assert note.file_content == Regex(r"new_key: author name")
assert note.rename_metadata("frontmatter_Key2", "article", "new_key") is True
assert note.frontmatter.dict["frontmatter_Key2"] == ["new_key", "note"]
assert note.file_content == Regex(r" - new_key")
assert note.file_content != Regex(r" - article")
assert note.rename_metadata("bottom_key1", "new_key") is True
assert "bottom_key1" not in note.inline_metadata.dict
assert "new_key" in note.inline_metadata.dict
assert note.file_content == Regex(r"new_key:: bottom_key1_value")
assert note.rename_metadata("new_key", "bottom_key1_value", "new_value") is True
assert note.inline_metadata.dict["new_key"] == ["new_value"]
assert note.file_content == Regex(r"new_key:: new_value")
def test_replace_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()
new_frontmatter = """---
date_created: '2022-12-22'
tags:
- frontmatter_tag1
- frontmatter_tag2
- shared_tag
- 📅/frontmatter_tag3
frontmatter_Key1: some_new_key_here
frontmatter_Key2:
- article
- note
shared_key1: shared_key1_value
shared_key2: shared_key2_value1
---"""
assert new_frontmatter in note.file_content
assert "# Heading 1" in note.file_content
assert "```python" in note.file_content
note2 = Note(note_path="tests/fixtures/test_vault/no_metadata.md")
note2.replace_frontmatter()
note2.frontmatter.dict = {"key1": "value1", "key2": "value2"}
note2.replace_frontmatter()
new_frontmatter = """---
key1: value1
key2: value2
---"""
assert new_frontmatter in note2.file_content
assert "Lorem ipsum dolor sit amet" in note2.file_content
def test_write(sample_note, tmp_path) -> None:
"""Test writing note to file."""
note = Note(note_path=sample_note)
note.sub(pattern="Heading 1", replacement="Heading 2")
note.write()
note = Note(note_path=sample_note)
assert "Heading 2" in note.file_content
assert "Heading 1" not in note.file_content
new_path = Path(tmp_path / "new_note.md")
note.write(new_path)
note2 = Note(note_path=new_path)
assert "Heading 2" in note2.file_content
assert "Heading 1" not in note2.file_content

112
tests/patterns_test.py Normal file
View File

@@ -0,0 +1,112 @@
# type: ignore
"""Tests for the regex module."""
import pytest
from obsidian_metadata.models.patterns import Patterns
TAG_CONTENT: str = "#1 #2 **#3** [[#4]] [[#5|test]] #6#notag #7_8 #9/10 #11-12 #13; #14, #15. #16: #17* #18(#19) #20[#21] #22\\ #23& #24# #25 **#26** #📅/tag"
INLINE_METADATA: str = """
**1:: 1**
2_2:: [[2_2]] | 2
asdfasdf [3:: 3] asdfasdf [7::7] asdf
[4:: 4] [5:: 5]
> 6:: 6
**8**:: **8**
10::
📅11:: 11/📅/11
emoji_📅_key:: 📅emoji_📅_key_value
"""
FRONTMATTER_CONTENT: str = """
---
tags:
- tag_1
- tag_2
-
- 📅/tag_3
frontmatter_Key1: "frontmatter_Key1_value"
frontmatter_Key2: ["note", "article"]
shared_key1: 'shared_key1_value'
---
more content
---
horizontal: rule
---
"""
CORRECT_FRONTMATTER_WITH_SEPARATORS: str = """---
tags:
- tag_1
- tag_2
-
- 📅/tag_3
frontmatter_Key1: "frontmatter_Key1_value"
frontmatter_Key2: ["note", "article"]
shared_key1: 'shared_key1_value'
---"""
CORRECT_FRONTMATTER_NO_SEPARATORS: str = """
tags:
- tag_1
- tag_2
-
- 📅/tag_3
frontmatter_Key1: "frontmatter_Key1_value"
frontmatter_Key2: ["note", "article"]
shared_key1: 'shared_key1_value'
"""
def test_regex():
"""Test regexes."""
pattern = Patterns()
assert pattern.find_inline_tags.findall(TAG_CONTENT) == [
"1",
"2",
"3",
"4",
"5",
"6",
"7_8",
"9/10",
"11-12",
"13",
"14",
"15",
"16",
"17",
"18",
"19",
"20",
"21",
"22",
"23",
"24",
"25",
"26",
"📅/tag",
]
result = pattern.find_inline_metadata.findall(INLINE_METADATA)
assert result == [
("", "", "1", "1**"),
("", "", "2_2", "[[2_2]] | 2"),
("3", "3", "", ""),
("7", "7", "", ""),
("", "", "4", "4] [5:: 5]"),
("", "", "8**", "**8**"),
("", "", "11", "11/📅/11"),
("", "", "emoji_📅_key", "📅emoji_📅_key_value"),
]
found = pattern.frontmatt_block_with_separators.search(FRONTMATTER_CONTENT).group("frontmatter")
assert found == CORRECT_FRONTMATTER_WITH_SEPARATORS
found = pattern.frontmatt_block_no_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")
assert pattern.validate_tag_text.search("test_tag") is None
assert pattern.validate_tag_text.search("#asdf").group(0) == "#"

116
tests/utilities_test.py Normal file
View File

@@ -0,0 +1,116 @@
# type: ignore
"""Test the utilities module."""
from obsidian_metadata._utils import (
clean_dictionary,
dict_contains,
dict_values_to_lists_strings,
remove_markdown_sections,
vault_validation,
)
def test_dict_contains() -> None:
"""Test dict_contains."""
d = {"key1": ["value1", "value2"], "key2": ["value3", "value4"], "key3": ["value5", "value6"]}
assert dict_contains(d, "key1") is True
assert dict_contains(d, "key5") is False
assert dict_contains(d, "key1", "value1") is True
assert dict_contains(d, "key1", "value5") is False
assert dict_contains(d, "key[1-2]", is_regex=True) is True
assert dict_contains(d, "^1", is_regex=True) is False
assert dict_contains(d, r"key\d", r"value\d", is_regex=True) is True
assert dict_contains(d, "key1$", "^alue", is_regex=True) is False
assert dict_contains(d, r"key\d", "value5", is_regex=True) is True
def test_dict_values_to_lists_strings():
"""Test converting dictionary values to lists of strings."""
dictionary = {
"key1": "value1",
"key2": ["value2", "value3", None],
"key3": {"key4": "value4"},
"key5": {"key6": {"key7": "value7"}},
"key6": None,
"key8": [1, 3, None, 4],
"key9": [None, "", "None"],
"key10": "None",
"key11": "",
}
result = dict_values_to_lists_strings(dictionary)
assert result == {
"key1": ["value1"],
"key10": ["None"],
"key11": [""],
"key2": ["None", "value2", "value3"],
"key3": {"key4": ["value4"]},
"key5": {"key6": {"key7": ["value7"]}},
"key6": ["None"],
"key8": ["1", "3", "4", "None"],
"key9": ["", "None", "None"],
}
result = dict_values_to_lists_strings(dictionary, strip_null_values=True)
assert result == {
"key1": ["value1"],
"key10": [],
"key11": [],
"key2": ["value2", "value3"],
"key3": {"key4": ["value4"]},
"key5": {"key6": {"key7": ["value7"]}},
"key6": [],
"key8": ["1", "3", "4"],
"key9": ["", "None"],
}
def test_vault_validation():
"""Test vault validation."""
assert vault_validation("tests/") is True
assert "Path is not a directory" in vault_validation("pyproject.toml")
assert "Path does not exist" in vault_validation("tests/vault2")
def test_remove_markdown_sections():
"""Test removing markdown sections."""
text: str = """
---
key: value
---
Lorem ipsum `dolor sit` amet.
```bash
echo "Hello World"
```
---
dd
---
"""
result = remove_markdown_sections(
text,
strip_codeblocks=True,
strip_frontmatter=True,
strip_inlinecode=True,
)
assert "```bash" not in result
assert "`dolor sit`" not in result
assert "---\nkey: value" not in result
assert "`" not in result
result = remove_markdown_sections(text)
assert "```bash" in result
assert "`dolor sit`" in result
assert "---\nkey: value" in result
assert "`" in result
def test_clean_dictionary():
"""Test cleaning a dictionary."""
dictionary = {" *key* ": ["**value**", "[[value2]]", "#value3"]}
new_dict = clean_dictionary(dictionary)
assert new_dict == {"key": ["value", "value2", "value3"]}

248
tests/vault_test.py Normal file
View File

@@ -0,0 +1,248 @@
# type: ignore
"""Tests for the Vault module."""
from pathlib import Path
from obsidian_metadata._config import Config
from obsidian_metadata.models import Vault
from tests.helpers import Regex
def test_vault_creation(test_vault):
"""Test creating a Vault object."""
vault_path = test_vault
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
vault = Vault(config=config)
assert vault.vault_path == vault_path
assert vault.backup_path == Path(f"{vault_path}.bak")
assert vault.new_vault_path == Path(f"{vault_path}.new")
assert vault.dry_run is False
assert str(vault.exclude_paths[0]) == Regex(r".*\.git")
assert vault.num_notes() == 2
assert vault.metadata.dict == {
"Inline Tags": [
"inline_tag_bottom1",
"inline_tag_bottom2",
"inline_tag_top1",
"inline_tag_top2",
"intext_tag1",
"intext_tag2",
"shared_tag",
],
"bottom_key1": ["bottom_key1_value"],
"bottom_key2": ["bottom_key2_value"],
"date_created": ["2022-12-22"],
"emoji_📅_key": ["emoji_📅_key_value"],
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "note"],
"intext_key": ["intext_value"],
"shared_key1": ["shared_key1_value"],
"shared_key2": ["shared_key2_value1", "shared_key2_value2"],
"tags": [
"frontmatter_tag1",
"frontmatter_tag2",
"shared_tag",
"📅/frontmatter_tag3",
],
"top_key1": ["top_key1_value"],
"top_key2": ["top_key2_value"],
"top_key3": ["top_key3_value_as_link"],
}
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 = Vault(config=config, path_filter="front")
assert vault.num_notes() == 4
vault_path = sample_vault
config = Config(config_path="tests/fixtures/sample_vault_config.toml", vault_path=vault_path)
vault2 = Vault(config=config, path_filter="mixed")
assert vault2.num_notes() == 1
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 = Vault(config=config, dry_run=False)
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 = Vault(config=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 = Vault(config=config, dry_run=False)
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 = Vault(config=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 = Vault(config=config)
vault.info()
captured = capsys.readouterr()
assert captured.out == Regex(r"Vault +\│ /[\d\w]+")
assert captured.out == Regex(r"Notes being edited +\\d+")
assert captured.out == Regex(r"Backup +\│ None")
def test_contains_inline_tag(test_vault) -> None:
"""Test if the vault contains an inline tag."""
vault_path = test_vault
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
vault = Vault(config=config)
assert vault.contains_inline_tag("tag") is False
assert vault.contains_inline_tag("intext_tag2") is True
def test_contains_metadata(test_vault) -> None:
"""Test if the vault contains a metadata key."""
vault_path = test_vault
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
vault = Vault(config=config)
assert vault.contains_metadata("key") is False
assert vault.contains_metadata("top_key1") is True
assert vault.contains_metadata("top_key1", "no_value") is False
assert vault.contains_metadata("top_key1", "top_key1_value") is True
def test_delete_inline_tag(test_vault) -> None:
"""Test deleting an inline tag."""
vault_path = test_vault
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
vault = Vault(config=config)
assert vault.delete_inline_tag("no tag") is False
assert vault.delete_inline_tag("intext_tag2") is True
assert vault.metadata.dict["Inline Tags"] == [
"inline_tag_bottom1",
"inline_tag_bottom2",
"inline_tag_top1",
"inline_tag_top2",
"intext_tag1",
"shared_tag",
]
def test_delete_metadata(test_vault) -> None:
"""Test deleting a metadata key/value."""
vault_path = test_vault
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
vault = Vault(config=config)
assert vault.delete_metadata("no key") == 0
assert vault.delete_metadata("top_key1", "no_value") == 0
assert vault.delete_metadata("top_key1", "top_key1_value") == 1
assert vault.metadata.dict["top_key1"] == []
assert vault.delete_metadata("top_key2") == 1
assert "top_key2" not in vault.metadata.dict
def test_rename_inline_tag(test_vault) -> None:
"""Test renaming an inline tag."""
vault_path = test_vault
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
vault = Vault(config=config)
assert vault.rename_inline_tag("no tag", "new_tag") is False
assert vault.rename_inline_tag("intext_tag2", "new_tag") is True
assert vault.metadata.dict["Inline Tags"] == [
"inline_tag_bottom1",
"inline_tag_bottom2",
"inline_tag_top1",
"inline_tag_top2",
"intext_tag1",
"new_tag",
"shared_tag",
]
def test_rename_metadata(test_vault) -> None:
"""Test renaming a metadata key/value."""
vault_path = test_vault
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
vault = Vault(config=config)
assert vault.rename_metadata("no key", "new_key") is False
assert vault.rename_metadata("tags", "nonexistent_value", "new_vaule") is False
assert vault.rename_metadata("tags", "frontmatter_tag1", "new_vaule") is True
assert vault.metadata.dict["tags"] == [
"frontmatter_tag2",
"new_vaule",
"shared_tag",
"📅/frontmatter_tag3",
]
assert vault.rename_metadata("tags", "new_key") is True
assert "tags" not in vault.metadata.dict
assert vault.metadata.dict["new_key"] == [
"frontmatter_tag2",
"new_vaule",
"shared_tag",
"📅/frontmatter_tag3",
]