app-settings 0.2.0.5 → 0.2.0.6
raw patch · 5 files changed
+240/−241 lines, 5 filesdep ~HUnitdep ~hspecPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: HUnit, hspec
API changes (from Hackage documentation)
- Data.AppSettings: instance Show GetSetting
+ Data.AppSettings: instance GHC.Show.Show Data.AppSettings.GetSetting
- Data.AppSettings: getSetting' :: Read a => Conf -> Setting a -> a
+ Data.AppSettings: getSetting' :: (Read a) => Conf -> Setting a -> a
- Data.AppSettings: setSetting :: Show a => Conf -> Setting a -> a -> Conf
+ Data.AppSettings: setSetting :: (Show a) => Conf -> Setting a -> a -> Conf
- Data.AppSettings: setting :: Show a => Setting a -> State Conf ()
+ Data.AppSettings: setting :: (Show a) => Setting a -> State Conf ()
Files
- Data/AppSettings.hs +50/−50
- Data/AppSettingsInternal.hs +13/−13
- Data/Serialization.hs +53/−54
- app-settings.cabal +3/−3
- tests/Tests.hs +121/−121
Data/AppSettings.hs view
@@ -1,20 +1,20 @@ {-# LANGUAGE RankNTypes, GADTs #-} module Data.AppSettings (- -- $intro- Conf,- DefaultConfig(..),- Setting(..),- GetSetting(..),- setting,- getDefaultConfig,- emptyDefaultConfig,- FileLocation(..),- readSettings,- ParseException,- saveSettings,- setSetting,- getSetting') where+ -- $intro+ Conf,+ DefaultConfig(..),+ Setting(..),+ GetSetting(..),+ setting,+ getDefaultConfig,+ emptyDefaultConfig,+ FileLocation(..),+ readSettings,+ ParseException,+ saveSettings,+ setSetting,+ getSetting') where import System.Directory import qualified Data.Map as M@@ -29,7 +29,7 @@ -- for the tests... instance Show GetSetting where- show _ = "GetSetting"+ show _ = "GetSetting" -- | Information about the default configuration. Contains -- all the settings (that you declare using 'getDefaultConfig')@@ -68,15 +68,15 @@ -- | Where to look for or store the configuration file. data FileLocation = AutoFromAppName String- -- ^ Automatically build the location based on the- -- application name. It will be ~\/.\<app name\>\/config.ini.- | Path FilePath- -- ^ Absolute path to a location on disk.+ -- ^ Automatically build the location based on the+ -- application name. It will be ~\/.\<app name\>\/config.ini.+ | Path FilePath+ -- ^ Absolute path to a location on disk. getPathForLocation :: FileLocation -> IO FilePath getPathForLocation location = case location of- AutoFromAppName appName -> getConfigFileName appName- Path path -> return path+ AutoFromAppName appName -> getConfigFileName appName+ Path path -> return path -- | Read settings from disk. -- Because it is doing file I/O it is smart to wrap the call@@ -105,26 +105,26 @@ -- @ -- readResult <- try $ readSettings (Path \"my.config\") -- case readResult of--- Right (conf, GetSetting getSetting) -> do--- let textSize = getSetting fontSize--- saveSettings emptyDefaultConfig (Path \"my.config\") conf--- Left (x :: SomeException) -> error \"Error reading the config file!\"+-- Right (conf, GetSetting getSetting) -> do+-- let textSize = getSetting fontSize+-- saveSettings emptyDefaultConfig (Path \"my.config\") conf+-- Left (x :: SomeException) -> error \"Error reading the config file!\" -- @ readSettings :: FileLocation -> IO (Conf, GetSetting) readSettings location = do- filePath <- getPathForLocation location- exists <- doesFileExist filePath- conf <- if exists- then readConfigFile filePath- else return M.empty- return (conf, GetSetting $ getSetting' conf)+ filePath <- getPathForLocation location+ exists <- doesFileExist filePath+ conf <- if exists+ then readConfigFile filePath+ else return M.empty+ return (conf, GetSetting $ getSetting' conf) -- | It is advised to run the save within a try call -- because it does disk I/O, otherwise the call is straightforward. saveSettings :: DefaultConfig -> FileLocation -> Conf -> IO () saveSettings (DefaultConfig defaults) location conf = do- filePath <- getPathForLocation location- writeConfigFile filePath (conf `M.union` defaults)+ filePath <- getPathForLocation location+ writeConfigFile filePath (conf `M.union` defaults) -- | Change the value of a setting. You'll have to call -- 'saveSettings' so that the change is written to disk.@@ -132,25 +132,25 @@ setSetting conf (Setting key _) v = M.insert key SettingInfo { value = show v, userSet=True } conf -- an empty list for the XX list key is written as XX= in the config file. setSetting conf (ListSetting key _) [] = M.insert key SettingInfo { value = "", userSet= True}- $ cleanListSetting key conf+ $ cleanListSetting key conf setSetting conf (ListSetting key _) elts = addListSettings True key elts 1- $ cleanListSetting key conf+ $ cleanListSetting key conf addListSettings :: Show b => Bool -> String -> [b] -> Int -> Conf -> Conf addListSettings _ _ [] _ = id addListSettings uset key (x:xs) index = M.insert keyForIndex SettingInfo { value = show x, userSet=uset }- . addListSettings uset key xs (index+1)- where keyForIndex = key ++ "_" ++ show index+ . addListSettings uset key xs (index+1)+ where keyForIndex = key ++ "_" ++ show index cleanListSetting :: String -> Conf -> Conf cleanListSetting key = M.filterWithKey (\k _ -> not $ isKeyForListSetting key k) getSettingsFolder :: String -> IO FilePath getSettingsFolder appName = do- home <- getHomeDirectory- let result = home ++ "/." ++ appName ++ "/"- createDirectoryIfMissing False result- return result+ home <- getHomeDirectory+ let result = home ++ "/." ++ appName ++ "/"+ createDirectoryIfMissing False result+ return result getConfigFileName :: String -> IO String getConfigFileName appName = (++"config.ini") <$> getSettingsFolder appName@@ -161,7 +161,7 @@ -- This library deals with read-write application settings. -- You will have to specify the settings that your application -- uses, their name, types and default values.--- Setting types must implement the 'Read' and 'Show' typeclasses. +-- Setting types must implement the 'Read' and 'Show' typeclasses. -- -- The settings are saved in a file in an INI-like key-value format -- (without sections).@@ -175,10 +175,10 @@ -- -- > fontSize :: Setting Double -- > fontSize = Setting "fontSize" 14--- > +-- > -- > dateFormat :: Setting String -- > dateFormat = Setting "dateFormat" "%x"--- > +-- > -- > backgroundColor :: Setting (Int, Int, Int) -- > backgroundColor = Setting "backcolor" (255, 0, 0) --@@ -249,13 +249,13 @@ -- -- > readResult <- try $ readSettings (AutoFromAppName "test") -- > case readResult of--- > Right (conf, GetSetting getSetting) -> do--- > let textSize = getSetting fontSize--- > saveSettings emptyDefaultConfig (AutoFromAppName "test") conf--- > Left (x :: SomeException) -> error "Error reading the config file!"+-- > Right (conf, GetSetting getSetting) -> do+-- > let textSize = getSetting fontSize+-- > saveSettings emptyDefaultConfig (AutoFromAppName "test") conf+-- > Left (x :: SomeException) -> error "Error reading the config file!" -- -- 'AutoFromAppName' specifies where to save the configuration file.--- And we've already covered the getSetting in this snippet, see +-- And we've already covered the getSetting in this snippet, see -- the 'readSettings' documentation for further information.--- +-- -- You can also look at the tests of the library on the github project for sample use.
Data/AppSettingsInternal.hs view
@@ -54,13 +54,13 @@ -- -- > testList= data Setting a where- Setting :: String -> a -> Setting a+ Setting :: String -> a -> Setting a - ListSetting :: (Read a, Show a) => String -> [a] -> Setting [a]+ ListSetting :: (Read a, Show a) => String -> [a] -> Setting [a] isKeyForListSetting :: String -> String -> Bool isKeyForListSetting settingKey key = (settingKey ++ "_") `isPrefixOf` key- && all isDigit (drop (length settingKey+1) key)+ && all isDigit (drop (length settingKey+1) key) -- TODO maybe another getSetting that'll tell you@@ -74,19 +74,19 @@ getSetting' :: (Read a) => Conf -> Setting a -> a getSetting' conf (Setting key defaultV) = fromMaybe defaultV $ getSettingValueFromConf conf key getSetting' conf (ListSetting key defaultV) = case getSettingValueFromConf conf $ key ++ "_1" of- -- an empty list for the XX list key is written as XX= in the config file.- Nothing -> case M.lookup key conf of- Nothing -> defaultV- _ -> []- Just x -> x : decodeListSetting conf key 2+ -- an empty list for the XX list key is written as XX= in the config file.+ Nothing -> case M.lookup key conf of+ Nothing -> defaultV+ _ -> []+ Just x -> x : decodeListSetting conf key 2 getSettingValueFromConf :: Read a => Conf -> String -> Maybe a getSettingValueFromConf conf key = do- asString <- M.lookup key conf- readMaybe $ value asString+ asString <- M.lookup key conf+ readMaybe $ value asString decodeListSetting :: Read a => Conf -> String -> Int -> [a] decodeListSetting conf key index = case getSettingValueFromConf conf fullKey of- Nothing -> []- Just v -> v:decodeListSetting conf key (index+1)- where fullKey = key ++ "_" ++ show index+ Nothing -> []+ Just v -> v:decodeListSetting conf key (index+1)+ where fullKey = key ++ "_" ++ show index
Data/Serialization.hs view
@@ -1,11 +1,11 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# OPTIONS_GHC -fno-warn-unused-do-bind #-} module Data.Serialization (- Conf,- SettingInfo(..),- readConfigFile,- writeConfigFile,- ParseException) where+ Conf,+ SettingInfo(..),+ readConfigFile,+ writeConfigFile,+ ParseException) where import System.IO import qualified Data.Text.IO as T@@ -26,19 +26,18 @@ -- | The configuration file is in an invalid format. data ParseException = ParseException FilePath String- deriving (Show, Typeable)+ deriving (Show, Typeable) instance Exception ParseException readConfigFile :: FilePath -> IO Conf readConfigFile path = do- contents <- T.readFile path- case parse parseConfigFile "" contents of- Left pe -> throwIO (ParseException path- $ "Invalid configuration file " ++ show (errorPos pe))- Right v -> return v+ contents <- T.readFile path+ case parse parseConfigFile "" contents of+ Left pe -> throwIO (ParseException path+ $ "Invalid configuration file " ++ show (errorPos pe))+ Right v -> return v -data ConfigElement = ConfigEntry String String- | Comment+data ConfigElement = ConfigEntry String String | Comment isConfigEntry :: ConfigElement -> Bool isConfigEntry (ConfigEntry _ _) = True@@ -46,65 +45,65 @@ parseConfigFile :: T.GenParser st Conf parseConfigFile = do- elements <- many $ comment <|> configEntry <|> emptyLine- let configEntries = filter isConfigEntry elements- return $ M.fromList $ map (\(ConfigEntry a b) ->- (a, SettingInfo {value=b, userSet=True})) configEntries+ elements <- many $ comment <|> configEntry <|> emptyLine+ let configEntries = filter isConfigEntry elements+ return $ M.fromList $ map (\(ConfigEntry a b) ->+ (a, SettingInfo {value=b, userSet=True})) configEntries comment :: T.GenParser st ConfigElement comment = char '#' >> finishLine >> return Comment configEntry :: T.GenParser st ConfigElement configEntry = do- key <- many1 $ noneOf " \t=\r\n"- char '='- val <- finishLine- -- so now we finished the parsing of the classical- -- key=value, however we support a little bit more,- -- you can do something like that:- -- key=[1,2,- -- 3,4,- -- 5, 6]- -- In that case the value will be- -- "[1,2,3,4,5, 6]"- -- => we can continue a setting on the next- -- line if that lines starts with a leading space.- blank <- optionMaybe $ string " "- fullVal <- if isNothing blank- then return val- else do- firstExtraLine <- finishLine- rest <- concat <$> many (string " " >> finishLine)- return $ val ++ firstExtraLine ++ rest- return $ ConfigEntry key fullVal+ key <- many1 $ noneOf " \t=\r\n"+ char '='+ val <- finishLine+ -- so now we finished the parsing of the classical+ -- key=value, however we support a little bit more,+ -- you can do something like that:+ -- key=[1,2,+ -- 3,4,+ -- 5, 6]+ -- In that case the value will be+ -- "[1,2,3,4,5, 6]"+ -- => we can continue a setting on the next+ -- line if that lines starts with a leading space.+ blank <- optionMaybe $ string " "+ fullVal <- if isNothing blank+ then return val+ else do+ firstExtraLine <- finishLine+ rest <- concat <$> many (string " " >> finishLine)+ return $ val ++ firstExtraLine ++ rest+ return $ ConfigEntry key fullVal finishLine :: T.GenParser st String finishLine = do- result <- many $ noneOf "\r\n"- many1 $ oneOf "\r\n"- return result+ result <- many $ noneOf "\r\n"+ many1 $ oneOf "\r\n"+ return result emptyLine :: T.GenParser st ConfigElement emptyLine = do- many1 $ oneOf "\r\n"- return Comment+ many1 $ oneOf "\r\n"+ return Comment writeConfigFile :: FilePath -> Conf -> IO () writeConfigFile path config = do- whenM (doesFileExist path) $- copyFile path $ path ++ ".bak"- withFile path WriteMode $ \handle -> do- hPutStrLn handle "# This file is autogenerated. You can change, comment and uncomment settings but text comments you may add will be lost."- mapM_ (uncurry $ writeConfigEntry handle) $ M.toList config- where whenM s r = s >>= flip when r+ whenM (doesFileExist path) $+ copyFile path $ path ++ ".bak"+ withFile path WriteMode $ \handle -> do+ hPutStrLn handle "# This file is autogenerated. You can change, comment and uncomment settings but text comments you may add will be lost."+ mapM_ (uncurry $ writeConfigEntry handle) $ M.toList config+ where whenM s r = s >>= flip when r writeConfigEntry :: Handle -> String -> SettingInfo -> IO () writeConfigEntry handle key (SettingInfo sValue sUserSet) = do- unless sUserSet $ hPutStr handle "# "- hPutStrLn handle $ key ++ "=" ++ (wrap sValue)+ unless sUserSet $ hPutStr handle "# "+ hPutStrLn handle $ key ++ "=" ++ wrap sValue wrap :: String -> String wrap str = if null rest- then str- else first ++ "\n " ++ wrap rest- where (first, rest) = splitAt 80 str+ then str+ else first ++ "\n " ++ wrap rest+ where (first, rest) = splitAt 80 str
app-settings.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: app-settings-version: 0.2.0.5+version: 0.2.0.6 synopsis: A library to manage application settings (INI file-like) description: A library to deal with application settings.@@ -128,8 +128,8 @@ main-is: Tests.hs default-language: Haskell2010 build-depends: base,- hspec >= 1.8 && <1.11,- HUnit >= 1.2 && <1.3,+ hspec,+ HUnit >= 1.2 && <1.4, mtl >= 2.1 && <2.3, containers == 0.5.*, directory == 1.2.*,
tests/Tests.hs view
@@ -26,180 +26,180 @@ defaultConfig :: DefaultConfig defaultConfig = getDefaultConfig $ do- setting textSizeFromWidth- setting textSizeFromHeight- setting textFill- setting testInlineList- setting testList+ setting textSizeFromWidth+ setting textSizeFromHeight+ setting textFill+ setting testInlineList+ setting testList main :: IO () main = hspec $ do- describe "unit tests" testIsKeyForListSetting- describe "load config" $ do- testEmptyFileDefaults- testPartialFileDefaults- testPartialFileDefaults2- testFileWithComments- testInvalidFile- testInvalidValue- testNonExistingFile- testReadLongSetting- describe "save config" $ do- testSaveUserSetAndDefaults- createBakBeforeSaving- wrapLongSettings- describe "set setting" testSetListSetting+ describe "unit tests" testIsKeyForListSetting+ describe "load config" $ do+ testEmptyFileDefaults+ testPartialFileDefaults+ testPartialFileDefaults2+ testFileWithComments+ testInvalidFile+ testInvalidValue+ testNonExistingFile+ testReadLongSetting+ describe "save config" $ do+ testSaveUserSetAndDefaults+ createBakBeforeSaving+ wrapLongSettings+ describe "set setting" testSetListSetting testEmptyFileDefaults :: Spec testEmptyFileDefaults = it "parses correctly an empty file with defaults" $ do readResult <- try $ readSettings (Path "tests/empty.config") case readResult of- Right (_, GetSetting getSetting) -> do- getSetting textSizeFromWidth `shouldBe` 0.04- getSetting textSizeFromHeight `shouldBe` 12.4- getSetting textFill `shouldBe` (1,1,0,1)- getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]- getSetting testList `shouldBe` ["list1", "list2", "list3"]- Left (x :: SomeException) -> assertBool (show x) False+ Right (_, GetSetting getSetting) -> do+ getSetting textSizeFromWidth `shouldBe` 0.04+ getSetting textSizeFromHeight `shouldBe` 12.4+ getSetting textFill `shouldBe` (1,1,0,1)+ getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]+ getSetting testList `shouldBe` ["list1", "list2", "list3"]+ Left (x :: SomeException) -> assertBool (show x) False testPartialFileDefaults :: Spec testPartialFileDefaults = it "parses correctly a partial file with defaults" $ do readResult <- try $ readSettings (Path "tests/partial.config") case readResult of- Right (_, GetSetting getSetting) -> do- getSetting textSizeFromWidth `shouldBe` 1.02- getSetting textSizeFromHeight `shouldBe` 12.4- getSetting textFill `shouldBe` (1,2,3,4)- getSetting testInlineList `shouldBe` ["un", "deux"]- getSetting testList `shouldBe` ["one", "two"]- Left (x :: SomeException) -> assertBool (show x) False+ Right (_, GetSetting getSetting) -> do+ getSetting textSizeFromWidth `shouldBe` 1.02+ getSetting textSizeFromHeight `shouldBe` 12.4+ getSetting textFill `shouldBe` (1,2,3,4)+ getSetting testInlineList `shouldBe` ["un", "deux"]+ getSetting testList `shouldBe` ["one", "two"]+ Left (x :: SomeException) -> assertBool (show x) False testPartialFileDefaults2 :: Spec testPartialFileDefaults2 = it "parses correctly a partial2 file with defaults" $ do readResult <- try $ readSettings (Path "tests/partial2.config") case readResult of- Right (_, GetSetting getSetting) -> do- getSetting textSizeFromWidth `shouldBe` 1.02- getSetting textSizeFromHeight `shouldBe` 12.4- getSetting textFill `shouldBe` (1,2,3,4)- getSetting testInlineList `shouldBe` ["un", "deux"]- getSetting testList `shouldBe` []- Left (x :: SomeException) -> assertBool (show x) False+ Right (_, GetSetting getSetting) -> do+ getSetting textSizeFromWidth `shouldBe` 1.02+ getSetting textSizeFromHeight `shouldBe` 12.4+ getSetting textFill `shouldBe` (1,2,3,4)+ getSetting testInlineList `shouldBe` ["un", "deux"]+ getSetting testList `shouldBe` []+ Left (x :: SomeException) -> assertBool (show x) False testFileWithComments :: Spec testFileWithComments = it "parses correctly a partial file with comments" $ do readResult <- try $ readSettings (Path "tests/test-save.txt") case readResult of- Right (_, GetSetting getSetting) -> do- getSetting textSizeFromWidth `shouldBe` 1.02- getSetting textSizeFromHeight `shouldBe` 12.4- getSetting textFill `shouldBe` (1,2,3,4)- getSetting testInlineList `shouldBe` ["un", "deux"]- getSetting testList `shouldBe` ["one", "two"]- Left (x :: SomeException) -> assertBool (show x) False+ Right (_, GetSetting getSetting) -> do+ getSetting textSizeFromWidth `shouldBe` 1.02+ getSetting textSizeFromHeight `shouldBe` 12.4+ getSetting textFill `shouldBe` (1,2,3,4)+ getSetting testInlineList `shouldBe` ["un", "deux"]+ getSetting testList `shouldBe` ["one", "two"]+ Left (x :: SomeException) -> assertBool (show x) False testInvalidValue :: Spec testInvalidValue = it "parses correctly a file with invalid values" $ do readResult <- try $ readSettings (Path "tests/brokenvalue.config") case readResult of- Right (_, GetSetting getSetting) -> do- -- give the default for the invalid value- getSetting textSizeFromWidth `shouldBe` 0.04- getSetting textSizeFromHeight `shouldBe` 12.4- getSetting textFill `shouldBe` (1,2,3,4)- getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]- getSetting testList `shouldBe` ["list1", "list2", "list3"]- Left (x :: SomeException) -> assertBool (show x) False+ Right (_, GetSetting getSetting) -> do+ -- give the default for the invalid value+ getSetting textSizeFromWidth `shouldBe` 0.04+ getSetting textSizeFromHeight `shouldBe` 12.4+ getSetting textFill `shouldBe` (1,2,3,4)+ getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]+ getSetting testList `shouldBe` ["list1", "list2", "list3"]+ Left (x :: SomeException) -> assertBool (show x) False testNonExistingFile :: Spec testNonExistingFile = it "returns empty config for a non-existing file" $ do- readResult <- try $ readSettings (Path "tests/dontexist.conf")- case readResult of- Right (_, GetSetting getSetting) -> do- getSetting textSizeFromWidth `shouldBe` 0.04- getSetting textSizeFromHeight `shouldBe` 12.4- getSetting textFill `shouldBe` (1,1,0,1)- getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]- getSetting testList `shouldBe` ["list1", "list2", "list3"]- Left (x :: SomeException) -> assertBool (show x) False+ readResult <- try $ readSettings (Path "tests/dontexist.conf")+ case readResult of+ Right (_, GetSetting getSetting) -> do+ getSetting textSizeFromWidth `shouldBe` 0.04+ getSetting textSizeFromHeight `shouldBe` 12.4+ getSetting textFill `shouldBe` (1,1,0,1)+ getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]+ getSetting testList `shouldBe` ["list1", "list2", "list3"]+ Left (x :: SomeException) -> assertBool (show x) False testReadLongSetting :: Spec testReadLongSetting = it "Reads setting files with setting values wrapped over several lines" $ do- readResult <- try $ readSettings (Path "tests/longsetting.conf") - case readResult of - Right (_, GetSetting getVal) -> do- let expected = replicate 20 "long string"- let actual = getVal testInlineList- assertEqual "doesn't match" expected actual- Left (x :: SomeException) -> assertBool (show x) False+ readResult <- try $ readSettings (Path "tests/longsetting.conf")+ case readResult of+ Right (_, GetSetting getVal) -> do+ let expected = replicate 20 "long string"+ let actual = getVal testInlineList+ assertEqual "doesn't match" expected actual+ Left (x :: SomeException) -> assertBool (show x) False testInvalidFile :: Spec testInvalidFile = it "reports errors properly for invalid files" $ do readResult <- try $ readSettings (Path "tests/broken.config") case readResult of- Left (_ :: SomeException) -> assertBool "ok" True- Right _ -> assertBool "did not get an error!" False+ Left (_ :: SomeException) -> assertBool "ok" True+ Right _ -> assertBool "did not get an error!" False testSaveUserSetAndDefaults :: Spec testSaveUserSetAndDefaults = it "saves a file with user-set and default settings" $ do- readResult <- try $ readSettings (Path "tests/partial.config") - case readResult of - Right (conf, _) -> do- saveSettings defaultConfig (Path "test.txt") conf- actual <- readFile "test.txt"- reference <- readFile "tests/test-save.txt"- actual `shouldBe` reference- removeFile "test.txt"- Left (x :: SomeException) -> assertBool (show x) False+ readResult <- try $ readSettings (Path "tests/partial.config")+ case readResult of+ Right (conf, _) -> do+ saveSettings defaultConfig (Path "test.txt") conf+ actual <- readFile "test.txt"+ reference <- readFile "tests/test-save.txt"+ actual `shouldBe` reference+ removeFile "test.txt"+ Left (x :: SomeException) -> assertBool (show x) False createBakBeforeSaving :: Spec createBakBeforeSaving = it "creates a backup of the config file before overwriting it" $ do- readResult <- try $ readSettings (Path "tests/partial.config") - case readResult of - Right (conf, _) -> do- copyFile "tests/partial.config" "p.config"- saveSettings defaultConfig (Path "p.config") conf- doesFileExist "p.config.bak" >>= flip shouldBe True- doesFileExist "p.config" >>= flip shouldBe True- removeFile "p.config"- removeFile "p.config.bak"- Left (x :: SomeException) -> assertBool (show x) False+ readResult <- try $ readSettings (Path "tests/partial.config")+ case readResult of+ Right (conf, _) -> do+ copyFile "tests/partial.config" "p.config"+ saveSettings defaultConfig (Path "p.config") conf+ doesFileExist "p.config.bak" >>= flip shouldBe True+ doesFileExist "p.config" >>= flip shouldBe True+ removeFile "p.config"+ removeFile "p.config.bak"+ Left (x :: SomeException) -> assertBool (show x) False wrapLongSettings :: Spec wrapLongSettings = it "wraps long settings when saving" $ do- readResult <- try $ readSettings (Path "tests/partial.config") - case readResult of - Right (conf, _) -> do- let conf1 = setSetting conf testInlineList $ replicate 20 "long string"- saveSettings defaultConfig (Path "xx.config") conf1- expected <- readFile "tests/longsetting.conf"- actual <- readFile "xx.config"- assertEqual "doesn't match" expected actual- removeFile "xx.config"- Left (x :: SomeException) -> assertBool (show x) False- + readResult <- try $ readSettings (Path "tests/partial.config")+ case readResult of+ Right (conf, _) -> do+ let conf1 = setSetting conf testInlineList $ replicate 20 "long string"+ saveSettings defaultConfig (Path "xx.config") conf1+ expected <- readFile "tests/longsetting.conf"+ actual <- readFile "xx.config"+ assertEqual "doesn't match" expected actual+ removeFile "xx.config"+ Left (x :: SomeException) -> assertBool (show x) False + testSetListSetting :: Spec testSetListSetting = it "overwrites correctly a list setting" $ do readResult <- try $ readSettings (Path "tests/empty.config") case readResult of- Right (conf, GetSetting getSetting) -> do- getSetting testList `shouldBe` ["list1", "list2", "list3"]- getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]- let conf0 = setSetting conf testList ["un"]- let conf1 = setSetting conf0 testInlineList ["one"]- getSetting' conf1 testList `shouldBe` ["un"]- getSetting' conf1 testInlineList `shouldBe` ["one"]- let conf2 = setSetting conf1 testList []- let conf3 = setSetting conf2 testInlineList []- getSetting' conf3 testList `shouldBe` []- getSetting' conf3 testInlineList `shouldBe` []- Left (x :: SomeException) -> assertBool (show x) False+ Right (conf, GetSetting getSetting) -> do+ getSetting testList `shouldBe` ["list1", "list2", "list3"]+ getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]+ let conf0 = setSetting conf testList ["un"]+ let conf1 = setSetting conf0 testInlineList ["one"]+ getSetting' conf1 testList `shouldBe` ["un"]+ getSetting' conf1 testInlineList `shouldBe` ["one"]+ let conf2 = setSetting conf1 testList []+ let conf3 = setSetting conf2 testInlineList []+ getSetting' conf3 testList `shouldBe` []+ getSetting' conf3 testInlineList `shouldBe` []+ Left (x :: SomeException) -> assertBool (show x) False testIsKeyForListSetting :: Spec testIsKeyForListSetting = it "checks correctly whether a key is attached to a list setting" $ do- isKeyForListSetting "listTest" "listTest_1" `shouldBe` True- isKeyForListSetting "listTest" "listTest_13" `shouldBe` True- isKeyForListSetting "listTest" "listTest_unrelated" `shouldBe` False- isKeyForListSetting "listTest" "listTest_1notanumber" `shouldBe` False- isKeyForListSetting "listTest" "listTestX_1" `shouldBe` False+ isKeyForListSetting "listTest" "listTest_1" `shouldBe` True+ isKeyForListSetting "listTest" "listTest_13" `shouldBe` True+ isKeyForListSetting "listTest" "listTest_unrelated" `shouldBe` False+ isKeyForListSetting "listTest" "listTest_1notanumber" `shouldBe` False+ isKeyForListSetting "listTest" "listTestX_1" `shouldBe` False