fortran-vars-0.3.1: test/StructureTableSpec.hs
module StructureTableSpec where
import qualified Data.Map as M
import Data.Generics.Uniplate.Data
import Test.Hspec
import Language.Fortran.Analysis ( Analysis )
import Language.Fortran.AST ( ProgramUnit
, Statement(..)
, Expression(..)
)
import Language.Fortran.Extras ( allPU )
import Language.Fortran.Extras.Test ( getTestProgramAnalysis )
import Language.Fortran.Vars.StructureTable
( StructureTable
, collectStructures
, StructureTableEntry(..)
, hasEntry
)
import Language.Fortran.Vars.SymbolTable
( collectSymbols )
import Language.Fortran.Vars.Types ( SymbolTable
, SemType(..)
, CharacterLen(..)
)
import Language.Fortran.Vars.TypeCheck
( typeOf )
getStructureTable :: String -> IO StructureTable
getStructureTable file =
testStructureTable file $ \_ structTable _ -> return structTable
testStructureTable
:: String
-> (ProgramUnit (Analysis ()) -> StructureTable -> SymbolTable -> IO a)
-> IO a
testStructureTable fp logic = do
pf <- getTestProgramAnalysis fp
let pu = head $ allPU pf
testStructureTablePU pu logic
testStructureTablePU
:: ProgramUnit (Analysis ())
-> (ProgramUnit (Analysis ()) -> StructureTable -> SymbolTable -> IO a)
-> IO a
testStructureTablePU pu logic = do
let symbolTable = collectSymbols pu
structTable = collectStructures symbolTable pu
logic pu structTable symbolTable
spec :: Spec
spec = do
describe "Field tests" $ do
it "test single field" $ do
structTable <- getStructureTable "test/structure_table/basic_structure.f"
let expStruct = M.fromList [("foo", [FieldEntry "bar" (TInteger 2)])]
structTable `shouldBe` expStruct
it "test structure referenced in structure" $ do
structTable <- getStructureTable "test/structure_table/structure2.f"
let expStruct = M.fromList
[ ("foo", [FieldEntry "bar" (TInteger 8)])
, ( "baz"
, [ FieldEntry "qux" (TCustom "foo")
, FieldEntry "quux" (TCharacter (CharLenInt 10) 1)
]
)
]
structTable `shouldBe` expStruct
it "multiple layer structures" $ do
structTable <- getStructureTable "test/structure_table/structure3.f"
let graultEntries = [FieldEntry "garply" (TCustom "quuz")]
quuzEntries =
[ FieldEntry "corge" (TCustom "baz")
, FieldEntry "foobar" (TInteger 2)
]
fooEntries = [FieldEntry "bar" (TInteger 8)]
bazEntries =
[ FieldEntry "qux" (TCustom "foo")
, FieldEntry "quux" (TCharacter (CharLenInt 10) 1)
]
structTable `shouldBe` M.fromList
[ ("grault", graultEntries)
, ("quuz" , quuzEntries)
, ("foo" , fooEntries)
, ("baz" , bazEntries)
]
it "structures and subscripts" $ do
pf <- getTestProgramAnalysis "test/structure_table/structure4.f"
let pus = allPU pf
sts = map collectSymbols pus
strctTables = zipWith collectStructures sts pus
head strctTables `shouldBe` M.fromList
[ ( "str_inner"
, [FieldEntry "inner_arr" (TArray (TInteger 1) (Just [(1, 5)]))]
)
]
(strctTables !! 1) `shouldBe` M.fromList
[ ( "str_inner"
, [FieldEntry "inner_arr" (TArray (TInteger 2) (Just [(1, 5)]))]
)
]
(strctTables !! 2) `shouldBe` M.fromList
[ ( "str_inner"
, [FieldEntry "inner_arr" (TArray (TInteger 1) (Just [(1, 3)]))]
)
, ( "str_outer"
, [ FieldEntry "outer_arr"
(TArray (TCustom "str_inner") (Just [(1, 5)]))
]
)
]
describe "Union tests" $ do
it "test unions in a structure" $ do
structTable <- getStructureTable "test/structure_table/union_struct.f"
let expStruct = M.fromList
[ ( "foo"
, [ UnionEntry
[ [FieldEntry "bar" (TInteger 4)]
, [ FieldEntry "baz" (TInteger 2)
, FieldEntry "qux" (TInteger 8)
]
]
]
)
]
structTable `shouldBe` expStruct
it "test size of union fields" $ do
structTable <- getStructureTable "test/structure_table/union_struct2.f"
let expStruct =
M.fromList [("quux", [FieldEntry "quuz" (TCustom "foo")])]
M.lookup "quux" structTable `shouldBe` M.lookup "quux" expStruct
describe "Check look ups" $ do
it "test hasEntry"
$ testStructureTable "test/structure_table/structure3.f"
$ \_ structTable _ -> do
let Just test = M.lookup "foo" structTable
hasEntry "bar" test `shouldBe` Right (TInteger 8)
let Just grault = M.lookup "grault" structTable
hasEntry "garply" grault `shouldBe` Right (TCustom "quuz")
it "Union data ref"
$ testStructureTable "test/structure_table/union_struct2.f"
$ \_ structTable _ -> do
let Just test = M.lookup "quux" structTable
hasEntry "quuz" test `shouldBe` Right (TCustom "foo")
let Just foo = M.lookup "foo" structTable
hasEntry "baz" foo `shouldBe` Right (TInteger 2)
hasEntry "bar" foo `shouldBe` Right (TInteger 4)
it "Get type of nested data reference expression"
$ testStructureTable "test/structure_table/structure3.f"
$ \pf structTable st -> do
let expr =
head
[ e
| e@ExpDataRef{} <-
universeBi pf :: [Expression (Analysis ())]
]
-- check looking up the expression succeeds and gives the correct type
typeOf structTable st expr
`shouldBe` Right (TCharacter (CharLenInt 10) 1)
it "Get type of union data reference expression"
$ testStructureTable "test/structure_table/union_struct3.f"
$ \pf structTable st -> do
let expr =
head
[ e
| e@ExpDataRef{} <-
universeBi pf :: [Expression (Analysis ())]
]
typeOf structTable st expr
`shouldBe` Right (TCharacter (CharLenInt 13) 1)
it "Get combination of data references and subscripts" $ do
pf <- getTestProgramAnalysis "test/structure_table/structure4.f"
let pus = allPU pf
logics
:: [ ProgramUnit (Analysis ())
-> StructureTable
-> SymbolTable
-> IO ()
]
logics = map
(\x pu structTable st -> do
let expr = head
[ e
| (StExpressionAssign _ _ e _) <-
universeBi pu :: [Statement (Analysis ())]
]
typeOf structTable st expr `shouldBe` x
)
[ Right (TInteger 1)
, Right (TInteger 2)
, Right (TArray (TInteger 1) (Just [(1, 3)]))
]
mapM_ (uncurry testStructureTablePU) $ zip pus logics
it "Character substrings" $ do
pf <- getTestProgramAnalysis "test/structure_table/structure5.f"
let pus = allPU pf
results = [Right (TCharacter (CharLenInt 1) 1), Right (TLogical 2)]
logic res pu strt symt = do
let expr = head
[ e
| (StExpressionAssign _ _ e _) <-
universeBi pu :: [Statement (Analysis ())]
]
typeOf strt symt expr `shouldBe` res
mapM_ (uncurry testStructureTablePU) $ zip pus (map logic results)