Вкусное Hunit-тестирование парсера парсека?

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

Я использую для этого модульные тесты tasty, и вот что у меня есть:

simpleLabels :: TestTree
simpleLabels = testGroup "Simple label searches"
    [ testCase "List comparison (same length)" $ -- just a test to make sure that the @?= works like it should
      [1, 2, 3] `compare` [1,2,2] @?= LT
      , 
      testCase "Phonetic = a " $ 
        parse umeQuery "Source" "Phonetic = a " @?= Right ( LabelInLabelType "Phonetic" ["a"] "=")  
    ]

Теперь этот поток правильно анализируется синтаксическим анализатором, когда я запускаю его в REPL:

> parse umeQuery "something"  (pack  "Phonetic = a ")
Right (LabelInLabelType "Phonetic" ["a"] "=")

Это похоже на то, что должно быть, и, следовательно, то, что я установил в тесте выше.

Теперь набор тестов вообще не собирается, выдавая ошибку:

TestQueryParser.hs:29:55:
    No instance for (Eq ParseError) arising from a use of ‘@?=’
    In the second argument of ‘($)’, namely
      ‘parse umeQuery "Ume Query : " "Phonetic = a "
       @?= Right (LabelInLabelType "Phonetic" ["a"] "=")’
    In the expression:
      testCase "Phonetic = a "
      $ parse umeQuery "Ume Query : " "Phonetic = a "
        @?= Right (LabelInLabelType "Phonetic" ["a"] "=")
    In the second argument of ‘testGroup’, namely
      ‘[testCase "List comparison (same length)"
        $ [1, 2, ....] `compare` [1, 2, ....] @?= LT,
        testCase "Phonetic = a "
        $ parse umeQuery "Ume Query : " "Phonetic = a "
          @?= Right (LabelInLabelType "Phonetic" ["a"] "=")]’

Почему мне это нужно, учитывая тот факт, что успешный/правильный синтаксический анализ должен привести к значению Right a?

Как лучше всего настроить модульный тест для синтаксического анализатора парсека?


person Fredrik Karlsson    schedule 21.07.2016    source источник
comment
Чтобы сравнить значение Either e a, как e, так и a должны быть экземплярами Eq в соответствии с определением Eq для Either: instance (Eq e, Eq a) => Eq (Either e a) where ..., потому что комплер не может знать, что у вас будет только Right, если тип Either. Как видите, Parsec вообще не предназначен для проверки своих сообщений об ошибках. Если вы хотите работать с сообщениями об ошибках, используйте Megaparsec (отказ от ответственности: я его автор) . Существует также hspec-megaparsec, если он того стоит.   -  person Mark Karpov    schedule 22.07.2016
comment
Вместо сравнения parse ... @?= Right ... вы должны сначала проверить, что результат синтаксического анализа не равен Left, а затем сравнить значения напрямую (без предварительного переноса в Right). Простой способ сделать это в этом случае either (const $ assertFailure "...") (@?= (LabelInLabelType ...)) (parse ...)   -  person user2407038    schedule 22.07.2016


Ответы (1)


Спасибо за все полезные комментарии.

Действительно, как было указано пользователем @user2407038, требовалось улучшить обработку сообщения об ошибке.

simpleLabels :: TestTree
simpleLabels = testGroup "Simple label searches"
    [
    testCase "Equality matching simple label" $ let 
        res = case (parse umeQuery "Source" "Phonetic = a ") of
            Right a -> a
            Left a -> error "Something"
    in res @?=  LabelInLabelType "Phonetic" ["a"] "="
    ]

работает. Сообщение об ошибке в приведенном выше примере явно не оптимально, но для текущего примера подходит.

person Fredrik Karlsson    schedule 22.07.2016