content: module System.HapistranoPropsSpec
    ( spec
    ) where
  
  import           Data.Char                           (isSpace)
  import           System.Hapistrano.Commands.Internal (mkGenericCommand,
                                                        quoteCmd, trim,
                                                        unGenericCommand)
  import           Test.Hspec                          hiding (shouldBe,
                                                        shouldReturn)
  import           Test.QuickCheck
  
  spec :: Spec
  spec =
    describe "QuickCheck" $
    context "Properties" $ do
      it "property of quote command" $ property propQuote'
      it "property of trimming a command" $
        property $ forAll trimGenerator propTrim'
      it "property of mkGenericCommand and unGenericCommand" $
        property $ forAll genericCmdGenerator propGenericCmd'
  
  -- Is quoted determine
  isQuoted :: String -> Bool
  isQuoted str = head str == '"' && last str == '"'
  
  -- | Quote function property
  propQuote :: String -> Bool
  propQuote str =
    if any isSpace str
      then isQuoted $ quoteCmd str
      else quoteCmd str == str
  
  propQuote' :: String -> Property
  propQuote' str =
    classify (any isSpace str) "has at least a space" $ propQuote str
  
  -- | Is trimmed
  isTrimmed' :: String -> Bool
  isTrimmed' [] = True
  isTrimmed' [x] = not $ isSpace x
  isTrimmed' str =
    let a = not . isSpace $ head str
        b = not . isSpace $ last str
     in a && b
  
  -- | Prop trimm
  propTrim :: String -> Bool
  propTrim = isTrimmed' . trim
  
  propTrim' :: String -> Property
  propTrim' str =
    classify (not $ isTrimmed' str) "non trimmed strings" $ propTrim str
  
  -- | Check that the string is perfect command String
  isCmdString :: String -> Bool
  isCmdString str = all ($str) [not . null, notElem '#', notElem '\n', isTrimmed']
  
  -- | Prop Generic Command
  -- If the string does not contain # or \n, is trimmed and non null, the command should be created
  propGenericCmd :: String -> Bool
  propGenericCmd str =
    if isCmdString str
      then maybe False ((== str) . unGenericCommand) (mkGenericCommand str)
      else maybe True ((/= str) . unGenericCommand) (mkGenericCommand str) -- Either the command cannot be created or the command str is different to the original
  
  propGenericCmd' :: String -> Property
  propGenericCmd' str =
    classify (isCmdString str) "perfect command string" propGenericCmd
  
  -- | Trim String Generator
  trimGenerator :: Gen String
  trimGenerator =
    let strGen = listOf arbitraryUnicodeChar
     in frequency
          [ (1, suchThat strGen isTrimmed')
          , (1, suchThat strGen (not . isTrimmed'))
          ]
  
  -- | Generic Command generator
  genericCmdGenerator :: Gen String
  genericCmdGenerator =
    let strGen = listOf $ elements $ ['A'..'Z'] ++ ['a'..'z'] ++ [' ', '#', '*', '/', '.']
     in frequency
          [(1, suchThat strGen isCmdString), (1, suchThat strGen (elem '#'))]
  