hpack 0.5.2 → 0.5.3
raw patch · 12 files changed
+314/−87 lines, 12 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Hpack.Config: instance Data CommonOptions
- Hpack.Config: instance Data Dependency
- Hpack.Config: instance Data ExecutableSection
- Hpack.Config: instance Data GitRef
- Hpack.Config: instance Data LibrarySection
- Hpack.Config: instance Data PackageConfig
- Hpack.Config: instance Data a => Data (CaptureUnknownFields a)
- Hpack.Config: instance Data a => Data (Section a)
- Hpack.Config: instance Typeable CaptureUnknownFields
- Hpack.Config: instance Typeable CommonOptions
- Hpack.Config: instance Typeable Dependency
- Hpack.Config: instance Typeable ExecutableSection
- Hpack.Config: instance Typeable GitRef
- Hpack.Config: instance Typeable LibrarySection
- Hpack.Config: instance Typeable PackageConfig
- Hpack.Config: instance Typeable Section
+ Hpack.Config: getModules :: FilePath -> IO [String]
- Hpack.Run: renderSourceRepository :: SourceRepository -> Stanza
+ Hpack.Run: renderSourceRepository :: SourceRepository -> Element
Files
- hpack.cabal +8/−2
- src/Hpack/Config.hs +42/−36
- src/Hpack/GenericsUtil.hs +46/−0
- src/Hpack/Haskell.hs +55/−0
- src/Hpack/Render.hs +11/−20
- src/Hpack/Run.hs +20/−20
- src/Hpack/Util.hs +22/−9
- test/Hpack/ConfigSpec.hs +30/−0
- test/Hpack/GenericsUtilSpec.hs +24/−0
- test/Hpack/HaskellSpec.hs +31/−0
- test/Hpack/RenderSpec.hs +9/−0
- test/Hpack/UtilSpec.hs +16/−0
hpack.cabal view
@@ -1,9 +1,9 @@--- This file has been generated from package.yaml by hpack version 0.5.1.+-- This file has been generated from package.yaml by hpack version 0.5.2. -- -- see: https://github.com/sol/hpack name: hpack-version: 0.5.2+version: 0.5.3 synopsis: An alternative format for Haskell packages homepage: https://github.com/sol/hpack#readme bug-reports: https://github.com/sol/hpack/issues@@ -36,6 +36,8 @@ Hpack.Config Hpack.Run other-modules:+ Hpack.GenericsUtil+ Hpack.Haskell Hpack.Render Hpack.Util default-language: Haskell2010@@ -84,10 +86,14 @@ other-modules: Helper Hpack.ConfigSpec+ Hpack.GenericsUtilSpec+ Hpack.HaskellSpec Hpack.RenderSpec Hpack.RunSpec Hpack.UtilSpec Hpack.Config+ Hpack.GenericsUtil+ Hpack.Haskell Hpack.Render Hpack.Run Hpack.Util
src/Hpack/Config.hs view
@@ -1,14 +1,12 @@ {-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE ViewPatterns #-} module Hpack.Config ( packageConfig , readPackageConfig@@ -21,6 +19,9 @@ , Library(..) , Executable(..) , SourceRepository(..)++-- exported for testing+, getModules ) where import Control.Applicative@@ -43,6 +44,7 @@ import System.FilePath import Hpack.Util+import Hpack.GenericsUtil packageConfig :: FilePath packageConfig = "package.yaml"@@ -50,26 +52,25 @@ githubBaseUrl :: String githubBaseUrl = "https://github.com/" -genericParseJSON_ :: forall a. (Typeable a, Generic a, GFromJSON (Rep a)) => Value -> Parser a+genericParseJSON_ :: forall a. (Generic a, GFromJSON (Rep a), HasTypeName a) => Value -> Parser a genericParseJSON_ = genericParseJSON defaultOptions {fieldLabelModifier = hyphenize name} where- name = (tyConName . typeRepTyCon . typeRep) (Proxy :: Proxy a)+ name :: String+ name = typeName (Proxy :: Proxy a) hyphenize :: String -> String -> String hyphenize name = camelTo '-' . drop (length name) class HasFieldNames a where- fieldNames :: a -> [String]- default fieldNames :: Data a => a -> [String]- fieldNames a = map (hyphenize name) (constrFields constr)- where- constr = toConstr a- name = showConstr constr+ fieldNames :: Proxy a -> [String] + default fieldNames :: (HasTypeName a, Generic a, Selectors (Rep a)) => Proxy a -> [String]+ fieldNames proxy = map (hyphenize $ typeName proxy) (selectors proxy)+ data CaptureUnknownFields a = CaptureUnknownFields { captureUnknownFieldsFields :: [String] , captureUnknownFieldsValue :: a-} deriving (Eq, Show, Generic, Data, Typeable)+} deriving (Eq, Show, Generic) instance (HasFieldNames a, FromJSON a) => FromJSON (CaptureUnknownFields a) where parseJSON v = captureUnknownFields <$> parseJSON v@@ -79,13 +80,13 @@ where unknown = keys \\ fields keys = map T.unpack (Map.keys o)- fields = fieldNames a+ fields = fieldNames (Proxy :: Proxy a) _ -> CaptureUnknownFields [] a data LibrarySection = LibrarySection { librarySectionExposedModules :: Maybe (List String) , librarySectionOtherModules :: Maybe (List String)-} deriving (Eq, Show, Generic, Data, Typeable)+} deriving (Eq, Show, Generic) instance HasFieldNames LibrarySection @@ -95,7 +96,7 @@ data ExecutableSection = ExecutableSection { executableSectionMain :: FilePath , executableSectionOtherModules :: Maybe (List String)-} deriving (Eq, Show, Generic, Data, Typeable)+} deriving (Eq, Show, Generic) instance HasFieldNames ExecutableSection @@ -108,7 +109,7 @@ , commonOptionsDefaultExtensions :: Maybe (List String) , commonOptionsGhcOptions :: Maybe (List GhcOption) , commonOptionsCppOptions :: Maybe (List CppOption)-} deriving (Eq, Show, Generic, Data, Typeable)+} deriving (Eq, Show, Generic) instance HasFieldNames CommonOptions @@ -134,7 +135,7 @@ , packageConfigLibrary :: Maybe (CaptureUnknownFields (Section LibrarySection)) , packageConfigExecutables :: Maybe (HashMap String (CaptureUnknownFields (Section ExecutableSection))) , packageConfigTests :: Maybe (HashMap String (CaptureUnknownFields (Section ExecutableSection)))-} deriving (Eq, Show, Generic, Data, Typeable)+} deriving (Eq, Show, Generic) instance HasFieldNames PackageConfig @@ -179,7 +180,7 @@ data Dependency = Dependency { dependencyName :: String , dependencyGitRef :: Maybe GitRef-} deriving (Eq, Show, Ord, Generic, Data, Typeable)+} deriving (Eq, Show, Ord, Generic) instance IsString Dependency where fromString name = Dependency name Nothing@@ -210,9 +211,8 @@ data GitRef = GitRef { gitRefUrl :: String , gitRefRef :: String-} deriving (Eq, Show, Ord, Generic, Data, Typeable)+} deriving (Eq, Show, Ord, Generic) -type GhcOption = String type CppOption = String data Package = Package {@@ -255,13 +255,10 @@ , sectionDefaultExtensions :: [String] , sectionGhcOptions :: [GhcOption] , sectionCppOptions :: [CppOption]-} deriving (Eq, Show, Functor, Foldable, Traversable, Data, Typeable)+} deriving (Eq, Show, Functor, Foldable, Traversable) instance HasFieldNames a => HasFieldNames (Section a) where- fieldNames section = (fieldNames (sectionData section) ++ fieldNames proxy)- where- proxy :: CommonOptions- proxy = CommonOptions Nothing Nothing Nothing Nothing Nothing+ fieldNames Proxy = fieldNames (Proxy :: Proxy a) ++ fieldNames (Proxy :: Proxy CommonOptions) instance FromJSON a => FromJSON (Section a) where parseJSON v = toSection <$> parseJSON v <*> parseJSON v@@ -398,19 +395,20 @@ sections = map (fmap $ mergeSections globalOptions) executables toExecutable :: (String, Section ExecutableSection) -> IO (Section Executable)- toExecutable (name, section) = traverse fromExecutableSection section+ toExecutable (name, section@Section{..}) = do+ (executable, ghcOptions) <- fromExecutableSection sectionData+ return (section {sectionData = executable, sectionGhcOptions = sectionGhcOptions ++ ghcOptions}) where- sourceDirs :: [FilePath]- sourceDirs = sectionSourceDirs section-- fromExecutableSection :: ExecutableSection -> IO Executable+ fromExecutableSection :: ExecutableSection -> IO (Executable, [GhcOption]) fromExecutableSection ExecutableSection{..} = do- modules <- maybe (filterMain . concat <$> mapM getModules sourceDirs) (return . fromList) executableSectionOtherModules- return (Executable name executableSectionMain modules)+ modules <- maybe (filterMain . concat <$> mapM getModules sectionSourceDirs) (return . fromList) executableSectionOtherModules+ return (Executable name mainSrcFile modules, ghcOptions) where filterMain :: [String] -> [String] filterMain = maybe id (filter . (/=)) (toModule $ splitDirectories executableSectionMain) + (mainSrcFile, ghcOptions) = parseMain executableSectionMain+ mergeSections :: Section global -> Section a -> Section a mergeSections globalOptions options = Section a sourceDirs dependencies defaultExtensions ghcOptions cppOptions@@ -441,14 +439,22 @@ exposedModules = maybe (modules \\ otherModules) fromList mExposedModules getModules :: FilePath -> IO [String]-getModules src = sort <$> do- exits <- doesDirectoryExist src- if exits- then toModules <$> getFilesRecursive src+getModules src_ = sort <$> do+ exists <- doesDirectoryExist src_+ if exists+ then do+ src <- canonicalizePath src_+ cwd <- getCurrentDirectory+ removeSetup cwd src . toModules <$> getFilesRecursive src else return [] where toModules :: [[FilePath]] -> [String] toModules = catMaybes . map toModule++ removeSetup :: FilePath -> FilePath -> [String] -> [String]+ removeSetup cwd src+ | src == cwd = filter (/= "Setup")+ | otherwise = id fromMaybeList :: Maybe (List a) -> [a] fromMaybeList = maybe [] fromList
+ src/Hpack/GenericsUtil.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+module Hpack.GenericsUtil (+ HasTypeName+, typeName+, Selectors+, selectors+) where++import Data.Proxy+import GHC.Generics++class HasTypeName a where+ typeName :: Proxy a -> String++instance (Datatype d, Generic a, Rep a ~ M1 D d m) => HasTypeName a where+ typeName _ = datatypeName (undefined :: M1 D d x y)++selectors :: (Generic a, Selectors (Rep a)) => Proxy a -> [String]+selectors = f+ where+ f :: forall a. (Generic a, Selectors (Rep a)) => Proxy a -> [String]+ f _ = selNames (Proxy :: Proxy (Rep a))++class Selectors a where+ selNames :: Proxy a -> [String]++instance Selectors f => Selectors (M1 D x f) where+ selNames _ = selNames (Proxy :: Proxy f)++instance Selectors f => Selectors (M1 C x f) where+ selNames _ = selNames (Proxy :: Proxy f)++instance Selector s => Selectors (M1 S s (K1 R t)) where+ selNames _ = [selName (undefined :: M1 S s (K1 R t) ())]++instance (Selectors a, Selectors b) => Selectors (a :*: b) where+ selNames _ = selNames (Proxy :: Proxy a) ++ selNames (Proxy :: Proxy b)++instance Selectors U1 where+ selNames _ = []
+ src/Hpack/Haskell.hs view
@@ -0,0 +1,55 @@+module Hpack.Haskell (+ isModule+, isQualifiedIdentifier+, isIdentifier+) where++import Data.Char++isModule :: [String] -> Bool+isModule name = (not . null) name && all isModuleName name++isModuleName :: String -> Bool+isModuleName name = case name of+ x : xs -> isUpper x && all isIdChar xs+ _ -> False++isQualifiedIdentifier :: [String] -> Bool+isQualifiedIdentifier name = case reverse name of+ x : xs -> isIdentifier x && isModule xs+ _ -> False++isIdentifier :: String -> Bool+isIdentifier name = case name of+ x : xs -> isLower x && all isIdChar xs && name `notElem` reserved+ _ -> False++reserved :: [String]+reserved = [+ "case"+ , "class"+ , "data"+ , "default"+ , "deriving"+ , "do"+ , "else"+ , "foreign"+ , "if"+ , "import"+ , "in"+ , "infix"+ , "infixl"+ , "infixr"+ , "instance"+ , "let"+ , "module"+ , "newtype"+ , "of"+ , "then"+ , "type"+ , "where"+ , "_"+ ]++isIdChar :: Char -> Bool+isIdChar c = isAlphaNum c || c == '_' || c == '\''
src/Hpack/Render.hs view
@@ -18,10 +18,7 @@ | WordList [String] deriving (Eq, Show) -data Field = Field String Value- deriving (Eq, Show)--data Stanza = Stanza String [Field] | Fields [Field]+data Element = Stanza String [Element] | Field String Value deriving (Eq, Show) data Lines = SingleLine String | MultipleLines [String]@@ -38,22 +35,16 @@ defaultRenderSettings :: RenderSettings defaultRenderSettings = RenderSettings 2 LeadingCommas -class Render a where- render :: RenderSettings -> Int -> a -> [String]--instance Render Stanza where- render settings nesting (Fields fields) = concatMap (render settings nesting) fields- render settings nesting (Stanza name fields) = name : renderFields fields- where- renderFields :: [Field] -> [String]- renderFields = concatMap (render settings $ succ nesting)--instance Render Field where- render settings nesting (Field name v) = case renderValue settings v of- SingleLine "" -> []- SingleLine x -> [indent settings nesting (name ++ ": " ++ x)]- MultipleLines [] -> []- MultipleLines xs -> (indent settings nesting name ++ ":") : map (indent settings $ succ nesting) xs+render :: RenderSettings -> Int -> Element -> [String]+render settings nesting (Stanza name elements) = indent settings nesting name : renderElements elements+ where+ renderElements :: [Element] -> [String]+ renderElements = concatMap (render settings $ succ nesting)+render settings nesting (Field name v) = case renderValue settings v of+ SingleLine "" -> []+ SingleLine x -> [indent settings nesting (name ++ ": " ++ x)]+ MultipleLines [] -> []+ MultipleLines xs -> (indent settings nesting name ++ ":") : map (indent settings $ succ nesting) xs renderValue :: RenderSettings -> Value -> Lines renderValue RenderSettings{..} v = case v of
src/Hpack/Run.hs view
@@ -46,18 +46,18 @@ header = unlines $ map formatField sortedFields - extraSourceFiles :: Field+ extraSourceFiles :: Element extraSourceFiles = Field "extra-source-files" (LineSeparatedList packageExtraSourceFiles) - dataFiles :: Field+ dataFiles :: Element dataFiles = Field "data-files" (LineSeparatedList packageDataFiles) sourceRepository = maybe [] (return . renderSourceRepository) packageSourceRepository library = maybe [] (return . renderLibrary) packageLibrary - stanzas :: [Stanza]- stanzas = Fields [extraSourceFiles] : Fields [dataFiles] : sourceRepository ++ library ++ renderExecutables packageExecutables ++ renderTests packageTests+ stanzas :: [Element]+ stanzas = extraSourceFiles : dataFiles : sourceRepository ++ library ++ renderExecutables packageExecutables ++ renderTests packageTests padding name = replicate (alignment - length name - 2) ' ' @@ -124,36 +124,36 @@ isEmptyLine = all isSpace -renderSourceRepository :: SourceRepository -> Stanza+renderSourceRepository :: SourceRepository -> Element renderSourceRepository SourceRepository{..} = Stanza "source-repository head" [ Field "type" "git" , Field "location" (Literal sourceRepositoryUrl) , Field "subdir" (maybe "" Literal sourceRepositorySubdir) ] -renderExecutables :: [Section Executable] -> [Stanza]+renderExecutables :: [Section Executable] -> [Element] renderExecutables = map renderExecutable -renderExecutable :: Section Executable -> Stanza+renderExecutable :: Section Executable -> Element renderExecutable section@(sectionData -> Executable{..}) = Stanza ("executable " ++ executableName) (renderExecutableSection section) -renderTests :: [Section Executable] -> [Stanza]+renderTests :: [Section Executable] -> [Element] renderTests = map renderTest -renderTest :: Section Executable -> Stanza+renderTest :: Section Executable -> Element renderTest section@(sectionData -> Executable{..}) = Stanza ("test-suite " ++ executableName) (Field "type" "exitcode-stdio-1.0" : renderExecutableSection section) -renderExecutableSection :: Section Executable -> [Field]+renderExecutableSection :: Section Executable -> [Element] renderExecutableSection section@(sectionData -> Executable{..}) = mainIs : renderSection section ++ [otherModules, defaultLanguage] where mainIs = Field "main-is" (Literal executableMain) otherModules = renderOtherModules executableOtherModules -renderLibrary :: Section Library -> Stanza+renderLibrary :: Section Library -> Element renderLibrary section@(sectionData -> Library{..}) = Stanza "library" $ renderSection section ++ [ renderExposedModules libraryExposedModules@@ -161,7 +161,7 @@ , defaultLanguage ] -renderSection :: Section a -> [Field]+renderSection :: Section a -> [Element] renderSection Section{..} = [ renderSourceDirs sectionSourceDirs , renderDefaultExtensions sectionDefaultExtensions@@ -170,26 +170,26 @@ , renderDependencies sectionDependencies ] -defaultLanguage :: Field+defaultLanguage :: Element defaultLanguage = Field "default-language" "Haskell2010" -renderSourceDirs :: [String] -> Field+renderSourceDirs :: [String] -> Element renderSourceDirs dirs = Field "hs-source-dirs" (CommaSeparatedList dirs) -renderExposedModules :: [String] -> Field+renderExposedModules :: [String] -> Element renderExposedModules modules = Field "exposed-modules" (LineSeparatedList modules) -renderOtherModules :: [String] -> Field+renderOtherModules :: [String] -> Element renderOtherModules modules = Field "other-modules" (LineSeparatedList modules) -renderDependencies :: [Dependency] -> Field+renderDependencies :: [Dependency] -> Element renderDependencies dependencies = Field "build-depends" (CommaSeparatedList $ map dependencyName dependencies) -renderGhcOptions :: [GhcOption] -> Field+renderGhcOptions :: [GhcOption] -> Element renderGhcOptions = Field "ghc-options" . WordList -renderCppOptions :: [GhcOption] -> Field+renderCppOptions :: [GhcOption] -> Element renderCppOptions = Field "cpp-options" . WordList -renderDefaultExtensions :: [String] -> Field+renderDefaultExtensions :: [String] -> Element renderDefaultExtensions = Field "default-extensions" . WordList
src/Hpack/Util.hs view
@@ -1,6 +1,8 @@ {-# LANGUAGE DeriveDataTypeable #-} module Hpack.Util ( List(..)+, GhcOption+, parseMain , toModule , getFilesRecursive , tryReadFile@@ -28,6 +30,8 @@ import System.FilePath import System.FilePath.Glob +import Hpack.Haskell+ sort :: [String] -> [String] sort = sortBy (comparing lexicographically) @@ -40,24 +44,33 @@ instance FromJSON a => FromJSON (List a) where parseJSON v = List <$> (parseJSON v <|> (return <$> parseJSON v)) +type GhcOption = String++parseMain :: String -> (FilePath, [GhcOption])+parseMain main = case reverse name of+ x : _ | isQualifiedIdentifier name && x `notElem` ["hs", "lhs"] -> (intercalate "/" (init name) ++ ".hs", ["-main-is " ++ main])+ _ | isModule name -> (intercalate "/" name ++ ".hs", ["-main-is " ++ main])+ _ -> (main, [])+ where+ name = splitOn '.' main++splitOn :: Char -> String -> [String]+splitOn c = go+ where+ go xs = case break (== c) xs of+ (ys, "") -> [ys]+ (ys, _:zs) -> ys : go zs+ toModule :: [FilePath] -> Maybe String toModule path = case reverse path of [] -> Nothing x : xs -> do m <- stripSuffix ".hs" x <|> stripSuffix ".lhs" x let name = reverse (m : xs)- guard (all isValidModuleName name) >> return (intercalate "." name)+ guard (isModule name) >> return (intercalate "." name) where stripSuffix :: String -> String -> Maybe String stripSuffix suffix x = reverse <$> stripPrefix (reverse suffix) (reverse x)---- See `Cabal.Distribution.ModuleName` (http://git.io/bj34)-isValidModuleName :: String -> Bool-isValidModuleName [] = False-isValidModuleName (c:cs) = isUpper c && all isValidModuleChar cs--isValidModuleChar :: Char -> Bool-isValidModuleChar c = isAlphaNum c || c == '_' || c == '\'' getFilesRecursive :: FilePath -> IO [[String]] getFilesRecursive baseDir = go []
test/Hpack/ConfigSpec.hs view
@@ -78,6 +78,25 @@ }|] parseEither parseJSON value `shouldBe` (Left "neither key \"git\" nor key \"github\" present" :: Either String Dependency) + describe "getModules" $ around_ inTempDirectory $ do+ it "returns Haskell modules in specified source directory" $ do+ touch "src/Foo.hs"+ touch "src/Bar/Baz.hs"+ touch "src/Setup.hs"+ getModules "src" >>= (`shouldMatchList` ["Foo", "Bar.Baz", "Setup"])++ context "when source directory is '.'" $ do+ it "ignores Setup" $ do+ touch "Foo.hs"+ touch "Setup.hs"+ getModules "." `shouldReturn` ["Foo"]++ context "when source directory is './.'" $ do+ it "ignores Setup" $ do+ touch "Foo.hs"+ touch "Setup.hs"+ getModules "./." `shouldReturn` ["Foo"]+ describe "readPackageConfig" $ around_ (inTempDirectoryNamed "foo") $ do it "warns on unknown fields" $ do writeFile "package.yaml" [i|@@ -394,6 +413,17 @@ |] Right (_, c) <- readPackageConfig "package.yaml" packageExecutables c `shouldBe` [section $ executable "foo" "driver/Main.hs"]++ it "accepts arbitrary entry points as main" $ do+ writeFile "package.yaml" [i|+ executables:+ foo:+ main: Foo+ |]+ Right (_, c) <- readPackageConfig "package.yaml"+ packageExecutables c `shouldBe` [+ (section $ executable "foo" "Foo.hs") {sectionGhcOptions = ["-main-is Foo"]}+ ] it "accepts source-dirs" $ do writeFile "package.yaml" [i|
+ test/Hpack/GenericsUtilSpec.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE DeriveGeneric #-}+module Hpack.GenericsUtilSpec (spec) where++import Test.Hspec++import Data.Proxy+import GHC.Generics++import Hpack.GenericsUtil++data Person = Person {+ _personName :: String+, _personAge :: Int+} deriving Generic++spec :: Spec+spec = do+ describe "selectors" $ do+ it "returns a list of record selectors" $ do+ selectors (Proxy :: Proxy Person) `shouldBe` ["_personName", "_personAge"]++ describe "typeName" $ do+ it "gets datatype name" $ do+ typeName (Proxy :: Proxy Person) `shouldBe` "Person"
+ test/Hpack/HaskellSpec.hs view
@@ -0,0 +1,31 @@+module Hpack.HaskellSpec (spec) where++import Test.Hspec++import Hpack.Haskell++spec :: Spec+spec = do+ describe "isModule" $ do+ it "accepts module names" $ do+ isModule ["Foo", "Bar"] `shouldBe` True++ it "rejects the empty list" $ do+ isModule [] `shouldBe` False++ describe "isQualifiedIdentifier" $ do+ it "accepts qualified Haskell identifiers" $ do+ isQualifiedIdentifier ["Foo", "Bar", "baz"] `shouldBe` True++ it "rejects invalid input" $ do+ isQualifiedIdentifier ["Foo", "Bar", "Baz"] `shouldBe` False++ describe "isIdentifier" $ do+ it "accepts Haskell identifiers" $ do+ isIdentifier "foo" `shouldBe` True++ it "rejects reserved keywords" $ do+ isIdentifier "case" `shouldBe` False++ it "rejects invalid input" $ do+ isIdentifier "Foo" `shouldBe` False
test/Hpack/RenderSpec.hs view
@@ -42,6 +42,15 @@ , " baz: 42" ] + it "renders nested stanzas" $ do+ let input = Stanza "foo" [Field "bar" "23", Stanza "baz" [Field "qux" "42"]]+ render defaultRenderSettings 0 input `shouldBe` [+ "foo"+ , " bar: 23"+ , " baz"+ , " qux: 42"+ ]+ context "when rendering a Field" $ do context "when rendering a MultipleLines value" $ do it "takes nesting into account" $ do
test/Hpack/UtilSpec.hs view
@@ -16,6 +16,22 @@ it "sorts lexicographically" $ do sort ["foo", "Foo"] `shouldBe` ["Foo", "foo" :: String] + describe "parseMain" $ do+ it "accepts source file" $ do+ parseMain "Main.hs" `shouldBe` ("Main.hs", [])++ it "accepts literate source file" $ do+ parseMain "Main.lhs" `shouldBe` ("Main.lhs", [])++ it "accepts module" $ do+ parseMain "Foo" `shouldBe` ("Foo.hs", ["-main-is Foo"])++ it "accepts hierarchical module" $ do+ parseMain "Foo.Bar.Baz" `shouldBe` ("Foo/Bar/Baz.hs", ["-main-is Foo.Bar.Baz"])++ it "accepts qualified identifier" $ do+ parseMain "Foo.bar" `shouldBe` ("Foo.hs", ["-main-is Foo.bar"])+ describe "toModule" $ do it "maps paths to module names" $ do toModule ["Foo", "Bar", "Baz.hs"] `shouldBe` Just "Foo.Bar.Baz"