camfort-1.0: tests/Camfort/Specification/Units/Analysis/ConsistentSpec.hs
-- TODO: Fix this
module Camfort.Specification.Units.Analysis.ConsistentSpec (spec) where
import Camfort.Analysis hiding (describe)
import Camfort.Analysis.ModFile (genModFiles)
import Camfort.Input (readParseSrcDir)
import Camfort.Specification.Units.Analysis (compileUnits)
import Camfort.Specification.Units.Analysis.Consistent (checkUnits)
import Camfort.Specification.Units.Monad (LiteralsOpt(..), unitOpts0, uoLiterals, runUnitAnalysis, UnitEnv(..))
import Control.Lens
import Language.Fortran.Util.ModFile (ModFile, emptyModFiles)
import System.FilePath ((</>))
import qualified Test.Hspec as Test
import Test.Hspec hiding (Spec)
spec :: Test.Spec
spec =
describe "consistency analysis" $ do
it "reports (simple) inconsistent units" $
"example-inconsist-1.f90" `unitsCheckReportIs` exampleInconsist1CheckReport
it "Polymorphic non-zero literal is not OK" $
"inconsistLitInPolyFun.f90" `unitsCheckReportIs` inconsistLitInPolyFunReport
it "Recursive Multiplication is not OK" $
"inconsistRecMult.f90" `unitsCheckReportIs` inconsistRecMultReport
describe "reports with varying Literal Modes" $ do
it "LitMixed" $
unitsCheckReportNoMod LitMixed "inconsist3.f90" inconsist3LitMixedReport
it "LitPoly" $
unitsCheckReportNoMod LitPoly "inconsist3.f90" inconsist3LitPolyReport
it "LitUnitless" $
unitsCheckReportNoMod LitUnitless "inconsist3.f90" inconsist3LitUnitlessReport
describe "cross-module" $
it "basic inconsistent" $
unitsCheckReportWithMod ["cross-module-a/crossmoduleprovider.f90"] "cross-module-a/crossmoduleuser.f90"
crossModuleInconsistBasicReport
describe "literals" $ do
it "nonzero literal with explicitly annotated polymorphic units-variable" $
"literal-nonzero-inconsist1.f90" `unitsCheckReportIs` literalNonZeroInconsist1Report
it "nonzero literal is unitless in poly-context" $
"literal-nonzero-inconsist2.f90" `unitsCheckReportIs` literalNonZeroInconsist2Report
it "monomorphism restriction is important (do-loop)" $
"literal-nonzero-inconsist3.f90" `unitsCheckReportIs` literalNonZeroInconsist3Report
-- it "monomorphism restriction is important (do-loop with zero-start)" $
-- "literal-nonzero-inconsist4.f90" `unitsCheckReportIs` literalNonZeroInconsist4Report
it "monomorphism restriction is important (goto)" $
"literal-nonzero-inconsist5.f90" `unitsCheckReportIs` literalNonZeroInconsist5Report
fixturesDir :: String
fixturesDir = "tests" </> "fixtures" </> "Specification" </> "Units"
-- | Assert that the report of performing units checking on a file is as expected.
unitsCheckReport :: LiteralsOpt -> [String] -> String -> String -> Expectation
unitsCheckReport lo modNames fileName expectedReport = do
let file = fixturesDir </> fileName
modPaths = fmap (fixturesDir </>) modNames
modFiles <- mapM mkTestModFile modPaths
[(pf,_)] <- readParseSrcDir Nothing modFiles file []
let uEnv = UnitEnv { unitOpts = uOpts, unitProgramFile = pf }
report <- runAnalysisT file (logOutputNone True) LogError modFiles $ runUnitAnalysis uEnv $ checkUnits
let res = report ^?! arResult . _ARSuccess
show res `shouldBe` expectedReport
where uOpts = unitOpts0 { uoLiterals = lo }
unitsCheckReportWithMod :: [String] -> String -> String -> Expectation
unitsCheckReportWithMod = unitsCheckReport LitMixed
unitsCheckReportNoMod :: LiteralsOpt -> String -> String -> Expectation
unitsCheckReportNoMod lo = unitsCheckReport lo []
-- | Assert that the report of performing units checking on a file is as expected.
unitsCheckReportIs :: String -> String -> Expectation
unitsCheckReportIs = unitsCheckReport LitMixed []
-- | Helper for producing a basic ModFile from a (terminal) module file.
mkTestModFile :: String -> IO ModFile
mkTestModFile file = head <$> genModFiles Nothing emptyModFiles compileUnits unitOpts0 file []
exampleInconsist1CheckReport :: String
exampleInconsist1CheckReport =
"\ntests/fixtures/Specification/Units/example-inconsist-1.f90: Inconsistent:\n\
\ - at 7:7: Units 's' and 'm' should be equal\n"
inconsist3LitMixedReport :: String
inconsist3LitMixedReport =
"\ntests/fixtures/Specification/Units/inconsist3.f90: Inconsistent:\n\
\ - at 6:3: 'j**2' should have the same units as 'k'\n"
inconsist3LitPolyReport :: String
inconsist3LitPolyReport =
"\ntests/fixtures/Specification/Units/inconsist3.f90: Inconsistent:\n\
\ - at 6:3: 'j**2' should have the same units as 'k'\n"
inconsist3LitUnitlessReport :: String
inconsist3LitUnitlessReport =
"\ntests/fixtures/Specification/Units/inconsist3.f90: Inconsistent:\n\
\ - at 6:3: 'j**2' should have the same units as 'k'\n"
inconsistLitInPolyFunReport :: String
inconsistLitInPolyFunReport =
"\ntests/fixtures/Specification/Units/inconsistLitInPolyFun.f90: Inconsistent:\n\
\ - at 10:3: 'a' should have the same units as 'result of sqr'\n\
\ - at 10:11: 'parameter 1 to sqr' should have unit 'm'\n"
inconsistRecMultReport :: String
inconsistRecMultReport =
"\ntests/fixtures/Specification/Units/inconsistRecMult.f90: Inconsistent:\n\
\ - at 4:15: 'parameter 2 to recur' should have unit 'm'\n"
crossModuleInconsistBasicReport :: String
crossModuleInconsistBasicReport =
"\ntests/fixtures/Specification/Units/cross-module-a/crossmoduleuser.f90: Inconsistent:\n\
\ - at 9:11: 'parameter 1 to add' should have unit 'm'\n"
literalNonZeroInconsist1Report :: String
literalNonZeroInconsist1Report =
"\ntests/fixtures/Specification/Units/literal-nonzero-inconsist1.f90: Inconsistent:\n\
\'literal number' should have unit '1'\n"
literalNonZeroInconsist2Report :: String
literalNonZeroInconsist2Report =
"\ntests/fixtures/Specification/Units/literal-nonzero-inconsist2.f90: Inconsistent:\n\
\ - at 6:3: 'b' should have the same units as 'result of f'\n\
\ - at 6:9: 'parameter 1 to f' should have unit 'm'\n"
literalNonZeroInconsist3Report :: String
literalNonZeroInconsist3Report =
"\ntests/fixtures/Specification/Units/literal-nonzero-inconsist3.f90: Inconsistent:\n\
\ - at 6:3: 'result of sqr' should have unit 'm'\n\
\ - at 6:11: 'parameter 1 to sqr' should have unit 'm'\n\
\ - at 7:3: 'result of sqr' should have unit 's'\n\
\ - at 7:11: 'parameter 1 to sqr' should have unit 's'\n"
-- literalNonZeroInconsist4Report :: String -- fixme
-- literalNonZeroInconsist4Report =
-- "\ntests/fixtures/Specification/Units/literal-nonzero-inconsist5.f90: Inconsistent:\n\
-- \- at 7:11: 'parameter 1 to sqr' should have unit 's'\n\
-- \- at 15:9: 'i' should have the same units as 'parameter 1 to sqr'\n\
-- \- at 17:12: 'i' should have unit '1'\n"
literalNonZeroInconsist5Report :: String
literalNonZeroInconsist5Report =
"\ntests/fixtures/Specification/Units/literal-nonzero-inconsist5.f90: Inconsistent:\n\
\ - at 6:3: 'result of sqr' should have unit 'm'\n\
\ - at 6:11: 'parameter 1 to sqr' should have unit 'm'\n"