-- Copyright (c) Microsoft. All rights reserved. -- Licensed under the MIT license. See LICENSE file in the project root for full license information. {-# LANGUAGE RecordWildCards #-} {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-} module Tests.Codegen ( verifyCodegen , verifyCppCodegen , verifyApplyCodegen , verifyCsCodegen , verifyCsCommCodegen ) where import System.FilePath import Control.Monad import Data.Monoid import Data.Maybe import Prelude import Data.Algorithm.DiffContext import Data.Text.Lazy (Text, unpack) import qualified Data.ByteString.Char8 as BS import Text.PrettyPrint (render, text) import Test.Tasty import Test.Tasty.Golden.Advanced import Language.Bond.Codegen.Templates import Language.Bond.Codegen.TypeMapping import Language.Bond.Syntax.Types (Bond(..), Import, Declaration) import Options import IO type Template = MappingContext -> String -> [Import] -> [Declaration] -> (String, Text) verifyCppCodegen :: FilePath -> TestTree verifyCppCodegen = verifyCodegen ["c++"] verifyCsCodegen :: FilePath -> TestTree verifyCsCodegen = verifyCodegen ["c#"] verifyCodegen :: [String] -> FilePath -> TestTree verifyCodegen args baseName = testGroup baseName $ verifyFiles (processOptions args) baseName verifyApplyCodegen :: [String] -> FilePath -> TestTree verifyApplyCodegen args baseName = testGroup baseName $ map (verifyFile options baseName cppTypeMapping "apply") templates where options = processOptions args templates = [ apply_h protocols (apply_attribute options) , apply_cpp protocols ] protocols = [ Protocol "bond::CompactBinaryReader" "bond::CompactBinaryWriter" , Protocol "bond::FastBinaryReader" "bond::FastBinaryWriter" , Protocol "bond::SimpleBinaryReader" "bond::SimpleBinaryWriter" ] verifyCsCommCodegen :: [String] -> FilePath -> TestTree verifyCsCommCodegen args baseName = testGroup baseName $ map (verifyFile (processOptions args) baseName csTypeMapping "") [ comm_interface_cs , comm_proxy_cs , comm_service_cs , types_cs Class (fieldMapping (processOptions args)) ] where fieldMapping Cs {..} = if readonly_properties then ReadOnlyProperties else if fields then PublicFields else Properties verifyFiles :: Options -> FilePath -> [TestTree] verifyFiles options baseName = map (verify (typeMapping options) "") (templates options) <> extra options where verify = verifyFile options baseName fieldMapping Cs {..} = if readonly_properties then ReadOnlyProperties else if fields then PublicFields else Properties typeMapping Cpp {..} = maybe cppTypeMapping cppCustomAllocTypeMapping allocator typeMapping Cs {} = csTypeMapping templates Cpp {..} = [ reflection_h , types_cpp , types_h header enum_header allocator ] templates Cs {..} = [ types_cs Class $ fieldMapping options ] extra Cs {} = [ testGroup "collection interfaces" $ map (verify csCollectionInterfacesTypeMapping "collection-interfaces") (templates options) ] extra Cpp {..} = [ testGroup "custom allocator" $ map (verify (cppCustomAllocTypeMapping "arena") "allocator") (templates $ options { allocator = Just "arena" }) | isNothing allocator ] verifyFile :: Options -> FilePath -> TypeMapping -> FilePath -> Template -> TestTree verifyFile options baseName typeMapping subfolder template = goldenTest suffix readGolden codegen cmp updateGolden where (suffix, _) = template (MappingContext typeMapping [] [] []) "" [] [] golden = "tests" "generated" subfolder baseName ++ suffix readGolden = BS.readFile golden updateGolden = BS.writeFile golden codegen = do aliasMapping <- parseAliasMappings $ using options namespaceMapping <- parseNamespaceMappings $ namespace options (Bond imports namespaces declarations) <- parseBondFile [] $ "tests" "schema" baseName <.> "bond" let mappingContext = MappingContext typeMapping aliasMapping namespaceMapping namespaces let (_, code) = template mappingContext baseName imports declarations return $ BS.pack $ unpack code cmp x y = return $ if x == y then Nothing else Just $ diff x y diff x y = render $ prettyContextDiff (text golden) (text "test output") (text . BS.unpack) (getContextDiff 3 (BS.lines x) (BS.lines y))