Germany | Finland | Saint Petersburg | Drive

Контроль событий (QPILE + M4)

Опубликовано в M4

Иллюстрация использования препроцессора с языком QPILE. Во время отладки и тестирования написанной программы часто требуется проверять исполнение (или неисполнение) определённых условий. Как упростить процесс?

Очевидно, в тексте портфеля необходимо вставить операторы проверки условия и соответствующей диагностики при её необходимости. Диагностикой может быть, например, системное сообщение, запись строки в лог-файл. Можно также установить breakpoint() и посмотреть содержимое переменных в отладчике. После окончания отладки все эти строки имеет смысл удалить.

Если программа несложная, то установить и потом удалить одну-две проверки не представляется проблемой. В случае, если портфель объёмный и логика сложная, таких проверок может быть весьма и весьма много. Если портфель на qpile пишется под заказ, то процесс тестирования должен быть как можно жестче по вполне очевидной причине. В этом случае количество проверок возрастает.

Как упростить процесс?

Я использую для этих целей макропроцессор M4. Макрос диагностики (в облегченном варианте) выглядит примерно так:

 


' ASSERT(Условие,ТекстСообщения)
' Level == 1 - системное сообщение
' Level == 2 - breakpoint()
' Level == 3 - запись в файл Assert.Txt
' Иначе - трассировка отсутствует
define(Assert, `ifdef(`DebugLevel',`ifelse'(
`DebugLevel',1,
`if $1
message($2)
end if',
`DebugLevel',2,
`if $1
breakpoint()
end if',
`DebugLevel',3,
`if $1
writeln("ASSERT.TXT",$2)
end if'
))')

Значение макроопределения DebugLevel определяет общую реакцию на событие - писать в файл, устанавливать breakpoint, выдавать системное сообщение, писать в файл либо вообще ничего не делать. Оба эти макроса я задаю где-нибудь в начале программы, в любом удобном месте. Второй макрос вызывается в месте, где необходимо контролировать событие. При появлении в тексте он разворачивается препроцессором в соответствующую последовательность операторов на языке QPILE. Отсутствие определения макроса DebugLevel или любое отличное от 1, 2 или 3 его значение  равносильно запрету генерации всех проверок.

Одно изменение значения макроса DebugLevel приводит к генерации нового портфеля с новой реакцией на события.  Например, такой фрагмент:

price = Get_Price()
Assert(price==0,"Ошибка получения цены")
buy(price)

предназначен для контроля значения переменной price. При значении DebugLevel равным 1 после обработки препроцессором, даст такой qpile код:

 

price = Get_Price()
if price==0
    message("Ошибка получения цены")
end if
buy(price)

Если в процессе работы портфеля переменной price станет равным нулю, то начнется обработка события - Вы получите системное сообщение.

При значении DebugLevel, установленым в 0, получится следующее:

price = Get_Price()
buy(price)

то есть проверка будет полностью отсутствовать.

В этом состоит основное достоинство подхода - отсутствие необходимости убирать проверки из кода портфеля по окончании процесса тестирования. Установка  DebugLevel в 0 (или отсутствие определения) отменяет генерацию проверок и в тексте на qpile после обработки препроцессором их не будет. Это позволяет использовать контроль событий не только в самой программе, но и в библиотеке  функций без необходимости их редактирования. Во время тестирования библиотечные функции могут, например, проверять правильность значений своих формальных параметров, а в конечном варианте, передаваемом Заказчику, таких проверок уже не будет.

Недостаточно прав для комментирования

Библиотека