haskell-debugger-0.13.0.0: test/haskell/Test/Integration/Conditional.hs
-- | Conditional breakpoint tests (issue #111) ported from the NodeJS testsuite.
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
module Test.Integration.Conditional (conditionalTests) where
import Test.DAP
import Test.Tasty
import Test.Tasty.HUnit
#ifdef mingw32_HOST_OS
import Test.Tasty.ExpectedFailure
#endif
import qualified DAP
import DAP (SourceBreakpoint(..), defaultSourceBreakpoint)
conditionalTests :: TestTree
conditionalTests =
#ifdef mingw32_HOST_OS
ignoreTestBecause "Needs to be fixed for Windows (#199)" $
#endif
testGroup "DAP.Integration.Conditional"
[ testCase "Conditional expression breakpoints" conditionalExpr
, testCase "Hit count breakpoints" hitCount
]
conditionalExpr :: Assertion
conditionalExpr =
testWith False
defaultSourceBreakpoint
{ sourceBreakpointLine = 13
, sourceBreakpointCondition = Just "im IM.! 0 == 2" }
-- Continuing just once is sufficient for it to exit now
(continueThread 0)
hitCount :: Assertion
hitCount =
testWith True
defaultSourceBreakpoint
{ sourceBreakpointLine = 13
, sourceBreakpointHitCondition = Just "2"
-- this ^ ignores 2 hits and stops at third.
}
-- Unlike conditional expression, we hit the breakpoint every time
-- after the ignore count, so run this twice
(continueThread 0 >> continueThread 0)
testWith :: Bool -> SourceBreakpoint -> TestDAP () -> Assertion
testWith needsForcing bp afterCheck =
withTestDAPServer "test/integration/T111" [] $ \test_dir server ->
withTestDAPServerClient server $ do
let cfg = mkLaunchConfig test_dir "T111.hs"
_ <- sync $ launchWith cfg
waitFiltering_ EventTy "initialized"
_ <- sync $ setBreakpointsIn test_dir "T111.hs" [bp]
_ <- sync configurationDone
assertStoppedLocation DAP.StoppedEventReasonBreakpoint 13
-- This assertion validates:
-- 1) we only stopped when im IM.! 0 == 2 (and not earlier)
-- 2) or we only stopped on the third iteration
-- This test is run with two different breakpoints to trigger the two
-- cases, but both are validated the same way.
vars <- fetchLocalVars
-- In the expression conditional case, we have already forced IM to evaluate the condition
-- In the hit conditional case, we haven't evaluated IM so we need to.
im <- (if needsForcing then forceLazy else pure) (vars % "im")
im @==? "IntMap"
imChild <- expandVar im
let _2v = imChild % "0"
_3v = imChild % "2"
_2v @==? "2"
_3v @==? "4"
afterCheck
waitForExitCode 0
disconnect