diff --git a/test/haskell/Test/Integration/Evaluate.hs b/test/haskell/Test/Integration/Evaluate.hs index 37178e01..389c5ec6 100644 --- a/test/haskell/Test/Integration/Evaluate.hs +++ b/test/haskell/Test/Integration/Evaluate.hs @@ -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 @@ evaluateTests = 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 @@ -38,3 +42,55 @@ evaluateStructured = [] -> 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 diff --git a/test/integration/T233/Other.hs b/test/integration/T233/Other.hs new file mode 100644 index 00000000..151efb78 --- /dev/null +++ b/test/integration/T233/Other.hs @@ -0,0 +1,6 @@ +module Other where + +process :: [Int] -> IO () +process xs = do + let n = length xs + print n diff --git a/test/integration/T233/T233.hs b/test/integration/T233/T233.hs new file mode 100644 index 00000000..3b6a4a24 --- /dev/null +++ b/test/integration/T233/T233.hs @@ -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