packages feed

registry-options-0.1.0.0: test/Test/Data/Registry/Options/SourcesSpec.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}

module Test.Data.Registry.Options.SourcesSpec where

import Data.ByteString.Lazy as BS
import Data.Registry
import Data.Registry.Options
import Data.Text qualified as T
import Data.Text.Encoding qualified as T
import Data.YAML as Y (decode)
import Protolude as P
import System.Directory (removeFile)
import System.Environment
import Test.Tasty.Hedgehogx

-- | This is a large test but it avoid issues with concurrent execution when
--   writing down separate tests
test_sources = test "values can be retrieved from various sources" $ do
  -- from the environment
  lexemes1 <- withEnv "OPTION_NAME" "value" $ getLexemesWith (setOptionNames os)
  lexemes1 === optionLexemes "option-name" "value"

  -- from YAML
  lexemes2 <- withConfigFile (T.unlines ["option_name:", "  - value"]) $ \path -> getLexemesWith (setOptionNames os . setConfigFilePath path)
  lexemes2 === optionLexemes "option-name" "value"

  -- from the command line
  lexemes3 <- liftIO . withArgs ["--option-name", "value"] $ getLexemesWith (setOptionNames os)
  lexemes3 === ambiguousLexemes "option-name" ["value"]

  -- with priorities
  lexemes4 <-
    withConfigFile (T.unlines ["option_name:", "  - value1"]) $ \path ->
      withEnv "OPTION_NAME" "value3" $
        withArgs ["--option-name", "value2"] $
          getLexemesWith (setOptionNames os . setConfigFilePath path)

  lexemes4 === optionLexemes "option-name" "value3"

test_collect_yaml_options = test "all paths can be retrieved from a Yaml document" $ do
  checkOptionsFrom
    [ "option_name:",
      "  - value"
    ]
    [(YamlName ["option_name"], ["value"])]

  checkOptionsFrom
    [ "section:",
      "  - option_name:",
      "    - value"
    ]
    [(YamlName ["section", "option_name"], ["value"])]

  checkOptionsFrom
    [ "- option_name:",
      "  - 10"
    ]
    [(YamlName ["option_name"], ["10"])]

  checkOptionsFrom
    [ "- option_name:",
      "    - true"
    ]
    [(YamlName ["option_name"], ["True"])]

-- * Helpers

parsers = switch @"optionName" [] <: defaults

os = getOptionNames $ make @(Parser "optionName" Bool) parsers

-- | Execute an action after writing the config file
withConfigFile :: MonadIO m => Text -> (Text -> IO a) -> m a
withConfigFile t f = do
  let configFileName = "config.yaml"
  liftIO $ P.writeFile configFileName t
  a <- liftIO (f $ toS configFileName)
  liftIO $ removeFile configFileName
  pure a

-- | Execute an action with given key/value in the environment
withEnv :: MonadIO m => Text -> Text -> IO a -> m a
withEnv key value action = liftIO $ do
  setEnv (toS key) (toS value)
  a <- action
  unsetEnv (toS key)
  pure a

-- | Check that parsing some yaml returns the expected option name/values
checkOptionsFrom ts expected = do
  let Right [yamlDoc] = Y.decode . BS.fromStrict . T.encodeUtf8 $ T.unlines ts
  let collected = collectYamlOptions yamlDoc
  collected === expected