wireform-proto-0.2.0.0: test-integration/Test/CodeGen.hs
module Test.CodeGen (codeGenTests) where
import Data.Map.Strict qualified as Map
import Data.Text (Text)
import Data.Text qualified as T
import Proto.CodeGen
import Proto.CodeGen.Types
import Proto.IDL.AST
import Proto.IDL.Annotations
import Proto.IDL.Parser
import Test.Syd
codeGenTests :: Spec
codeGenTests =
describe
"Code Generation"
$ sequence_
[ describe
"Type name conversion"
$ sequence_
[ it "simple name" $
hsTypeName "person" `shouldBe` "Person"
, it "already capitalized" $
hsTypeName "Person" `shouldBe` "Person"
, it "field name conversion" $
hsFieldName "first_name" `shouldBe` "firstName"
, it "field name no underscore" $
hsFieldName "name" `shouldBe` "name"
, it "enum constructor" $
hsEnumCon "Status" "STATUS_ACTIVE" `shouldBe` "StatusActive"
, it "module name" $
hsModuleName "com.example.api" `shouldBe` "Com.Example.Api"
]
, describe
"Code generation from parsed proto"
$ sequence_
[ it "generates module for simple message" $ do
let input =
unlines'
[ "syntax = \"proto3\";"
, "package test;"
, "message Person {"
, " string name = 1;"
, " int32 age = 2;"
, "}"
]
case parseProtoFile "<test>" input of
Left e -> expectationFailure (show e)
Right pf -> do
let emptyReg = Map.empty :: TypeRegistry
code = generateModuleText defaultGenerateOpts emptyReg "<test>" pf
(T.isInfixOf "data Person" code) `shouldBe` True
(T.isInfixOf "name" code) `shouldBe` True
(T.isInfixOf "module" code) `shouldBe` True
, it "proto3 optional scalar gets Maybe wrapper" $ do
let input =
unlines'
[ "syntax = \"proto3\";"
, "package test;"
, "message Presence {"
, " int32 required_field = 1;"
, " optional int32 optional_field = 2;"
, " optional string optional_name = 3;"
, "}"
]
case parseProtoFile "<test>" input of
Left e -> expectationFailure (show e)
Right pf -> do
let emptyReg = Map.empty :: TypeRegistry
code = generateModuleText defaultGenerateOpts emptyReg "<test>" pf
(T.isInfixOf "Maybe Int32" code) `shouldBe` True
(T.isInfixOf "Maybe Text" code) `shouldBe` True
(T.isInfixOf "Int32" code) `shouldBe` True
, it "generates enum" $ do
let input =
unlines'
[ "syntax = \"proto3\";"
, "enum Status {"
, " UNKNOWN = 0;"
, " ACTIVE = 1;"
, "}"
]
case parseProtoFile "<test>" input of
Left e -> expectationFailure (show e)
Right pf -> do
let emptyReg = Map.empty :: TypeRegistry
code = generateModuleText defaultGenerateOpts emptyReg "<test>" pf
(T.isInfixOf "data Status" code) `shouldBe` True
(T.isInfixOf "Active" code) `shouldBe` True
]
, describe
"Annotations"
$ sequence_
[ it "extract custom annotation" $ do
let input =
unlines'
[ "syntax = \"proto3\";"
, "option (my_annotation) = true;"
, "option (another_opt) = { key: \"value\" };"
]
case parseProtoFile "<test>" input of
Left e -> expectationFailure (show e)
Right pf -> do
let anns = extractAnnotations (protoOptions pf)
length anns `shouldBe` 2
case lookupAnnotation "my_annotation" anns of
Just (CBool True) -> pure ()
other -> expectationFailure ("Expected CBool True, got: " <> show other)
, it "lookup simple option" $ do
let input =
unlines'
[ "syntax = \"proto3\";"
, "option java_package = \"com.example\";"
]
case parseProtoFile "<test>" input of
Left e -> expectationFailure (show e)
Right pf -> do
case lookupSimpleOption "java_package" (protoOptions pf) of
Just (CString "com.example") -> pure ()
other -> expectationFailure ("Expected CString, got: " <> show other)
, it "extension option lookup" $ do
let input =
unlines'
[ "syntax = \"proto3\";"
, "option (custom.opt) = 42;"
]
case parseProtoFile "<test>" input of
Left e -> expectationFailure (show e)
Right pf -> do
case lookupExtensionOption "custom.opt" (protoOptions pf) of
Just (CInt 42) -> pure ()
other -> expectationFailure ("Expected CInt 42, got: " <> show other)
, it "hasOption check" $ do
let input =
unlines'
[ "syntax = \"proto3\";"
, "option deprecated = true;"
]
case parseProtoFile "<test>" input of
Left e -> expectationFailure (show e)
Right pf -> do
(hasOption "deprecated" (protoOptions pf)) `shouldBe` True
(not (hasOption "java_package" (protoOptions pf))) `shouldBe` True
, it "typed option extraction" $ do
optionAsInt (CInt 42) `shouldBe` Just 42
optionAsFloat (CFloat 3.14) `shouldBe` Just 3.14
optionAsBool (CBool True) `shouldBe` Just True
optionAsString (CString "hello") `shouldBe` Just "hello"
optionAsIdent (CIdent "FOO") `shouldBe` Just "FOO"
optionAsAggregate (CAggregate [("k", CInt 1)]) `shouldBe` Just [("k", CInt 1)]
optionAsInt (CString "nope") `shouldBe` Nothing
]
]
unlines' :: [Text] -> Text
unlines' = mconcat . fmap (<> "\n")