packages feed

greskell-core-0.1.0.0: test/Data/Greskell/GreskellSpec.hs

{-# LANGUAGE OverloadedStrings #-}
module Data.Greskell.GreskellSpec (main,spec) where

import qualified Data.Aeson as Aeson
import Data.String (fromString)
import Data.Text (Text, pack)
import Test.Hspec
import Test.QuickCheck (property)

import Data.Greskell.Greskell
  ( unsafeGreskell, toGremlin,
    unsafeFunCall,
    string, list, true, false, number, value,
    Greskell
  )

import Data.Greskell.Test.QuickCheck ()

main :: IO ()
main = hspec spec

spec :: Spec
spec = do
  spec_literals
  spec_other

spec_other :: Spec
spec_other = do
  describe "unsafeGreskell" $ it "should be just a raw script text" $ property $ \t ->
    (toGremlin $ unsafeGreskell t) `shouldBe` t
  describe "Num" $ do
    specify "integer" $ do
      let x = 123 :: Greskell Int
      toGremlin x `shouldBe` "123"
    specify "negative integer" $ do
      let x = -56 :: Greskell Int
      toGremlin x `shouldBe` "-(56)"
    specify "operations" $ do
      let x = (30 + 15 * 20 - 10) :: Greskell Int
      toGremlin x `shouldBe` "((30)+((15)*(20)))-(10)"
    specify "abs, signum" $ do
      let x = (signum $ abs (-100)) :: Greskell Int
      toGremlin x  `shouldBe` "java.lang.Long.signum(java.lang.Math.abs(-(100)))"
  describe "Fractional" $ do
    specify "floating point literal" $ do
      let x = 92.12 :: Greskell Double
      (toGremlin x) `shouldBe` "2303.0/25"
    specify "operations" $ do
      let x = (100.5 * recip 30.0 / 20.2) :: Greskell Double
      toGremlin x `shouldBe` "((201.0/2)*(1.0/(30.0/1)))/(101.0/5)"
  describe "Monoid" $ do
    specify "mempty" $ do
      let got = mempty :: Greskell Text
      toGremlin got `shouldBe` "\"\""
    specify "mappend" $ do
      let got = (mappend "foo" "bar") :: Greskell Text
      toGremlin got `shouldBe` "(\"foo\")+(\"bar\")"
  describe "unsafeFunCall" $ do
    it "should make function call" $ do
      (toGremlin $ unsafeFunCall "fun" ["foo", "bar"]) `shouldBe` "fun(foo,bar)"

spec_literals :: Spec
spec_literals = do
  describe "string and fromString" $ do
    specify "empty" $ checkStringLiteral "" "\"\""
    specify "words" $ checkStringLiteral "hoge foo bar"  "\"hoge foo bar\""
    specify "escaped" $ checkStringLiteral "foo 'aaa \n \t \\ \"bar\"" "\"foo 'aaa \\n \\t \\\\ \\\"bar\\\"\""
  describe "list" $ do
    specify "empty" $ do
      toGremlin (list []) `shouldBe` "[]"
    specify "num" $ do
      toGremlin (list $ [(10 :: Greskell Int), 20, 30]) `shouldBe` "[10,20,30]"
    specify "list of lists" $ do
      toGremlin (list $ map list $ [[("" :: Greskell Text)], ["foo", "bar"], ["buzz"]])
        `shouldBe` "[[\"\"],[\"foo\",\"bar\"],[\"buzz\"]]"
  describe "boolean" $ do
    specify "true" $ do
      toGremlin true `shouldBe` "true"
    specify "false" $ do
      toGremlin false `shouldBe` "false"
  describe "number" $ do
    specify "zero" $ do
      toGremlin (number 0) `shouldBe` "0.0"
    specify "positive integer" $ do
      toGremlin (number 1234) `shouldBe` "1234.0"
    specify "negative integer" $ do
      toGremlin (number (-292)) `shouldBe` "-292.0"
    specify "positive floating" $ do
      toGremlin (number 32.123) `shouldBe` "32.123"
    specify "negative floating" $ do
      toGremlin (number (-0.0943)) `shouldBe` "-9.43e-2"
    specify "big positive integer" $ do
      toGremlin (number 3.23e9) `shouldBe` "3.23e9"
  describe "value" $ do
    specify "null" $ do
      toGremlin (value Aeson.Null) `shouldBe` "null"
    specify "bool" $ do
      toGremlin (value $ Aeson.Bool False) `shouldBe` "false"
    specify "integer" $ do
      toGremlin (value $ Aeson.Number 100) `shouldBe` "100.0"
    specify "floating-point number" $ do
      toGremlin (value $ Aeson.Number 10.23) `shouldBe` "10.23"
    specify "String" $ do
      toGremlin (value $ Aeson.String "foobar") `shouldBe` "\"foobar\""
    specify "empty Array" $ do
      toGremlin (value $ Aeson.toJSON ([] :: [Int])) `shouldBe` "[]"
    specify "non-empty Array" $ do
      toGremlin (value $ Aeson.toJSON [(5 :: Int), 6, 7]) `shouldBe` "[5.0,6.0,7.0]"
    specify "empty Object" $ do
      toGremlin (value $ Aeson.object []) `shouldBe` "[:]"
  

checkStringLiteral :: String -> Text -> Expectation
checkStringLiteral input expected = do
  let input' = fromString input :: Greskell Text
  (toGremlin $ input') `shouldBe` expected
  (toGremlin $ string $ pack input) `shouldBe` expected