проверка форматированных сообщений - PullRequest
0 голосов
/ 18 октября 2019

Я пишу программное обеспечение, которое выполняет некоторый анализ входных данных и возвращает результат. Часть требований включает в себя, генерирует ноль или более предупреждений или ошибок и включает в себя те, которые в результате. Я также пишу модульные тесты, в которых, в частности, есть некоторые надуманные данные для проверки правильности выдачи предупреждений.

Мне нужно иметь возможность анализировать предупреждения / ошибки и проверять правильность выдачи ожидаемых сообщений. ,Я решил хранить сообщения в контейнере и ссылаться на них с идентификатором сообщения, который очень похож на то, как я делал локализацию в прошлом.

errormessages.py сейчас выглядит примерно так:

from enum import IntEnum
NO_MESSAGE = ('')
HELLO = ('Hello, World')
GOODBYE = ('Goodbye')

class MsgId(IntEnum):
    NO_MESSAGE = 0
    HELLO = 1
    GOODBYE = 2

Msg = {
    MessageId.NO_MESSAGE: NO_MESSAGE,
    MessageId.HELLO: HELLO,
    MessageId.GOODBYE: GOODBYE,
}

Итак, анализ может выглядеть примерно так:

from errormessages import Msg, MsgId
def analyse(_):
    errors = []
    errors.append(Msg[MsgId.HELLO])
    return _, errors

А в модульных тестах я могу сделать что-то похожее на

from errormessages import Msg, MsgId
from my import analyse
def test_hello():
    _, errors = analyse('toy')
    assert Msg[MsgId.HELLO] in errors

Но некоторые изсообщения форматируются, и я думаю, что это будет чертовски сложно при разборе сообщений для модульных тестов. Я думал, что добавлю ароматы сообщений;один для форматирования, а другой для разбора:

обновлено errormessages.py:

from enum import IntEnum
import re
FORMAT_NO_MESSAGE = ('')
FORMAT_HELLO = ('Hello, {}')
FORMAT_GOODBYE = ('Goodbye')

PARSE_NO_MESSAGE = re.compile(r'^$')
PARSE_HELLO = re.compile(r'^Hello, (.*)$')
PARSE_GOODBYE = re.compile('^Goodbye$')

class MsgId(IntEnum):
    NO_MESSAGE = 0
    HELLO = 1
    GOODBYE = 2

Msg = {
    MessageId.NO_MESSAGE: (FORMAT_NO_MESSAGE, PARSE_NO_MESSAGE),
    MessageId.HELLO: (FORMAT_HELLO, PARSE_HELLO),
    MessageId.GOODBYE: (FORMAT_GOODBYE, PARSE_GOODBYE),
}

Так что анализ может выглядеть так:

from errormessages import Msg, MsgId
def analyse(_):
    errors = []
    errors.append(Msg[MsgId.HELLO][0].format('World'))
    return _, errors

И в блокетесты, которые я могу сделать:

from errormessages import Msg, MsgId
from my import analyse
import re
def test_hello():
    _, errors = analyse('toy')
    expected = {v: [] for v in MsgId}
    expected[MsgId.HELLO] = [
        Msg[MsgId.HELLO][1].match(msg)
        for msg in errors
    ]
    for _,v in expected.items():
        if _ == MsgId.HELLO:
            assert v
        else:
            assert not v

Мне было интересно, есть ли способ лучше / проще? В частности, сообщения эффективно повторяются дважды;один раз для форматера и один раз для регулярного выражения. Есть ли способ использовать одну строку как для форматирования, так и для захвата регулярных выражений?

1 Ответ

1 голос
/ 18 октября 2019

Если все сообщения хранятся в виде шаблонов форматных строк (например, "Hello", или "Hello, {}" или "Hello, {firstname} {surname}"), то вы можете генерировать регулярные выражения непосредственно из шаблонов:

import re
import random
import string

def format_string_to_regex(format_string: str) -> re.Pattern:
    """Convert a format string template to a regex."""
    unique_string = ''.join(random.choices(string.ascii_letters, k=24))
    stripped_fields = re.sub(r"\{[^\{\}]*\}(?!\})", unique_string, format_string)
    pattern = re.escape(stripped_fields).replace(unique_string, "(.*)")
    pattern = pattern.replace("\{\{","\{").replace("\}\}", "\}")
    return re.compile(f"^{pattern}$")

def is_error_message(error: str, expected_message: MessageId) -> bool:
    """Returns whether the error plausibly matches the MessageId."""
    expected_format = format_string_to_regex(Msg[expected_message])
    return bool(expected_format.match(error))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...