2021-03-15 19:10:01 +03:00
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
2021-04-21 15:06:25 +03:00
|
|
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
module Psl.Generator.ModelTest where
|
|
|
|
|
2021-04-28 18:36:00 +03:00
|
|
|
import Parser.Common (runWaspParser)
|
|
|
|
import qualified Psl.Ast.Model as AST
|
|
|
|
import Psl.Common.ModelTest (sampleBodyAst)
|
|
|
|
import Psl.Generator.Model (generateModel)
|
2021-03-15 19:10:01 +03:00
|
|
|
import qualified Psl.Parser.Model
|
2021-04-28 18:36:00 +03:00
|
|
|
import Test.Tasty.Hspec
|
|
|
|
import Test.Tasty.QuickCheck
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
spec_generatePslModel :: Spec
|
|
|
|
spec_generatePslModel = do
|
2021-04-28 18:36:00 +03:00
|
|
|
describe "Complex example" $ do
|
|
|
|
let pslModelAst = AST.Model "User" sampleBodyAst
|
2021-03-15 19:10:01 +03:00
|
|
|
|
2021-04-28 18:36:00 +03:00
|
|
|
it "parse(generate(sampleBodyAst)) == sampleBodyAst" $ do
|
|
|
|
runWaspParser Psl.Parser.Model.model (generateModel pslModelAst) `shouldBe` Right pslModelAst
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
prop_generatePslModel :: Property
|
2021-04-28 18:36:00 +03:00
|
|
|
prop_generatePslModel = mapSize (const 100) $ \modelAst ->
|
|
|
|
within 1000000 $
|
2021-03-15 19:10:01 +03:00
|
|
|
runWaspParser Psl.Parser.Model.model (generateModel modelAst) `shouldBe` Right modelAst
|
|
|
|
|
|
|
|
instance Arbitrary AST.Model where
|
2021-04-28 18:36:00 +03:00
|
|
|
arbitrary = AST.Model <$> arbitraryIdentifier <*> arbitrary
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
instance Arbitrary AST.Body where
|
2021-04-28 18:36:00 +03:00
|
|
|
arbitrary = do
|
|
|
|
fieldElement <- AST.ElementField <$> arbitrary
|
|
|
|
elementsBefore <- scale (const 5) arbitrary
|
|
|
|
elementsAfter <- scale (const 5) arbitrary
|
|
|
|
return $ AST.Body $ elementsBefore ++ [fieldElement] ++ elementsAfter
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
instance Arbitrary AST.Element where
|
2021-04-28 18:36:00 +03:00
|
|
|
arbitrary =
|
|
|
|
oneof
|
|
|
|
[ AST.ElementField <$> arbitrary,
|
|
|
|
AST.ElementBlockAttribute <$> arbitrary
|
|
|
|
]
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
instance Arbitrary AST.Field where
|
2021-04-28 18:36:00 +03:00
|
|
|
arbitrary = do
|
|
|
|
name <- arbitraryIdentifier
|
|
|
|
fieldType <- arbitrary
|
|
|
|
modifiers <- oneof [(: []) <$> arbitrary, return []]
|
|
|
|
attrs <- scale (const 5) arbitrary
|
|
|
|
return $
|
|
|
|
AST.Field
|
|
|
|
{ AST._name = name,
|
|
|
|
AST._type = fieldType,
|
|
|
|
AST._typeModifiers = modifiers,
|
|
|
|
AST._attrs = attrs
|
|
|
|
}
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
instance Arbitrary AST.FieldType where
|
2021-04-28 18:36:00 +03:00
|
|
|
arbitrary =
|
|
|
|
oneof
|
|
|
|
[ return AST.String,
|
|
|
|
return AST.Boolean,
|
|
|
|
return AST.Int,
|
|
|
|
return AST.BigInt,
|
|
|
|
return AST.Float,
|
|
|
|
return AST.Decimal,
|
|
|
|
return AST.DateTime,
|
|
|
|
return AST.Json,
|
|
|
|
return AST.Bytes,
|
|
|
|
AST.Unsupported . show <$> arbitraryIdentifier,
|
|
|
|
AST.UserType <$> arbitraryIdentifier
|
|
|
|
]
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
instance Arbitrary AST.FieldTypeModifier where
|
2021-04-28 18:36:00 +03:00
|
|
|
arbitrary = oneof [return AST.List, return AST.Optional]
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
instance Arbitrary AST.Attribute where
|
2021-04-28 18:36:00 +03:00
|
|
|
arbitrary = do
|
|
|
|
name <-
|
|
|
|
frequency
|
|
|
|
[ (2, arbitraryIdentifier),
|
|
|
|
(1, ("db." ++) <$> arbitraryIdentifier)
|
|
|
|
]
|
|
|
|
args <- scale (const 5) arbitrary
|
|
|
|
return $ AST.Attribute {AST._attrName = name, AST._attrArgs = args}
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
instance Arbitrary AST.AttributeArg where
|
2021-04-28 18:36:00 +03:00
|
|
|
arbitrary =
|
|
|
|
oneof
|
|
|
|
[ AST.AttrArgNamed <$> arbitraryIdentifier <*> arbitrary,
|
|
|
|
AST.AttrArgUnnamed <$> arbitrary
|
|
|
|
]
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
instance Arbitrary AST.AttrArgValue where
|
2021-04-28 18:36:00 +03:00
|
|
|
arbitrary =
|
|
|
|
oneof
|
|
|
|
[ AST.AttrArgString <$> arbitraryNonEmptyPrintableString,
|
|
|
|
AST.AttrArgIdentifier <$> arbitraryIdentifier,
|
|
|
|
AST.AttrArgFunc <$> arbitraryIdentifier,
|
|
|
|
AST.AttrArgFieldRefList <$> scale (const 5) (listOf1 arbitraryIdentifier),
|
2021-03-15 19:10:01 +03:00
|
|
|
-- NOTE: For now we are not supporting negative numbers.
|
|
|
|
-- I couldn't figure out from Prisma docs if there could be the case
|
|
|
|
-- where these numbers could be negative. Probably we should take care of that case.
|
2021-04-28 18:36:00 +03:00
|
|
|
AST.AttrArgNumber
|
|
|
|
<$> oneof
|
|
|
|
[ show <$> (arbitrary :: Gen Int) `suchThat` (>= 0),
|
|
|
|
show <$> (arbitrary :: Gen Float) `suchThat` (>= 0)
|
|
|
|
]
|
|
|
|
-- NOTE: Unknown is commented out because unknown should contain only values
|
|
|
|
-- that are not recognized as any other type of attribute argument,
|
|
|
|
-- and defining how those are generated is not so simple, so I skipped it for now.
|
|
|
|
-- , AST.AttrArgUnknown <$> arbitraryNonEmptyPrintableString
|
|
|
|
]
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
arbitraryNonEmptyPrintableString :: Gen String
|
|
|
|
arbitraryNonEmptyPrintableString = listOf1 arbitraryPrintableChar
|
|
|
|
|
|
|
|
arbitraryAlpha :: Gen Char
|
2021-04-28 18:36:00 +03:00
|
|
|
arbitraryAlpha = elements $ ['a' .. 'z'] ++ ['A' .. 'Z']
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
arbitraryAlphaNum :: Gen Char
|
2021-04-28 18:36:00 +03:00
|
|
|
arbitraryAlphaNum = elements $ ['a' .. 'z'] ++ ['A' .. 'Z'] ++ ['0' .. '9']
|
2021-03-15 19:10:01 +03:00
|
|
|
|
|
|
|
arbitraryIdentifier :: Gen String
|
|
|
|
arbitraryIdentifier = (:) <$> arbitraryAlpha <*> listOf arbitraryAlphaNum
|