{-# LANGUAGE OverloadedStrings #-} module Main where import Control.Monad (liftM) import Data.Monoid ((<>)) import Data.Hashable (Hashable) import Data.Text (Text) import Data.List as List import Data.Text as Text import qualified Data.Text as ST import Test.Tasty (defaultMain, testGroup) import Test.Tasty.QuickCheck (testProperty) import Test.QuickCheck (Gen, Property, Arbitrary(..), elements, sized, oneof, listOf) import Test.QuickCheck.Monadic (assert) import Data.Yaml(Object, Value(Object, Null)) import qualified Data.HashMap.Strict as HashMap import Data.Yaml.Config.Internal (Config(Config), Key, subconfig, keys, fullpath) 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' >>= \(keys, obj) -> return $ DeepObject (Config [] obj) $ List.tail keys deepConfig' :: Int -> Gen ([Key], Object) deepConfig' 0 = arbitrary >>= \newKey -> return $ ([newKey], newObject []) deepConfig' n | n > 0 = do newKey <- arbitrary (keys, newNode) <- deepConfig' (pred n) return $ (newKey : keys, newObject [(List.head keys , Object newNode)]) testCorrectSubconfigPath :: DeepObject -> Bool testCorrectSubconfigPath (DeepObject _ []) = True testCorrectSubconfigPath (DeepObject config (key : others)) = maybe False (`subcheck` others) $ subconfig key config where subcheck sc keys = testCorrectSubconfigPath $ DeepObject sc keys testWrongSubconfigPath :: DeepObject -> Bool testWrongSubconfigPath (DeepObject config []) = List.null $ keys config testWrongSubconfigPath (DeepObject config (nextKey : others)) = maybe nextCheck (const False) $ subconfig wrongKey config where nextCheck = maybe False (testWrongSubconfigPath . nextDeep) $ subconfig nextKey config nextDeep = flip DeepObject others wrongKey = nextKey <> "_" testCorrectPath :: DeepObject -> Bool testCorrectPath = testCorrectPath' [] testCorrectPath' path (DeepObject config (nextKey : others)) = checkPath config && (maybe False (`subcheck` others) $ subconfig nextKey config) where subcheck sc keys = testCorrectPath' (nextKey : path) $ DeepObject sc keys checkPath c = fullpath c nextKey == (ST.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 ]