Haskell quickcheck - как сгенерировать только печатные строки
У меня есть набор простых демо-программ, которые кодируют/декодируют строки и хотят сгенерировать для них несколько тестов QuickCheck, но ограничивать тесты только печатными строками. Использование защиты слишком медленное и не выполняется из-за слишком большого количества сгенерированных и отклоненных тестовых примеров, поэтому я хочу создать безопасный генератор для этого домена.
Ссылки на это, которые я видел, говорят, что (1) определяют один собственный произвольный экземпляр для Char и используют его для генерации только печатаемых символов для строк или (2) для обертывания самих функций в newtype и написать для него произвольный экземпляр.
Но попытка сделать (1) не удается, потому что в Test.QuickCheck есть определение для этого, и как бы это сделать - создать генератор safeChar для нового типа, а затем снова создать адаптер для проверенные функции? (В разделе книги RWH об этом отмечается, что он устарел, рекомендуя это определение DIY Char.)
Попытка сделать (2) кажется, что я могу либо добавить защитника в тестовое предложение, которое является локализованным и простым (но не работает), либо написав новую оболочку и связанный с ней генератор, который кажется более беспорядочным.
Ясно, что это просто (!), и все инструменты предоставлены, но кто-то может посоветовать, правильно ли это это сделать, и дать пример того, как лучше всего это сделать?
Ответы
Ответ 1
Отправной точкой является генератор genSafeChar
, который может иметь тип Gen Char
. Например:
genSafeChar :: Gen Char
genSafeChar = elements ['a'..'z']
Затем вы можете построить это в генератор genSafeString
, например. с listOf
:
genSafeString :: Gen String
genSafeString = listOf genSafeChar
На этом этапе у вас есть несколько разумных вариантов. Создайте обертку newtype
для String
:
newtype SafeString = SafeString { unwrapSafeString :: String }
deriving Show
instance Arbitrary SafeString where
arbitrary = SafeString <$> genSafeString
(в этом случае вы можете просто вставить определение genSafeString
)
и вы можете использовать его примерно так:
testWibble (SafeString str) = str == str
Или вы можете использовать forAll
в каждой точке, где вам нужна безопасная строка:
testWibble = forAll genSafeString $ \str -> str == str