{-# LANGUAGE OverloadedLists #-}
module Parser.ExprSpec (spec) where

import           Test.Hspec
import           Test.Hspec.Megaparsec
import           Text.Megaparsec

import           Puppet.Parser
import           Puppet.Parser.Internal
import           XPrelude

expressions :: [(Text, Expression)]
expressions =
    [ ("5 + 3 * 2", 5 + 3 * 2)
    , ("5+2 == 7", Equal (5 + 2) 7)
    , ("include(foo::bar)",  Terminal (UFunctionCall "include" ["foo::bar"] ))
    , ("fail(('foo'))",  Terminal (UFunctionCall "fail" ["foo"] ))
    , ("test(foo,bar)",  Terminal (UFunctionCall "test" ["foo", "bar"] ))
    , ("extlib::test()",  Terminal (UFunctionCall "extlib::test" [] ))
    , ("extlib::test(fail('foo'))",  Terminal (UFunctionCall "extlib::test" [Terminal (UFunctionCall "fail" [Terminal (UString "foo")])]))
    , ("test(extlib::test())",  Terminal (UFunctionCall "test" [Terminal (UFunctionCall "extlib::test" [])] ))
    , ("test ( foo , bar )",  Terminal (UFunctionCall "test" ["foo", "bar"] ))
    , ("$y ? {\
     \ undef   => 'undef',\
     \ default => 'default',\
    \ }",  ConditionalValue (Terminal (UVariableReference "y"))
           [ SelectorValue UUndef :!: Terminal (UString "undef")
           , SelectorDefault :!: Terminal (UString "default")])
    , ("$x", Terminal (UVariableReference "x"))
    , ("x($y)", Terminal (UFunctionCall "x" [ Terminal (UVariableReference "y") ]))
    , ("\"$\"", Terminal (UInterpolable [Terminal (UString "$")]))
    , ("\"${x}\"", Terminal (UInterpolable [Terminal (UVariableReference "x")]))
    , ("$x[ 3 ]",  Lookup (Terminal (UVariableReference "x")) (Terminal (UNumber 3)))
    , ("\"${ os[ 'architecture' ]}\"", Terminal (UInterpolable [Lookup (Terminal (UVariableReference "os")) (Terminal (UString "architecture"))]))
    , ("\"${facts['os']['architecture']}\"", Terminal (UInterpolable [Lookup (Lookup (Terminal (UVariableReference "facts")) (Terminal (UString "os"))) (Terminal (UString "architecture"))]))
    , ("\"${x[$y]}\"", Terminal (UInterpolable [Lookup (Terminal (UVariableReference "x")) (Terminal (UVariableReference "y")) ]))
    , ("\"${x($y)}\"", Terminal (UInterpolable [ Terminal (UFunctionCall "x" [ Terminal (UVariableReference "y") ] ) ] ))
    , ("\"${x($y)}$'\"", Terminal (UInterpolable [ Terminal (UFunctionCall "x" [ Terminal (UVariableReference "y") ])
                                                 , Terminal (UString "$"),Terminal (UString "'")]))
    ]

invalid :: [Text]
invalid = [ "$os['name]"
          -- pending
          -- , "$os ['name']"
           -- interpolation
          , "\"${os['name]}\""
          , "\"${os[name}\""
          , "\"${os[name]\""
          ]

testExpression (t,e) = it ("should parse " <> toS t) $ parse (expression <* eof) "" t `shouldParse` e

testInvalid s = it ("rejects " <> toS s) $ shouldFailOn (parse (expression <* eof) "") s

spec = do
  describe "Expression parser" $ mapM_ testExpression expressions
  describe "Invalid expression" $ mapM_ testInvalid invalid
