{-# LANGUAGE OverloadedStrings #-}
module Main where
import Control.Monad (liftM)
import Data.List as List
import Data.Monoid ((<>))
import Data.Text as Text
import qualified Data.HashMap.Strict as HashMap
import Data.Yaml (Object, Value (Object))
import Test.QuickCheck (Arbitrary (..), Gen, expectFailure, sized)
import Test.QuickCheck.Monadic (monadicIO, run)
import Test.Tasty (defaultMain, testGroup)
import Test.Tasty.QuickCheck (Property, testProperty)
import Data.Yaml.Config.Internal (Config (Config), Key, fullpath, keys, subconfig)
type CorrectPath = [Key]
data DeepObject = DeepObject Config CorrectPath deriving (Eq, Show)
instance Arbitrary Text where
arbitrary = liftM Text.pack arbitrary
instance Arbitrary DeepObject where
arbitrary = deepConfig
newObject :: [(Key, Value)] -> Object
newObject = HashMap.fromList
deepConfig :: Gen DeepObject
deepConfig = sized deepConfig' >>= \(ks, obj) ->
return $ DeepObject (Config [] obj) $ List.tail ks
deepConfig' :: Int -> Gen ([Key], Object)
deepConfig' 0 = arbitrary >>= \newKey -> return ([newKey], newObject [])
deepConfig' n | n > 0 = do
newKey <- arbitrary
(ks, newNode) <- deepConfig' (pred n)
return (newKey : ks, newObject [(List.head ks , Object newNode)])
testCorrectSubconfigPath :: DeepObject -> Bool
testCorrectSubconfigPath (DeepObject _ []) = True
testCorrectSubconfigPath (DeepObject config (key : others)) =
maybe False (`subcheck` others) $ subconfig key config
where
subcheck sc = testCorrectSubconfigPath . DeepObject sc
testWrongSubconfigPath' :: DeepObject -> Property
testWrongSubconfigPath' = expectFailure . monadicIO . run . testWrongSubconfigPath
testWrongSubconfigPath :: DeepObject -> IO Bool
testWrongSubconfigPath (DeepObject config []) = return . List.null $ keys config
testWrongSubconfigPath (DeepObject config (nextKey : others)) =
maybe nextCheck (const $ return False) $ subconfig wrongKey config
where
nextCheck = maybe (return False) (testWrongSubconfigPath . nextDeep) $
subconfig nextKey config
nextDeep = flip DeepObject others
wrongKey = nextKey <> "_"
testCorrectPath :: DeepObject -> Bool
testCorrectPath = testCorrectPath' []
where
testCorrectPath' path (DeepObject config (nextKey : others)) = checkPath config
&& maybe False (`subcheck` others) (subconfig nextKey config)
where
subcheck sc = testCorrectPath' (nextKey : path) . DeepObject sc
checkPath c = fullpath c nextKey ==
Text.intercalate "." (List.reverse $ nextKey : path)
testCorrectPath' _ (DeepObject config []) = List.null $ keys config
main :: IO ()
main = defaultMain $ testGroup "Tests"
[ testProperty "wrongSubconfigPath" testWrongSubconfigPath'
, testProperty "correctSubconfigPath" testCorrectSubconfigPath
, testProperty "correctPath" testCorrectPath
]