haskell-debugger 0.13.0.0 → 0.13.1.0
raw patch · 23 files changed
+281/−71 lines, 23 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ GHC.Debugger.Breakpoint.Map: instance GHC.Debugger.View.Class.DebugView (GHC.Debugger.Breakpoint.Map.BreakpointMap a)
+ GHC.Debugger.Utils: showModule :: Module -> String
+ GHC.Debugger.Utils.Orphans: instance GHC.Debugger.View.Class.DebugView (GHC.Unit.Module.Env.ModuleEnv a)
+ GHC.Debugger.Utils.Orphans: instance GHC.Debugger.View.Class.DebugView GHC.Unit.Types.Module
Files
- CHANGELOG.md +6/−0
- haskell-debugger.cabal +3/−2
- haskell-debugger/GHC/Debugger/Breakpoint.hs +9/−8
- haskell-debugger/GHC/Debugger/Breakpoint/Map.hs +9/−0
- haskell-debugger/GHC/Debugger/Session/Builtin.hs +4/−4
- haskell-debugger/GHC/Debugger/Utils.hs +6/−0
- haskell-debugger/GHC/Debugger/Utils/Orphans.hs +14/−1
- hdb/Development/Debug/Adapter/Stopped.hs +0/−1
- test/golden/self-debug-cli/self-debug-cli.no-tmp-dir.external.ghc-914.hdb-stdout +0/−52
- test/golden/self-debug-cli/self-debug-cli.no-tmp-dir.external.hdb-test +4/−0
- test/golden/standalone-multi-module/Helper.hs +5/−0
- test/golden/standalone-multi-module/Main.hs +9/−0
- test/golden/standalone-multi-module/standalone-multi-module.ghc-914.hdb-stdout +9/−0
- test/golden/standalone-multi-module/standalone-multi-module.hdb-stdin +4/−0
- test/golden/standalone-multi-module/standalone-multi-module.hdb-test +1/−0
- test/haskell/Main.hs +2/−0
- test/haskell/Test/Integration/Basic.hs +38/−0
- test/haskell/Test/Integration/Evaluate.hs +59/−3
- test/haskell/Test/Integration/SelfDebug.hs +62/−0
- test/integration/T233/Other.hs +6/−0
- test/integration/T233/T233.hs +17/−0
- test/integration/standalone-multi-module/Helper.hs +5/−0
- test/integration/standalone-multi-module/Main.hs +9/−0
CHANGELOG.md view
@@ -1,5 +1,11 @@ # Revision history for haskell-debugger +## 0.13.1.0 -- 2026-04-28++* Fix critical bug which caused certain breakpoints to be overwritten by or+ confused with breakpoints from separate modules.+* Fix: Make forcing a thunk invalidate all threads+ ## 0.13.0.0 -- 2026-04-24 Features:
haskell-debugger.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.12 name: haskell-debugger-version: 0.13.0.0+version: 0.13.1.0 synopsis: A step-through debugger for GHC Haskell @@ -243,7 +243,8 @@ Test.Integration.Stdout, Test.Integration.Conditional, Test.Integration.Evaluate,- Test.Integration.StackTrace+ Test.Integration.StackTrace,+ Test.Integration.SelfDebug build-depends: base >=4.14, async,
haskell-debugger/GHC/Debugger/Breakpoint.hs view
@@ -33,6 +33,7 @@ import GHC.Debugger.Utils import GHC.Debugger.Interface.Messages import qualified GHC.Debugger.Breakpoint.Map as BM+import Data.Function -------------------------------------------------------------------------------- -- * Breakpoints@@ -192,14 +193,14 @@ mms <- getModuleByPath file case mms of Right ms -> do- hsc_env <- getSession- imodBreaks <- liftIO $ expectJust <$> readIModBreaksMaybe (hsc_HUG hsc_env) (ms_mod ms)- return- [ ibi- | ibi <- BM.keys bm- , getBreakSourceMod ibi imodBreaks == ms_mod ms- -- assert: status is always > disabled- ]+ hug <- hsc_HUG <$> getSession+ -- Return all active IBIs whose occurrence (source) module+ -- matches the argument source module.+ map fst <$> filterM (\(ibi, info) -> do+ ibi_occ_mod <- getBreakSourceMod ibi <$> readIModBreaks hug ibi & liftIO+ assert (bpInfoStatus info /= BreakpointDisabled) $+ return (ibi_occ_mod == ms_mod ms)+ ) (BM.toList bm) Left e -> do logSDoc Logger.Warning e return []
haskell-debugger/GHC/Debugger/Breakpoint/Map.hs view
@@ -17,6 +17,8 @@ import GHC.ByteCode.Breakpoints import GHC.Utils.Outputable (Outputable) import qualified Data.IntMap as IM+import GHC.Debugger.View.Class+import GHC.Debugger.Utils (showModule) -- | A map keyed by 'InternalBreakpointId' newtype BreakpointMap a = BreakpointMap (ModuleEnv (IM.IntMap a))@@ -77,3 +79,10 @@ | (m, im) <- moduleEnvToList bm , (bix, a) <- IM.toList im ]++instance DebugView (BreakpointMap a) where+ debugValue (BreakpointMap b) = simpleValue "BreakpointMap" (not $ isEmptyModuleEnv b)+ debugFields bm = pure $ VarFields+ [ (showModule ibi_info_mod ++ "(" ++ show ibi_info_index ++ ")", VarFieldValue v)+ | (InternalBreakpointId{ibi_info_mod, ibi_info_index}, v) <- toList bm+ ]
haskell-debugger/GHC/Debugger/Session/Builtin.hs view
@@ -147,16 +147,16 @@ -- | The contents of GHC.Debugger.View.Class in memory debuggerViewClassContents :: StringBuffer-debuggerViewClassContents = stringToStringBuffer $(embedStringFile "haskell-debugger-view/src/GHC/Debugger/View/Class.hs")+debuggerViewClassContents = stringToStringBuffer $(embedStringFile =<< makeRelativeToProject "haskell-debugger-view/src/GHC/Debugger/View/Class.hs") -- | The contents of GHC.Debugger.View.Containers in memory debuggerViewContainersContents :: StringBuffer-debuggerViewContainersContents = stringToStringBuffer $(embedStringFile "haskell-debugger-view/src/GHC/Debugger/View/Containers.hs")+debuggerViewContainersContents = stringToStringBuffer $(embedStringFile =<< makeRelativeToProject "haskell-debugger-view/src/GHC/Debugger/View/Containers.hs") -- | GHC.Debugger.View.Text debuggerViewTextContents :: StringBuffer-debuggerViewTextContents = stringToStringBuffer $(embedStringFile "haskell-debugger-view/src/GHC/Debugger/View/Text.hs")+debuggerViewTextContents = stringToStringBuffer $(embedStringFile =<< makeRelativeToProject "haskell-debugger-view/src/GHC/Debugger/View/Text.hs") -- | GHC.Debugger.View.ByteString debuggerViewByteStringContents :: StringBuffer-debuggerViewByteStringContents = stringToStringBuffer $(embedStringFile "haskell-debugger-view/src/GHC/Debugger/View/ByteString.hs")+debuggerViewByteStringContents = stringToStringBuffer $(embedStringFile =<< makeRelativeToProject "haskell-debugger-view/src/GHC/Debugger/View/ByteString.hs")
haskell-debugger/GHC/Debugger/Utils.hs view
@@ -105,3 +105,9 @@ num :: Parser Int num = decimal +--------------------------------------------------------------------------------+-- * DebugView utils+--------------------------------------------------------------------------------++showModule :: Module -> String+showModule = showSDocUnsafe . withPprStyle (PprDump alwaysQualify) . ppr
haskell-debugger/GHC/Debugger/Utils/Orphans.hs view
@@ -1,9 +1,22 @@ {-# OPTIONS_GHC -Wno-orphans #-}-module GHC.Debugger.Utils.Orphans where+module GHC.Debugger.Utils.Orphans () where import GHC.Debugger.View.Class import GHC.Data.FastString+import GHC.Unit.Module+import GHC.Debugger.Utils (showModule) instance DebugView FastString where debugValue t = simpleValue (unpackFS t) False debugFields _ = pure (VarFields [])++instance DebugView Module where+ debugValue t = simpleValue (showModule t) False+ debugFields _ = pure (VarFields [])++instance DebugView (ModuleEnv a) where+ debugValue m = simpleValue "ModuleEnv" (not $ isEmptyModuleEnv m)+ debugFields m = pure $ VarFields+ [ (showModule k, VarFieldValue v)+ | (k, v) <- moduleEnvToList m+ ]
hdb/Development/Debug/Adapter/Stopped.hs view
@@ -148,7 +148,6 @@ ForcedVariable _ -> sendInvalidatedEvent defaultInvalidatedEvent { invalidatedEventAreas = [InvalidatedAreasVariables]- , invalidatedEventStackFrameId = Just 0 -- TODO: REVERSE LOOKUP OF (StackFrameIx threadId frameIx) } VariableFields _ -> return ()
test/golden/self-debug-cli/self-debug-cli.no-tmp-dir.external.ghc-914.hdb-stdout view
@@ -1,55 +1,3 @@-[ 1 of 53] Compiling Development.Debug.Adapter.Handles ( <PROJECT-ROOT>/hdb/Development/Debug/Adapter/Handles.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[ 2 of 53] Compiling Development.Debug.Options ( <PROJECT-ROOT>/hdb/Development/Debug/Options.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[ 3 of 53] Compiling Development.Debug.Session.Setup ( <PROJECT-ROOT>/hdb/Development/Debug/Session/Setup.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[ 4 of 53] Compiling GHC.Debugger.Breakpoint.Map ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Breakpoint/Map.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[ 5 of 53] Compiling GHC.Debugger.Runtime.Compile.Cache ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Compile/Cache.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[ 6 of 53] Compiling GHC.Debugger.Runtime.Term.Key ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Term/Key.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[ 7 of 53] Compiling GHC.Debugger.Interface.Messages ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Interface/Messages.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[ 8 of 53] Compiling GHC.Debugger.Runtime.Interpreter.Custom ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Interpreter/Custom.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[ 9 of 53] Compiling Development.Debug.Adapter ( <PROJECT-ROOT>/hdb/Development/Debug/Adapter.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[10 of 53] Compiling Development.Debug.Adapter.Proxy ( <PROJECT-ROOT>/hdb/Development/Debug/Adapter/Proxy.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[11 of 53] Compiling Development.Debug.Adapter.Output ( <PROJECT-ROOT>/hdb/Development/Debug/Adapter/Output.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[12 of 53] Compiling Development.Debug.Adapter.Interface ( <PROJECT-ROOT>/hdb/Development/Debug/Adapter/Interface.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[13 of 53] Compiling Development.Debug.Adapter.Stopped ( <PROJECT-ROOT>/hdb/Development/Debug/Adapter/Stopped.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[14 of 53] Compiling Development.Debug.Adapter.Exit.Helpers ( <PROJECT-ROOT>/hdb/Development/Debug/Adapter/Exit/Helpers.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[15 of 53] Compiling Development.Debug.Adapter.Exit ( <PROJECT-ROOT>/hdb/Development/Debug/Adapter/Exit.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[16 of 53] Compiling Development.Debug.Adapter.ExceptionInfo ( <PROJECT-ROOT>/hdb/Development/Debug/Adapter/ExceptionInfo.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[17 of 53] Compiling Development.Debug.Adapter.Evaluation ( <PROJECT-ROOT>/hdb/Development/Debug/Adapter/Evaluation.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[18 of 53] Compiling Development.Debug.Adapter.Stepping ( <PROJECT-ROOT>/hdb/Development/Debug/Adapter/Stepping.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[19 of 53] Compiling Development.Debug.Adapter.Breakpoints ( <PROJECT-ROOT>/hdb/Development/Debug/Adapter/Breakpoints.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[20 of 53] Compiling GHC.Debugger.Runtime.Thread.Map ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Thread/Map.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[21 of 53] Compiling GHC.Debugger.Session ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Session.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[22 of 53] Compiling GHC.Debugger.Session.Builtin ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Session/Builtin.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[23 of 53] Compiling GHC.Debugger.Session.Interactive ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Session/Interactive.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[24 of 53] Compiling GHC.Debugger.Utils ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Utils.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[25 of 53] Compiling GHC.Debugger.View.Class ( <PROJECT-ROOT>/haskell-debugger-view/src/GHC/Debugger/View/Class.hs, interpreted )[haskell-debugger-view-<VERSION>-inplace]-[26 of 53] Compiling GHC.Debugger.View.ByteString ( <PROJECT-ROOT>/haskell-debugger-view/src/GHC/Debugger/View/ByteString.hs, interpreted )[haskell-debugger-view-<VERSION>-inplace]-[27 of 53] Compiling GHC.Debugger.Utils.Orphans ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Utils/Orphans.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[28 of 53] Compiling GHC.Debugger.Runtime.Instances.Discover[boot] ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Instances/Discover.hs-boot, interpreted )[haskell-debugger-<VERSION>-inplace]-[29 of 53] Compiling GHC.Debugger.Monad ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Monad.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[30 of 53] Compiling GHC.Debugger.Runtime.Instances.Discover ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Instances/Discover.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[31 of 53] Compiling GHC.Debugger.Runtime.Eval ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Eval.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[32 of 53] Compiling GHC.Debugger.Runtime.Compile ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Compile.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[33 of 53] Compiling GHC.Debugger.Runtime.Eval.RemoteExpr ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Eval/RemoteExpr.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[34 of 53] Compiling GHC.Debugger.Runtime.Term.Parser ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Term/Parser.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[35 of 53] Compiling GHC.Debugger.Runtime.Instances ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Instances.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[36 of 53] Compiling GHC.Debugger.Runtime.Eval.RemoteExpr.Builtin ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Eval/RemoteExpr/Builtin.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[37 of 53] Compiling GHC.Debugger.Runtime.Thread.Stack ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Thread/Stack.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[38 of 53] Compiling GHC.Debugger.Runtime.Thread ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime/Thread.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[39 of 53] Compiling GHC.Debugger.Stopped.Exception ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Stopped/Exception.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[40 of 53] Compiling GHC.Debugger.Runtime ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Runtime.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[41 of 53] Compiling GHC.Debugger.Stopped.Variables ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Stopped/Variables.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[42 of 53] Compiling GHC.Debugger.Stopped ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Stopped.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[43 of 53] Compiling GHC.Debugger.Run ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Run.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[44 of 53] Compiling GHC.Debugger.Breakpoint ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger/Breakpoint.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[45 of 53] Compiling GHC.Debugger ( <PROJECT-ROOT>/haskell-debugger/GHC/Debugger.hs, interpreted )[haskell-debugger-<VERSION>-inplace]-[46 of 53] Compiling Development.Debug.Interactive ( <PROJECT-ROOT>/hdb/Development/Debug/Interactive.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[47 of 53] Compiling Development.Debug.Adapter.Init ( <PROJECT-ROOT>/hdb/Development/Debug/Adapter/Init.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[48 of 53] Compiling GHC.Debugger.View.Containers ( <PROJECT-ROOT>/haskell-debugger-view/src/GHC/Debugger/View/Containers.hs, interpreted )[haskell-debugger-view-<VERSION>-inplace]-[49 of 53] Compiling GHC.Debugger.View.Text ( <PROJECT-ROOT>/haskell-debugger-view/src/GHC/Debugger/View/Text.hs, interpreted )[haskell-debugger-view-<VERSION>-inplace]-[50 of 53] Compiling Paths_haskell_debugger ( <AUTOGEN-DIR>/Paths_haskell_debugger.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[51 of 53] Compiling Development.Debug.Options.Parser ( <PROJECT-ROOT>/hdb/Development/Debug/Options/Parser.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb]-[52 of 53] Compiling Main ( <PROJECT-ROOT>/hdb/Main.hs, interpreted )[haskell-debugger-<VERSION>-inplace-hdb] (hdb) Stopped at breakpoint (hdb) this FastString should be displayed pretty as a string (SHOULD NOT SEE ITS FULL INTERNALS). (hdb) We have a DebugView FastString instance at this breakpoint.
test/golden/self-debug-cli/self-debug-cli.no-tmp-dir.external.hdb-test view
@@ -9,6 +9,9 @@ # too prone to changing because it reports source lines of the actual debugger # source, which we change all the time (unlike testsuite programs). #+# 3.1) Grep out all `[27 of 53] Compiling ...` lines. Everytime we added a+# module it would force the test to be updated and was prone to conflicts.+# # 4) Normalize cabal autogen paths (e.g. `Paths_haskell_debugger.hs`). # It's not immediately clear why these go in .cache/hie-bios/... rather than in # $HDB_CACHE_DIR, but I guess it's an autogen thing rather than the actual@@ -24,6 +27,7 @@ $HDB -v0 hdb/Main.hs < "test/golden/self-debug-cli/self-debug-cli.hdb-stdin" 2>&1 \ | grep -v "BreakFound" \+ | grep -v "] Compiling" \ | sed \ -e 's|[^ ]*/Paths_haskell_debugger.hs|<AUTOGEN-DIR>/Paths_haskell_debugger.hs|g' \ -e 's|haskell-debugger-[0-9.][0-9.]*-inplace|haskell-debugger-<VERSION>-inplace|g' \
+ test/golden/standalone-multi-module/Helper.hs view
@@ -0,0 +1,5 @@+module Helper where++greet :: String -> IO ()+greet name = do+ putStrLn ("Hello, " ++ name ++ "!")
+ test/golden/standalone-multi-module/Main.hs view
@@ -0,0 +1,9 @@+module Main where++import Helper++main :: IO ()+main = do+ putStrLn "Starting..."+ greet "world"+ putStrLn "Done."
+ test/golden/standalone-multi-module/standalone-multi-module.ghc-914.hdb-stdout view
@@ -0,0 +1,9 @@+[1 of 4] Compiling GHC.Debugger.View.Class ( in-memory:GHC.Debugger.View.Class, interpreted )[haskell-debugger-view-in-memory]+[2 of 4] Compiling Helper ( <TEMPORARY-DIRECTORY>/Helper.hs, interpreted )[main]+[3 of 4] Compiling Main ( <TEMPORARY-DIRECTORY>/Main.hs, interpreted )[main]+(hdb) BreakFound {changed = True, breakId = [InternalBreakpointId Main 5], sourceSpan = SourceSpan {file = "<TEMPORARY-DIRECTORY>/Main.hs", startLine = 7, endLine = 7, startCol = 3, endCol = 25}}+(hdb) BreakFound {changed = True, breakId = [InternalBreakpointId Helper 4], sourceSpan = SourceSpan {file = "<TEMPORARY-DIRECTORY>/./Helper.hs", startLine = 5, endLine = 5, startCol = 3, endCol = 38}}+(hdb) Stopped at breakpoint+(hdb) Starting...+Stopped at breakpoint+(hdb) Exiting...
+ test/golden/standalone-multi-module/standalone-multi-module.hdb-stdin view
@@ -0,0 +1,4 @@+break Main.hs 7+break Helper.hs 5+run+continue
+ test/golden/standalone-multi-module/standalone-multi-module.hdb-test view
@@ -0,0 +1,1 @@+$HDB Main.hs -v 0 < standalone-multi-module.hdb-stdin
test/haskell/Main.hs view
@@ -38,6 +38,7 @@ import Test.Integration.Conditional (conditionalTests) import Test.Integration.Evaluate (evaluateTests) import Test.Integration.StackTrace (stackTraceTests)+import Test.Integration.SelfDebug (selfDebugTests) import Test.Utils import qualified Data.Char as C import qualified Data.Text as T@@ -102,6 +103,7 @@ , conditionalTests , evaluateTests , stackTraceTests+ , selfDebugTests ] -- | Receives as an argument the path to the @*.hdb-test@ which contains the
test/haskell/Test/Integration/Basic.hs view
@@ -27,6 +27,10 @@ , testCase "accepts internalInterpreter launch option" internalInterpreterOption ] ]+ , testGroup "Multi-module standalone (no cabal/hie.yaml)"+ [ testCase "breakpoints in two modules (#297)" multiModuleStandaloneBreakpoints+ , testCase "breakpoints in two modules (flipped) (#297)" multiModuleStandaloneBreakpoints2+ ] ] basicForConfig :: TestName -> FilePath -> FilePath -> TestTree@@ -88,4 +92,38 @@ let cfg = (mkLaunchConfig test_dir "Main.hs") { lcInternalInterpreter = Just True } -- TODO: Automatically run all tests with internal interpreter too? hitBreakpointWith cfg 6+ disconnect++-- | Two-module standalone project (no cabal, no hie.yaml): set a breakpoint in+-- each module, run, hit the first (Main.hs), continue, hit the second (Helper.hs).+-- (#297)+multiModuleStandaloneBreakpoints :: Assertion+multiModuleStandaloneBreakpoints =+ withTestDAPServer "test/integration/standalone-multi-module" [] $ \test_dir server ->+ withTestDAPServerClient server $ do+ let cfg = mkLaunchConfig test_dir "Main.hs"+ _ <- sync $ launchWith cfg+ waitFiltering_ EventTy "initialized"+ _ <- sync $ setLineBreakpoints test_dir "Main.hs" [7]+ _ <- sync $ setLineBreakpoints test_dir "Helper.hs" [5]+ _ <- sync configurationDone+ assertStoppedLocation DAP.StoppedEventReasonBreakpoint 7+ continueThread 0+ assertStoppedLocation DAP.StoppedEventReasonBreakpoint 5+ disconnect++-- | Same as above, but flip the order of the setLineBreakpoints calls (#297)+multiModuleStandaloneBreakpoints2 :: Assertion+multiModuleStandaloneBreakpoints2 =+ withTestDAPServer "test/integration/standalone-multi-module" [] $ \test_dir server ->+ withTestDAPServerClient server $ do+ let cfg = mkLaunchConfig test_dir "Main.hs"+ _ <- sync $ launchWith cfg+ waitFiltering_ EventTy "initialized"+ _ <- sync $ setLineBreakpoints test_dir "Helper.hs" [5]+ _ <- sync $ setLineBreakpoints test_dir "Main.hs" [7]+ _ <- sync configurationDone+ assertStoppedLocation DAP.StoppedEventReasonBreakpoint 7+ continueThread 0+ assertStoppedLocation DAP.StoppedEventReasonBreakpoint 5 disconnect
test/haskell/Test/Integration/Evaluate.hs view
@@ -1,15 +1,14 @@--- | Evaluate request tests (issue #116) ported from the NodeJS testsuite.+-- | Evaluate request tests ported from the NodeJS testsuite. {-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module Test.Integration.Evaluate (evaluateTests) where import Control.Monad.IO.Class (liftIO)+import Data.List (isInfixOf) import Test.DAP import Test.Tasty import Test.Tasty.HUnit-#ifdef mingw32_HOST_OS import Test.Tasty.ExpectedFailure-#endif import qualified DAP evaluateTests :: TestTree@@ -20,6 +19,11 @@ testGroup "DAP.Integration.Evaluate" [ testCase "Return structured representation for evaluated expressions (issue #116)" evaluateStructured+ , testCase "Imported module bindings available in evaluate context (issue #233)"+ evaluateImportedBindings+ , expectFailBecause "#299" $+ testCase "Bindings from other modules not available in evaluate context (issue #233)"+ evaluateImportedBindingsNotInOtherModule ] evaluateStructured :: Assertion@@ -37,4 +41,56 @@ (v1:_) -> v1 @==? "\'b\'" [] -> liftIO $ assertFailure $ "No variable named 1 in evaluation result: " ++ show respChildren+ disconnect++-- | Test that bindings from imported modules are available when evaluating+-- expressions at a breakpoint (issue #233).+evaluateImportedBindings :: Assertion+evaluateImportedBindings =+ withTestDAPServer "test/integration/T233" [] $ \test_dir server ->+ withTestDAPServerClient server $ do+ let cfg = mkLaunchConfig test_dir "T233.hs"+ hitBreakpointWith cfg 15++ -- sort is imported from Data.List+ sortResp <- evaluate "show (sort xs)"+ liftIO $ assertEqual "sort xs result" "\"[1,1,2,3,4,5,6,9]\"" (DAP.evaluateResponseResult sortResp)++ -- Map is a qualified import+ mapResp <- evaluate "show (Map.lookup \"a\" m)"+ liftIO $ assertEqual "Map.lookup result" "\"Just 1\"" (DAP.evaluateResponseResult mapResp)++ disconnect++-- | Test that bindings from modules not imported at the stopped location are+-- NOT available in the evaluate context (issue #233).+evaluateImportedBindingsNotInOtherModule :: Assertion+evaluateImportedBindingsNotInOtherModule =+ withTestDAPServer "test/integration/T233" [] $ \test_dir server ->+ withTestDAPServerClient server $ do+ let cfg = mkLaunchConfig test_dir "T233.hs"++ _ <- sync $ launchWith cfg+ waitFiltering_ EventTy "initialized"+ -- T233.hs imports Data.Map.Strict as Map; Other.hs does not+ _ <- sync $ setLineBreakpoints test_dir "T233.hs" [15]+ _ <- sync $ setLineBreakpoints test_dir "Other.hs" [4]+ _ <- sync configurationDone+ _ <- assertStoppedLocation DAP.StoppedEventReasonBreakpoint 15++ -- Stopped in T233.hs which imports Data.List and Data.Map.Strict as Map+ sortResp <- evaluate "show (sort xs)"+ liftIO $ assertEqual "sort xs result" "\"[1,1,2,3,4,5,6,9]\"" (DAP.evaluateResponseResult sortResp)++ -- Resume and stop at breakpoint in Other.hs, which does not import Map+ continueThread 0+ _ <- assertStoppedLocation DAP.StoppedEventReasonBreakpoint 4++ -- Map is not imported in Other.hs; evaluating Map.fromList should fail+ mapFailResp <- evaluate "Map.fromList [(1,'a')]"+ let result = DAP.evaluateResponseResult mapFailResp+ liftIO $ assertBool+ ("expected 'not in scope' error for Map.fromList, got: " ++ show result)+ ("not in scope" `isInfixOf` show result)+ disconnect
+ test/haskell/Test/Integration/SelfDebug.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+module Test.Integration.SelfDebug (selfDebugTests) where++import System.Directory+import System.FilePath+import Control.Monad+import Control.Monad.IO.Class (liftIO)+import Data.Aeson+import Test.DAP+import Test.DAP.Messages.Parser (Event(..))+import Test.Tasty+import Test.Tasty.HUnit+import qualified DAP+import DAP.Types (StoppedEvent(..))+#ifdef mingw32_HOST_OS+import Test.Tasty.ExpectedFailure+#endif++selfDebugTests :: TestTree+selfDebugTests =+#ifdef mingw32_HOST_OS+ ignoreTestBecause "Needs to be fixed for Windows (#199)" $+#endif+ testGroup "DAP.Integration.SelfDebug"+ [ testCase "debug the debugger itself via DAP" selfDebugDAPTest+ ]++selfDebugDAPTest :: Assertion+selfDebugDAPTest = do+ withTestDAPServer "." [] $ \test_dir server -> do -- Self-debug test copies project root to temp dir+ doesFileExist (test_dir </> "cabal.project") >>= \exists ->+ unless exists $ writeFile (test_dir </> "cabal.project")+ "packages: . haskell-debugger-view\nallow-newer: ghc-bignum,containers,time,ghc,base,template-haskell"+ doesFileExist (test_dir </> "hie.yaml") >>= \exists ->+ unless exists $ writeFile (test_dir </> "hie.yaml")+ "cradle:\n cabal:\n component: \"all\""+ withTestDAPServerClient server $ do+ let cfg = LaunchConfig+ { lcProjectRoot = test_dir+ , lcEntryFile = Just "hdb/Main.hs"+ , lcEntryPoint = Just "main"+ , lcEntryArgs = ["cli", "test/golden/self-debug-cli/Main.hs"]+ , lcExtraGhcArgs = []+ , lcInternalInterpreter = Nothing+ }++ _ <- sync $ launchWith cfg+ waitFiltering_ EventTy "initialized"++ _ <- sync $ setFunctionBreakpointsRequest @_ @Value $ object+ [ "breakpoints" .= [ object [ "name" .= ("runDebugger" :: String) ] ] ]++ _ <- sync configurationDone++ Event{eventBody = Just StoppedEvent{stoppedEventReason = reason}}+ <- waitFiltering EventTy "stopped"+ liftIO $ assertEqual "expected breakpoint stop"+ reason DAP.StoppedEventReasonBreakpoint+ -- fixme: should we reply with StoppedEventReasonFunctionBreakpoint instead?++ disconnect
+ test/integration/T233/Other.hs view
@@ -0,0 +1,6 @@+module Other where++process :: [Int] -> IO ()+process xs = do+ let n = length xs+ print n
+ test/integration/T233/T233.hs view
@@ -0,0 +1,17 @@+module Main where++import Data.List (sort, nub)+import qualified Data.Map.Strict as Map+import Other (process)++main :: IO ()+main = do+ let xs = [3, 1, 4, 1, 5, 9, 2, 6] :: [Int]+ let m = Map.fromList [("a", 1), ("b", 2)] :: Map.Map String Int+ check xs m+ process xs++check :: [Int] -> Map.Map String Int -> IO ()+check xs m = do+ print xs+ print m
+ test/integration/standalone-multi-module/Helper.hs view
@@ -0,0 +1,5 @@+module Helper where++greet :: String -> IO ()+greet name = do+ putStrLn ("Hello, " ++ name ++ "!")
+ test/integration/standalone-multi-module/Main.hs view
@@ -0,0 +1,9 @@+module Main where++import Helper++main :: IO ()+main = do+ putStrLn "Starting..."+ greet "world"+ putStrLn "Done."