Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 45 additions & 13 deletions tests/test_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ def test_para(self):
assert_correct_node('<w-para><w-text-block>text</w-text-block></w-para>')
assert_incorrect_node('<w-para attr="value"><w-text-block>text</w-text-block></w-para>')
assert_incorrect_node('<w-para> x <w-text-block>text</w-text-block></w-para>')
# indent should be 0+ (non-negative), not negative values
assert_correct_node(
'<w-para skip="1" indent="-5" role="date" align="right"><w-text-block>text</w-text-block></w-para>')
'<w-para skip="1" indent="5" role="date" align="right"><w-text-block>text</w-text-block></w-para>')
# Test that negative indent values are now rejected
assert_incorrect_node('<w-para indent="-5"><w-text-block>text</w-text-block></w-para>')
assert_incorrect_node('<w-para indent="a"><w-text-block>text</w-text-block></w-para>')
assert_incorrect_node('<w-para role="a"><w-text-block>text</w-text-block></w-para>')
assert_incorrect_node('<w-para align="a"><w-text-block>text</w-text-block></w-para>')
Expand Down Expand Up @@ -195,57 +198,86 @@ def create_typed_format(f_type: str, text: str = ""):
assert_incorrect_node(create_typed_format("bold", "<z/>"))

def test_w_lang(self):
assert_correct_node("<w-lang lang='en' dir='ltr'>test</w-entity>")
assert_correct_node("<w-lang lang='en' dir='rtl'>test</w-entity>")
assert_correct_node("<w-lang lang='en'>test</w-entity>")
assert_incorrect_node("<w-lang dir='ltr'>test</w-entity>")
assert_incorrect_node("<w-lang lang='very long'></w-entity>")
# According to spec: both lang and dir are optional (No - not required)
assert_correct_node("<w-lang lang='en' dir='ltr'>test</w-lang>")
assert_correct_node("<w-lang lang='en' dir='rtl'>test</w-lang>")
assert_correct_node("<w-lang lang='en'>test</w-lang>")
# Both attributes are optional, so only dir should also be valid
assert_correct_node("<w-lang dir='ltr'>test</w-lang>")
# Empty w-lang should be valid (both attributes optional)
assert_correct_node("<w-lang>test</w-lang>")
# Test that very long lang codes are rejected (MaxLength=12)
assert_incorrect_node("<w-lang lang='very-long-code'>test</w-lang>")

def test_w_entity(self):
assert_correct_node("<w-entity type='addressee' value='value'></w-entity>")
assert_correct_node("<w-entity type='addressee' value='value'>text</w-entity>")
assert_incorrect_node("<w-entity type='wrong'></w-entity>")

def test_note(self):
# According to spec: w-note-body contains w-note-para, which contains w-text-block
correct_content = ('<w-note-header>Header</w-note-header>'
'<w-note-body><w-text-block>Body</w-text-block></w-note-body>')
'<w-note-body><w-note-para><w-text-block>Body</w-text-block></w-note-para></w-note-body>')
assert_correct_node(f'<w-note>{correct_content}</w-note>')
assert_incorrect_node('<w-note></w-note>')
# Test with w-note-para structure
assert_correct_node(
'''<w-note>
<w-note-header>Header</w-note-header>
<w-note-body><w-text-block>Body<br/></w-text-block></w-note-body>
<w-note-body><w-note-para><w-text-block>Body<br/></w-text-block></w-note-para></w-note-body>
</w-note>'''
)
# Test with multiple w-note-para elements
assert_correct_node(
'''<w-note>
<w-note-header>Header</w-note-header>
<w-note-body>
<w-note-para><w-text-block>First paragraph</w-text-block></w-note-para>
<w-note-para><w-text-block>Second paragraph</w-text-block></w-note-para>
</w-note-body>
</w-note>'''
)
# Test w-note-header with inline elements (allowed per spec)
assert_correct_node(
'''<w-note>
<w-note-header><a href="#ref">8</a></w-note-header>
<w-note-body><w-note-para><w-text-block>Body</w-text-block></w-note-para></w-note-body>
</w-note>'''
)
# Test duplicate w-note-header should fail
assert_incorrect_node(
'''<w-note>
<w-note-header>Header</w-note-header>
<w-note-header>Header</w-note-header>
<w-note-body><w-text-block>Body<br/></w-text-block></w-note-body>
<w-note-body><w-note-para><w-text-block>Body<br/></w-text-block></w-note-para></w-note-body>
</w-note>'''
)
# Test duplicate w-note-body should fail
assert_incorrect_node(
'''<w-note>
<w-note-body><w-text-block>Body<br/></w-text-block></w-note-body>
<w-note-body><w-note-para><w-text-block>Body<br/></w-text-block></w-note-para></w-note-body>
<w-note-header>Header</w-note-header>
<w-note-body><w-text-block>Body<br/></w-text-block></w-note-body>
<w-note-body><w-note-para><w-text-block>Body<br/></w-text-block></w-note-para></w-note-body>
</w-note>'''
)
# Test wrong element name should fail
assert_incorrect_node(
'<w-note>'
'<w-note-head>Header</w-note-head>'
'<w-note-body><w-text-block>Body</w-text-block></w-note-body>'
'<w-note-body><w-note-para><w-text-block>Body</w-text-block></w-note-para></w-note-body>'
'</w-note>')
# Test text directly in w-note should fail
assert_incorrect_node(
f'''<w-note>
{correct_content}
text
</w-note>'''
)
# Test w-note-header with inline tag (br) should fail - header should contain only text or specific inline elements
assert_incorrect_node(
'''<w-note>
<w-note-header>Header<br/></w-note-header>
<w-note-body><w-text-block>Body</w-text-block></w-note-body>
<w-note-body><w-note-para><w-text-block>Body</w-text-block></w-note-para></w-note-body>
</w-note>'''
)

Expand Down
43 changes: 32 additions & 11 deletions weml_validator/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

INLINES = ["", "a", "br", "w-entity", "w-format", "w-lang", "w-non-egw", "w-note", "w-page", "w-sent"]
BLOCKS = ["figure", "w-list", "w-text-block", "table", "hr"]
CONTAINERS = ["w-heading", "w-page", "w-para", "w-para-group"]
CONTAINERS = ["w-heading", "w-page", "w-para", "w-para-group", "w-toc"]

validator_instance.add_validator(ChildrenSubsetValidator(
tag='div',
Expand All @@ -20,7 +20,8 @@
tag="w-heading",
attribute_rules={
"skip": [AttributeRuleEnum(None, "1")],
"level": [AttributeRuleRequired(), AttributeRuleEnum("1", "2", "3", "4", "5", "6")]
"level": [AttributeRuleRequired(), AttributeRuleEnum("1", "2", "3", "4", "5", "6")],
"alt-text": [AttributeRuleOptional()]
},
allowed_children=["w-text-block"],
required_children={"w-text-block": 1},
Expand All @@ -32,8 +33,7 @@
attribute_rules={
"skip": [AttributeRuleEnum(None, "1")],
"indent": [
AttributeRuleEnum(None, "0", "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9", "-10", "1", "2", "3",
"4", "5", "6", "7", "8", "9", "10")],
AttributeRuleEnum(None, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10")],
"align": [AttributeRuleEnum(None, "left", "right", "center", "justify")],
"role": [AttributeRuleEnum(None, "address", "addressee", "author", "date", "place", "introduction",
"letterhead", "salutation", "signature-date", "signature-line", "signature-source",
Expand All @@ -49,6 +49,7 @@
tag="w-para-group",
attribute_rules={
"skip": [AttributeRuleEnum(None, "1")],
"type": [AttributeRuleEnum(None, "frame")]
},
allowed_children=["w-para"],
required_children={"w-para": None}
Expand All @@ -67,6 +68,10 @@

validator_instance.add_validator(ChildrenSubsetValidator(
tag='figure',
attribute_rules={
"align": [AttributeRuleEnum(None, "left", "center", "right", "justify")],
"wrap": [AttributeRuleEnum(None, "0", "1")]
},
allowed_children=["img", "figcaption"],
required_children={"img": 1, "figcaption": lambda x: x <= 1},
))
Expand All @@ -81,7 +86,9 @@
tag='img',
attribute_rules={
"src": [AttributeRuleRequired()],
"alt": [AttributeRuleOptional()]
"alt": [AttributeRuleOptional()],
"width": [AttributeRuleOptional()],
"height": [AttributeRuleOptional()]
}
))

Expand Down Expand Up @@ -200,7 +207,7 @@
validator_instance.add_validator(ChildrenSubsetValidator(
tag="w-lang",
attribute_rules={
"lang": [AttributeRuleRequired(), AttributeRuleMaxLength(5)],
"lang": [AttributeRuleOptional(), AttributeRuleMaxLength(12)],
"dir": [AttributeRuleEnum(None, "ltr", "rtl")]
},
allowed_children=INLINES
Expand All @@ -219,7 +226,7 @@
tag="w-note",
attribute_rules={
"type": [
AttributeRuleEnum(None, "footnote", "endnote")
AttributeRuleEnum(None, "footnote", "chapter-endnote", "book-endnote")
]
},
allowed_children=["w-note-header", "w-note-body"],
Expand All @@ -229,14 +236,24 @@

validator_instance.add_validator(ChildrenSubsetValidator(
tag="w-note-body",
allowed_children=["w-text-block"],
required_children={"w-text-block": None}
allowed_children=["w-note-para"],
required_children={"w-note-para": None}
))

validator_instance.add_validator(ChildrenSubsetValidator(
tag="w-note-para",
attribute_rules={
"indent": [AttributeRuleEnum(None, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10")],
"align": [AttributeRuleEnum(None, "left", "center", "right", "justify")]
},
allowed_children=["w-text-block"],
required_children={"w-text-block": 1},
expected_child_count=1
))

validator_instance.add_validator(ChildrenSubsetValidator(
tag="w-note-header",
allowed_children=[""],
required_children={"": None}
allowed_children=["", "a"]
))

validator_instance.add_validator(EmptyTagValidator(
Expand All @@ -252,6 +269,10 @@
unique=True
))

validator_instance.add_validator(EmptyTagValidator(
tag="w-toc"
))

# endregion

__all__ = ["validator_instance"]