Files
novelWriter/tests/test_text/test_text_patterns.py
T
2024-09-22 17:37:12 +02:00

317 lines
8.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
novelWriter Patterns Module Tester
====================================
This file is a part of novelWriter
Copyright 20182024, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
import re
import pytest
from novelwriter import CONFIG
from novelwriter.constants import nwUnicode
from novelwriter.text.patterns import REGEX_PATTERNS
def allMatches(regEx: re.Pattern, text: str) -> list[list[str]]:
"""Get all matches for a regex."""
result = []
for match in re.finditer(regEx, text):
result.append([
(match.group(n), match.start(n), match.end(n))
for n in range((match.lastindex or 0) + 1)
])
return result
@pytest.mark.core
def testTextPatterns_Words():
"""Test the word split regex."""
regEx = REGEX_PATTERNS.wordSplit
# Spaces
assert allMatches(regEx, "one two three") == [
[("one", 0, 3)], [("two", 4, 7)], [("three", 8, 13)]
]
# Hyphens
assert allMatches(regEx, "one-two-three") == [
[("one", 0, 3)], [("two", 4, 7)], [("three", 8, 13)]
]
# Em Dashes
assert allMatches(regEx, "one\u2014two\u2014three") == [
[("one", 0, 3)], [("two", 4, 7)], [("three", 8, 13)]
]
# Em Dashes
assert allMatches(regEx, "one\u2014two\u2014three") == [
[("one", 0, 3)], [("two", 4, 7)], [("three", 8, 13)]
]
# Plus
assert allMatches(regEx, "one+two+three") == [
[("one", 0, 3)], [("two", 4, 7)], [("three", 8, 13)]
]
# Slash
assert allMatches(regEx, "one/two/three") == [
[("one", 0, 3)], [("two", 4, 7)], [("three", 8, 13)]
]
# Brackets
assert allMatches(regEx, "one[two]three") == [
[("one", 0, 3)], [("two", 4, 7)], [("three", 8, 13)]
]
# Colon
assert allMatches(regEx, "one:two:three") == [
[("one", 0, 3)], [("two", 4, 7)], [("three", 8, 13)]
]
@pytest.mark.core
def testTextPatterns_Markdown():
"""Test the markdown pattern regexes."""
# Bold
regEx = REGEX_PATTERNS.markdownBold
assert allMatches(regEx, "one **two** three") == [
[("**two**", 4, 11), ("**", 4, 6), ("two", 6, 9), ("**", 9, 11)]
]
assert allMatches(regEx, "one **two* three") == []
assert allMatches(regEx, "one *two** three") == []
assert allMatches(regEx, "one**two**three") == []
# Italic
regEx = REGEX_PATTERNS.markdownItalic
assert allMatches(regEx, "one _two_ three") == [
[("_two_", 4, 9), ("_", 4, 5), ("two", 5, 8), ("_", 8, 9)]
]
assert allMatches(regEx, "one __two_ three") == []
assert allMatches(regEx, "one _two__ three") == [
[("_two__", 4, 10), ("_", 4, 5), ("two_", 5, 9), ("_", 9, 10)]
]
assert allMatches(regEx, "one_two_three") == []
# Strike
regEx = REGEX_PATTERNS.markdownStrike
assert allMatches(regEx, "one ~~two~~ three") == [
[("~~two~~", 4, 11), ("~~", 4, 6), ("two", 6, 9), ("~~", 9, 11)]
]
assert allMatches(regEx, "one ~~two~ three") == []
assert allMatches(regEx, "one ~two~~ three") == []
assert allMatches(regEx, "one~~two~~three") == []
@pytest.mark.core
def testTextPatterns_ShortcodesPlain():
"""Test the shortcode pattern regexes."""
regEx = REGEX_PATTERNS.shortcodePlain
# Test Usage
# ==========
# General, normal usage
assert allMatches(regEx, "one [b]two[/b] three") == [
[("[b]", 4, 7), ("[b]", 4, 7)],
[("[/b]", 10, 14), ("[/b]", 10, 14)],
]
# General, no spaces
assert allMatches(regEx, "one[b]two[/b]three") == [
[("[b]", 3, 6), ("[b]", 3, 6)],
[("[/b]", 9, 13), ("[/b]", 9, 13)],
]
# General, with padding
assert allMatches(regEx, "one [b] two [/b] three") == [
[("[b]", 4, 7), ("[b]", 4, 7)],
[("[/b]", 12, 16), ("[/b]", 12, 16)],
]
# General, with escapes
assert allMatches(regEx, "one \\[b]two[/b\\] three") == []
# Test Formats
# ============
# Bold
assert allMatches(regEx, "one [b]two[/b] three") == [
[("[b]", 4, 7), ("[b]", 4, 7)],
[("[/b]", 10, 14), ("[/b]", 10, 14)],
]
# Italic
assert allMatches(regEx, "one [i]two[/i] three") == [
[("[i]", 4, 7), ("[i]", 4, 7)],
[("[/i]", 10, 14), ("[/i]", 10, 14)],
]
# Strike
assert allMatches(regEx, "one [s]two[/s] three") == [
[("[s]", 4, 7), ("[s]", 4, 7)],
[("[/s]", 10, 14), ("[/s]", 10, 14)],
]
# Underline
assert allMatches(regEx, "one [u]two[/u] three") == [
[("[u]", 4, 7), ("[u]", 4, 7)],
[("[/u]", 10, 14), ("[/u]", 10, 14)],
]
# Mark
assert allMatches(regEx, "one [m]two[/m] three") == [
[("[m]", 4, 7), ("[m]", 4, 7)],
[("[/m]", 10, 14), ("[/m]", 10, 14)],
]
# Superscript
assert allMatches(regEx, "one [sup]two[/sup] three") == [
[("[sup]", 4, 9), ("[sup]", 4, 9)],
[("[/sup]", 12, 18), ("[/sup]", 12, 18)],
]
# Subscript
assert allMatches(regEx, "one [sub]two[/sub] three") == [
[("[sub]", 4, 9), ("[sub]", 4, 9)],
[("[/sub]", 12, 18), ("[/sub]", 12, 18)],
]
# Test Invalid
# ============
assert allMatches(regEx, "one [x]two[/x] three") == []
@pytest.mark.core
def testTextPatterns_ShortcodesValue():
"""Test the shortcode with value pattern regexes."""
regEx = REGEX_PATTERNS.shortcodeValue
assert allMatches(regEx, "one [footnote:two] three") == [
[("[footnote:two]", 4, 18), ("[footnote:", 4, 14), ("two", 14, 17), ("]", 17, 18)]
]
@pytest.mark.core
def testTextPatterns_DialogueStyle():
"""Test the dialogue style pattern regexes."""
# Set the config
CONFIG.fmtSQuoteOpen = nwUnicode.U_LSQUO
CONFIG.fmtSQuoteClose = nwUnicode.U_RSQUO
CONFIG.fmtDQuoteOpen = nwUnicode.U_LDQUO
CONFIG.fmtDQuoteClose = nwUnicode.U_RDQUO
CONFIG.dialogStyle = 3
# Closed
# ======
CONFIG.allowOpenDial = False
regEx = REGEX_PATTERNS.dialogStyle
# Defined single quotes are recognised
assert allMatches(regEx, "one \u2018two\u2019 three") == [
[("\u2018two\u2019", 4, 9)]
]
# Defined double quotes are recognised
assert allMatches(regEx, "one \u201ctwo\u201d three") == [
[("\u201ctwo\u201d", 4, 9)]
]
# Straight single quotes are ignored
assert allMatches(regEx, "one 'two' three") == []
# Straight double quotes are ignored
assert allMatches(regEx, "one \"two\" three") == []
# Skipping whitespace is not allowed
assert allMatches(regEx, "one\u2018two\u2019three") == []
# Open
# ====
CONFIG.allowOpenDial = True
regEx = REGEX_PATTERNS.dialogStyle
# Defined single quotes are recognised also when open
assert allMatches(regEx, "one \u2018two three") == [
[("\u2018two three", 4, 14)]
]
# Defined double quotes are recognised also when open
assert allMatches(regEx, "one \u201ctwo three") == [
[("\u201ctwo three", 4, 14)]
]
@pytest.mark.core
def testTextPatterns_DialogueSpecial():
"""Test the special dialogue style pattern regexes."""
# Set the config
CONFIG.fmtSQuoteOpen = nwUnicode.U_LSQUO
CONFIG.fmtSQuoteClose = nwUnicode.U_RSQUO
CONFIG.fmtDQuoteOpen = nwUnicode.U_LDQUO
CONFIG.fmtDQuoteClose = nwUnicode.U_RDQUO
CONFIG.dialogStyle = 3
CONFIG.dialogLine = nwUnicode.U_ENDASH
CONFIG.narratorBreak = nwUnicode.U_ENDASH
CONFIG.altDialogOpen = "::"
CONFIG.altDialogClose = "::"
# Dialogue Line
# =============
regEx = REGEX_PATTERNS.dialogLine
# Check dialogue line in first position
assert allMatches(regEx, "\u2013 one two three") == [
[("\u2013 one two three", 0, 15)]
]
# Check dialogue line in second position
assert allMatches(regEx, " \u2013 one two three") == []
# Narrator Break
# ==============
regEx = REGEX_PATTERNS.narratorBreak
# Narrator break with no padding
assert allMatches(regEx, "one \u2013two\u2013 three") == [
[("\u2013two\u2013", 4, 9)]
]
# Narrator break with padding
assert allMatches(regEx, "one \u2013 two \u2013 three") == []
# Alternative Dialogue
# ====================
regEx = REGEX_PATTERNS.altDialogStyle
# With no padding
assert allMatches(regEx, "one ::two:: three") == [
[("::two::", 4, 11)]
]
# With padding
assert allMatches(regEx, "one :: two :: three") == [
[(":: two ::", 4, 13)]
]