hsini 0.5.1.2 → 0.5.1.3
raw patch · 9 files changed
+283/−268 lines, 9 filesdep +hsinidep ~basedep ~mtlPVP: minor bump suggested
API additions: PVP suggests at least a minor version bump
Dependencies added: hsini
Dependency ranges changed: base, mtl
API changes (from Hackage documentation)
+ Data.Ini.Reader.Internals: CommentL :: IniFile
+ Data.Ini.Reader.Internals: IniOtherError :: String -> IniReaderError
+ Data.Ini.Reader.Internals: IniParserError :: String -> IniReaderError
+ Data.Ini.Reader.Internals: IniSyntaxError :: String -> IniReaderError
+ Data.Ini.Reader.Internals: OptionContL :: String -> IniFile
+ Data.Ini.Reader.Internals: OptionL :: String -> String -> IniFile
+ Data.Ini.Reader.Internals: SectionL :: String -> IniFile
+ Data.Ini.Reader.Internals: buildConfig :: [IniFile] -> IniParseResult Config
+ Data.Ini.Reader.Internals: data IniFile
+ Data.Ini.Reader.Internals: data IniReaderError
+ Data.Ini.Reader.Internals: eatWhiteSpace :: Parser String
+ Data.Ini.Reader.Internals: iniParser :: Parser [IniFile]
+ Data.Ini.Reader.Internals: instance GHC.Classes.Eq Data.Ini.Reader.Internals.IniFile
+ Data.Ini.Reader.Internals: instance GHC.Classes.Eq Data.Ini.Reader.Internals.IniReaderError
+ Data.Ini.Reader.Internals: instance GHC.Show.Show Data.Ini.Reader.Internals.IniFile
+ Data.Ini.Reader.Internals: instance GHC.Show.Show Data.Ini.Reader.Internals.IniReaderError
+ Data.Ini.Reader.Internals: noiseParser :: Parser IniFile
+ Data.Ini.Reader.Internals: optContParser :: Parser IniFile
+ Data.Ini.Reader.Internals: optLineParser :: Parser IniFile
+ Data.Ini.Reader.Internals: secParser :: Parser IniFile
+ Data.Ini.Reader.Internals: type IniParseResult = Either IniReaderError
Files
- hsini.cabal +30/−40
- package.yaml +0/−43
- src/Data/Ini.hs +26/−21
- src/Data/Ini/Reader.hs +19/−16
- src/Data/Ini/Reader/Internals.hs +59/−46
- src/Data/Ini/Types.hs +6/−5
- stack.yaml +0/−10
- tst/Ini.hs +32/−27
- tst/ReaderI.hs +111/−60
hsini.cabal view
@@ -1,66 +1,56 @@--- This file has been generated from package.yaml by hpack version 0.28.2.------ see: https://github.com/sol/hpack------ hash: 0a9d3d220e23a6165acb4a43a8293ef95e41667b8afd689196d833adad1dba85+cabal-version: 3.0+name: hsini+version: 0.5.1.3+synopsis: ini configuration files+description:+ Library for reading and writing configuration files in INI format (see <https://en.wikipedia.org/wiki/INI_file>). -name: hsini-version: 0.5.1.2-synopsis: ini configuration files-description: Library for reading and writing configuration files in INI format (see <https://en.wikipedia.org/wiki/INI_file>).-category: Configuration, Data-maintainer: Magnus Therning <magnus@therning.org>-license: BSD3-license-file: LICENSE-build-type: Simple-cabal-version: >= 1.10-extra-source-files:- package.yaml- stack.yaml+category: Configuration, Data+author: Magnus Therning <magnus@therning.org>+maintainer: Magnus Therning <magnus@therning.org>+license: BSD-3-Clause+license-file: LICENSE+build-type: Simple source-repository head- type: git+ type: git location: https://github.com/magthe/hsini.git library exposed-modules:- Data.Ini- Data.Ini.Reader- Data.Ini.Types- other-modules:- Data.Ini.Reader.Internals- hs-source-dirs:- src+ Data.Ini+ Data.Ini.Reader+ Data.Ini.Reader.Internals+ Data.Ini.Types++ hs-source-dirs: src build-depends:- base <5+ , base <5 , bytestring , containers , mtl , parsec+ default-language: Haskell2010 test-suite hsini-tests- type: exitcode-stdio-1.0- main-is: Main.hs+ type: exitcode-stdio-1.0+ main-is: Main.hs other-modules:- Ini- ReaderI- Data.Ini- Data.Ini.Reader- Data.Ini.Reader.Internals- Data.Ini.Types- Paths_hsini- hs-source-dirs:- tst- src+ Ini+ ReaderI++ hs-source-dirs: tst build-depends:- base+ , base <5 , bytestring , containers+ , hsini , mtl , parsec , tasty , tasty-hunit , tasty-quickcheck , tasty-th+ default-language: Haskell2010
− package.yaml
@@ -1,43 +0,0 @@-name: hsini-version: 0.5.1.2-synopsis: ini configuration files-description: >-- Library for reading and writing configuration files in INI format (see- <https://en.wikipedia.org/wiki/INI_file>).-maintainer: Magnus Therning <magnus@therning.org>-license: BSD3-category: Configuration, Data-extra-source-files:- - package.yaml- - stack.yaml--git: https://github.com/magthe/hsini.git--library:- source-dirs:- - src- dependencies:- - base <5- - bytestring- - containers- - mtl- - parsec- other-modules:- - Data.Ini.Reader.Internals--tests:- hsini-tests:- source-dirs:- - tst- - src- main: Main.hs- dependencies:- - base- - bytestring- - containers- - mtl- - parsec- - tasty- - tasty-hunit- - tasty-quickcheck- - tasty-th
src/Data/Ini.hs view
@@ -1,14 +1,15 @@--- |--- Module : Data.Ini--- Copyright : 2011-2014 Magnus Therning--- License : BSD3------ A representation of configuration options. It consists of /sections/,--- each which can contain 0 or more /options/. Each options is a /key/,--- /value/ pair.------ This module contains the API for constructing, manipulating, and querying--- configurations.+{- |+Module : Data.Ini+Copyright : 2011-2014 Magnus Therning+License : BSD3++A representation of configuration options. It consists of /sections/,+each which can contain 0 or more /options/. Each options is a /key/,+/value/ pair.++This module contains the API for constructing, manipulating, and querying+configurations.+-} module Data.Ini where -- {{{1 imports@@ -18,11 +19,13 @@ import Data.Ini.Types -- {{{1 configurations+ -- | Constructs an empty configuration. emptyConfig :: Config emptyConfig = M.empty -- {{{1 sections+ -- | Returns @True@ iff the configuration has a section with that name. hasSection :: SectionName -> Config -> Bool hasSection = M.member@@ -40,6 +43,7 @@ delSection = M.delete -- {{{1 options+ -- | Returns @True@ if the names section has the option. hasOption :: SectionName -> OptionName -> Config -> Bool hasOption sn on cfg = isJust $ getSection sn cfg >>= M.lookup on@@ -49,24 +53,25 @@ getOption sn on cfg = getSection sn cfg >>= M.lookup on -- | Returns a list of all options in the section.-options :: SectionName -> Config -> [OptionName]+options :: SectionName -> Config -> [OptionName] options sn cfg = maybe [] M.keys (getSection sn cfg) -- | Sets the value of the option, adding it if it doesn't exist. setOption :: SectionName -> OptionName -> OptionValue -> Config -> Config-setOption sn on ov cfg = maybe (M.insert sn new_s cfg) (\ sec -> M.insert sn (M.insert on ov sec) cfg) s- where- s = getSection sn cfg- new_s = M.insert on ov M.empty+setOption sn on ov cfg = maybe (M.insert sn new_s cfg) (\sec -> M.insert sn (M.insert on ov sec) cfg) s+ where+ s = getSection sn cfg+ new_s = M.insert on ov M.empty -- | Removes the option if it exists. Empty sections are pruned. delOption :: SectionName -> OptionName -> Config -> Config-delOption sn on cfg = if sEmptyAfterDelete+delOption sn on cfg =+ if sEmptyAfterDelete then M.delete sn cfg- else maybe cfg (\ sec -> M.insert sn (M.delete on sec) cfg) s- where- s = getSection sn cfg- sEmptyAfterDelete = maybe True (\ sec -> M.empty == M.delete on sec) s+ else maybe cfg (\sec -> M.insert sn (M.delete on sec) cfg) s+ where+ s = getSection sn cfg+ sEmptyAfterDelete = maybe True (\sec -> M.empty == M.delete on sec) s -- | Returns all options and their values of a section. allItems :: SectionName -> Config -> [(OptionName, OptionValue)]
src/Data/Ini/Reader.hs view
@@ -1,25 +1,28 @@--- |--- Module : Data.Ini.Reader--- Copyright : 2011-2014 Magnus Therning--- License : BSD3------ Parser for configurations.-module Data.Ini.Reader- ( parse- , IniReaderError(..)- , IniParseResult- ) where+{- |+Module : Data.Ini.Reader+Copyright : 2011-2014 Magnus Therning+License : BSD3 +Parser for configurations.+-}+module Data.Ini.Reader (+ parse,+ IniReaderError (..),+ IniParseResult,+) where+ import Control.Monad.Except import qualified Text.ParserCombinators.Parsec as P -import Data.Ini.Types import Data.Ini.Reader.Internals+import Data.Ini.Types -- | Parser for a configuration contained in a 'String'. parse :: String -> IniParseResult Config-parse s = let+parse s =+ let pr = P.parse iniParser "ini" s- in case pr of- Left e -> throwError . IniParserError $ show e- Right is -> buildConfig is+ in+ case pr of+ Left e -> throwError . IniParserError $ show e+ Right is -> buildConfig is
src/Data/Ini/Reader/Internals.hs view
@@ -1,10 +1,12 @@ {-# LANGUAGE FlexibleContexts #-}--- |--- Module : Data.Ini.Reader.Internals--- Copyright : 2011-2014 Magnus Therning--- License : BSD3------ Internal functions used in 'Data.Ini.Reader'.++{- |+Module : Data.Ini.Reader.Internals+Copyright : 2011-2014 Magnus Therning+License : BSD3++Internal functions used in 'Data.Ini.Reader'.+-} module Data.Ini.Reader.Internals where import Control.Monad.Except@@ -34,7 +36,8 @@ -- | Build a configuration from a list of 'IniFile' items. buildConfig :: [IniFile] -> IniParseResult Config-buildConfig ifs = let+buildConfig ifs =+ let isComment CommentL = True isComment _ = False @@ -43,7 +46,7 @@ -- merge together OptionL and subsequent OptionContL items mergeOptions [] = return [] mergeOptions (s@(SectionL _) : ifs) = (s :) `liftM` mergeOptions ifs- mergeOptions (CommentL : ifs ) = (CommentL :) `liftM` mergeOptions ifs+ mergeOptions (CommentL : ifs) = (CommentL :) `liftM` mergeOptions ifs mergeOptions (OptionL on ov : OptionContL ov2 : ifs) = mergeOptions $ (OptionL on (ov ++ ov2)) : ifs mergeOptions (o@(OptionL on ov) : ifs) = (o :) `liftM` mergeOptions ifs mergeOptions _ = throwError $ IniSyntaxError "Syntax error in INI file."@@ -55,65 +58,75 @@ sn <- get let na = setOption sn on ov a buildit na is-- in mergeOptions fIfs >>= (\ is -> return . fst $ runState (buildit emptyConfig is) "default")+ in+ mergeOptions fIfs >>= (\is -> return . fst $ runState (buildit emptyConfig is) "default") -- | Consumer of whitespace \"@ \t@\". eatWhiteSpace :: Parser String eatWhiteSpace = many $ oneOf " \t" --- | Parser for the start-of-section line. It expects the line to start with a--- @[@ then find the section name, and finally a @]@. The section name may be--- surrounded by any number of white space characters (see 'eatWhiteSpace').+{- | Parser for the start-of-section line. It expects the line to start with a+@[@ then find the section name, and finally a @]@. The section name may be+surrounded by any number of white space characters (see 'eatWhiteSpace').+-} secParser :: Parser IniFile-secParser = let- validSecNameChrs = ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ "._-/@\" "- in do- char '['- eatWhiteSpace- sn <- many1 $ oneOf validSecNameChrs- eatWhiteSpace- char ']'- manyTill anyChar newline- return $ SectionL sn+secParser =+ let+ validSecNameChrs = ['a' .. 'z'] ++ ['A' .. 'Z'] ++ ['0' .. '9'] ++ "._-/@\" "+ in+ do+ char '['+ eatWhiteSpace+ sn <- many1 $ oneOf validSecNameChrs+ eatWhiteSpace+ char ']'+ manyTill anyChar newline+ return $ SectionL sn --- | Parser for a single line of an option. The line must start with an option--- name, then a @=@ must be found, and finally the rest of the line is taken as--- the option value. The equal sign may be surrounded by any number of white--- space characters (see 'eatWhiteSpace').+{- | Parser for a single line of an option. The line must start with an option+name, then a @=@ must be found, and finally the rest of the line is taken as+the option value. The equal sign may be surrounded by any number of white+space characters (see 'eatWhiteSpace').+-} optLineParser :: Parser IniFile-optLineParser = let- validOptNameChrs = ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ "_-/@"- in do- on <- many1 $ oneOf validOptNameChrs- eatWhiteSpace- char '='- eatWhiteSpace- ov <- manyTill anyChar newline- return $ OptionL on ov+optLineParser =+ let+ validOptNameChrs = ['a' .. 'z'] ++ ['A' .. 'Z'] ++ ['0' .. '9'] ++ "_-/@"+ in+ do+ on <- many1 $ oneOf validOptNameChrs+ eatWhiteSpace+ char '='+ eatWhiteSpace+ ov <- manyTill anyChar newline+ return $ OptionL on ov --- | Parser for an option-value continuation line. The line must start with--- either a space or a tab character (\"@ \t@\"). Everything else on the line,--- until the newline character, is taken as the continuation of an option--- value.+{- | Parser for an option-value continuation line. The line must start with+either a space or a tab character (\"@ \t@\"). Everything else on the line,+until the newline character, is taken as the continuation of an option+value.+-} optContParser :: Parser IniFile optContParser = do oneOf " \t" eatWhiteSpace oc <- noneOf " \t" ov <- manyTill anyChar newline- return $ OptionContL $ oc:ov+ return $ OptionContL $ oc : ov --- | Parser for "noise" in the configuration file, such as comments and empty--- lines. (Note that lines containing only space characters will be--- successfully parsed by 'optContParser'.)+{- | Parser for "noise" in the configuration file, such as comments and empty+lines. (Note that lines containing only space characters will be+successfully parsed by 'optContParser'.)+-} noiseParser :: Parser IniFile-noiseParser = let+noiseParser =+ let commentP = do oneOf "#;" manyTill anyChar newline emptyL = newline >> return ""- in choice [commentP, emptyL] >> return CommentL+ in+ choice [commentP, emptyL] >> return CommentL iniParser :: Parser [IniFile] iniParser =
src/Data/Ini/Types.hs view
@@ -1,11 +1,12 @@--- |--- Module : Data.Ini.Types--- Copyright : 2011-2014 Magnus Therning--- License : BSD3+{- |+Module : Data.Ini.Types+Copyright : 2011-2014 Magnus Therning+License : BSD3+-} module Data.Ini.Types where -import qualified Data.Map as M import Control.Arrow (second)+import qualified Data.Map as M type Config = M.Map SectionName Section
− stack.yaml
@@ -1,10 +0,0 @@-resolver: lts-11.11--packages:- - '.'--extra-deps: []--flags: {}--extra-package-dbs: []
tst/Ini.hs view
@@ -1,9 +1,10 @@-{-# OPTIONS_GHC -XTemplateHaskell #-}+{-# LANGUAGE TemplateHaskell #-}+ -- Copyright : 2011-2014 Magnus Therning -- License : BSD3-module Ini- ( allTests- ) where+module Ini (+ allTests,+) where -- {{{1 imports import Data.Maybe@@ -18,54 +19,58 @@ -- adding and then deleting a section is a no-op (if the section doesn't exist -- already) prop_secAddDel sn cfglst = delSection sn (setOption sn "foo" "bar" cfg2) == cfg2- where- cfg = cfgFromList cfglst- cfg2 = delSection sn cfg -- must make sure the section doesn't exist before adding+ where+ cfg = cfgFromList cfglst+ cfg2 = delSection sn cfg -- must make sure the section doesn't exist before adding -- after adding a section the config has such a section prop_secAddHas sn cfglst = hasSection sn (setOption sn "foo" "bar" cfg)- where cfg = cfgFromList cfglst+ where+ cfg = cfgFromList cfglst -- after adding a section it's possible to get it prop_secAddGet sn cfglst = isJust $ getSection sn (setOption sn "foo" "bar" cfg)- where cfg = cfgFromList cfglst+ where+ cfg = cfgFromList cfglst -- after deleting a section it's gone prop_secDelGet sn cfglst = isNothing $ getSection sn $ delSection sn cfg2- where- cfg = cfgFromList cfglst- cfg2 = setOption sn "foo" "bar" cfg+ where+ cfg = cfgFromList cfglst+ cfg2 = setOption sn "foo" "bar" cfg -- {{{1 option properties -- setting and then deleting an option is a no-op (if the option doesn't exist -- already) prop_optSetDel sn on ov cfglst = delOption sn on (setOption sn on ov cfg) == cfg2- where- cfg = cfgFromList cfglst- cfg2 = delOption sn on cfg+ where+ cfg = cfgFromList cfglst+ cfg2 = delOption sn on cfg -- after setting an option it's there prop_optSetHas sn on ov cfglst = hasOption sn on (setOption sn on ov cfg)- where cfg = cfgFromList cfglst+ where+ cfg = cfgFromList cfglst -- after setting an option it's possible to get it prop_optSetGet sn on ov cfglst = isJust $ getOption sn on $ setOption sn on ov cfg- where cfg = cfgFromList cfglst+ where+ cfg = cfgFromList cfglst -- after deleting a section it's gone prop_optDelGet sn on ov cfglst = isNothing $ getOption sn on $ delOption sn on cfg2- where- cfg = cfgFromList cfglst- cfg2 = setOption sn on ov cfg+ where+ cfg = cfgFromList cfglst+ cfg2 = setOption sn on ov cfg -- getting all items-prop_optAllItems cfglst = (length _cfglst > 0) ==> lstItems == (allItems sn cfg)- where- cfg = cfgFromList cfglst- _cfglst = cfgToList cfg- -- sn = head . sort $ map fst _cfglst- sn = head $ map fst _cfglst- lstItems = fromJust $ lookup sn _cfglst+prop_optAllItems cfglst = not (null _cfglst) ==> lstItems == allItems sn cfg+ where+ cfg = cfgFromList cfglst+ _cfglst = cfgToList cfg+ -- sn = head . sort $ map fst _cfglst+ sn = head $ map fst _cfglst+ lstItems = fromJust $ lookup sn _cfglst -- {{{1 allTests allTests :: TestTree
tst/ReaderI.hs view
@@ -1,10 +1,11 @@ {-# LANGUAGE FlexibleContexts #-}-{-# OPTIONS_GHC -XTemplateHaskell #-}+{-# LANGUAGE TemplateHaskell #-}+ -- Copyright : 2011-2014 Magnus Therning -- License : BSD3-module ReaderI- (allTests- ) where+module ReaderI (+ allTests,+) where import Test.Tasty import Test.Tasty.HUnit@@ -15,142 +16,192 @@ -- Convenience function that translates a parser result to something that's -- easier to check.-p2E p s t = let+p2E p s t =+ let res = P.parse p s t- in case res of- Left _ -> Left "bad"- Right e -> Right e+ in+ case res of+ Left _ -> Left "bad"+ Right e -> Right e -- {{{1 secParser-case_secParserAllowedChars1 = let+case_secParserAllowedChars1 =+ let expected = Right $ SectionL "foo" actual = p2E secParser "sec" "[foo]\n"- in expected @=? actual+ in+ expected @=? actual -case_secParserAllowedChars2 = let+case_secParserAllowedChars2 =+ let expected = Right $ SectionL "FooBar" actual = p2E secParser "sec" "[FooBar]\n"- in expected @=? actual+ in+ expected @=? actual -case_secParserAllowedChars3 = let+case_secParserAllowedChars3 =+ let expected = Right $ SectionL "@Foo/Bar-" actual = p2E secParser "sec" "[@Foo/Bar-]\n"- in expected @=? actual+ in+ expected @=? actual -case_secParserAllowedChars4 = let+case_secParserAllowedChars4 =+ let expected = Right $ SectionL "foo123" actual = p2E secParser "sec" "[foo123]\n"- in expected @=? actual+ in+ expected @=? actual -case_secParserAllowedChars5 = let+case_secParserAllowedChars5 =+ let expected = Right $ SectionL "_foo" actual = p2E secParser "sec" "[_foo]\n"- in expected @=? actual+ in+ expected @=? actual -case_secParserDropSpace = let+case_secParserDropSpace =+ let expected = Right $ SectionL "foo" actual = p2E secParser "sec" "[ \tfoo\t ]\n"- in expected @=? actual+ in+ expected @=? actual -case_secParserDropTrailing = let+case_secParserDropTrailing =+ let expected = Right $ SectionL "foo" actual = p2E secParser "sec" "[foo] \t foobar\n"- in expected @=? actual+ in+ expected @=? actual -case_secParserAllowGit1 = let+case_secParserAllowGit1 =+ let expected = Right $ SectionL "branch \"master\"" actual = p2E secParser "sec" "[branch \"master\"]\n"- in expected @=? actual+ in+ expected @=? actual -case_secParserAllowGit2 = let+case_secParserAllowGit2 =+ let expected = Right $ SectionL "foo \"bar.baz\"" actual = p2E secParser "sec" "[foo \"bar.baz\"]\n"- in expected @=? actual+ in+ expected @=? actual -- {{{1 optLineParser-case_optLineParserAllowedChars1 = let+case_optLineParserAllowedChars1 =+ let expected = Right $ OptionL "foo" "bar" actual = p2E optLineParser "optLine" "foo=bar\n"- in expected @=? actual+ in+ expected @=? actual -case_optLineParserAllowedChars2 = let+case_optLineParserAllowedChars2 =+ let expected = Right $ OptionL "Foo" "bAr" actual = p2E optLineParser "optLine" "Foo=bAr\n"- in expected @=? actual+ in+ expected @=? actual -case_optLineParserAllowedChars3 = let+case_optLineParserAllowedChars3 =+ let expected = Right $ OptionL "foo@/foo-" "bar" actual = p2E optLineParser "optLine" "foo@/foo-=bar\n"- in expected @=? actual+ in+ expected @=? actual -case_optLineParserAllowedChars4 = let+case_optLineParserAllowedChars4 =+ let expected = Right $ OptionL "foo123" "bar" actual = p2E optLineParser "optLine" "foo123=bar\n"- in expected @=? actual+ in+ expected @=? actual -case_optLineParserAllowedChars5 = let+case_optLineParserAllowedChars5 =+ let expected = Right $ OptionL "_foo" "bar" actual = p2E optLineParser "optLine" "_foo=bar\n"- in expected @=? actual+ in+ expected @=? actual -case_optLineParserDisallowedChars1 = let+case_optLineParserDisallowedChars1 =+ let expected = Left "bad" actual = p2E optLineParser "optLine" "foo.bar=baz\n"- in expected @=? actual+ in+ expected @=? actual -case_optLineParserDropSpace = let+case_optLineParserDropSpace =+ let expected = Right $ OptionL "foo" "bar" actual = p2E optLineParser "optLine" "foo\t \t=\t \t bar\n"- in expected @=? actual+ in+ expected @=? actual -case_optLineParserKeepSpace = let+case_optLineParserKeepSpace =+ let expected = Right $ OptionL "foo" "bar \t \t" actual = p2E optLineParser "optLine" "foo\t \t=\t \t bar \t \t\n"- in expected @=? actual+ in+ expected @=? actual -- {{{1 optContParser-case_optContParserSpace = let+case_optContParserSpace =+ let expected = Right $ OptionContL "foo" actual = p2E optContParser "optCont" " foo\n"- in expected @=? actual+ in+ expected @=? actual -case_optContParserTab = let- expected = Right $OptionContL "foo"+case_optContParserTab =+ let+ expected = Right $ OptionContL "foo" actual = p2E optContParser "optCont" "\tfoo\n"- in expected @=? actual+ in+ expected @=? actual -case_optContParserKeepTrailing = let+case_optContParserKeepTrailing =+ let expected = Right $ OptionContL "foo \t\t" actual = p2E optContParser "optCont" "\tfoo \t\t\n"- in expected @=? actual+ in+ expected @=? actual -- {{{1 noiseParser-case_noiseParserEmptyLine = let+case_noiseParserEmptyLine =+ let expected = Right CommentL actual = p2E noiseParser "noise" "\n"- in expected @=? actual+ in+ expected @=? actual -case_noiseParserComment1 = let+case_noiseParserComment1 =+ let expected = Right CommentL actual = p2E noiseParser "noise" "# a comment\n"- in expected @=? actual+ in+ expected @=? actual -case_noiseParserComment2 = let+case_noiseParserComment2 =+ let expected = Right CommentL actual = p2E noiseParser "noise" "; another comment\n"- in expected @=? actual+ in+ expected @=? actual -case_noiseParserNonEmpty = let+case_noiseParserNonEmpty =+ let expected = Left "bad" actual = p2E noiseParser "noise" " \n"- in expected @=? actual+ in+ expected @=? actual -- {{{1 iniParser case_iniParserEmpty :: Assertion case_iniParserEmpty = expected @=? actual- where- expected = Right []- actual = p2E iniParser "parsing empty file" ""+ where+ expected = Right []+ actual = p2E iniParser "parsing empty file" "" -- {{{1 buildConfig -- TBD