packages feed

aeson-flowtyped-0.8.1: test/Spec.hs

{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE DeriveGeneric       #-}
{-# LANGUAGE GADTs               #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}
import           Data.Aeson            (Value)
import           Data.Aeson.Flow
import           Data.Functor.Foldable (Fix (..))
import           Data.HashMap.Strict   (HashMap)
import           Data.Proxy            (Proxy (..))
import           Data.Text             (Text)
import           Data.Tree             (Tree)
import           Data.Vector           (Vector)
import           GHC.Generics
import           Test.Tasty
import           Test.Tasty.HUnit

data User = User
  { username  :: Text
  , realname  :: Maybe Text
  , dob       :: Maybe (Int, Int, Int)
  , extraInfo :: Value
  } deriving (Generic)

instance FlowTyped User

data Recur = Recur
  { asdf   :: Int
  , stuff  :: [User]
  , recurs :: [Recur]
  } deriving (Generic)

instance FlowTyped Recur

data Adt2 = A2 | B2 deriving (Generic)
instance FlowTyped Adt2

data Adt3 = A3 | B3 | C3 deriving (Generic)
instance FlowTyped Adt3

data Adt4 = A4 | B4 | C4 | D4 deriving (Generic)
instance FlowTyped Adt4

data Codep = Codep
  { corecurs :: [Recur]
  , cousers  :: [User]
  } deriving (Generic)

instance FlowTyped Codep

data Hmap = Hmap (HashMap Text User)
  deriving (Generic)

instance FlowTyped Hmap

data Poly2 a b = Poly2 a b | Poly2Go (Poly2 a b)
  deriving (Generic)

instance (Typeable a, FlowTyped a, Typeable b, FlowTyped b) =>
         FlowTyped (Poly2 a b) where
  flowTypeVars _ =
    [ typeRep (Var :: Var 0)
    , typeRep (Var :: Var 1)
    ]

main :: IO ()
main = defaultMain $ testGroup "aeson-flowtyped"
  [ testCase "nullable" $
     showFlowType (flowType (Proxy :: Proxy (Maybe Int))) @=?
     showFlowType (Fix (Nullable (Fix (Prim Number))))

  , testCase "array" $ do
     showFlowType (flowType (Proxy :: Proxy [Int])) @=?
       showFlowType (Fix (Array (Fix (Prim Number))))

     showFlowType (flowType (Proxy :: Proxy (Vector Int))) @=?
       showFlowType (Fix (Array (Fix (Prim Number))))

    -- XXX: actually use Eq

  , testCase "User export" $
    "export type User =\n\
    \  {| extraInfo: mixed,\n\
    \     tag: 'User',\n\
    \     realname: ?string,\n\
    \     username: string,\n\
    \     dob: ?[number,number,number] |};" @=?
    exportFlowTypeAs "User" (flowType (Proxy :: Proxy User))

  , testCase "Recursive type export" $
    "export type Recur =\n\
    \  {| tag: 'Recur', stuff: User[], recurs: Recur[], asdf: number |};" @=?
    exportFlowTypeAs "Recur" (flowType (Proxy :: Proxy Recur))

  , testCase "Nullary string tags (2 tags)" $
    "export type Adt2 =\n\
    \  'A2' |\n\
    \  'B2';" @=?
    exportFlowTypeAs "Adt2" (flowType (Proxy :: Proxy Adt2))

  , testCase "Nullary string tags (3 tags)" $
    "export type Adt3 =\n\
    \  'A3' |\n\
    \  'B3' |\n\
    \  'C3';" @=?
    exportFlowTypeAs "Adt3" (flowType (Proxy :: Proxy Adt3))

  , testCase "Nullary string tags (4 tags)" $
    "export type Adt4 =\n\
    \  'A4' |\n\
    \  'B4' |\n\
    \  'C4' |\n\
    \  'D4';" @=?
    exportFlowTypeAs "Adt4" (flowType (Proxy :: Proxy Adt4))

  , testCase "map-style object / hashmap instance" $
    "export type Hmap =\n\
    \  { [key: string]: User };" @=?
    exportFlowTypeAs "Hmap" (flowType (Proxy :: Proxy (HashMap Text User)))

  , testCase "parens around nullable array" $
    "export type T =\n\
    \  ?(string[]);" @=?
    exportFlowTypeAs "T" (flowType (Proxy :: Proxy (Maybe [Text])))

  , testCase "parens around nullable array of nullable elements" $
    "export type T =\n\
    \  ?((?string)[]);" @=?
    exportFlowTypeAs "T" (flowType (Proxy :: Proxy (Maybe [Maybe Text])))

  , testCase "module export" $
    "// @flow\n\
    \// This module has been generated by aeson-flowtyped.\n\n\
    \export type Codep =\n\
    \  {| corecurs: Recur[], tag: 'Codep', cousers: User[] |};\n\
    \export type User =\n\
    \  {| extraInfo: mixed,\n\
    \     tag: 'User',\n\
    \     realname: ?string,\n\
    \     username: string,\n\
    \     dob: ?[number,number,number] |};\n\
    \export type Recur =\n\
    \  {| tag: 'Recur', stuff: User[], recurs: Recur[], asdf: number |};\n" @=?
    generateFlowModule defaultFlowModuleOptions
    [ Export (Proxy :: Proxy Codep)
    ]

  , testCase "polymorphism (arity 1)" $
    "// @flow\n\
    \// This module has been generated by aeson-flowtyped.\n\n\
    \export type Tree<A> =\n\
    \  [A,Tree<A>[]];\n" @=?
    generateFlowModule defaultFlowModuleOptions
    [ Export (Proxy :: Proxy (Tree (Var 0)))
    ]

  , testCase "polymorphism (arity 2)" $
    "// @flow\n\
    \// This module has been generated by aeson-flowtyped.\n\n\
    \export type Poly2<A, B> =\n\
    \  {| tag: 'Poly2', contents: [A,B] |} |\n\
    \  {| tag: 'Poly2Go', contents: Poly2<A, B> |};\n" @=?
    generateFlowModule defaultFlowModuleOptions
    [ Export (Proxy :: Proxy (Poly2 (Var 0) (Var 1)))
    ]
  ]