packages feed

hydra-0.14.0: src/test/haskell/Hydra/Reference/AlgorithmWSpec.hs

{-
stack ghci hydra:lib hydra:hydra-test

Test.Hspec.hspec Hydra.Reference.AlgorithmWSpec.spec
-}
module Hydra.Reference.AlgorithmWSpec where

import Hydra.Kernel
import Hydra.Sources.Libraries
import Hydra.TestUtils
import Hydra.TestData
import qualified Hydra.Extract.Core as ExtractCore
import Hydra.Dsl.Terms as Terms
import qualified Hydra.Dsl.Annotations as Ann
import qualified Hydra.Dsl.Types as Types
import qualified Hydra.Show.Core as ShowCore
import qualified Hydra.Reference.AlgorithmWBridge as W

import qualified Hydra.TestUtils as TU
import Hydra.Testing
import Hydra.TestSuiteSpec
import Hydra.Test.TestSuite
import qualified Hydra.Dsl.Meta.Testing as Testing

import qualified Test.Hspec as H
import qualified Test.QuickCheck as QC
import qualified Data.List as L
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Control.Exception as Exception
import Control.Monad


testHydraContext = W.HydraContext $ graphPrimitives testGraph

inferType :: Term -> IO (Either String (Term, TypeScheme))
inferType term = do
  result <- Exception.try (W.termToInferredTerm testHydraContext term)
    :: IO (Either Exception.SomeException (Term, TypeScheme))
  return $ case result of
    Left e -> Left (show e)
    Right r -> Right r

-- | Strip class constraints from a TypeScheme, since the reference Algorithm W
--   implementation does not track type class constraints.
stripConstraints :: TypeScheme -> TypeScheme
stripConstraints ts = ts { typeSchemeConstraints = Nothing }

expectType :: Term -> TypeScheme -> H.SpecWith ()
expectType term ts = do
  result <- H.runIO $ inferType term
  case result of
    Left err -> H.it "inferred type (skipped: unsupported by reference implementation)" $
      H.pendingWith err
    Right (iterm, its) -> do
      H.it "inferred type" $
        H.shouldBe (ShowCore.typeScheme $ stripConstraints its) (ShowCore.typeScheme $ stripConstraints ts)
      H.it "inferred term" $
        H.shouldBe (ShowCore.term $ removeTypesFromTerm iterm) (ShowCore.term $ removeTypesFromTerm term)

algorithmWRunner :: TestRunner
algorithmWRunner desc tcase = if Testing.isDisabled tcase || Testing.isDisabledForMinimalInference tcase
  then Nothing
  else case testCaseWithMetadataCase tcase of
    TestCaseInference (InferenceTestCase input output) -> Just $ expectType input output
    _ -> Nothing

spec :: H.Spec
spec = runTestGroup "" algorithmWRunner allTests