{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeOperators #-} module Sum where -- base import GHC.Generics import Data.Typeable -- aeson import Data.Aeson (FromJSON, ToJSON) -- containers import qualified Data.Map as Map -- hspec import Test.Hspec -- QuickCheck import Test.QuickCheck hiding (Result, Success) -- quickcheck-arbitrary-adt import Test.QuickCheck.Arbitrary.ADT import Test.Aeson.Internal.ADT.GoldenSpecs -- servant import Servant.API -- ocaml-export import OCaml.Export hiding (mkGoldenFiles) import Util type SumPackage = OCamlPackage "sum" NoDependency :> (OCamlModule '["OnOrOff"] :> OnOrOff :<|> OCamlModule '["NameOrIdNumber"] :> NameOrIdNumber :<|> OCamlModule '["SumVariant"] :> SumVariant :<|> OCamlModule '["WithTuple"] :> WithTuple :<|> OCamlModule '["SumWithRecord"] :> SumWithRecord -- :> SumWithRecordMixed :<|> OCamlModule '["Result"] :> Result TypeParameterRef0 TypeParameterRef1 -- :> ComplexResult TypeParameterRef0 TypeParameterRef1 TypeParameterRef2 :<|> OCamlModule '["NewType"] :> NewType) compareInterfaceFiles :: FilePath -> SpecWith () compareInterfaceFiles = compareFiles "test/interface" "sum" True compareNoInterfaceFiles :: FilePath -> SpecWith () compareNoInterfaceFiles = compareFiles "test/nointerface" "sum" False mkGolden :: forall a. (ToADTArbitrary a, ToJSON a) => Proxy a -> IO () mkGolden Proxy = mkGoldenFileForType 10 (Proxy :: Proxy a) "test/interface/golden/golden/sum" mkGoldenFiles :: IO () mkGoldenFiles = do mkGolden (Proxy :: Proxy OnOrOff) mkGolden (Proxy :: Proxy NameOrIdNumber) mkGolden (Proxy :: Proxy SumVariant) mkGolden (Proxy :: Proxy WithTuple) mkGolden (Proxy :: Proxy SumWithRecord) mkGolden (Proxy :: Proxy (Result TypeParameterRef0 TypeParameterRef1)) mkGolden (Proxy :: Proxy NewType) spec :: Spec spec = do runIO mkGoldenFiles let dir = "test/interface/temp" runIO $ mkPackage (Proxy :: Proxy SumPackage) (PackageOptions dir "sum" Map.empty True $ Just $ SpecOptions "__tests__/sum" "golden/sum" "http://localhost:8082") describe "OCaml Declaration with Interface: Sum Types" $ do compareInterfaceFiles "OnOrOff" compareInterfaceFiles "NameOrIdNumber" compareInterfaceFiles "SumVariant" compareInterfaceFiles "WithTuple" compareInterfaceFiles "SumWithRecord" compareInterfaceFiles "Result" compareInterfaceFiles "NewType" data OnOrOff = On | Off deriving (Show,Eq,Generic,OCamlType,ToJSON,FromJSON) instance Arbitrary OnOrOff where arbitrary = elements [On, Off] instance ToADTArbitrary OnOrOff data NameOrIdNumber = Name String | IdNumber Int deriving (Show, Eq, Generic, OCamlType,ToJSON,FromJSON) instance Arbitrary NameOrIdNumber where arbitrary = oneof [Name <$> arbitrary, IdNumber <$> arbitrary] instance ToADTArbitrary NameOrIdNumber data Result a b = Success a | Error b deriving (Show, Eq, Generic, ToJSON, FromJSON) instance Arbitrary (Result TypeParameterRef0 TypeParameterRef1) where arbitrary = oneof [Success <$> arbitrary, Error <$> arbitrary] instance ToADTArbitrary (Result TypeParameterRef0 TypeParameterRef1) instance (Typeable a, OCamlType a, Typeable b, OCamlType b) => (OCamlType (Result a b)) data ComplexResult a b c = CR0 a | CR1 a b | CR2 b (c,a) | CR3 String b Int a | CR4 { cr4b :: b, cr4ac :: (a,c) } | CR5 deriving (Show, Eq, Generic, ToJSON, FromJSON) instance Arbitrary (ComplexResult TypeParameterRef0 TypeParameterRef1 TypeParameterRef2) where arbitrary = oneof [ CR0 <$> arbitrary , CR1 <$> arbitrary <*> arbitrary , CR2 <$> arbitrary <*> arbitrary , CR3 <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary , CR4 <$> arbitrary <*> arbitrary , pure CR5 ] instance ToADTArbitrary (ComplexResult TypeParameterRef0 TypeParameterRef1 TypeParameterRef2) instance (Typeable a, OCamlType a, Typeable b, OCamlType b, Typeable c, OCamlType c) => (OCamlType (ComplexResult a b c)) data SumVariant = HasNothing | HasSingleInt Int | HasSingleTuple (Int,Int) | HasMultipleInts Int Int | HasMultipleTuples (Int,Int) (Int,Int) | HasMixed Int String Double deriving (Show,Eq,Generic, OCamlType, ToJSON, FromJSON) instance Arbitrary SumVariant where arbitrary = oneof [ pure HasNothing , HasSingleInt <$> arbitrary , HasSingleTuple <$> arbitrary , HasMultipleInts <$> arbitrary <*> arbitrary , HasMultipleTuples <$> arbitrary <*> arbitrary , HasMixed <$> arbitrary <*> arbitrary <*> arbitrary ] instance ToADTArbitrary SumVariant type Tuple = (Int,Int) data WithTuple = WithTuple Tuple deriving (Show,Eq,Generic, OCamlType, ToJSON, FromJSON) instance Arbitrary WithTuple where arbitrary = WithTuple <$> arbitrary instance ToADTArbitrary WithTuple data SumWithRecord = A1 {a1 :: Int} | B2 {b2 :: String, b3 :: Int} deriving (Show,Eq,Generic, OCamlType, ToJSON, FromJSON) instance Arbitrary SumWithRecord where arbitrary = oneof [ A1 <$> arbitrary , B2 <$> arbitrary <*> arbitrary ] instance ToADTArbitrary SumWithRecord data SumWithRecordMixed = SRM1 {srm1 :: Int} | SRM2 | SRM3 {srm2 :: String, srm3 :: Float} | SRM4 Int (String, Double) deriving (Show,Eq,Generic, OCamlType, ToJSON, FromJSON) instance Arbitrary SumWithRecordMixed where arbitrary = oneof [ SRM1 <$> arbitrary , pure SRM2 , SRM3 <$> arbitrary <*> arbitrary , SRM4 <$> arbitrary <*> arbitrary ] instance ToADTArbitrary SumWithRecordMixed newtype NewType = NewType Int deriving (Show,Eq,Generic,OCamlType, ToJSON, FromJSON) instance Arbitrary NewType where arbitrary = NewType <$> arbitrary instance ToADTArbitrary NewType {- introduce Enumerator extra type is made but anything coming after the enumerator is broken λ> toOCamlType (Proxy :: Proxy (ComplexResult TypeParameterRef0 TypeParameterRef1 TypeParameterRef2)) OCamlDatatype (HaskellTypeMetaData "ComplexResult" "Sum" "main") "ComplexResult" (OCamlValueConstructor (MultipleConstructors [MultipleConstructors [NamedConstructor "CR0" (OCamlTypeParameterRef "a0"),MultipleConstructors [NamedConstructor "CR1" (Values (OCamlTypeParameterRef "a0") (OCamlTypeParameterRef "a1")),NamedConstructor "CR2" (Values (OCamlTypeParameterRef "a1") (OCamlPrimitiveRef (OTuple2 (OCamlDatatype (HaskellTypeMetaData "a2" "OCaml.BuckleScript.Types" "ocaml-export") "a2" (OCamlValueConstructor (NamedConstructor "a2" (OCamlTypeParameterRef "a2")))) (OCamlDatatype (HaskellTypeMetaData "a0" "OCaml.BuckleScript.Types" "ocaml-export") "a0" (OCamlValueConstructor (NamedConstructor "a0" (OCamlTypeParameterRef "a0")))))))]],MultipleConstructors [NamedConstructor "CR3" (Values (Values (OCamlPrimitiveRef (OList (OCamlPrimitive OChar))) (OCamlTypeParameterRef "a1")) (Values (OCamlPrimitiveRef OInt) (OCamlTypeParameterRef "a0"))),MultipleConstructors [RecordConstructor "CR4" (Values (OCamlField "cr4b" (OCamlTypeParameterRef "a1")) (OCamlField "cr4ac" (OCamlPrimitiveRef (OTuple2 (OCamlDatatype (HaskellTypeMetaData "a0" "OCaml.BuckleScript.Types" "ocaml-export") "a0" (OCamlValueConstructor (NamedConstructor "a0" (OCamlTypeParameterRef "a0")))) (OCamlDatatype (HaskellTypeMetaData "a2" "OCaml.BuckleScript.Types" "ocaml-export") "a2" (OCamlValueConstructor (NamedConstructor "a2" (OCamlTypeParameterRef "a2")))))))),NamedConstructor "CR5" OCamlEmpty]]])) λ> toOCamlType (Proxy :: Proxy SumWithRecord) OCamlDatatype (HaskellTypeMetaData "SumWithRecord" "Sum" "main") "SumWithRecord" (OCamlSumOfRecordConstructor "SumWithRecord" (MultipleConstructors [RecordConstructor "A1" (OCamlField "a1" (OCamlPrimitiveRef OInt)),RecordConstructor "B2" (Values (OCamlField "b2" (OCamlPrimitiveRef (OList (OCamlPrimitive OChar)))) (OCamlField "b3" (OCamlPrimitiveRef OInt)))])) -}