packages feed

ghcup-0.2.1.0: test/ghcup-test/GHCup/Types/JSONSpec.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE TypeApplications #-}

module GHCup.Types.JSONSpec where

import GHCup.ArbitraryTypes ()
import GHCup.Prelude
import GHCup.Types hiding ( defaultSettings )
import GHCup.Types.Dhall ()
import GHCup.Types.JSON ()

import Control.Monad (when, forM_)
import System.FilePath
import Test.Aeson.GenericSpecs
import Test.Hspec.Golden
import Test.Hspec

import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Aeson.Encode.Pretty as Aeson
import qualified Data.Yaml as YAML

#if defined(DHALL)
import Dhall.Marshal.Encode ()
import qualified Dhall.Core as Dhall
import qualified Dhall.Binary as Dhall
import qualified Dhall hiding (Text)
import qualified Data.Void as V
import Dhall.Yaml (dhallToYaml, defaultOptions)
import Dhall.JSON (convertToHomogeneousMaps, Conversion(..))
#endif

spec :: Spec
spec = do
  roundtripSpecs (Proxy @LinuxDistro)
  roundtripSpecs (Proxy @EnvSpec)
  roundtripSpecs (Proxy @ConfigSpec)
  roundtripSpecs (Proxy @MakeSpec)
  roundtripSpecs (Proxy @SymlinkInputSpec)
  roundtripSpecs (Proxy @InstallationSpecInput)
  roundtripSpecs (Proxy @Tool)
  roundtripSpecs (Proxy @TargetVersion)
  roundtripSpecs (Proxy @VersionInfo)
  roundtripSpecs (Proxy @Architecture)
  roundtripSpecs (Proxy @Platform)
  roundtripSpecs (Proxy @VersionRange)
  roundtripSpecs (Proxy @URLSource)
  roundtripSpecs (Proxy @UserSettings)
  roundtripSpecs (Proxy @GHCupDownloads)
  roundtripSpecs (Proxy @ToolInfo)
  roundtripSpecs (Proxy @ToolDescription)
  roundtripSpecs (Proxy @ToolVersionSpec)
  roundtripSpecs (Proxy @VersionMetadata)
  roundtripSpecs (Proxy @RevisionSpec)
  roundtripSpecs (Proxy @VersionInfo)
  roundtripSpecs (Proxy @ArchitectureSpec)
  roundtripSpecs (Proxy @PlatformSpec)
  roundtripSpecs (Proxy @PlatformVersionSpec)
  roundtripSpecs (Proxy @DownloadInfo)
  roundtripSpecs (Proxy @GHCupInfo)
#if !defined(i386_HOST_ARCH)
  when (not isWindows) $
    roundtripAndGoldenSpecsWithSettings (defaultSettings { goldenDirectoryOption = CustomDirectoryName "test/ghcup-test/golden/unix", sampleSize = 2 }) (Proxy @GHCupInfo)
#endif

  describe "Parse old metadata" $ do
    forM_ yamls $ \v ->
      it v $ do
        (Right info) <- YAML.decodeFileEither @GHCupInfo $ "data/test/ghcup-" <> v
        pure $ Golden {
             output = decUTF8Safe' $ Aeson.encodePretty info
           , encodePretty = T.unpack
           , writeToFile = T.writeFile
           , readFromFile = T.readFile
           , goldenFile = "test/ghcup-test/golden/old_metadata/ghcup-" <> dropExtension v
           , actualFile = Nothing
           , failFirstTime = False
           }

#if defined(DHALL)
  describe "Dhall roundtrip" $ do
    beforeAll (do
        info <- YAML.decodeFileEither @GHCupInfo "data/test/ghcup-0.1.0.yaml" >>= either (fail . show) pure
        let expr = Dhall.denote $ Dhall.embed @GHCupInfo Dhall.inject info
        pure (info, expr)
      ) $ do
          it "Normal dhall" $ \(info, expr) -> do
            nInfo <- roundTripNormal expr
            nInfo `shouldBe` info
          it "Binary dhall" $ \(info, expr) -> do
            bInfo <- roundTripBinary expr
            bInfo `shouldBe` info
          it "dhall-to-yaml" $ \(info, expr) -> do
            yInfo <- roundTripYaml expr
            yInfo `shouldBe` info
#endif
 where
  yamls = [ "0.0.1.json"
          , "0.0.2.json"
          , "0.0.3.yaml"
          , "0.0.4.yaml"
          , "0.0.5.yaml"
          , "0.0.6.yaml"
          , "0.0.7.yaml"
          , "0.0.8.yaml"
          , "0.0.9.yaml"
          , "0.1.0.yaml"
          ]
#if defined(DHALL)
  roundTripNormal :: Dhall.Expr V.Void V.Void -> IO GHCupInfo
  roundTripNormal expr = do
    let dhallCode = Dhall.pretty expr
    Dhall.input @GHCupInfo Dhall.auto dhallCode

  roundTripBinary :: Dhall.Expr V.Void V.Void -> IO GHCupInfo
  roundTripBinary expr = do
    let dhallCode = Dhall.encodeExpression expr
    expr' <- either (fail . show) pure $ Dhall.decodeExpression @V.Void @V.Void dhallCode
    Dhall.rawInput Dhall.auto expr'

  -- using dhall-to-yaml essentially
  roundTripYaml :: Dhall.Expr V.Void V.Void -> IO GHCupInfo
  roundTripYaml (convertToHomogeneousMaps NoConversion -> expr) = do
    let dhallCode = Dhall.pretty expr
    yaml <- dhallToYaml defaultOptions Nothing dhallCode
    either (fail . show) pure $ YAML.decodeEither' yaml
#endif