fix tests for markdown

This commit is contained in:
phernandez
2024-12-21 16:49:30 -06:00
parent 7dfea0c704
commit 4d331a4ac9
5 changed files with 66 additions and 65 deletions
+18 -18
View File
@@ -1,12 +1,13 @@
"""Tests for frontmatter parsing."""
from datetime import datetime
from datetime import datetime, UTC
from textwrap import dedent
import pytest
from basic_memory.markdown import EntityFrontmatter
from basic_memory.markdown.exceptions import ParseError
from basic_memory.markdown.frontmatter_parser import FrontmatterParser
def test_parse_frontmatter():
"""Test parsing basic frontmatter."""
@@ -15,18 +16,18 @@ def test_parse_frontmatter():
id: test/basic
created: 2024-12-21T14:00:00Z
modified: 2024-12-21T14:00:00Z
tags: [test, base]
tags: test, base
""")
parser = FrontmatterParser()
result = parser.parse(text)
result = EntityFrontmatter.from_text(text)
assert result.type == "component"
assert result.id == "test/basic"
assert result.created == datetime(2024, 12, 21, 14, 0)
assert result.modified == datetime(2024, 12, 21, 14, 0)
assert result.created == datetime(2024, 12, 21, 14, 0, tzinfo=UTC)
assert result.modified == datetime(2024, 12, 21, 14, 0, tzinfo=UTC)
assert result.tags == ["test", "base"]
def test_parse_frontmatter_comma_tags():
"""Test parsing frontmatter with comma-separated tags."""
text = dedent("""
@@ -37,11 +38,11 @@ def test_parse_frontmatter_comma_tags():
tags: first, second, third
""")
parser = FrontmatterParser()
result = parser.parse(text)
result = EntityFrontmatter.from_text(text)
assert result.tags == ["first", "second", "third"]
def test_parse_frontmatter_missing_required():
"""Test error on missing required fields."""
text = dedent("""
@@ -52,9 +53,9 @@ def test_parse_frontmatter_missing_required():
tags: []
""")
parser = FrontmatterParser()
with pytest.raises(ParseError):
parser.parse(text)
EntityFrontmatter.from_text(text)
def test_parse_frontmatter_invalid_date():
"""Test error on invalid date format."""
@@ -63,12 +64,12 @@ def test_parse_frontmatter_invalid_date():
id: test/dates
created: not-a-date
modified: 2024-12-21T14:00:00Z
tags: []
tags:
""")
parser = FrontmatterParser()
with pytest.raises(ParseError):
parser.parse(text)
EntityFrontmatter.from_text(text)
def test_parse_frontmatter_whitespace():
"""Test handling of various whitespace in frontmatter."""
@@ -77,12 +78,11 @@ def test_parse_frontmatter_whitespace():
id: test/whitespace
created: 2024-12-21T14:00:00Z
modified: 2024-12-21T14:00:00Z
tags: [ one, two , three ]
tags: one, two , three
""")
parser = FrontmatterParser()
result = parser.parse(text)
result = EntityFrontmatter.from_text(text)
assert result.type == "component"
assert result.id == "test/whitespace"
assert result.tags == ["one", "two", "three"]
assert result.tags == ["one", "two", "three"]
+11 -15
View File
@@ -2,10 +2,8 @@
from textwrap import dedent
import pytest
from basic_memory.markdown import EntityMetadata
from basic_memory.markdown.exceptions import ParseError
from basic_memory.markdown.metadata_parser import MetadataParser
def test_parse_metadata():
"""Test parsing basic metadata."""
@@ -15,22 +13,21 @@ def test_parse_metadata():
status: active
""")
parser = MetadataParser()
result = parser.parse(text)
result = EntityMetadata.from_text(text)
assert result.metadata["owner"] == "team-auth"
assert result.metadata["priority"] == "high"
assert result.metadata["status"] == "active"
def test_parse_metadata_empty():
"""Test parsing empty metadata."""
text = ""
parser = MetadataParser()
result = parser.parse(text)
result = EntityMetadata.from_text(text)
assert result.metadata == {}
def test_parse_metadata_whitespace():
"""Test handling of various whitespace in metadata."""
text = dedent("""
@@ -39,13 +36,13 @@ def test_parse_metadata_whitespace():
status: active
""")
parser = MetadataParser()
result = parser.parse(text)
result = EntityMetadata.from_text(text)
assert result.metadata["owner"] == "team-auth"
assert result.metadata["priority"] == "high"
assert result.metadata["status"] == "active"
def test_parse_metadata_multiline_values():
"""Test handling of multiline metadata values."""
text = dedent("""
@@ -56,13 +53,13 @@ def test_parse_metadata_multiline_values():
status: active
""")
parser = MetadataParser()
result = parser.parse(text)
result = EntityMetadata.from_text(text)
assert result.metadata["owner"] == "team-auth"
assert result.metadata["status"] == "active"
assert len(result.metadata["description"].splitlines()) == 3
def test_parse_metadata_invalid():
"""Test handling of invalid metadata format."""
text = dedent("""
@@ -70,8 +67,7 @@ def test_parse_metadata_invalid():
priority: high
""")
parser = MetadataParser()
result = parser.parse(text)
result = EntityMetadata.from_text(text)
assert "priority" in result.metadata
assert "owner" not in result.metadata
assert "owner" not in result.metadata
+9 -8
View File
@@ -2,6 +2,7 @@
import pytest
from basic_memory.markdown import Observation
from basic_memory.markdown.parser import EntityParser, ParseError
@@ -9,7 +10,7 @@ def test_parse_observation_basic():
"""Test basic observation parsing with category and tags."""
parser = EntityParser()
obs = parser._parse_observation("- [design] Core feature #important #mvp")
obs = Observation.from_line("- [design] Core feature #important #mvp")
assert obs is not None
assert obs.category == "design"
@@ -22,7 +23,7 @@ def test_parse_observation_with_context():
"""Test observation parsing with context in parentheses."""
parser = EntityParser()
obs = parser._parse_observation(
obs = Observation.from_line(
"- [feature] Authentication system #security #auth (Required for MVP)"
)
assert obs is not None
@@ -37,25 +38,25 @@ def test_parse_observation_edge_cases():
parser = EntityParser()
# Multiple word tags
obs = parser._parse_observation("- [tech] Database #high-priority #needs-review")
obs = Observation.from_line("- [tech] Database #high-priority #needs-review")
assert obs is not None
assert set(obs.tags) == {"high-priority", "needs-review"}
# Multiple word category
obs = parser._parse_observation("- [user experience] Design #ux")
obs = Observation.from_line("- [user experience] Design #ux")
assert obs is not None
assert obs.category == "user experience"
# Parentheses in content shouldn't be treated as context
obs = parser._parse_observation("- [code] Function (x) returns y #function")
obs = Observation.from_line("- [code] Function (x) returns y #function")
assert obs is not None
assert obs.content == "Function (x) returns y"
assert obs.context is None
# Multiple hashtags together
obs = parser._parse_observation("- [test] Feature #important#urgent#now")
obs = Observation.from_line("- [test] Feature #important#urgent#now")
assert obs is not None
assert set(obs.tags) == {"important", "urgent", "now"}
@@ -66,8 +67,8 @@ def test_parse_observation_errors():
# Missing category brackets
with pytest.raises(ParseError, match="missing category"):
parser._parse_observation("- Design without brackets #test")
Observation.from_line("- Design without brackets #test")
# Unclosed category
with pytest.raises(ParseError, match="unclosed category"):
parser._parse_observation("- [design Core feature #test")
Observation.from_line("- [design Core feature #test")
+8 -7
View File
@@ -2,6 +2,7 @@
import pytest
from basic_memory.markdown import Relation
from basic_memory.markdown.parser import EntityParser, ParseError
@@ -9,7 +10,7 @@ def test_parse_relation_basic():
"""Test basic relation parsing."""
parser = EntityParser()
rel = parser._parse_relation("- implements [[Auth Service]]")
rel = Relation.from_line("- implements [[Auth Service]]")
assert rel is not None
assert rel.type == "implements"
assert rel.target == "Auth Service"
@@ -20,7 +21,7 @@ def test_parse_relation_with_context():
"""Test relation parsing with context."""
parser = EntityParser()
rel = parser._parse_relation("- depends_on [[Database]] (Required for persistence)")
rel = Relation.from_line("- depends_on [[Database]] (Required for persistence)")
assert rel is not None
assert rel.type == "depends_on"
assert rel.target == "Database"
@@ -32,17 +33,17 @@ def test_parse_relation_edge_cases():
parser = EntityParser()
# Multiple word type
rel = parser._parse_relation("- is used by [[Client App]] (Primary consumer)")
rel = Relation.from_line("- is used by [[Client App]] (Primary consumer)")
assert rel is not None
assert rel.type == "is used by"
# Brackets in context
rel = parser._parse_relation("- implements [[API]] (Follows [OpenAPI] spec)")
rel = Relation.from_line("- implements [[API]] (Follows [OpenAPI] spec)")
assert rel is not None
assert rel.context == "Follows [OpenAPI] spec"
# Extra spaces
rel = parser._parse_relation("- specifies [[Format]] (Documentation)")
rel = Relation.from_line("- specifies [[Format]] (Documentation)")
assert rel is not None
assert rel.type == "specifies"
assert rel.target == "Format"
@@ -54,8 +55,8 @@ def test_parse_relation_errors():
# Missing target brackets
with pytest.raises(ParseError, match="missing \\[\\["):
parser._parse_relation("- implements Auth Service")
Relation.from_line("- implements Auth Service")
# Unclosed target
with pytest.raises(ParseError, match="missing ]]"):
parser._parse_relation("- implements [[Auth Service")
Relation.from_line("- implements [[Auth Service")
+20 -17
View File
@@ -1,6 +1,5 @@
"""Tests for edge cases in markdown parsing."""
from datetime import datetime
from textwrap import dedent
import pytest
@@ -8,15 +7,12 @@ import pytest
from basic_memory.markdown import (
EntityParser,
ParseError,
Entity,
EntityFrontmatter,
EntityContent,
EntityMetadata,
)
def test_unicode_content(tmp_path):
"""Test handling of Unicode content including emoji and non-Latin scripts."""
content = dedent('''
content = dedent("""
---
type: test
id: test/unicode
@@ -41,10 +37,10 @@ def test_unicode_content(tmp_path):
category: test
status: active
---
''')
""")
test_file = tmp_path / "unicode.md"
test_file.write_text(content, encoding='utf-8')
test_file.write_text(content, encoding="utf-8")
parser = EntityParser()
entity = parser.parse_file(test_file)
@@ -54,12 +50,13 @@ def test_unicode_content(tmp_path):
assert "👍" in entity.content.observations[0].content
assert "测试" in entity.content.observations[1].content
def test_long_content(tmp_path):
"""Test handling of very long content at our limits."""
# Create a long observation right at our length limit
long_obs = "x" * 995 + " #tag" # 1000 chars with tag
content = dedent(f'''
content = dedent(f"""
---
type: test
id: test/long
@@ -78,7 +75,7 @@ def test_long_content(tmp_path):
## Relations
- related_to [[{"Very long entity name " * 10}]] (Long context test)
''')
""")
test_file = tmp_path / "long.md"
test_file.write_text(content)
@@ -90,6 +87,7 @@ def test_long_content(tmp_path):
assert len(entity.content.observations[0].content) == 995
assert len(entity.content.description) > 1000
def test_missing_sections(tmp_path):
"""Test handling of files missing required sections."""
content = dedent("""
@@ -104,9 +102,10 @@ def test_missing_sections(tmp_path):
with pytest.raises(ParseError):
parser.parse_file(test_file)
def test_nested_structures(tmp_path):
"""Test handling of nested markdown structures."""
content = dedent('''
content = dedent("""
---
type: test
id: test/nested
@@ -126,7 +125,7 @@ def test_nested_structures(tmp_path):
- contains [[Sub Entity]]
- and [[Another Entity]]
- also [[Third Entity]]
''')
""")
test_file = tmp_path / "nested.md"
test_file.write_text(content)
@@ -138,21 +137,25 @@ def test_nested_structures(tmp_path):
assert len(entity.content.observations) == 1
assert len(entity.content.relations) == 1
def test_mixed_newlines(tmp_path):
"""Test handling of different newline styles (\n, \r\n, \r)."""
content = "---\\ntype: test\\r\\nid: test/newlines\\ncreated: 2024-12-21T14:00:00Z\\rmodified: 2024-12-21T14:00:00Z\\ntags: [test]\\n---\\n\\r\\n# Test\\r\\n## Observations\\n- [test] Line 1\\r- [test] Line 2\\n".replace('\\n', '\n').replace('\\r', '\r')
content = "---\\ntype: test\\r\\nid: test/newlines\\ncreated: 2024-12-21T14:00:00Z\\rmodified: 2024-12-21T14:00:00Z\\ntags: [test]\\n---\\n\\r\\n# Test\\r\\n## Observations\\n- [test] Line 1\\r- [test] Line 2\\n".replace(
"\\n", "\n"
).replace("\\r", "\r")
test_file = tmp_path / "newlines.md"
test_file.write_text(content, encoding='utf-8')
test_file.write_text(content, encoding="utf-8")
parser = EntityParser()
entity = parser.parse_file(test_file)
assert len(entity.content.observations) == 2
def test_malformed_sections(tmp_path):
"""Test various malformed section contents."""
content = dedent('''
content = dedent("""
---
type: test
id: test/malformed
@@ -174,7 +177,7 @@ def test_malformed_sections(tmp_path):
- missing type [[Entity]]
- incomplete [[
- ]] backwards
''')
""")
test_file = tmp_path / "malformed.md"
test_file.write_text(content)
@@ -184,4 +187,4 @@ def test_malformed_sections(tmp_path):
# Should skip invalid entries but not fail completely
assert len(entity.content.observations) == 0
assert len(entity.content.relations) == 0
assert len(entity.content.relations) == 0