Как отладить расходящийся тест с помощью QuickCheck - PullRequest
1 голос
/ 07 ноября 2019

У меня есть некоторый код синтаксического анализа с использованием Megaparsec, который я написал для тестирования простого свойства (оно генерирует случайное дерево выражений, красиво печатает его, а затем проверяет, что результат анализируется обратно в исходное дерево).

К сожалению, кажется, что есть ошибка, и если я запускаю тесты без каких-либо ограничений, я вижу, как процесс GHC выделяет все больше и больше памяти, пока я либо не уничтожу его, либо убийца OOM не доберется туда первым.

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

prop_parse_expr :: Property
prop_parse_expr =
  forAll arbitrary $
  (\ pe ->
     let str = prettyParExpr 0 pe in
       counterexample ("Rendered to: " ++ show str) $
       trace ("STARTING TEST: " ++ show str) $
       case parse (expr <* eof) "" str of
         Left _ -> trace "NOPE" $ False
         Right _ -> trace "GOOD" $ True)

Если я скомпилирую с профилированием (используя stack test --profile)Я могу запустить полученный бинарный файл с опциями RTS. Ага, подумал я и побежал с -xc, думая, что получу полезную трассировку стека, когда отправлю SIGINT на застрявшую работу. Кажется нет. Запуск с

./long/path/to/foo-test -j1 --test-seed 1 +RTS -xc

Я вижу этот вывод:

STARTING TEST: "0"
GOOD
STARTING TEST: "(x [( !0 )]) "
STARTING TEST: "({ 2 {( !0 )}} ) "
STARTING TEST: "{ 2{ ( x[0? {( 0) ,( x ) } :((0 )? (x ):0) -: ( -(^( x  )) ) ]), 0**( x )} } "
STARTING TEST: "| (0? (x[({ 1{ (0)? x : ( 0 ) }} ) ]) :(~&( 0) ?( x):( (x ) ^( x ) )))"
STARTING TEST: "(0 )"
STARTING TEST: "0"
^C*** Exception (reporting due to +RTS -xc): (THUNK_STATIC), stack trace: 
  Test.Framework.Improving.runImprovingIO,
  called from Test.Framework.Providers.QuickCheck2.runProperty,
  called from Test.Framework.Providers.QuickCheck2.runTest,
  called from Test.Framework.Runners.Core.runSimpleTest,
  called from Test.Framework.Runners.Core.runTestTree.go,
  called from Test.Framework.Runners.Core.runTestTree,
  called from Test.Framework.Runners.Core.runTests',
  called from Test.Framework.Runners.Core.runTests,
  called from Test.Framework.Runners.Console.defaultMainWithOpts,
  called from Test.Framework.Runners.Console.defaultMainWithArgs,
  called from Test.Framework.Runners.Console.defaultMain,
  called from Main.main
<snip: 2 more identical backtraces>
*** Exception (reporting due to +RTS -xc): (THUNK_STATIC), stack trace: 
  Test.Framework.Runners.Console.Utilities.hideCursorDuring,
  called from Test.Framework.Runners.Console.Run.showRunTestsTop,
  called from Test.Framework.Improving.runImprovingIO,
  called from Test.Framework.Providers.QuickCheck2.runProperty,
  called from Test.Framework.Providers.QuickCheck2.runTest,
  called from Test.Framework.Runners.Core.runSimpleTest,
  called from Test.Framework.Runners.Core.runTestTree.go,
  called from Test.Framework.Runners.Core.runTestTree,
  called from Test.Framework.Runners.Core.runTests',
  called from Test.Framework.Runners.Core.runTests,
  called from Test.Framework.Runners.Console.defaultMainWithOpts,
  called from Test.Framework.Runners.Console.defaultMainWithArgs,
  called from Test.Framework.Runners.Console.defaultMain,
  called from Main.main

Может кто-нибудь сказать мне:

  1. Почему я вижу несколько STARTING TEST строкбез GOOD или NOPE между ними, несмотря на -j1?

  2. Как получить фактическую трассировку стека, которая показывает, где тест выделяет всю свою память?

Спасибо за любые идеи!

...