lss-0.1.0.0: spec/Main.hs
{-# LANGUAGE OverloadedStrings #-}
module Main where
import qualified Data.Attoparsec.Text as A
import Data.Either (rights)
import qualified Data.Map as M
import Data.Text (Text)
import qualified Data.Text as T
import qualified Language.Css.Parse as P
import qualified Language.Css.Syntax as C
import Language.Lss
import Test.Hspec
isLeft :: Either a b -> Bool
isLeft (Left _) = True
isLeft _ = False
type TConst = (Text, Text)
type TFunc = ([Text], [TConst], [Text])
buildState :: [(Text, TFunc)] -> [TConst] -> LssState
buildState fs cs = LssState (M.fromList (consts cs)) (M.fromList (funcs fs))
where consts = map (\(i,e) -> let Right expr = A.parseOnly P.exprp e
in (C.Ident (T.unpack i), expr))
funcs = map (\(i, (ps, lcs, b)) -> let params = rights (map (A.parseOnly P.identp) ps)
cs' = M.fromList $ consts lcs
rules = rights (map (A.parseOnly P.rulesetp) b)
in (C.Ident (T.unpack i), LssFunc params cs' rules))
buildApp :: Text -> [Text] -> LssApp
buildApp n as = let Right name = A.parseOnly P.identp n
args = rights (map (A.parseOnly P.exprp) as)
in LssApp name args
unRight :: Either a b -> b
unRight (Right v) = v
unRight _ = error "Expected right"
main :: IO ()
main = hspec $ do
describe "parseDefs" $ do
it "should parse a bare const" $ do
parseDefs "x = #ccc" `shouldBe` (Right (buildState [] [("x", "#ccc")]))
it "should parse two consts" $ do
parseDefs "x = #ccc\n y = 10em" `shouldBe` (Right (buildState [] [ ("x", "#ccc")
, ("y", "10em")]))
it "should parse an argumentless, empty function" $ do
parseDefs "x {}" `shouldBe` (Right (buildState [("x", ([],[],[]))] []))
it "should parse an argumentless, empty function with parens" $ do
parseDefs "x() {}" `shouldBe` (Right (buildState [("x", ([],[],[]))] []))
it "should not parse a function with a space before parens" $ do
parseDefs "x () {}" `shouldSatisfy` isLeft
it "should parse an argumentless empty fuction with some css inside" $ do
parseDefs "x { p { font-size: 1em; } }" `shouldBe`
(Right (buildState [("x", ([],[],["p { font-size: 1em; }"]))] []))
it "should parse local constants within a function" $ do
parseDefs "x { y = 10em }" `shouldBe` (Right (buildState [("x", ([],[("y", "10em")],[]))]
[]))
it "should parse a one argument function" $ do
parseDefs "x(size) {}" `shouldBe`
(Right (buildState [("x", (["size"],[],[]))] []))
it "should parse arguments in a function" $ do
parseDefs "x(size, weight) {}" `shouldBe`
(Right (buildState [("x", (["size", "weight"],[],[]))] []))
describe "parseApp" $ do
it "should parse bare function name" $
parseApp "foo" `shouldBe` (Right (buildApp "foo" []))
it "should parse a function with parens" $
parseApp "foo()" `shouldBe` (Right (buildApp "foo" []))
it "should parse a function with one argument" $
parseApp "foo(#ccc)" `shouldBe` (Right (buildApp "foo" ["#ccc"]))
describe "apply" $ do
it "should produce body of argumentless function" $
apply (unRight $ parseDefs "x { p { font-size: 1em; } }")
(C.Ident "x")
[]
`shouldBe` (Right [unRight $ A.parseOnly P.rulesetp "p { font-size: 1em; }"])
it "should do replacement within function" $
apply (unRight $ parseDefs "x(size) { p { font-size: size; } }")
(C.Ident "x")
[unRight $ A.parseOnly P.exprp "10em"]
`shouldBe` (Right [unRight $ A.parseOnly P.rulesetp "p { font-size: 10em; }"])