khoj/tests/test_orgnode.py
Debanjum Singh Solanky b9a6e80629 Make OrgNode tags stable sorted to find new entries for incremental updates
- Having Tags as sets was returning them in a different order
  everytime
- This resulted in spuriously identifying existing entries as new
  because their tags ordering changed
- Converting tags to list fixes the issue and identifies updated new
  entries for incremental update correctly
2022-09-10 20:59:52 +03:00

177 lines
No EOL
5.7 KiB
Python

# Standard Packages
import datetime
from os.path import relpath
from pathlib import Path
# Internal Packages
from src.processor.org_mode import orgnode
# Test
# ----------------------------------------------------------------------------------------------------
def test_parse_minimal_entry(tmp_path):
"Test parsing of entry with minimal fields"
# Arrange
entry = f'''
* Heading
Body Line 1'''
orgfile = create_file(tmp_path, entry)
# Act
entries = orgnode.makelist(orgfile)
# Assert
assert len(entries) == 1
assert entries[0].Heading() == "Heading"
assert entries[0].Tags() == list()
assert entries[0].Body() == "Body Line 1"
assert entries[0].Priority() == ""
assert entries[0].Property("ID") == ""
assert entries[0].Closed() == ""
assert entries[0].Scheduled() == ""
assert entries[0].Deadline() == ""
# ----------------------------------------------------------------------------------------------------
def test_parse_complete_entry(tmp_path):
"Test parsing of entry with all important fields"
# Arrange
entry = f'''
*** DONE [#A] Heading :Tag1:TAG2:tag3:
CLOSED: [1984-04-01 Sun 12:00] SCHEDULED: <1984-04-01 Sun 09:00> DEADLINE: <1984-04-01 Sun>
:PROPERTIES:
:ID: 123-456-789-4234-1231
:END:
:LOGBOOK:
CLOCK: [1984-04-01 Sun 09:00]--[1984-04-01 Sun 12:00] => 3:00
- Clocked Log 1
:END:
Body Line 1
Body Line 2'''
orgfile = create_file(tmp_path, entry)
# Act
entries = orgnode.makelist(orgfile)
# Assert
assert len(entries) == 1
assert entries[0].Heading() == "Heading"
assert entries[0].Todo() == "DONE"
assert entries[0].Tags() == ["Tag1", "TAG2", "tag3"]
assert entries[0].Body() == "- Clocked Log 1\nBody Line 1\nBody Line 2"
assert entries[0].Priority() == "A"
assert entries[0].Property("ID") == "id:123-456-789-4234-1231"
assert entries[0].Closed() == datetime.date(1984,4,1)
assert entries[0].Scheduled() == datetime.date(1984,4,1)
assert entries[0].Deadline() == datetime.date(1984,4,1)
assert entries[0].Logbook() == [(datetime.datetime(1984,4,1,9,0,0), datetime.datetime(1984,4,1,12,0,0))]
# ----------------------------------------------------------------------------------------------------
def test_all_links_to_entry_rendered(tmp_path):
"Ensure all links to entry rendered in property drawer from entry"
# Arrange
entry = f'''
*** [#A] Heading :tag1:
:PROPERTIES:
:ID: 123-456-789-4234-1231
:END:
Body Line 1
*** Heading2
Body Line 2
'''
orgfile = create_file(tmp_path, entry)
normalized_orgfile = f'~/{relpath(orgfile, start=Path.home())}'
# Act
entries = orgnode.makelist(orgfile)
# Assert
# SOURCE link rendered with Heading
assert f':SOURCE: [[file:{normalized_orgfile}::*{entries[0].Heading()}]]' in f'{entries[0]}'
# ID link rendered with ID
assert f':ID: id:123-456-789-4234-1231' in f'{entries[0]}'
# LINE link rendered with line number
assert f':LINE: file:{normalized_orgfile}::2' in f'{entries[0]}'
# ----------------------------------------------------------------------------------------------------
def test_source_link_to_entry_escaped_for_rendering(tmp_path):
"Test SOURCE link renders with square brackets in filename, heading escaped for org-mode rendering"
# Arrange
entry = f'''
*** [#A] Heading[1] :tag1:
:PROPERTIES:
:ID: 123-456-789-4234-1231
:END:
Body Line 1'''
orgfile = create_file(tmp_path, entry, filename="test[1].org")
# Act
entries = orgnode.makelist(orgfile)
# Assert
assert len(entries) == 1
# parsed heading from entry
assert entries[0].Heading() == "Heading[1]"
# ensure SOURCE link has square brackets in filename, heading escaped in rendered entries
normalized_orgfile = f'~/{relpath(orgfile, start=Path.home())}'
escaped_orgfile = f'{normalized_orgfile}'.replace("[1]", "\\[1\\]")
assert f':SOURCE: [[file:{escaped_orgfile}::*Heading\[1\]' in f'{entries[0]}'
# ----------------------------------------------------------------------------------------------------
def test_parse_multiple_entries(tmp_path):
"Test parsing of multiple entries"
# Arrange
content = f'''
*** FAILED [#A] Heading1 :tag1:
CLOSED: [1984-04-01 Sun 12:00] SCHEDULED: <1984-04-01 Sun 09:00> DEADLINE: <1984-04-01 Sun>
:PROPERTIES:
:ID: 123-456-789-4234-0001
:END:
:LOGBOOK:
CLOCK: [1984-04-01 Sun 09:00]--[1984-04-01 Sun 12:00] => 3:00
- Clocked Log 1
:END:
Body 1
*** CANCELLED [#A] Heading2 :tag2:
CLOSED: [1984-04-02 Sun 12:00] SCHEDULED: <1984-04-02 Sun 09:00> DEADLINE: <1984-04-02 Sun>
:PROPERTIES:
:ID: 123-456-789-4234-0002
:END:
:LOGBOOK:
CLOCK: [1984-04-02 Mon 09:00]--[1984-04-02 Mon 12:00] => 3:00
- Clocked Log 2
:END:
Body 2
'''
orgfile = create_file(tmp_path, content)
# Act
entries = orgnode.makelist(orgfile)
# Assert
assert len(entries) == 2
for index, entry in enumerate(entries):
assert entry.Heading() == f"Heading{index+1}"
assert entry.Todo() == "FAILED" if index == 0 else "CANCELLED"
assert entry.Tags() == [f"tag{index+1}"]
assert entry.Body() == f"- Clocked Log {index+1}\nBody {index+1}\n\n"
assert entry.Priority() == "A"
assert entry.Property("ID") == f"id:123-456-789-4234-000{index+1}"
assert entry.Closed() == datetime.date(1984,4,index+1)
assert entry.Scheduled() == datetime.date(1984,4,index+1)
assert entry.Deadline() == datetime.date(1984,4,index+1)
assert entry.Logbook() == [(datetime.datetime(1984,4,index+1,9,0,0), datetime.datetime(1984,4,index+1,12,0,0))]
# Helper Functions
def create_file(tmp_path, entry, filename="test.org"):
org_file = tmp_path / f"notes/{filename}"
org_file.parent.mkdir()
org_file.touch()
org_file.write_text(entry)
return org_file