diff --git a/haskell-ide-engine.cabal b/haskell-ide-engine.cabal index 3cdea5830..b45ddde93 100644 --- a/haskell-ide-engine.cabal +++ b/haskell-ide-engine.cabal @@ -173,10 +173,11 @@ test-suite unit-test DiffSpec ExtensibleStateSpec GhcModPluginSpec - LiquidSpec HaRePluginSpec HooglePluginSpec JsonSpec + LiquidSpec + PackagePluginSpec Spec -- Technically cabal-helper should be a 'run-tool-depends', but that doesn't exist yet build-tool-depends: cabal-helper:cabal-helper-main, hspec-discover:hspec-discover diff --git a/src/Haskell/Ide/Engine/Plugin/Package.hs b/src/Haskell/Ide/Engine/Plugin/Package.hs index 767c38eed..7076295bd 100644 --- a/src/Haskell/Ide/Engine/Plugin/Package.hs +++ b/src/Haskell/Ide/Engine/Plugin/Package.hs @@ -67,7 +67,7 @@ data AddParams = AddParams { rootDirParam :: FilePath -- ^ The root directory. , fileParam :: ModulePath -- ^ A path to a module inside the -- library/executable/test-suite you want to - -- add the package to. May be a realtive oir + -- add the package to. May be a relative or -- absolute path, thus, must be normalised. , packageParam :: Package -- ^ The name of the package to add. } @@ -76,7 +76,7 @@ data AddParams = AddParams -- | FilePath to a cabal package description file. type CabalFilePath = FilePath -- | FilePath to a package.yaml package description file. -type PackageYamlFilePath = FilePath +type HpackFilePath = FilePath -- | FilePath to a module within the project. -- May be used to establish what component the dependency shall be added to. type ModulePath = FilePath @@ -88,8 +88,14 @@ type Package = T.Text -- Supported are `*.cabal` and `package.yaml` specifications. -- Moreover, may fail with an IOException in case of a filesystem problem. addCmd :: CommandFunc AddParams J.WorkspaceEdit -addCmd = CmdSync $ \(AddParams rootDir modulePath pkg) -> do +addCmd = CmdSync addCmd' +-- | Add a package to the project's dependencies. +-- May fail if no project dependency specification can be found. +-- Supported are `*.cabal` and `package.yaml` specifications. +-- Moreover, may fail with an IOException in case of a filesystem problem. +addCmd' :: AddParams -> IdeGhcM (IdeResult J.WorkspaceEdit) +addCmd' (AddParams rootDir modulePath pkg) = do packageType <- liftIO $ findPackageType rootDir fileMap <- GM.mkRevRedirMapFunc @@ -105,9 +111,10 @@ addCmd = CmdSync $ \(AddParams rootDir modulePath pkg) -> do liftToGhc $ editHpackPackage absFp relModulePath pkg NoPackage -> return $ IdeResultFail (IdeError PluginError "No package.yaml or .cabal found" Null) -data PackageType = CabalPackage FilePath -- ^ Location of Cabal File. - | HpackPackage FilePath -- ^ Location of `package.yaml` +data PackageType = CabalPackage FilePath -- ^ Location of Cabal File. May be relative. + | HpackPackage FilePath -- ^ Location of `package.yaml`. May be relative. | NoPackage -- ^ No package format has been found. + deriving (Show, Eq) -- | Find the package type the project with the given root uses. -- Might have weird results if there is more than one cabal package specification @@ -129,12 +136,13 @@ findPackageType rootDir = do return $ fromMaybe NoPackage $ asum [HpackPackage <$> mHpack, CabalPackage <$> mCabal] -- | Edit a hpack package to add the given package to the package.yaml. +-- If package.yaml is not in an expected format, will fail fatally. -- -- Currently does not preserve format. -- Keep an eye out on this other GSOC project! -- https://github.com/wisn/format-preserving-yaml -editHpackPackage :: PackageYamlFilePath -- ^ Path to the package.yaml file - -- containing the package description. +editHpackPackage :: HpackFilePath -- ^ Path to the package.yaml file + -- containing the package description. -> ModulePath -- ^ Path to the module where the command has -- been issued in. -- Used to find out what component the @@ -148,19 +156,29 @@ editHpackPackage fp modulePath pkgName = do case Y.decodeThrow contents :: Maybe Object of Just obj -> do + -- Map over all major components, such as "executable", "executables", + -- "tests" and "benchmarks". Note, that "library" is a major component, + -- but its structure is different and can not be mapped over in the same way. + -- + -- Only adds the package if the declared "source-dirs" field is part of the + -- module path, or if no "source-dirs" is declared. let compsMapped = mapComponentTypes (ensureObject $ mapComponents (ensureObject $ mapCompDependencies addDep)) obj - let addDepToMainLib = fromMaybe True $ do - Object lib <- HM.lookup "library" compsMapped - sourceDirs <- HM.lookup "source-dirs" lib - return $ isInSourceDir sourceDirs + -- Is there a global "dependencies" yaml object? + let addDepToMainDep = fromMaybe False $ do + Array _ <- HM.lookup "dependencies" compsMapped + return True - let newPkg = if addDepToMainLib - then mapMainDependencies addDep compsMapped - else compsMapped + -- Either add the package to only the top-level "dependencies", + -- or to all main components of which the given module is part of. + let newPkg + | addDepToMainDep = mapMainDependencies addDep obj + -- Map over the library component at last, since it has different structure. + | otherwise = mapLibraryDependency addDep compsMapped - newPkgText = T.decodeUtf8 $ Y.encode newPkg + let newPkgText = T.decodeUtf8 $ Y.encode newPkg + -- Construct the WorkSpaceEdit let numOldLines = length $ T.lines $ T.decodeUtf8 contents range = J.Range (J.Position 0 0) (J.Position numOldLines 0) textEdit = J.TextEdit range newPkgText @@ -179,10 +197,18 @@ editHpackPackage fp modulePath pkgName = do mapMainDependencies :: (Value -> Value) -> Object -> Object mapMainDependencies f o = - let g "dependencies" = f + let g :: T.Text -> Value -> Value + g "dependencies" = f g _ = id in HM.mapWithKey g o + mapLibraryDependency :: (Value -> Value) -> Object -> Object + mapLibraryDependency f o = + let g :: T.Text -> Value -> Value + g "library" (Y.Object o') = Y.Object (mapCompDependencies f o') + g _ x = x + in HM.mapWithKey g o + mapComponentTypes :: (Value -> Value) -> Object -> Object mapComponentTypes f o = let g "executables" = f diff --git a/test/functional/FunctionalCodeActionsSpec.hs b/test/functional/FunctionalCodeActionsSpec.hs index e1439c4cb..07ab9d6ff 100644 --- a/test/functional/FunctionalCodeActionsSpec.hs +++ b/test/functional/FunctionalCodeActionsSpec.hs @@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE CPP #-} module FunctionalCodeActionsSpec where @@ -179,7 +180,9 @@ spec = describe "code actions" $ do ] ] describe "add package suggestions" $ do - it "adds to .cabal files" $ runSession hieCommand fullCaps "test/testdata/addPackageTest/cabal" $ do + -- Only execute this test with ghc 8.4.4, below seems to be broken in the package. +#if (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(8,4,0,0))) + it "adds to .cabal files" $ runSession hieCommand fullCaps "test/testdata/addPackageTest/cabal-exe" $ do doc <- openDoc "AddPackage.hs" "haskell" -- ignore the first empty hlint diagnostic publish @@ -203,9 +206,9 @@ spec = describe "code actions" $ do contents <- getDocumentEdit . TextDocumentIdentifier =<< getDocUri "add-package-test.cabal" liftIO $ T.lines contents `shouldSatisfy` \x -> any (\l -> "text -any" `T.isSuffixOf` (x !! l)) [15, 16] - +#endif it "adds to hpack package.yaml files" $ - runSession hieCommand fullCaps "test/testdata/addPackageTest/hpack" $ do + runSession hieCommand fullCaps "test/testdata/addPackageTest/hpack-exe" $ do doc <- openDoc "app/Asdf.hs" "haskell" -- ignore the first empty hlint diagnostic publish @@ -229,9 +232,35 @@ spec = describe "code actions" $ do contents <- getDocumentEdit . TextDocumentIdentifier =<< getDocUri "package.yaml" liftIO $ do - T.lines contents !! 33 `shouldSatisfy` T.isSuffixOf "zlib" - T.lines contents !! 12 `shouldNotSatisfy` T.isSuffixOf "zlib" - T.lines contents !! 13 `shouldNotSatisfy` T.isSuffixOf "zlib" + T.lines contents !! 3 `shouldSatisfy` T.isSuffixOf "zlib" + T.lines contents !! 21 `shouldNotSatisfy` T.isSuffixOf "zlib" + + it "adds to hpack package.yaml files if both are present" $ + runSession hieCommand fullCaps "test/testdata/addPackageTest/hybrid-exe" $ do + doc <- openDoc "app/Asdf.hs" "haskell" + + -- ignore the first empty hlint diagnostic publish + [_,diag:_] <- count 2 waitForDiagnostics + + let preds = [ T.isPrefixOf "Could not load module ‘Codec.Compression.GZip’" + , T.isPrefixOf "Could not find module ‘Codec.Compression.GZip’" + ] + in liftIO $ diag ^. L.message `shouldSatisfy` \x -> any (\f -> f x) preds + + mActions <- getAllCodeActions doc + let allActions = map fromAction mActions + action = head allActions + + liftIO $ do + action ^. L.title `shouldBe` "Add zlib as a dependency" + forM_ allActions $ \a -> a ^. L.kind `shouldBe` Just CodeActionQuickFix + forM_ allActions $ \a -> a ^. L.command . _Just . L.command `shouldSatisfy` T.isSuffixOf "package:add" + + executeCodeAction action + + contents <- getDocumentEdit . TextDocumentIdentifier =<< getDocUri "package.yaml" + liftIO $ + T.lines contents !! 21 `shouldSatisfy` T.isSuffixOf "zlib" -- ----------------------------------- @@ -318,10 +347,11 @@ spec = describe "code actions" $ do contents <- documentContents doc - liftIO $ contents `shouldBe` - "module TypedHoles where\n\ - \foo :: [Int] -> Int\n\ - \foo x = " <> suggestion + liftIO $ contents `shouldBe` T.concat + [ "module TypedHoles where\n" + , "foo :: [Int] -> Int\n" + , "foo x = " <> suggestion + ] it "shows more suggestions" $ runSession hieCommand fullCaps "test/testdata" $ do diff --git a/test/testdata/addPackageTest/cabal/AddPackage.hs b/test/testdata/addPackageTest/cabal-exe/AddPackage.hs similarity index 100% rename from test/testdata/addPackageTest/cabal/AddPackage.hs rename to test/testdata/addPackageTest/cabal-exe/AddPackage.hs diff --git a/test/testdata/addPackageTest/cabal-exe/add-package-test.cabal b/test/testdata/addPackageTest/cabal-exe/add-package-test.cabal new file mode 100644 index 000000000..edd2a92a7 --- /dev/null +++ b/test/testdata/addPackageTest/cabal-exe/add-package-test.cabal @@ -0,0 +1,14 @@ +name: add-package-test +version: 0.1.0.0 +license: BSD3 +author: Luke Lau +maintainer: luke_lau@icloud.com +build-type: Simple +extra-source-files: ChangeLog.md +cabal-version: >=1.10 + +executable AddPackage + exposed-modules: ./. + main-is: AddPackage.hs + build-depends: base >=4.7 && <5 + default-language: Haskell2010 \ No newline at end of file diff --git a/test/testdata/addPackageTest/cabal-lib/AddPackage.hs b/test/testdata/addPackageTest/cabal-lib/AddPackage.hs new file mode 100644 index 000000000..24015b598 --- /dev/null +++ b/test/testdata/addPackageTest/cabal-lib/AddPackage.hs @@ -0,0 +1,4 @@ +module AddPackage where + +import Data.Text +foo = pack "I'm a Text" \ No newline at end of file diff --git a/test/testdata/addPackageTest/cabal/add-package-test.cabal b/test/testdata/addPackageTest/cabal-lib/add-package-test.cabal similarity index 100% rename from test/testdata/addPackageTest/cabal/add-package-test.cabal rename to test/testdata/addPackageTest/cabal-lib/add-package-test.cabal diff --git a/test/testdata/addPackageTest/hpack/app/Asdf.hs b/test/testdata/addPackageTest/hpack-exe/app/Asdf.hs similarity index 100% rename from test/testdata/addPackageTest/hpack/app/Asdf.hs rename to test/testdata/addPackageTest/hpack-exe/app/Asdf.hs diff --git a/test/testdata/addPackageTest/hpack/package.yaml b/test/testdata/addPackageTest/hpack-exe/package.yaml similarity index 80% rename from test/testdata/addPackageTest/hpack/package.yaml rename to test/testdata/addPackageTest/hpack-exe/package.yaml index bf6d37c39..3be56682f 100644 --- a/test/testdata/addPackageTest/hpack/package.yaml +++ b/test/testdata/addPackageTest/hpack-exe/package.yaml @@ -22,9 +22,6 @@ description: Please see the README on GitHub at = 4.7 && < 5 -library: - source-dirs: src - executables: asdf-exe: main: Main.hs @@ -34,15 +31,4 @@ executables: - -rtsopts - -with-rtsopts=-N dependencies: - - asdf - -tests: - asdf-test: - main: Spec.hs - source-dirs: test - ghc-options: - - -threaded - - -rtsopts - - -with-rtsopts=-N - dependencies: - - asdf + - asdf \ No newline at end of file diff --git a/test/testdata/addPackageTest/hpack-lib/app/Asdf.hs b/test/testdata/addPackageTest/hpack-lib/app/Asdf.hs new file mode 100644 index 000000000..ec4b22911 --- /dev/null +++ b/test/testdata/addPackageTest/hpack-lib/app/Asdf.hs @@ -0,0 +1,7 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Asdf where + +import Codec.Compression.GZip + +main = return $ compress "hello" \ No newline at end of file diff --git a/test/testdata/addPackageTest/hpack-lib/package.yaml b/test/testdata/addPackageTest/hpack-lib/package.yaml new file mode 100644 index 000000000..2ba0fe5b4 --- /dev/null +++ b/test/testdata/addPackageTest/hpack-lib/package.yaml @@ -0,0 +1,25 @@ +name: asdf +version: 0.1.0.0 +github: "githubuser/asdf" +license: BSD3 +author: "Author name here" +maintainer: "example@example.com" +copyright: "2018 Author name here" + +extra-source-files: +- README.md +- ChangeLog.md + +# Metadata used when publishing your package +# synopsis: Short description of your package +# category: Web + +# To avoid duplicated efforts in documentation and dealing with the +# complications of embedding Haddock markup inside cabal files, it is +# common to point users to the README.md file. +description: Please see the README on GitHub at + +library: + source-dirs: app + dependencies: + - base >= 4.7 && < 5 diff --git a/test/testdata/addPackageTest/hybrid-exe/AddPackage.hs b/test/testdata/addPackageTest/hybrid-exe/AddPackage.hs new file mode 100644 index 000000000..963020508 --- /dev/null +++ b/test/testdata/addPackageTest/hybrid-exe/AddPackage.hs @@ -0,0 +1,2 @@ +import Data.Text +foo = pack "I'm a Text" \ No newline at end of file diff --git a/test/testdata/addPackageTest/hybrid-exe/app/Asdf.hs b/test/testdata/addPackageTest/hybrid-exe/app/Asdf.hs new file mode 100644 index 000000000..fdd639ffe --- /dev/null +++ b/test/testdata/addPackageTest/hybrid-exe/app/Asdf.hs @@ -0,0 +1,5 @@ +{-# LANGUAGE OverloadedStrings #-} + +import Codec.Compression.GZip + +main = return $ compress "hello" \ No newline at end of file diff --git a/test/testdata/addPackageTest/hybrid-exe/asdf.cabal b/test/testdata/addPackageTest/hybrid-exe/asdf.cabal new file mode 100644 index 000000000..79425af44 --- /dev/null +++ b/test/testdata/addPackageTest/hybrid-exe/asdf.cabal @@ -0,0 +1,60 @@ +cabal-version: 1.12 + +-- This file has been generated from package.yaml by hpack version 0.31.2. +-- +-- see: https://github.com/sol/hpack +-- +-- hash: a63a1c272a979a805027c5855cbe062ec4698b6ea6dbe59dd5f7aa34b15656a6 + +name: asdf +version: 0.1.0.0 +description: Please see the README on GitHub at +homepage: https://github.com/githubuser/asdf#readme +bug-reports: https://github.com/githubuser/asdf/issues +author: Author name here +maintainer: example@example.com +copyright: 2018 Author name here +license: BSD3 +build-type: Simple +extra-source-files: + README.md + ChangeLog.md + +source-repository head + type: git + location: https://github.com/githubuser/asdf + +library + other-modules: + Paths_asdf + hs-source-dirs: + src + build-depends: + base >=4.7 && <5 + default-language: Haskell2010 + +executable asdf-exe + main-is: Main.hs + other-modules: + Asdf + Paths_asdf + hs-source-dirs: + app + ghc-options: -threaded -rtsopts -with-rtsopts=-N + build-depends: + asdf + , base >=4.7 && <5 + default-language: Haskell2010 + +test-suite asdf-test + type: exitcode-stdio-1.0 + main-is: Spec.hs + other-modules: + Paths_asdf + hs-source-dirs: + test + ghc-options: -threaded -rtsopts -with-rtsopts=-N + build-depends: + asdf + , base >=4.7 && <5 + default-language: Haskell2010 diff --git a/test/testdata/addPackageTest/hybrid-exe/package.yaml b/test/testdata/addPackageTest/hybrid-exe/package.yaml new file mode 100644 index 000000000..8d9524972 --- /dev/null +++ b/test/testdata/addPackageTest/hybrid-exe/package.yaml @@ -0,0 +1,34 @@ +name: asdf +version: 0.1.0.0 +github: "githubuser/asdf" +license: BSD3 +author: "Author name here" +maintainer: "example@example.com" +copyright: "2018 Author name here" + +extra-source-files: +- README.md +- ChangeLog.md + +# Metadata used when publishing your package +# synopsis: Short description of your package +# category: Web + +# To avoid duplicated efforts in documentation and dealing with the +# complications of embedding Haddock markup inside cabal files, it is +# common to point users to the README.md file. +description: Please see the README on GitHub at + +library: + source-dirs: src + +executables: + asdf-exe: + main: Main.hs + source-dirs: app + ghc-options: + - -threaded + - -rtsopts + - -with-rtsopts=-N + dependencies: + - asdf \ No newline at end of file diff --git a/test/testdata/addPackageTest/hybrid-lib/app/Asdf.hs b/test/testdata/addPackageTest/hybrid-lib/app/Asdf.hs new file mode 100644 index 000000000..1bed3539c --- /dev/null +++ b/test/testdata/addPackageTest/hybrid-lib/app/Asdf.hs @@ -0,0 +1,5 @@ +{-# LANGUAGE OverloadedStrings #-} +module Asdf where +import Codec.Compression.GZip + +main = return $ compress "hello" \ No newline at end of file diff --git a/test/testdata/addPackageTest/hybrid-lib/asdf.cabal b/test/testdata/addPackageTest/hybrid-lib/asdf.cabal new file mode 100644 index 000000000..dbe8509b7 --- /dev/null +++ b/test/testdata/addPackageTest/hybrid-lib/asdf.cabal @@ -0,0 +1,36 @@ +cabal-version: 1.12 + +-- This file has been generated from package.yaml by hpack version 0.31.2. +-- +-- see: https://github.com/sol/hpack +-- +-- hash: 0a09a2280cfeb48f88861d105a48255e71ec34cc865390f1d038119511564661 + +name: asdf +version: 0.1.0.0 +description: Please see the README on GitHub at +homepage: https://github.com/githubuser/asdf#readme +bug-reports: https://github.com/githubuser/asdf/issues +author: Author name here +maintainer: example@example.com +copyright: 2018 Author name here +license: BSD3 +build-type: Simple +extra-source-files: + README.md + ChangeLog.md + +source-repository head + type: git + location: https://github.com/githubuser/asdf + +library + exposed-modules: + Asdf + other-modules: + Paths_asdf + hs-source-dirs: + app + build-depends: + base >=4.7 && <5 + default-language: Haskell2010 diff --git a/test/testdata/addPackageTest/hybrid-lib/package.yaml b/test/testdata/addPackageTest/hybrid-lib/package.yaml new file mode 100644 index 000000000..2ba0fe5b4 --- /dev/null +++ b/test/testdata/addPackageTest/hybrid-lib/package.yaml @@ -0,0 +1,25 @@ +name: asdf +version: 0.1.0.0 +github: "githubuser/asdf" +license: BSD3 +author: "Author name here" +maintainer: "example@example.com" +copyright: "2018 Author name here" + +extra-source-files: +- README.md +- ChangeLog.md + +# Metadata used when publishing your package +# synopsis: Short description of your package +# category: Web + +# To avoid duplicated efforts in documentation and dealing with the +# complications of embedding Haddock markup inside cabal files, it is +# common to point users to the README.md file. +description: Please see the README on GitHub at + +library: + source-dirs: app + dependencies: + - base >= 4.7 && < 5 diff --git a/test/testdata/addPackageTest/invalid/AddPackage.hs b/test/testdata/addPackageTest/invalid/AddPackage.hs new file mode 100644 index 000000000..963020508 --- /dev/null +++ b/test/testdata/addPackageTest/invalid/AddPackage.hs @@ -0,0 +1,2 @@ +import Data.Text +foo = pack "I'm a Text" \ No newline at end of file diff --git a/test/unit/HaRePluginSpec.hs b/test/unit/HaRePluginSpec.hs index ec797ce70..6d425118f 100644 --- a/test/unit/HaRePluginSpec.hs +++ b/test/unit/HaRePluginSpec.hs @@ -239,9 +239,9 @@ hareSpec = do lreq = setTypecheckedModule u req = liftToGhc $ TestDeferM $ findTypeDef u (toPos (24, 7)) r <- dispatchRequestPGoto $ lreq >> req - r `shouldBe` IdeResultOk + r `shouldBe` IdeResultOk [ Location - (filePathToUri $ cwd "test/testdata/gototest/src/Lib.hs") + (filePathToUri $ cwd "test/testdata/gototest/src/Lib.hs") (Range (toPos (18, 1)) (toPos (18, 26))) ] it "can not find non-local definition of type def" $ do diff --git a/test/unit/PackagePluginSpec.hs b/test/unit/PackagePluginSpec.hs new file mode 100644 index 000000000..cc220ef22 --- /dev/null +++ b/test/unit/PackagePluginSpec.hs @@ -0,0 +1,326 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE CPP #-} + +module PackagePluginSpec where + +import Control.Monad ( forM_ ) +import qualified Data.Aeson as Json +import qualified Data.Text as T +import qualified Data.HashMap.Strict as H +import Haskell.Ide.Engine.MonadTypes +import Haskell.Ide.Engine.Plugin.Package +import System.FilePath +import System.Directory +import Test.Hspec +import TestUtils + +main :: IO () +main = hspec spec + +spec :: Spec +spec = describe "Package plugin" packageSpec + +testdata :: FilePath +testdata = "test/testdata/addPackageTest" + +testPlugins :: IdePlugins +testPlugins = pluginDescToIdePlugins [packageDescriptor "package"] + +cabalProject :: [FilePath] +cabalProject = ["cabal-lib", "cabal-exe"] + +hpackProject :: [FilePath] +hpackProject = ["hpack-lib", "hpack-exe", "hybrid-lib", "hybrid-exe"] + +packageSpec :: Spec +packageSpec = do + cwd <- runIO getCurrentDirectory + describe "Find correct package type" $ do + forM_ hpackProject $ \hpack -> + it ("hpack project find package.yaml (\"" ++ hpack ++ "\")") $ do + let fp = testdata hpack + packageType <- findPackageType fp + packageType `shouldBe` HpackPackage (fp "package.yaml") + forM_ cabalProject $ \cabal -> + it ("hpack project find cabal file (\"" ++ cabal ++ "\")") $ do + let fp = testdata cabal + packageType <- findPackageType fp + packageType `shouldBe` CabalPackage "add-package-test.cabal" + it "Find no project description if none is present " $ do + let fp = cwd testdata "invalid" + packageType <- findPackageType fp + packageType `shouldBe` NoPackage + it "Throws exception if path is invalid" $ do + let fp = testdata "unknownPath" + findPackageType fp `shouldThrow` anyIOException + describe "Add the package to the correct file" $ do + it "Add package to .cabal to executable component" + $ withCurrentDirectory (testdata "cabal-exe") + $ do + let + fp = cwd testdata "cabal-exe" + uri = filePathToUri $ fp "add-package-test.cabal" + args = AddParams fp (fp "AddPackage.hs") "text" + act = addCmd' args + textEdits = +#if (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(8,4,0,0))) + List + [ TextEdit (Range (Position 0 0) (Position 7 27)) $ T.concat + [ "cabal-version: >=1.10\n" + , "name: add-package-test\n" + , "version: 0.1.0.0\n" + , "license: BSD3\n" + , "maintainer: luke_lau@icloud.com\n" + , "author: Luke Lau\n" + , "build-type: Simple\n" + , "extra-source-files:\n" + , " ChangeLog.md" + ] + , TextEdit (Range (Position 10 0) (Position 13 34)) $ T.concat + [ " main-is: AddPackage.hs\n" + , " default-language: Haskell2010\n" + , " build-depends:\n" + , " base >=4.7 && <5,\n" + , " text -any" + ] + ] +#else + List -- TODO: this seems to indicate that the command does nothing + [ TextEdit (Range (Position 0 0) (Position 7 27)) $ T.concat + [ "name: add-package-test\n" + , "version: 0.1.0.0\n" + , "cabal-version: >=1.10\n" + , "build-type: Simple\n" + , "license: BSD3\n" + , "maintainer: luke_lau@icloud.com\n" + , "author: Luke Lau\n" + , "extra-source-files:\n" + , " ChangeLog.md" + ] + , TextEdit (Range (Position 9 0) (Position 13 34)) $ T.concat + [ "executable AddPackage\n" + , " main-is: AddPackage.hs\n" + ] + ] +#endif + res = IdeResultOk + $ WorkspaceEdit (Just $ H.singleton uri textEdits) Nothing + testCommand testPlugins act "package" "add" args res + + it "Add package to .cabal to library component" + $ withCurrentDirectory (testdata "cabal-lib") + $ do + let + fp = cwd testdata "cabal-lib" + uri = filePathToUri $ fp "add-package-test.cabal" + args = AddParams fp (fp "AddPackage.hs") "text" + act = addCmd' args + textEdits = +#if (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(8,4,0,0))) + List + [ TextEdit (Range (Position 0 0) (Position 7 27)) $ T.concat + [ "cabal-version: >=1.10\n" + , "name: add-package-test\n" + , "version: 0.1.0.0\n" + , "license: BSD3\n" + , "maintainer: luke_lau@icloud.com\n" + , "author: Luke Lau\n" + , "build-type: Simple\n" + , "extra-source-files:\n" + , " ChangeLog.md" + ] + , TextEdit (Range (Position 10 0) (Position 13 34)) $ T.concat + [ " exposed-modules:\n" + , " AddPackage\n" + , " default-language: Haskell2010\n" + , " build-depends:\n" + , " base >=4.7 && <5,\n" + , " text -any" + ] + ] +#else + List + [ TextEdit (Range (Position 0 0) (Position 7 27)) $ T.concat + [ "name: add-package-test\n" + , "version: 0.1.0.0\n" + , "cabal-version: >=1.10\n" + , "build-type: Simple\n" + , "license: BSD3\n" + , "maintainer: luke_lau@icloud.com\n" + , "author: Luke Lau\n" + , "extra-source-files:\n" + , " ChangeLog.md" + ] + , TextEdit (Range (Position 10 0) (Position 13 34)) $ T.concat + [ " exposed-modules:\n" + , " AddPackage\n" + , " build-depends:\n" + , " base >=4.7 && <5,\n" + , " text -any\n" + , " default-language: Haskell2010\n" + ] + ] +#endif + res = IdeResultOk + $ WorkspaceEdit (Just $ H.singleton uri textEdits) Nothing + testCommand testPlugins act "package" "add" args res + + + it "Add package to package.yaml to executable component" + $ withCurrentDirectory (testdata "hpack-exe") + $ do + let + fp = cwd testdata "hpack-exe" + uri = filePathToUri $ fp "package.yaml" + args = AddParams fp (fp "app" "Asdf.hs") "zlib" + act = addCmd' args + res = IdeResultOk + $ WorkspaceEdit (Just $ H.singleton uri textEdits) Nothing + textEdits = List + [ TextEdit (Range (Position 0 0) (Position 34 0)) $ T.concat + [ "copyright: 2018 Author name here\n" + , "maintainer: example@example.com\n" + , "dependencies:\n" + , "- zlib\n" + , "- base >= 4.7 && < 5\n" + , "name: asdf\n" + , "version: 0.1.0.0\n" + , "extra-source-files:\n" + , "- README.md\n" + , "- ChangeLog.md\n" + , "author: Author name here\n" + , "github: githubuser/asdf\n" + , "license: BSD3\n" + , "executables:\n" + , " asdf-exe:\n" + , " source-dirs: app\n" + , " main: Main.hs\n" + , " ghc-options:\n" + , " - -threaded\n" + , " - -rtsopts\n" + , " - -with-rtsopts=-N\n" + , " dependencies:\n" + , " - asdf\n" + , "description: Please see the README on GitHub at \n" + ] + ] + testCommand testPlugins act "package" "add" args res + + it "Add package to package.yaml to library component" + $ withCurrentDirectory (testdata "hpack-lib") + $ do + let + fp = cwd testdata "hpack-lib" + uri = filePathToUri $ fp "package.yaml" + args = AddParams fp (fp "app" "Asdf.hs") "zlib" + act = addCmd' args + res = IdeResultOk + $ WorkspaceEdit (Just $ H.singleton uri textEdits) Nothing + textEdits = + List + [ TextEdit (Range (Position 0 0) (Position 25 0)) $ T.concat + [ "library:\n" + , " source-dirs: app\n" + , " dependencies:\n" + , " - zlib\n" + , " - base >= 4.7 && < 5\n" + , "copyright: 2018 Author name here\n" + , "maintainer: example@example.com\n" + , "name: asdf\n" + , "version: 0.1.0.0\n" + , "extra-source-files:\n" + , "- README.md\n" + , "- ChangeLog.md\n" + , "author: Author name here\n" + , "github: githubuser/asdf\n" + , "license: BSD3\n" + , "description: Please see the README on GitHub at \n" + ] + ] + testCommand testPlugins act "package" "add" args res + it + "Add package to package.yaml in hpack project with generated cabal to executable component" + $ withCurrentDirectory (testdata "hybrid-exe") + $ do + let + fp = cwd testdata "hybrid-exe" + uri = filePathToUri $ fp "package.yaml" + args = AddParams fp (fp "app" "Asdf.hs") "zlib" + act = addCmd' args + res = IdeResultOk + $ WorkspaceEdit (Just $ H.singleton uri textEdits) Nothing + textEdits = List + [ TextEdit (Range (Position 0 0) (Position 34 0)) $ T.concat + [ "library:\n" + , " source-dirs: src\n" + , "copyright: 2018 Author name here\n" + , "maintainer: example@example.com\n" + , "name: asdf\n" + , "version: 0.1.0.0\n" + , "extra-source-files:\n" + , "- README.md\n" + , "- ChangeLog.md\n" + , "author: Author name here\n" + , "github: githubuser/asdf\n" + , "license: BSD3\n" + , "executables:\n" + , " asdf-exe:\n" + , " source-dirs: app\n" + , " main: Main.hs\n" + , " ghc-options:\n" + , " - -threaded\n" + , " - -rtsopts\n" + , " - -with-rtsopts=-N\n" + , " dependencies:\n" + , " - zlib\n" + , " - asdf\n" + , "description: Please see the README on GitHub at \n" + ] + ] + testCommand testPlugins act "package" "add" args res + it "Add package to package.yaml in hpack project with generated cabal to library component" + $ withCurrentDirectory (testdata "hybrid-lib") + $ do + let + fp = cwd testdata "hybrid-lib" + uri = filePathToUri $ fp "package.yaml" + args = AddParams fp (fp "app" "Asdf.hs") "zlib" + act = addCmd' args + res = IdeResultOk + $ WorkspaceEdit (Just $ H.singleton uri textEdits) Nothing + textEdits = List + [ TextEdit (Range (Position 0 0) (Position 25 0)) $ T.concat + [ "library:\n" + , " source-dirs: app\n" + , " dependencies:\n" + , " - zlib\n" + , " - base >= 4.7 && < 5\n" + , "copyright: 2018 Author name here\n" + , "maintainer: example@example.com\n" + , "name: asdf\n" + , "version: 0.1.0.0\n" + , "extra-source-files:\n" + , "- README.md\n" + , "- ChangeLog.md\n" + , "author: Author name here\n" + , "github: githubuser/asdf\n" + , "license: BSD3\n" + , "description: Please see the README on GitHub at \n" + ] + ] + testCommand testPlugins act "package" "add" args res + it "Do nothing on NoPackage" + $ withCurrentDirectory (testdata "invalid") + $ do + let + fp = cwd testdata "invalid" + args = AddParams fp (fp "app" "Asdf.hs") "zlib" + act = addCmd' args + res = + IdeResultFail + (IdeError PluginError + "No package.yaml or .cabal found" + Json.Null + ) + testCommand testPlugins act "package" "add" args res diff --git a/test/utils/TestUtils.hs b/test/utils/TestUtils.hs index 526608352..91ffc3203 100644 --- a/test/utils/TestUtils.hs +++ b/test/utils/TestUtils.hs @@ -101,8 +101,12 @@ setupStackFiles = files :: [FilePath] files = [ "./test/testdata/" - , "./test/testdata/addPackageTest/cabal/" - , "./test/testdata/addPackageTest/hpack/" + , "./test/testdata/addPackageTest/cabal-exe/" + , "./test/testdata/addPackageTest/hpack-exe/" + , "./test/testdata/addPackageTest/hybrid-exe/" + , "./test/testdata/addPackageTest/cabal-lib/" + , "./test/testdata/addPackageTest/hpack-lib/" + , "./test/testdata/addPackageTest/hybrid-lib/" , "./test/testdata/addPragmas/" , "./test/testdata/badProjects/cabal/" , "./test/testdata/completion/" @@ -253,7 +257,7 @@ xmlFormatter = silent { failure ! message (reasonAsString err) $ "" #if MIN_VERSION_hspec(2,5,0) - examplePending path _ reason = + examplePending path _ reason = #else examplePending path reason = #endif