diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Changelog
+
+## [0.0.0.0] - 2024-07-08
+
+First version
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,5 @@
+# Sydtest License
+
+Copyright (c) 2024 Tom Sydney Kerckhove
+
+See the Sydtest License at https://github.com/NorfairKing/sydtest/blob/master/sydtest/LICENSE.md for the full license text.
diff --git a/app/Main.hs b/app/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Main.hs
@@ -0,0 +1,114 @@
+{-# LANGUAGE ApplicativeDo #-}
+{-# LANGUAGE RecordWildCards #-}
+
+module Main where
+
+import Data.Text (Text)
+import OptEnvConf
+import Paths_opt_env_conf_test (version)
+
+main :: IO ()
+main = do
+  s <-
+    runSettingsParser
+      version
+      "Example opt-env-conf-based application"
+  print (s :: Instructions)
+
+data Instructions = Instructions !Settings !Dispatch
+  deriving (Show)
+
+instance HasParser Instructions where
+  settingsParser =
+    withLocalYamlConfig $
+      Instructions
+        <$> settingsParser
+        <*> settingsParser
+
+data Dispatch
+  = DispatchCreate !String
+  | DispatchRead
+  | DispatchUpdate !String !String
+  | DispatchDelete
+  deriving (Show)
+
+instance HasParser Dispatch where
+  settingsParser =
+    commands
+      [ command "create" "Create" $
+          DispatchCreate
+            <$> setting
+              [ help "The item to create",
+                reader str,
+                argument,
+                metavar "STR"
+              ],
+        command "read" "Read" $ pure DispatchRead,
+        command "update" "Update" $
+          DispatchUpdate
+            <$> setting
+              [ help "The item identifier of the item to update",
+                reader str,
+                argument,
+                metavar "STR"
+              ]
+            <*> setting
+              [ help "The contents of the item to update",
+                reader str,
+                argument,
+                metavar "STR"
+              ],
+        command "delete" "Delete" $ pure DispatchDelete
+      ]
+
+data Settings = Settings
+  { settingLogLevel :: String,
+    settingPaymentSettings :: Maybe PaymentSettings
+  }
+  deriving (Show)
+
+instance HasParser Settings where
+  settingsParser = do
+    settingLogLevel <-
+      setting
+        [ help "minimal severity of log messages",
+          reader str,
+          metavar "LOG_LEVEL",
+          name "log-level",
+          value "DEBUG"
+        ]
+    settingPaymentSettings <- optional $ subSettings "payment"
+    pure Settings {..}
+
+data PaymentSettings = PaymentSettings
+  { paymentSetPublicKey :: String,
+    paymentSetSecretKey :: Text,
+    paymentSetCurrency :: Maybe String
+  }
+  deriving (Show)
+
+instance HasParser PaymentSettings where
+  settingsParser = do
+    paymentSetPublicKey <-
+      setting
+        [ help "Public key",
+          reader str,
+          name "public-key",
+          metavar "PUBLIC_KEY"
+        ]
+    paymentSetSecretKey <-
+      mapIO readSecretTextFile $
+        filePathSetting
+          [ help "Secret key",
+            name "secret-key",
+            metavar "SECRET_KEY_FILE"
+          ]
+    paymentSetCurrency <-
+      optional $
+        setting
+          [ help "Currency",
+            reader str,
+            name "currency",
+            metavar "CURRENCY"
+          ]
+    pure PaymentSettings {..}
diff --git a/opt-env-conf-test.cabal b/opt-env-conf-test.cabal
new file mode 100644
--- /dev/null
+++ b/opt-env-conf-test.cabal
@@ -0,0 +1,268 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.36.0.
+--
+-- see: https://github.com/sol/hpack
+
+name:           opt-env-conf-test
+version:        0.0.0.0
+synopsis:       A testing companion package for opt-env-conf
+copyright:      Copyright: (c) 2024 Tom Sydney Kerckhove
+license:        OtherLicense
+license-file:   LICENSE.md
+build-type:     Simple
+extra-source-files:
+    CHANGELOG.md
+    test_resources/completion/bash-completion-script.bash
+    test_resources/completion/fish-completion-script.fish
+    test_resources/completion/zsh-completion-script.zsh
+    test_resources/docs/args/config-docs.txt
+    test_resources/docs/args/config.txt
+    test_resources/docs/args/docs.txt
+    test_resources/docs/args/env-docs.txt
+    test_resources/docs/args/env.txt
+    test_resources/docs/args/help.txt
+    test_resources/docs/args/man.txt
+    test_resources/docs/args/opt-docs.txt
+    test_resources/docs/args/opt-long.txt
+    test_resources/docs/args/opt-short.txt
+    test_resources/docs/args/reference.txt
+    test_resources/docs/args/show.txt
+    test_resources/docs/args/version.txt
+    test_resources/docs/big-config/config-docs.txt
+    test_resources/docs/big-config/config.txt
+    test_resources/docs/big-config/docs.txt
+    test_resources/docs/big-config/env-docs.txt
+    test_resources/docs/big-config/env.txt
+    test_resources/docs/big-config/help.txt
+    test_resources/docs/big-config/man.txt
+    test_resources/docs/big-config/opt-docs.txt
+    test_resources/docs/big-config/opt-long.txt
+    test_resources/docs/big-config/opt-short.txt
+    test_resources/docs/big-config/reference.txt
+    test_resources/docs/big-config/show.txt
+    test_resources/docs/big-config/version.txt
+    test_resources/docs/empty/config-docs.txt
+    test_resources/docs/empty/config.txt
+    test_resources/docs/empty/docs.txt
+    test_resources/docs/empty/env-docs.txt
+    test_resources/docs/empty/env.txt
+    test_resources/docs/empty/help.txt
+    test_resources/docs/empty/man.txt
+    test_resources/docs/empty/opt-docs.txt
+    test_resources/docs/empty/opt-long.txt
+    test_resources/docs/empty/opt-short.txt
+    test_resources/docs/empty/reference.txt
+    test_resources/docs/empty/show.txt
+    test_resources/docs/empty/version.txt
+    test_resources/docs/enable-disable/config-docs.txt
+    test_resources/docs/enable-disable/config.txt
+    test_resources/docs/enable-disable/docs.txt
+    test_resources/docs/enable-disable/env-docs.txt
+    test_resources/docs/enable-disable/env.txt
+    test_resources/docs/enable-disable/help.txt
+    test_resources/docs/enable-disable/man.txt
+    test_resources/docs/enable-disable/opt-docs.txt
+    test_resources/docs/enable-disable/opt-long.txt
+    test_resources/docs/enable-disable/opt-short.txt
+    test_resources/docs/enable-disable/reference.txt
+    test_resources/docs/enable-disable/show.txt
+    test_resources/docs/enable-disable/version.txt
+    test_resources/docs/greet/config-docs.txt
+    test_resources/docs/greet/config.txt
+    test_resources/docs/greet/docs.txt
+    test_resources/docs/greet/env-docs.txt
+    test_resources/docs/greet/env.txt
+    test_resources/docs/greet/help.txt
+    test_resources/docs/greet/man.txt
+    test_resources/docs/greet/opt-docs.txt
+    test_resources/docs/greet/opt-long.txt
+    test_resources/docs/greet/opt-short.txt
+    test_resources/docs/greet/reference.txt
+    test_resources/docs/greet/show.txt
+    test_resources/docs/greet/version.txt
+    test_resources/docs/hidden/config-docs.txt
+    test_resources/docs/hidden/config.txt
+    test_resources/docs/hidden/docs.txt
+    test_resources/docs/hidden/env-docs.txt
+    test_resources/docs/hidden/env.txt
+    test_resources/docs/hidden/help.txt
+    test_resources/docs/hidden/man.txt
+    test_resources/docs/hidden/opt-docs.txt
+    test_resources/docs/hidden/opt-long.txt
+    test_resources/docs/hidden/opt-short.txt
+    test_resources/docs/hidden/reference.txt
+    test_resources/docs/hidden/show.txt
+    test_resources/docs/hidden/version.txt
+    test_resources/docs/optional/config-docs.txt
+    test_resources/docs/optional/config.txt
+    test_resources/docs/optional/docs.txt
+    test_resources/docs/optional/env-docs.txt
+    test_resources/docs/optional/env.txt
+    test_resources/docs/optional/help.txt
+    test_resources/docs/optional/man.txt
+    test_resources/docs/optional/opt-docs.txt
+    test_resources/docs/optional/opt-long.txt
+    test_resources/docs/optional/opt-short.txt
+    test_resources/docs/optional/reference.txt
+    test_resources/docs/optional/show.txt
+    test_resources/docs/optional/version.txt
+    test_resources/docs/sub-commands/config-docs.txt
+    test_resources/docs/sub-commands/config.txt
+    test_resources/docs/sub-commands/docs.txt
+    test_resources/docs/sub-commands/env-docs.txt
+    test_resources/docs/sub-commands/env.txt
+    test_resources/docs/sub-commands/help.txt
+    test_resources/docs/sub-commands/man.txt
+    test_resources/docs/sub-commands/opt-docs.txt
+    test_resources/docs/sub-commands/opt-long.txt
+    test_resources/docs/sub-commands/opt-short.txt
+    test_resources/docs/sub-commands/reference.txt
+    test_resources/docs/sub-commands/show.txt
+    test_resources/docs/sub-commands/version.txt
+    test_resources/docs/three-commands/config-docs.txt
+    test_resources/docs/three-commands/config.txt
+    test_resources/docs/three-commands/docs.txt
+    test_resources/docs/three-commands/env-docs.txt
+    test_resources/docs/three-commands/env.txt
+    test_resources/docs/three-commands/help.txt
+    test_resources/docs/three-commands/man.txt
+    test_resources/docs/three-commands/opt-docs.txt
+    test_resources/docs/three-commands/opt-long.txt
+    test_resources/docs/three-commands/opt-short.txt
+    test_resources/docs/three-commands/reference.txt
+    test_resources/docs/three-commands/show.txt
+    test_resources/docs/three-commands/version.txt
+    test_resources/docs/verbose/config-docs.txt
+    test_resources/docs/verbose/config.txt
+    test_resources/docs/verbose/docs.txt
+    test_resources/docs/verbose/env-docs.txt
+    test_resources/docs/verbose/env.txt
+    test_resources/docs/verbose/help.txt
+    test_resources/docs/verbose/man.txt
+    test_resources/docs/verbose/opt-docs.txt
+    test_resources/docs/verbose/opt-long.txt
+    test_resources/docs/verbose/opt-short.txt
+    test_resources/docs/verbose/reference.txt
+    test_resources/docs/verbose/show.txt
+    test_resources/docs/verbose/version.txt
+    test_resources/docs/yes-no/config-docs.txt
+    test_resources/docs/yes-no/config.txt
+    test_resources/docs/yes-no/docs.txt
+    test_resources/docs/yes-no/env-docs.txt
+    test_resources/docs/yes-no/env.txt
+    test_resources/docs/yes-no/help.txt
+    test_resources/docs/yes-no/man.txt
+    test_resources/docs/yes-no/opt-docs.txt
+    test_resources/docs/yes-no/opt-long.txt
+    test_resources/docs/yes-no/opt-short.txt
+    test_resources/docs/yes-no/reference.txt
+    test_resources/docs/yes-no/show.txt
+    test_resources/docs/yes-no/version.txt
+    test_resources/error/all-or-nothing-relevant.txt
+    test_resources/error/all-or-nothing.txt
+    test_resources/error/check-failed-checkEither.txt
+    test_resources/error/check-failed-checkMaybe.txt
+    test_resources/error/empty-choice.txt
+    test_resources/error/empty.txt
+    test_resources/error/missing-argument.txt
+    test_resources/error/missing-env.txt
+    test_resources/error/missing-option.txt
+    test_resources/error/missing-options.txt
+    test_resources/error/missing-var.txt
+    test_resources/error/missing-vars.txt
+    test_resources/error/read-int-argument.txt
+    test_resources/error/read-int-option.txt
+    test_resources/error/read-int-options.txt
+    test_resources/error/required-command.txt
+    test_resources/error/some-none.txt
+    test_resources/error/unfolding-tombstone-option.txt
+    test_resources/error/unfolding-tombstone-switch.txt
+    test_resources/error/unreadable-var.txt
+    test_resources/error/unreadable-vars.txt
+    test_resources/error/unrecognised-command.txt
+    test_resources/lint/config-without-load.txt
+    test_resources/lint/dash-in-long.txt
+    test_resources/lint/dash-in-short.txt
+    test_resources/lint/empty-setting.txt
+    test_resources/lint/no-commands.txt
+    test_resources/lint/no-dashed-for-option.txt
+    test_resources/lint/no-dashed-for-switch.txt
+    test_resources/lint/no-metavar-for-argument.txt
+    test_resources/lint/no-metavar-for-env.txt
+    test_resources/lint/no-metavar-for-option.txt
+    test_resources/lint/no-reader-for-argument.txt
+    test_resources/lint/no-reader-for-env.txt
+    test_resources/lint/no-reader-for-option.txt
+    test_resources/lint/null-setting.txt
+    test_resources/lint/only-default.txt
+    test_resources/lint/unreadable-example.txt
+
+library
+  exposed-modules:
+      OptEnvConf.Args.Gen
+      OptEnvConf.EnvMap.Gen
+      OptEnvConf.Test
+  other-modules:
+      Paths_opt_env_conf_test
+  hs-source-dirs:
+      src/
+  ghc-options: -Wall
+  build-depends:
+      base <5
+    , genvalidity
+    , genvalidity-containers
+    , opt-env-conf
+    , safe-coloured-text
+    , sydtest
+    , text
+  default-language: Haskell2010
+
+executable opt-env-conf-example
+  main-is: Main.hs
+  other-modules:
+      Paths_opt_env_conf_test
+  hs-source-dirs:
+      app
+  build-depends:
+      base <5
+    , opt-env-conf
+    , text
+  default-language: Haskell2010
+
+test-suite opt-env-conf-test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  other-modules:
+      OptEnvConf.APISpec
+      OptEnvConf.ArgsSpec
+      OptEnvConf.CompletionSpec
+      OptEnvConf.EnvMapSpec
+      OptEnvConf.ErrorSpec
+      OptEnvConf.LintSpec
+      OptEnvConf.NonDetSpec
+      OptEnvConf.ReaderSpec
+      OptEnvConf.RunSpec
+      Paths_opt_env_conf_test
+  hs-source-dirs:
+      test/
+  ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
+  build-tool-depends:
+      sydtest-discover:sydtest-discover
+  build-depends:
+      QuickCheck
+    , aeson
+    , base <5
+    , containers
+    , genvalidity-aeson
+    , genvalidity-sydtest
+    , genvalidity-text
+    , mtl
+    , opt-env-conf
+    , opt-env-conf-test
+    , path
+    , pretty-show
+    , safe-coloured-text
+    , sydtest
+    , text
+  default-language: Haskell2010
diff --git a/src/OptEnvConf/Args/Gen.hs b/src/OptEnvConf/Args/Gen.hs
new file mode 100644
--- /dev/null
+++ b/src/OptEnvConf/Args/Gen.hs
@@ -0,0 +1,15 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module OptEnvConf.Args.Gen where
+
+import Data.GenValidity
+import Data.GenValidity.Containers ()
+import OptEnvConf.Args
+
+instance GenValid Dashed
+
+instance (GenValid a) => GenValid (Tomb a)
+
+instance GenValid Arg
+
+instance GenValid Args
diff --git a/src/OptEnvConf/EnvMap/Gen.hs b/src/OptEnvConf/EnvMap/Gen.hs
new file mode 100644
--- /dev/null
+++ b/src/OptEnvConf/EnvMap/Gen.hs
@@ -0,0 +1,9 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module OptEnvConf.EnvMap.Gen where
+
+import Data.GenValidity
+import Data.GenValidity.Containers ()
+import OptEnvConf.EnvMap
+
+instance GenValid EnvMap
diff --git a/src/OptEnvConf/Test.hs b/src/OptEnvConf/Test.hs
new file mode 100644
--- /dev/null
+++ b/src/OptEnvConf/Test.hs
@@ -0,0 +1,52 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
+
+module OptEnvConf.Test
+  ( settingsLintSpec,
+    parserLintSpec,
+    parserLintTest,
+    goldenSettingsReferenceDocumentationSpec,
+    goldenParserReferenceDocumentationSpec,
+    pureGoldenReferenceDocumentation,
+  )
+where
+
+import Data.Text (Text)
+import qualified Data.Text as T
+import GHC.Stack (HasCallStack, withFrozenCallStack)
+import OptEnvConf
+import OptEnvConf.Lint
+import Test.Syd
+import Text.Colour
+
+settingsLintSpec :: forall a. (HasCallStack) => (HasParser a) => Spec
+settingsLintSpec = withFrozenCallStack $ parserLintSpec (settingsParser @a)
+
+parserLintSpec :: forall a. (HasCallStack) => Parser a -> Spec
+parserLintSpec parser =
+  withFrozenCallStack $
+    specify "pass the lint test" $
+      parserLintTest parser
+
+parserLintTest :: Parser a -> IO ()
+parserLintTest parser =
+  case lintParser parser of
+    Nothing -> pure ()
+    Just errs ->
+      expectationFailure $ T.unpack $ renderChunksText With24BitColours $ renderLintErrors errs
+
+goldenSettingsReferenceDocumentationSpec :: forall a. (HasCallStack) => (HasParser a) => FilePath -> String -> Spec
+goldenSettingsReferenceDocumentationSpec path progname = withFrozenCallStack $ goldenParserReferenceDocumentationSpec (settingsParser @a) path progname
+
+goldenParserReferenceDocumentationSpec :: (HasCallStack) => Parser a -> FilePath -> String -> Spec
+goldenParserReferenceDocumentationSpec parser path progname = withFrozenCallStack $ do
+  specify "produces the same reference documentation as before" $
+    pureGoldenReferenceDocumentation path progname parser
+
+pureGoldenReferenceDocumentation :: FilePath -> String -> Parser a -> GoldenTest Text
+pureGoldenReferenceDocumentation path progname parser =
+  pureGoldenTextFile path $
+    renderChunksText With24BitColours $
+      renderReferenceDocumentation progname $
+        parserDocs parser
diff --git a/test/OptEnvConf/APISpec.hs b/test/OptEnvConf/APISpec.hs
new file mode 100644
--- /dev/null
+++ b/test/OptEnvConf/APISpec.hs
@@ -0,0 +1,312 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module OptEnvConf.APISpec (spec) where
+
+import Data.Map (Map)
+import Data.Text (Text)
+import Data.Version
+import GHC.Stack (HasCallStack, withFrozenCallStack)
+import OptEnvConf
+import OptEnvConf.Test
+import Test.Syd
+import Text.Colour
+import Text.Show.Pretty as Pretty
+
+spec :: Spec
+spec = do
+  exampleParserSpec "empty" "empty parser" emptyParser
+  exampleParserSpec "args" "args parser" argsParser
+  exampleParserSpec "optional" "optional argument" optionalParser
+  exampleParserSpec "big-config" "example with a big configuration" bigConfigParser
+  exampleParserSpec "hidden" "example with hidden settings" hiddenParser
+  exampleParserSpec "enable-disable" "enableDisableSwitch example" enableDisableParser
+  exampleParserSpec "yes-no" "yesNoSwitch example" yesNoParser
+  exampleParserSpec "verbose" "verbosity example" verboseParser
+  exampleParserSpec "greet" "hello world example" greetParser
+  exampleParserSpec "three-commands" "example with three commands" threeCommandsParser
+  exampleParserSpec "sub-commands" "example with subcommands" subCommandsParser
+
+exampleParserSpec :: (HasCallStack) => FilePath -> String -> Parser a -> Spec
+exampleParserSpec dir progDesc p = withFrozenCallStack $ describe dir $ do
+  let version = makeVersion [0, 0, 0]
+  let parser = internalParser version p
+
+  it "passes the linter" $
+    parserLintTest parser
+
+  it "shows the parser in the same way" $
+    goldenStringFile ("test_resources/docs/" <> dir <> "/show.txt") $
+      case Pretty.parseValue (showParserABit (parserEraseSrcLocs p)) of
+        Nothing -> expectationFailure "Error parsing value"
+        Just v -> pure $ Pretty.valToStr v
+
+  it "produces the same docs structure as before" $
+    pureGoldenStringFile ("test_resources/docs/" <> dir <> "/docs.txt") $
+      ppShow $
+        parserDocs p
+
+  it "produces the same opt docs structure as before" $
+    pureGoldenStringFile ("test_resources/docs/" <> dir <> "/opt-docs.txt") $
+      ppShow $
+        parserOptDocs p
+
+  it "produces the same env docs structure as before" $
+    pureGoldenStringFile ("test_resources/docs/" <> dir <> "/env-docs.txt") $
+      ppShow $
+        parserConfDocs p
+
+  it "produces the same conf docs structure as before" $
+    pureGoldenStringFile ("test_resources/docs/" <> dir <> "/config-docs.txt") $
+      ppShow $
+        parserEnvDocs p
+
+  it "documents the version page in the same way" $
+    pureGoldenChunksFile ("test_resources/docs/" <> dir <> "/version.txt") $
+      renderVersionPage dir version
+
+  it "documents the help page in the same way" $
+    pureGoldenChunksFile ("test_resources/docs/" <> dir <> "/help.txt") $
+      renderHelpPage dir progDesc $
+        parserDocs parser
+
+  it "documents the short opt parser in the same way" $
+    pureGoldenChunksFile ("test_resources/docs/" <> dir <> "/opt-short.txt") $
+      renderShortOptDocs dir $
+        parserOptDocs parser
+
+  it "documents the long opt parser in the same way" $
+    pureGoldenChunksFile ("test_resources/docs/" <> dir <> "/opt-long.txt") $
+      renderLongOptDocs $
+        parserOptDocs parser
+
+  it "documents the env parser in the same way" $
+    pureGoldenChunksFile ("test_resources/docs/" <> dir <> "/env.txt") $
+      renderEnvDocs $
+        parserEnvDocs parser
+
+  it "documents the conf parser in the same way" $
+    pureGoldenChunksFile ("test_resources/docs/" <> dir <> "/config.txt") $
+      renderConfDocs $
+        parserConfDocs parser
+
+  it "documents the man page in the same way" $
+    pureGoldenTextFile ("test_resources/docs/" <> dir <> "/man.txt") $
+      renderChunksText WithoutColours $
+        renderManPage dir version progDesc $
+          parserDocs parser
+
+  it "renders the reference documentation in the same way" $
+    pureGoldenChunksFile ("test_resources/docs/" <> dir <> "/reference.txt") $
+      renderReferenceDocumentation dir $
+        parserDocs parser
+
+pureGoldenChunksFile :: FilePath -> [Chunk] -> GoldenTest Text
+pureGoldenChunksFile fp cs =
+  pureGoldenTextFile fp $ renderChunksText With24BitColours cs
+
+data Greet = Greet !String !String !Bool
+
+greetParser :: Parser Greet
+greetParser =
+  subEnv "GREET_" $
+    withLocalYamlConfig $
+      Greet
+        <$> setting
+          [ reader str,
+            option,
+            short 'g',
+            long "greeting",
+            metavar "GREETING",
+            env "GREETING",
+            conf "greeting",
+            value "Hello",
+            help "Greeting to use"
+          ]
+        <*> setting
+          [ reader str,
+            argument,
+            help "Who to greet",
+            value "world",
+            metavar "SUBJECT"
+          ]
+        <*> setting
+          [ reader exists,
+            switch True,
+            short 'p',
+            long "polite",
+            env "POLITE",
+            conf "polite",
+            metavar "ANY",
+            value False,
+            help "Whether to be polite"
+          ]
+
+data BigConfig = BigConfig (Map String (Map String Int))
+
+bigConfigParser :: Parser BigConfig
+bigConfigParser =
+  withLocalYamlConfig $
+    BigConfig
+      <$> setting
+        [ conf "big",
+          help "multi-line config codec explanation, the same option twice."
+        ]
+
+data Args = Args [String]
+
+argsParser :: Parser Args
+argsParser =
+  Args
+    <$> many
+      ( setting
+          [ reader str,
+            argument,
+            help "Argument",
+            metavar "ARGUMENT"
+          ]
+      )
+
+data Optional = Optional (Maybe String)
+
+optionalParser :: Parser Optional
+optionalParser =
+  Optional
+    <$> optional
+      ( setting
+          [ reader str,
+            argument,
+            help "Argument",
+            metavar "ARGUMENT"
+          ]
+      )
+
+data Hidden = Hidden String
+
+hiddenParser :: Parser Hidden
+hiddenParser =
+  Hidden
+    <$> setting
+      [ reader str,
+        argument,
+        hidden,
+        metavar "STR",
+        value "default",
+        help "Example of a hidden setting"
+      ]
+
+data EnableDisable = EnableDisable Bool
+
+enableDisableParser :: Parser EnableDisable
+enableDisableParser =
+  withLocalYamlConfig $
+    EnableDisable
+      <$> enableDisableSwitch
+        True
+        [ long "example",
+          help "Example of an enable/disable switch",
+          env "EXAMPLE",
+          conf "example"
+        ]
+
+data YesNo = YesNo Bool
+
+yesNoParser :: Parser YesNo
+yesNoParser =
+  withLocalYamlConfig $
+    YesNo
+      <$> yesNoSwitch
+        True
+        [ long "example",
+          help "Example of a yes/no switch",
+          env "EXAMPLE",
+          conf "example"
+        ]
+
+data Empty = Empty
+
+emptyParser :: Parser Empty
+emptyParser =
+  pure Empty
+
+data ThreeCommands
+  = One !String
+  | Two !Int !Bool
+  | Three
+
+threeCommandsParser :: Parser ThreeCommands
+threeCommandsParser =
+  withLocalYamlConfig $
+    commands
+      [ command "one" "first" $
+          One
+            <$> setting
+              [ help "argument",
+                reader str,
+                metavar "STR",
+                argument
+              ],
+        command "two" "second" $
+          Two
+            <$> setting
+              [ help "number",
+                reader auto,
+                option,
+                metavar "INT",
+                name "number",
+                short 'n'
+              ]
+            <*> enableDisableSwitch
+              False
+              [ help "enable extra",
+                name "enable"
+              ],
+        command "three" "third" (pure Three)
+      ]
+
+data SubCommands
+  = Top !String
+  | Sub !Sub1 !Sub2
+
+subCommandsParser :: Parser SubCommands
+subCommandsParser =
+  withLocalYamlConfig $
+    commands
+      [ command "top" "command without subcommands" $
+          Top
+            <$> setting
+              [ help "name",
+                reader str,
+                metavar "NAME",
+                name "name"
+              ],
+        command "sub" "command with subcommands" $ Sub <$> sub1Parser <*> sub2Parser
+      ]
+
+data Sub1 = A | B
+
+sub1Parser :: Parser Sub1
+sub1Parser =
+  commands
+    [ command "a" "A" $ pure A,
+      command "b" "B" $ pure B
+    ]
+
+data Sub2 = C | D
+
+sub2Parser :: Parser Sub2
+sub2Parser =
+  commands
+    [ command "c" "C" $ pure C,
+      command "d" "D" $ pure D
+    ]
+
+verboseParser :: Parser Int
+verboseParser =
+  length
+    <$> many
+      ( setting
+          [ help "Verbosity level. Use multiple to increase verbosity",
+            short 'v',
+            switch ()
+          ]
+      )
diff --git a/test/OptEnvConf/ArgsSpec.hs b/test/OptEnvConf/ArgsSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/OptEnvConf/ArgsSpec.hs
@@ -0,0 +1,91 @@
+{-# LANGUAGE OverloadedLists #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module OptEnvConf.ArgsSpec (spec) where
+
+import Data.List.NonEmpty (NonEmpty (..))
+import OptEnvConf.Args
+import OptEnvConf.Args.Gen ()
+import Test.QuickCheck hiding (Args)
+import Test.Syd
+import Test.Syd.Validity
+
+spec :: Spec
+spec = do
+  describe "parseArg" $ do
+    it "produces valid args" $
+      producesValid parseArg
+    it "roundtrips with renderArg" $
+      forAllValid $ \s ->
+        renderArg (parseArg s) `shouldBe` s
+
+  describe "parseArgs" $ do
+    it "produces valid Args" $
+      producesValid parseArgs
+
+    let annoyingStrings :: Gen [String]
+        annoyingStrings = genListOf $ genListOf $ oneof [genValid, pure '-']
+    it "produces valid Argss for annoying strings" $
+      forAll annoyingStrings $
+        shouldBeValid . parseArgs
+
+    it "parses empty args as an empty arg map" $
+      parseArgs [] `shouldBe` emptyArgs
+
+  describe "renderDashed" $ do
+    it "roundtrips with parseArg for long dashed" $
+      forAllValid $ \n ->
+        parseArg (renderDashed (DashedLong n)) `shouldBe` ArgDashed True n
+
+    it "roundtrips with parseArg for short dashed" $
+      forAllValid $ \c ->
+        parseArg (renderDashed (DashedShort c)) `shouldBe` ArgDashed False (c :| [])
+
+  describe "consumeArgument" $ do
+    it "does not consume anything if there is nothing to consume" $
+      consumeArgument [] `shouldBe` []
+    it "consumes any argument if there is only one" $
+      forAllValid $ \a ->
+        consumeArgument [Live a]
+          `shouldBe` [(renderArg a, [])]
+
+  describe "consumeOption" $ do
+    it "fails to consume if there are no dasheds" $
+      forAllValid $ \as ->
+        consumeOption [] as `shouldBe` Nothing
+    it "fails to consume if there are no arguments" $
+      forAllValid $ \ds ->
+        consumeOption ds [] `shouldBe` Nothing
+    it "does not consume a mismatched option" $
+      consumeOption ["--foo"] ["--bar", "quux"] `shouldBe` Nothing
+    it "consumes a short option" $
+      consumeOption ["-f"] ["-f", "foo"] `shouldBe` Just ("foo", [Dead])
+    it "consumes a long option" $
+      consumeOption ["--foo"] ["--foo", "foo"] `shouldBe` Just ("foo", [Dead])
+    it "consumes an option at the front first" $
+      consumeOption ["-f"] ["-f", "foo", "-f", "bar"] `shouldBe` Just ("foo", [Dead, "-f", "bar"])
+    it "consumes a folded option" $
+      consumeOption ["-f"] ["-vf", "foo"] `shouldBe` Just ("foo", ["-v", Dead])
+    it "consumes a long option with an equals sign" $
+      consumeOption ["--file"] ["--file=foo.txt"] `shouldBe` Just ("foo.txt", [Dead])
+    it "consumes a short option in shorthand notation" $
+      consumeOption ["-f"] ["-ffoo.txt"] `shouldBe` Just ("foo.txt", [Dead])
+
+  describe "consumeSwitch" $ do
+    it "fails to consume if there are no dasheds" $
+      forAllValid $ \as ->
+        consumeSwitch [] as `shouldBe` Nothing
+    it "fails to consume if there are no arguments" $
+      forAllValid $ \ds ->
+        consumeSwitch ds [] `shouldBe` Nothing
+
+    it "does not consume a mismatched switch" $
+      consumeSwitch ["--foo"] ["--bar"] `shouldBe` Nothing
+    it "consumes a short switch if there are no other args" $
+      consumeSwitch ["-v"] ["-v"] `shouldBe` Just [Dead]
+    it "consumes a long switch if there are no other args" $
+      consumeSwitch ["--verbose"] ["--verbose"] `shouldBe` Just [Dead]
+    it "consumes a switch at the front first" $
+      consumeSwitch ["-a", "-b"] ["-a", "-b"] `shouldBe` Just [Dead, "-b"]
+    it "consumes a folded switch at the front first" $
+      consumeSwitch ["-a", "-b"] ["-ab"] `shouldBe` Just ["-b"]
diff --git a/test/OptEnvConf/CompletionSpec.hs b/test/OptEnvConf/CompletionSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/OptEnvConf/CompletionSpec.hs
@@ -0,0 +1,37 @@
+{-# LANGUAGE QuasiQuotes #-}
+
+module OptEnvConf.CompletionSpec (spec) where
+
+import OptEnvConf.Completion
+import OptEnvConf.Parser
+import OptEnvConf.Setting
+import Path
+import Test.Syd
+
+spec :: Spec
+spec = do
+  describe "bash" $ do
+    it "produces the same bash completion script" $
+      pureGoldenStringFile "test_resources/completion/bash-completion-script.bash" $
+        bashCompletionScript [absfile|/usr/bin/example-executable|] "example-executable"
+  describe "zsh" $ do
+    it "produces the same zsh completion script" $
+      pureGoldenStringFile "test_resources/completion/zsh-completion-script.zsh" $
+        zshCompletionScript [absfile|/usr/bin/example-executable|] "example-executable"
+  describe "fish" $ do
+    it "produces the same fish completion script" $
+      pureGoldenStringFile "test_resources/completion/fish-completion-script.fish" $
+        fishCompletionScript [absfile|/usr/bin/example-executable|] "example-executable"
+
+  describe "pureCompletionQuery" $ do
+    it "can complete a short switch from a single dash" $
+      pureCompletionQuery (setting [short 'e']) 1 ["-"]
+        `shouldBe` [Completion "-e" Nothing]
+    it "can complete a long switch from a single dash" $
+      pureCompletionQuery (setting [long "example"]) 1 ["-"]
+        `shouldBe` [Completion "--example" Nothing]
+    it "can complete a long switch from a double dash" $
+      pureCompletionQuery (setting [long "example"]) 1 ["--"]
+        `shouldBe` [Completion "--example" Nothing]
+
+    pending "can complete a long switch with an equals sign"
diff --git a/test/OptEnvConf/EnvMapSpec.hs b/test/OptEnvConf/EnvMapSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/OptEnvConf/EnvMapSpec.hs
@@ -0,0 +1,11 @@
+module OptEnvConf.EnvMapSpec (spec) where
+
+import qualified OptEnvConf.EnvMap as EM
+import Test.Syd
+import Test.Syd.Validity
+
+spec :: Spec
+spec = do
+  describe "parseEnvMap" $ do
+    it "produces valid EnvMaps" $
+      producesValid EM.parse
diff --git a/test/OptEnvConf/ErrorSpec.hs b/test/OptEnvConf/ErrorSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/OptEnvConf/ErrorSpec.hs
@@ -0,0 +1,186 @@
+module OptEnvConf.ErrorSpec (spec) where
+
+import Data.GenValidity.Aeson ()
+import Data.Text (Text)
+import GHC.Stack (HasCallStack, withFrozenCallStack)
+import OptEnvConf
+import OptEnvConf.Args as Args
+import qualified OptEnvConf.EnvMap as EnvMap
+import OptEnvConf.Error
+import Test.Syd
+import Text.Colour
+
+spec :: Spec
+spec = do
+  parseArgsErrorSpec
+    "empty"
+    (empty :: Parser String)
+    []
+  parseArgsErrorSpec
+    "missing-argument"
+    (setting [reader str, argument, help "example argument", metavar "ARGUMENT"] :: Parser String)
+    []
+  parseArgsErrorSpec
+    "missing-option"
+    (setting [reader str, option, long "foo", help "example option", metavar "FOO"] :: Parser String)
+    []
+  parseArgsErrorSpec
+    "missing-options"
+    ( (,)
+        <$> setting [reader str, option, long "foo", help "example option 1", metavar "FOO"]
+        <*> setting [reader str, option, long "bar", help "example option 2", metavar "BAR"] ::
+        Parser (String, String)
+    )
+    []
+  parseArgsErrorSpec
+    "read-int-argument"
+    (setting [argument, reader auto, help "integer option", metavar "INT"] :: Parser Int)
+    ["five"]
+  parseArgsErrorSpec
+    "read-int-option"
+    (setting [option, reader auto, long "num", help "integer option", metavar "INT"] :: Parser Int)
+    ["--num", "five"]
+  parseArgsErrorSpec
+    "read-int-options"
+    ( (,)
+        <$> setting [option, reader auto, long "foo", help "integer option 1", metavar "INT"]
+        <*> setting [option, reader auto, long "bar", help "integer option 2", metavar "INT"] ::
+        Parser (Int, Int)
+    )
+    ["--foo", "n", "--bar", "m"]
+  parseArgsErrorSpec
+    "some-none"
+    (some $ setting [reader str, argument] :: Parser [String])
+    []
+
+  parseArgsErrorSpec
+    "required-command"
+    ( commands
+        [ command "one" "first" $ pure '1',
+          command "two" "second" $ pure '2'
+        ]
+    )
+    []
+
+  parseArgsErrorSpec
+    "unrecognised-command"
+    ( commands
+        [ command "one" "first" $ pure '1',
+          command "two" "second" $ pure '2'
+        ]
+    )
+    ["three"]
+
+  parseArgsErrorSpec
+    "unfolding-tombstone-option"
+    ( (,)
+        <$> setting [option, short 'a', reader str]
+        <*> setting [option, short 'b', reader str] ::
+        Parser (String, String)
+    )
+    ["-ba", "foo", "bar"]
+
+  parseArgsErrorSpec
+    "unfolding-tombstone-switch"
+    ( (,)
+        <$> setting [switch (), short 'v']
+        <*> setting [option, short 'f', reader str] ::
+        Parser ((), String)
+    )
+    ["-fv", "foo"]
+
+  parseEnvErrorSpec
+    "missing-var"
+    (setting [reader str, env "FOO"] :: Parser String)
+    []
+  parseEnvErrorSpec
+    "missing-vars"
+    ( (,)
+        <$> setting [reader str, env "FOO"]
+        <*> setting [reader str, env "BAR"] ::
+        Parser (String, String)
+    )
+    []
+
+  parseEnvErrorSpec
+    "missing-env"
+    (setting [reader str, env "FOO"] :: Parser String)
+    []
+  parseEnvErrorSpec
+    "unreadable-var"
+    (setting [reader auto, env "FOO"] :: Parser Int)
+    [("FOO", "n")]
+  parseEnvErrorSpec
+    "unreadable-vars"
+    ( (,)
+        <$> setting [reader auto, env "FOO"]
+        <*> setting [reader auto, env "BAR"] ::
+        Parser (Int, Int)
+    )
+    [("FOO", "n"), ("BAR", "m")]
+
+  parseArgsErrorSpec
+    "empty-choice"
+    (choice [] :: Parser String)
+    []
+
+  parseArgsErrorSpec
+    "check-failed-checkMaybe"
+    (checkMaybe (const Nothing) (setting [argument, reader str, env "FOO", value "bar"]) :: Parser String)
+    []
+  parseArgsErrorSpec
+    "check-failed-checkEither"
+    (checkEither (const $ Left "example error") (setting [argument, reader str, env "FOO", value "bar"]) :: Parser String)
+    []
+
+  parseArgsErrorSpec
+    "all-or-nothing"
+    ( choice
+        [ allOrNothing $
+            (,)
+              <$> setting [option, long "foo", reader auto, help "This one will exist", metavar "CHAR"]
+              <*> setting [option, long "bar", reader auto, help "This one will not exist", metavar "CHAR"],
+          pure ('a', 'b')
+        ]
+    )
+    ["--foo", "'a'"]
+  parseArgsErrorSpec
+    "all-or-nothing-relevant"
+    ( (,)
+        <$> choice
+          [ allOrNothing $
+              (,)
+                <$> setting [option, long "foo", reader auto, help "This one will exist", metavar "CHAR"]
+                <*> setting [option, long "bar", reader auto, help "This one will not exist", metavar "CHAR"],
+            pure ('a', 'b')
+          ]
+        <*> choice [] ::
+        Parser ((Char, Char), Char)
+    )
+    ["--foo", "'a'"]
+
+parseArgsErrorSpec :: (HasCallStack) => (Show a) => FilePath -> Parser a -> [String] -> Spec
+parseArgsErrorSpec fp p args =
+  withFrozenCallStack $
+    it (unwords ["renders the", fp, "error the same as before"]) $
+      let path = "test_resources/error/" <> fp <> ".txt"
+       in goldenChunksFile path $ do
+            errOrResult <- runParserOn p (parseArgs args) EnvMap.empty Nothing
+            case errOrResult of
+              Right a -> expectationFailure $ unlines ["Should not have been able to parse, but did and got:", show a]
+              Left errs -> pure $ renderErrors $ eraseErrorSrcLocs errs
+
+parseEnvErrorSpec :: (HasCallStack) => (Show a) => FilePath -> Parser a -> [(String, String)] -> Spec
+parseEnvErrorSpec fp p e =
+  withFrozenCallStack $
+    it (unwords ["renders the", fp, "error the same as before"]) $
+      let path = "test_resources/error/" <> fp <> ".txt"
+       in goldenChunksFile path $ do
+            errOrResult <- runParserOn p emptyArgs (EnvMap.parse e) Nothing
+            case errOrResult of
+              Right a -> expectationFailure $ unlines ["Should not have been able to parse, but did and got:", show a]
+              Left errs -> pure $ renderErrors $ eraseErrorSrcLocs errs
+
+goldenChunksFile :: FilePath -> IO [Chunk] -> GoldenTest Text
+goldenChunksFile fp cs =
+  goldenTextFile fp $ renderChunksText With24BitColours <$> cs
diff --git a/test/OptEnvConf/LintSpec.hs b/test/OptEnvConf/LintSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/OptEnvConf/LintSpec.hs
@@ -0,0 +1,148 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module OptEnvConf.LintSpec (spec) where
+
+import Data.Text (Text)
+import GHC.Stack (HasCallStack, withFrozenCallStack)
+import OptEnvConf
+import OptEnvConf.Lint
+import Test.Syd
+import Text.Colour
+
+spec :: Spec
+spec = do
+  goldenLintTest
+    "null-setting"
+    (setting [])
+  goldenLintTest
+    "empty-setting"
+    ( setting
+        [ help "Empty setting"
+        ]
+    )
+  goldenLintTest
+    "only-default"
+    ( setting
+        [ help "Only a default value",
+          value ()
+        ]
+    )
+  goldenLintTest
+    "dash-in-short"
+    ( setting
+        [ help "Dash in a 'short'",
+          switch True,
+          short '-'
+        ]
+    )
+  goldenLintTest
+    "dash-in-long"
+    ( setting
+        [ help "Dash in a 'long'",
+          switch True,
+          long "--switch"
+        ]
+    )
+  goldenLintTest
+    "no-reader-for-argument"
+    ( setting
+        [ argument,
+          metavar "STR",
+          help "Example"
+        ]
+    )
+  goldenLintTest
+    "no-metavar-for-argument"
+    ( setting
+        [ reader str,
+          argument,
+          help "Example"
+        ] ::
+        Parser String
+    )
+  goldenLintTest
+    "no-reader-for-option"
+    ( setting
+        [ option,
+          long "example",
+          metavar "STR",
+          help "Example"
+        ]
+    )
+  goldenLintTest
+    "no-dashed-for-option"
+    ( setting
+        [ reader str,
+          option,
+          metavar "STR",
+          help "Example"
+        ] ::
+        Parser String
+    )
+  goldenLintTest
+    "no-metavar-for-option"
+    ( setting
+        [ reader str,
+          long "example",
+          option,
+          help "Example"
+        ] ::
+        Parser String
+    )
+  goldenLintTest
+    "no-dashed-for-switch"
+    ( setting
+        [ switch True,
+          help "Example"
+        ]
+    )
+  goldenLintTest
+    "no-reader-for-env"
+    ( setting
+        [ env "EXAMPLE",
+          help "Example"
+        ]
+    )
+  goldenLintTest
+    "no-metavar-for-env"
+    ( setting
+        [ reader str,
+          env "EXAMPLE",
+          help "Example"
+        ] ::
+        Parser String
+    )
+  goldenLintTest
+    "no-commands"
+    (commands [])
+  goldenLintTest
+    "config-without-load"
+    ( setting
+        [ help "Config parser with no way to load a config.",
+          conf "example"
+        ] ::
+        Parser String
+    )
+  goldenLintTest
+    "unreadable-example"
+    ( setting
+        [ help "Example value isn't readable",
+          argument,
+          reader auto,
+          example "NaN",
+          metavar "INT"
+        ] ::
+        Parser Int
+    )
+
+goldenLintTest :: (HasCallStack) => FilePath -> Parser a -> Spec
+goldenLintTest fp parser = withFrozenCallStack $
+  it "produces the same lint error for this parser" $
+    goldenChunksFile ("test_resources/lint/" <> fp <> ".txt") $ do
+      case lintParser parser of
+        Nothing -> expectationFailure "Parser was valid."
+        Just errs -> pure $ renderLintErrors errs
+
+goldenChunksFile :: FilePath -> IO [Chunk] -> GoldenTest Text
+goldenChunksFile fp cs =
+  goldenTextFile fp $ renderChunksText With24BitColours <$> cs
diff --git a/test/OptEnvConf/NonDetSpec.hs b/test/OptEnvConf/NonDetSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/OptEnvConf/NonDetSpec.hs
@@ -0,0 +1,44 @@
+{-# LANGUAGE ApplicativeDo #-}
+
+module OptEnvConf.NonDetSpec (spec) where
+
+import Control.Applicative
+import Control.Monad
+import Control.Monad.Trans
+import OptEnvConf.NonDet
+import Test.Syd
+
+spec :: Spec
+spec = do
+  describe "runNonDet" $ do
+    it "can guard against previous values" $
+      runNonDet
+        ( do
+            a <- liftNonDetTList [1, 2 :: Int]
+            b <- liftNonDetTList [3, 4]
+            guard $ even $ a + b
+            pure (a, b)
+        )
+        `shouldBe` [(1, 3), (2, 4)]
+    it "can recover from failures with <|>" $
+      runNonDet
+        ( do
+            a <- liftNonDetTList [1, 2 :: Int]
+            f <- liftNonDetTList [even] <|> liftNonDetTList [odd]
+            guard $ f a
+            pure a
+        )
+        `shouldBe` [1, 2]
+
+  describe "runNonDetT" $ do
+    it "can recover from underlying errors" $ do
+      let f :: NonDetT (Either String) Int
+          f = do
+            i <- liftNonDetTList [1, 2]
+            if odd i
+              then do
+                () <- empty
+                lift (Left "err")
+              else pure i
+
+      runNonDetT f `shouldBe` Right [2]
diff --git a/test/OptEnvConf/ReaderSpec.hs b/test/OptEnvConf/ReaderSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/OptEnvConf/ReaderSpec.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module OptEnvConf.ReaderSpec (spec) where
+
+import Data.GenValidity.Text ()
+import Data.List.NonEmpty (NonEmpty (..))
+import OptEnvConf.Reader
+import Test.Syd
+import Test.Syd.Validity
+
+spec :: Spec
+spec = do
+  describe "renderCommaSeparated" $
+    it "escapes commas and backslashes" $
+      renderCommaSeparated ("hi" :| [",", "\\", "ho"])
+        `shouldBe` "hi,\\,,\\\\,ho"
+
+  describe "parseCommaSeparated" $ do
+    it "roundtrips with renderCommaSeparated starting from Strings" $
+      forAllValid $ \s ->
+        renderCommaSeparated (parseCommaSeparated s)
+          `shouldBe` s
+    it "roundtrips with renderCommaSeparated starting from lists" $
+      forAllValid $ \l ->
+        parseCommaSeparated (renderCommaSeparated l) `shouldBe` l
+
+  describe "commaSeparated" $ do
+    pure ()
diff --git a/test/OptEnvConf/RunSpec.hs b/test/OptEnvConf/RunSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/OptEnvConf/RunSpec.hs
@@ -0,0 +1,630 @@
+{-# LANGUAGE LambdaCase #-}
+
+module OptEnvConf.RunSpec (spec) where
+
+import Control.Applicative
+import Data.Aeson as JSON (Object, Value (Null), toJSON)
+import qualified Data.Aeson.Key as Key
+import qualified Data.Aeson.KeyMap as KeyMap
+import Data.GenValidity.Aeson ()
+import Data.List.NonEmpty (NonEmpty (..))
+import qualified Data.List.NonEmpty as NE
+import Data.Text (Text)
+import qualified Data.Text as T
+import GHC.Stack (HasCallStack, withFrozenCallStack)
+import OptEnvConf
+import OptEnvConf.Args as Args
+import OptEnvConf.Args.Gen ()
+import OptEnvConf.EnvMap (EnvMap (..))
+import qualified OptEnvConf.EnvMap as EnvMap
+import OptEnvConf.EnvMap.Gen ()
+import OptEnvConf.Error
+import Test.Syd
+import Test.Syd.Validity
+import Text.Colour
+
+spec :: Spec
+spec = do
+  describe "runParser" $ do
+    describe "pure" $ do
+      it "can parse a pure value from anything" $
+        forAllValid $ \args ->
+          forAllValid $ \e ->
+            forAllValid $ \mConf ->
+              forAllValid $ \expected ->
+                shouldParse (pure expected) args e mConf (expected :: Int)
+
+    describe "fmap" $ do
+      it "can parse a mapped value from anything" $
+        forAllValid $ \args ->
+          forAllValid $ \e ->
+            forAllValid $ \mConf ->
+              forAllValid $ \i -> do
+                let expected = succ i
+                shouldParse (fmap succ $ pure i) args e mConf (expected :: Int)
+
+    describe "<*>" $ do
+      it "can parse two values with ap" $
+        forAllValid $ \args ->
+          forAllValid $ \e ->
+            forAllValid $ \mConf ->
+              forAllValid $ \i -> do
+                let p = (,) <$> pure (succ i) <*> pure i
+                let expected = (succ i, i :: Int)
+                shouldParse p args e mConf expected
+
+    describe "Select" $ do
+      it "can use the second parser with select" $
+        forAllValid $ \args ->
+          forAllValid $ \e ->
+            forAllValid $ \mConf ->
+              forAllValid $ \i -> do
+                let p = select (pure (Left i :: Either Int Int)) (pure succ)
+                let expected = succ i
+                shouldParse p args e mConf expected
+
+      it "can avoid the second parser with select" $
+        forAllValid $ \args ->
+          forAllValid $ \e ->
+            forAllValid $ \mConf ->
+              forAllValid $ \i -> do
+                let p = select (pure (Right i :: Either Int Int)) (pure succ)
+                let expected = i
+                shouldParse p args e mConf expected
+
+    describe "Empty" $ do
+      it "can fail to parse an empty value" $
+        forAllValid $ \args ->
+          forAllValid $ \e ->
+            forAllValid $ \mConf -> do
+              let p = empty :: Parser Int
+              shouldFail p args e mConf $ \case
+                ParseErrorEmpty :| [] -> True
+                _ -> False
+
+    describe "Alt" $ do
+      it "can parse a Left value with Alt" $
+        forAllValid $ \args ->
+          forAllValid $ \e ->
+            forAllValid $ \mConf ->
+              forAllValid $ \i -> do
+                let p = (Left <$> pure i) <|> (Right <$> pure (succ i))
+                let expected = Left (i :: Int)
+                shouldParse p args e mConf expected
+
+      it "can parse a Right value with Alt" $
+        forAllValid $ \args ->
+          forAllValid $ \e ->
+            forAllValid $ \mConf ->
+              forAllValid $ \i -> do
+                let p = empty `ParserAlt` (Right <$> pure i)
+                let expected = Right (i :: Int) :: Either Int Int
+                shouldParse p args e mConf expected
+
+    describe "Many" $ do
+      it "can pass many args" $
+        forAllValid $ \e ->
+          forAllValid $ \mConf ->
+            forAllValid $ \ls -> do
+              let args = emptyArgs {unArgs = map (Live . ArgPlain) ls}
+              let p = many $ setting [reader str, argument]
+              let expected = ls
+              shouldParse p args e mConf expected
+
+    describe "Some" $ do
+      it "fails to parse zero args" $
+        forAllValid $ \e ->
+          forAllValid $ \mConf -> do
+            let args = emptyArgs {unArgs = []}
+            let p = some $ setting [reader str, argument] :: Parser [String]
+            shouldFail p args e mConf $ \case
+              ParseErrorMissingArgument _ :| [] -> True
+              _ -> False
+
+      it "can parse some args" $
+        forAllValid $ \e ->
+          forAllValid $ \mConf ->
+            forAllValid $ \ls -> do
+              let args = emptyArgs {unArgs = map (Live . ArgPlain) (NE.toList ls)}
+              let p = some $ setting [reader str, argument]
+              let expected = NE.toList ls
+              shouldParse p args e mConf expected
+
+    describe "MapIO" $ do
+      it "can run an IO action on the result of a parser" $
+        forAllValid $ \args ->
+          forAllValid $ \e ->
+            forAllValid $ \mConf ->
+              forAllValid $ \i -> do
+                let p = mapIO (pure . succ) (pure (i :: Int))
+                let expected = succ i
+                shouldParse p args e mConf expected
+
+    describe "WithConfig" $ do
+      it "can replace the config object" $
+        forAllValid $ \args ->
+          forAllValid $ \e ->
+            forAllValid $ \c1 ->
+              forAllValid $ \c2' ->
+                forAllValid $ \(key, val) -> do
+                  let c2 = KeyMap.insert key (toJSON val) c2'
+                  let p =
+                        withConfig (pure (Just c2)) $
+                          setting [conf (Key.toString key)]
+                  let expected = val :: Text
+                  shouldParse p args e (Just c1) expected
+
+    describe "subArgs" $ do
+      it "can prefix a switch parser" $
+        forAllValid $ \a' ->
+          forAllValid $ \e ->
+            forAllValid $ \mConf ->
+              forAllValid $ \prefix ->
+                forAllValid $ \(key, val) -> do
+                  let prefixedKey = Args.prefixDashed prefix (DashedLong key)
+                  let a = a' {unArgs = Live (Args.renderDashedArg prefixedKey) : unArgs a'}
+                  let p =
+                        subArgs prefix $
+                          setting
+                            [ reader str,
+                              switch val,
+                              long (NE.toList key)
+                            ]
+                  let expected = val :: String
+                  shouldParse p a e mConf expected
+
+      it "can prefix an option parser" $
+        forAllValid $ \a' ->
+          forAllValid $ \e ->
+            forAllValid $ \mConf ->
+              forAllValid $ \prefix ->
+                forAllValid $ \(key, val) -> do
+                  let prefixedKey = Args.prefixDashed prefix (DashedLong key)
+                  let a = a' {unArgs = Live (Args.renderDashedArg prefixedKey) : Live (ArgPlain val) : unArgs a'}
+                  let p =
+                        subArgs prefix $
+                          setting
+                            [ reader str,
+                              option,
+                              long (NE.toList key)
+                            ]
+                  let expected = val
+                  shouldParse p a e mConf expected
+
+    describe "subEnv" $ do
+      it "can prefix an env var parser" $
+        forAllValid $ \args ->
+          forAllValid $ \e' ->
+            forAllValid $ \mConf ->
+              forAllValid $ \prefix ->
+                forAllValid $ \(key, val) -> do
+                  let prefixedKey = prefix <> key
+                  let e = EnvMap.insert prefixedKey val e'
+                  let p = subEnv prefix $ setting [reader str, env key]
+                  let expected = val
+                  shouldParse p args e mConf expected
+
+    describe "subConfig" $ do
+      it "can prefix a conf val parser" $
+        forAllValid $ \args ->
+          forAllValid $ \e ->
+            forAllValid $ \c' ->
+              forAllValid $ \prefix ->
+                forAllValid $ \(key, val) -> do
+                  let c = KeyMap.insert prefix (toJSON (KeyMap.singleton key (toJSON val))) c'
+                  let p =
+                        subConfig (Key.toString prefix) $
+                          setting [conf (Key.toString key)]
+                  let expected = val :: Text
+                  shouldParse p args e (Just c) expected
+
+    describe "Setting" $ do
+      it "can parse a single arg" $
+        forAllValid $ \e ->
+          forAllValid $ \mConf ->
+            forAllValid $ \arg -> do
+              let args = emptyArgs {unArgs = [Live (ArgPlain arg)]}
+              let p = setting [reader str, argument]
+              let expected = arg
+              shouldParse p args e mConf expected
+
+      it "can parse a single option" $
+        forAllValid $ \e ->
+          forAllValid $ \mConf ->
+            forAllValid $ \(l, r) -> do
+              let args =
+                    emptyArgs
+                      { unArgs =
+                          [ Live (Args.renderDashedArg (DashedLong l)),
+                            Live (ArgPlain r)
+                          ]
+                      }
+              let p = setting [reader str, option, long $ NE.toList l]
+              let expected = r
+              shouldParse p args e mConf expected
+
+      it "can parse a many of the same option" $
+        forAllValid $ \e ->
+          forAllValid $ \mConf ->
+            forAllValid $ \(l, rs) -> do
+              let args =
+                    emptyArgs
+                      { unArgs =
+                          concatMap
+                            ( \v ->
+                                [ Live (Args.renderDashedArg (DashedLong l)),
+                                  Live (ArgPlain v)
+                                ]
+                            )
+                            rs
+                      }
+              let p = many $ setting [reader str, option, long $ NE.toList l]
+              let expected = rs :: [String]
+              shouldParse p args e mConf expected
+
+      it "can parse a single env var" $
+        forAllValid $ \args ->
+          forAllValid $ \e' ->
+            forAllValid $ \mConf ->
+              forAllValid $ \(key, val) -> do
+                let e = EnvMap.insert key val e'
+                let p = setting [reader str, env key]
+                let expected = val
+                shouldParse p args e mConf expected
+
+      it "can parse a single config value" $
+        forAllValid $ \args ->
+          forAllValid $ \e ->
+            forAllValid $ \c' ->
+              forAllValid $ \(key, val) -> do
+                let c = KeyMap.insert key (toJSON val) c'
+                let p = setting [conf (Key.toString key)]
+                let expected = val :: Text
+                shouldParse p args e (Just c) expected
+
+      it "parses Null as the default value" $
+        forAllValid $ \args ->
+          forAllValid $ \e ->
+            forAllValid $ \c' ->
+              forAllValid $ \key -> do
+                let c = KeyMap.insert key JSON.Null c'
+                let defaultVal = "hi"
+                let p = setting [conf (Key.toString key), value defaultVal]
+                let expected = defaultVal
+                shouldParse p args e (Just c) expected
+
+    describe "Unit tests" $ do
+      argParseSpec
+        ["--foo", "bar"]
+        (setting [reader str, option, long "foo"])
+        "bar"
+      argParseSpec
+        ["--foo", "bar"]
+        (many $ setting [reader str, option, long "foo"])
+        ["bar"]
+      argParseSpec
+        ["--foo", "bar", "--foo", "quux"]
+        (many $ setting [reader str, option, long "foo"])
+        ["bar", "quux"]
+      argParseSpec
+        ["--foo", "bar", "-f", "quux"]
+        (many $ setting [reader str, option, short 'f', long "foo"])
+        ["bar", "quux"]
+      argParseSpec
+        ["-f", "bar", "--foo", "quux"]
+        (many $ setting [reader str, option, short 'f', long "foo"])
+        ["bar", "quux"]
+
+      -- Switch before argument
+      argParseSpec
+        ["--foo", "bar"]
+        ((,) <$> setting [switch True, long "foo"] <*> setting [reader str, argument])
+        (True, "bar")
+
+      -- Note that this could also be parsed as (False, "--foo") with a
+      -- leftover argument but somehow that's not what we want.
+      -- (Maybe we could "just" disallow extra arguments while parsing?
+      -- No because then "--help" doesn't work.)
+      argParseSpec
+        ["--foo", "bar"]
+        ((,) <$> setting [switch True, long "foo", value False] <*> setting [reader str, argument])
+        (True, "bar")
+
+      -- Switch before argument, but defined after
+      argParseSpec
+        ["--foo", "bar"]
+        ((,) <$> setting [reader str, argument] <*> setting [switch True, long "foo"])
+        ("bar", True)
+
+      -- Dashed as argument
+      -- This example shows that we can't just skip dasheds when looking for
+      -- arguments.
+      argParseSpec
+        ["--foo", "bar"]
+        ((,) <$> setting [reader str, argument] <*> setting [reader str, argument])
+        ("--foo", "bar")
+
+      -- Dashed as value for an option
+      -- This example shows that we can't "just" treat any argument with dashed
+      -- as an option key or switch.
+      -- They could be a value.
+      argParseSpec
+        ["--foo", "--bar"]
+        (setting [reader str, option, long "foo"])
+        "--bar"
+
+      -- Short dashed as a value for an option
+      -- This example shows that we can't "just" unfold combined short options.
+      -- They could be a value.
+      argParseSpec
+        ["--foo", "-dfu"]
+        (setting [reader str, option, long "foo"])
+        "-dfu"
+
+      -- Here an argument has a value that looks like a command name but
+      -- should still be treated as an argument.
+      argParseSpec
+        ["command", "arg"]
+        ( (,)
+            <$> setting [reader str, argument]
+            <*> commands
+              [ command "command" "command" (pure '1'),
+                command "arg" "command" (pure '2')
+              ]
+        )
+        ("command", '2')
+
+      -- Same as above but with an option instead of an argument
+      argParseSpec
+        ["--option", "command", "arg"]
+        ( (,)
+            <$> setting [reader str, option, long "option"]
+            <*> commands
+              [ command "command" "command" (pure '1'),
+                command "arg" "command" (pure '2')
+              ]
+        )
+        ("command", '2')
+
+      -- Unfolding switches
+      argParseSpecs
+        ( length
+            <$> many
+              ( setting
+                  [ help "verbosity",
+                    switch (),
+                    long "verbose",
+                    short 'v'
+                  ]
+              )
+        )
+        [ ([], 0),
+          (["-v"], 1),
+          (["--verbose"], 1),
+          (["-v", "-v"], 2),
+          (["-v", "--verbose"], 2),
+          (["-vv"], 2),
+          (["-vv", "--verbose"], 3),
+          (["-vv", "--verbose", "-v"], 4)
+        ]
+
+      -- Unfolding short options as well
+      argParseSpecs
+        ( (,)
+            <$> ( length
+                    <$> many
+                      ( setting
+                          [ help "verbosity",
+                            switch (),
+                            short 'v'
+                          ]
+                      )
+                )
+            <*> setting
+              [ reader str,
+                option,
+                short 'f',
+                example ("file" :: String)
+              ]
+        )
+        [ (["-f", "foo"], (0, "foo")),
+          (["-v", "-f", "foo"], (1, "foo")),
+          (["-vf", "foo", "-v"], (2, "foo")),
+          (["-vvf", "foo"], (2, "foo")),
+          (["-vvf", "foo", "-v"], (3, "foo"))
+        ]
+
+      -- Unfolding short switches
+      argParseSpecs
+        ( (,)
+            <$> many
+              ( setting
+                  [ reader str,
+                    option,
+                    long "file",
+                    short 'f'
+                  ]
+              )
+            <*> ( length
+                    <$> many
+                      ( setting
+                          [ help "verbosity",
+                            switch (),
+                            short 'v'
+                          ]
+                      )
+                )
+        )
+        [ ([], ([], 0)),
+          (["--file", "foo", "-v"], (["foo"], 1)),
+          (["-vf", "foo"], (["foo"], 1))
+        ]
+      -- Equals version of long option
+      argParseSpecs
+        ( setting
+            [ option,
+              reader str,
+              long "file"
+            ]
+        )
+        [ (["--file", "foo"], "foo"),
+          (["--file=foo"], "foo")
+        ]
+
+      -- Shorthand version of short option
+      argParseSpecs
+        ( setting
+            [ option,
+              reader str,
+              short 'f'
+            ]
+        )
+        [ (["-f", "foo"], "foo"),
+          (["-ffoo"], "foo")
+        ]
+
+      argParseSpecs
+        (enableDisableSwitch True [long "example", env "EXAMPLE", conf "example"])
+        [ ([], True),
+          (["--enable-example"], True),
+          (["--disable-example"], False)
+        ]
+
+      argParseSpecs
+        (enableDisableSwitch False [long "example", env "EXAMPLE", conf "example"])
+        [ ([], False),
+          (["--enable-example"], True),
+          (["--disable-example"], False)
+        ]
+
+      envParseSpecs
+        (enableDisableSwitch True [long "example", env "EXAMPLE", env "ALTERNATIVE", conf "example"])
+        [ ([], True),
+          ([("EXAMPLE", "False")], False),
+          ([("ALTERNATIVE", "False")], False),
+          ([("EXAMPLE", "True")], True),
+          ([("ALTERNATIVE", "True")], True)
+        ]
+
+      envParseSpecs
+        (enableDisableSwitch False [long "example", env "EXAMPLE", env "ALTERNATIVE", conf "example"])
+        [ ([], False),
+          ([("EXAMPLE", "True")], True),
+          ([("ALTERNATIVE", "True")], True),
+          ([("EXAMPLE", "False")], False),
+          ([("ALTERNATIVE", "False")], False)
+        ]
+
+      argParseSpecs
+        ( commands
+            [ command "one" "first" $ pure '1',
+              command "two" "second" $ pure '2'
+            ]
+        )
+        [ (["one"], '1'),
+          (["two"], '2')
+        ]
+
+      argParseSpecs
+        ((Left <$> setting [switch True, long "bash-completion-script"]) <|> (Right <$> setting [reader str, argument]))
+        [ (["--bash-completion-script"], Left True),
+          (["arg"], Right "arg")
+        ]
+      argParseSpecs
+        ((Left <$> setting [switch True, long "bash-completion-script"]) <|> (Right <$> optional (setting [reader str, argument])))
+        [ (["--bash-completion-script"], Left True),
+          (["arg"], Right (Just "arg"))
+        ]
+
+      argParseSpecs
+        ( optional
+            ( allOrNothing
+                ( (,)
+                    <$> setting [reader str, option, long "foo"]
+                    <*> optional (setting [reader str, option, long "bar"])
+                )
+            ) ::
+            Parser (Maybe (String, Maybe String))
+        )
+        [ ([], Nothing),
+          (["--foo", "foo"], Just ("foo", Nothing))
+        ]
+      -- Default values should not count as parsed:
+      argParseSpecs
+        ( choice
+            [ allOrNothing $
+                (,)
+                  <$> setting [option, long "foo", reader auto, help "This one will exist", metavar "CHAR", value 'c']
+                  <*> setting [option, long "bar", reader auto, help "This one will not exist", metavar "CHAR"],
+              pure ('a', 'b')
+            ]
+        )
+        [ ([], ('a', 'b')),
+          (["--foo", "'c'", "--bar", "'d'"], ('c', 'd'))
+        ]
+
+      argParseSpecs
+        ( (,)
+            <$> setting [option, long "before", reader auto, help "before", metavar "CHAR"]
+            <*> optional
+              ( allOrNothing $
+                  (,)
+                    <$> setting [option, long "baz", reader auto, help "This one will exist", metavar "CHAR"]
+                    <*> setting [option, long "quux", reader auto, help "This one will not exist", metavar "CHAR"]
+              ) ::
+            Parser (Char, Maybe (Char, Char))
+        )
+        [ (["--before", "'m'"], ('m', Nothing))
+        ]
+
+argParseSpecs :: (HasCallStack) => (Show a, Eq a) => Parser a -> [([String], a)] -> Spec
+argParseSpecs p table = withFrozenCallStack $ mapM_ (\(args, result) -> argParseSpec args p result) table
+
+argParseSpec :: (HasCallStack) => (Show a, Eq a) => [String] -> Parser a -> a -> Spec
+argParseSpec args p expected = withFrozenCallStack $ do
+  it (unwords ["parses", show args, "as", show expected]) $ do
+    let argMap = parseArgs args
+    errOrRes <- runParserOn p argMap EnvMap.empty Nothing
+    case errOrRes of
+      Left err -> expectationFailure $ T.unpack $ renderChunksText With24BitColours $ renderErrors err
+      Right actual -> actual `shouldBe` expected
+
+envParseSpecs :: (HasCallStack) => (Show a, Eq a) => Parser a -> [([(String, String)], a)] -> Spec
+envParseSpecs p table = withFrozenCallStack $ mapM_ (\(envs, result) -> envParseSpec envs p result) table
+
+envParseSpec :: (HasCallStack) => (Show a, Eq a) => [(String, String)] -> Parser a -> a -> Spec
+envParseSpec envVars p expected = withFrozenCallStack $ do
+  it (unwords ["parses", show envVars, "as", show expected]) $ do
+    let envMap = EnvMap.parse envVars
+    errOrRes <- runParserOn p emptyArgs envMap Nothing
+    case errOrRes of
+      Left err -> expectationFailure $ T.unpack $ renderChunksText With24BitColours $ renderErrors err
+      Right actual -> actual `shouldBe` expected
+
+shouldParse ::
+  (Show a, Eq a) =>
+  Parser a ->
+  Args ->
+  EnvMap ->
+  Maybe JSON.Object ->
+  a ->
+  IO ()
+shouldParse p args e mConf expected = do
+  errOrRes <- runParserOn p args e mConf
+  context (showParserABit p) $ case errOrRes of
+    Left errs -> expectationFailure $ T.unpack $ renderChunksText With24BitColours $ renderErrors errs
+    Right actual -> actual `shouldBe` expected
+
+shouldFail ::
+  (Show a) =>
+  Parser a ->
+  Args ->
+  EnvMap ->
+  Maybe JSON.Object ->
+  (NonEmpty ParseErrorMessage -> Bool) ->
+  IO ()
+shouldFail p args e mConf isExpected = do
+  errOrRes <- runParserOn p args e mConf
+  case errOrRes of
+    Left errs -> NE.map parseErrorMessage errs `shouldSatisfy` isExpected
+    Right actual -> expectationFailure $ show actual
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF sydtest-discover #-}
diff --git a/test_resources/completion/bash-completion-script.bash b/test_resources/completion/bash-completion-script.bash
new file mode 100644
--- /dev/null
+++ b/test_resources/completion/bash-completion-script.bash
@@ -0,0 +1,16 @@
+_opt_env_conf_completion_example_executable()
+{
+    local CMDLINE
+    local IFS=$'\n'
+    CMDLINE=(--query-opt-env-conf-completion)
+    CMDLINE+=(--completion-index $COMP_CWORD)
+
+    for arg in ${COMP_WORDS[@]}; do
+        CMDLINE=(${CMDLINE[@]} --completion-word $arg)
+    done
+
+    COMPREPLY=( $(/usr/bin/example-executable "${CMDLINE[@]}") )
+    echo "${COMPREPLY[@]}" > hm.log
+}
+
+complete -o filenames -F _opt_env_conf_completion_example_executable example-executable
diff --git a/test_resources/completion/fish-completion-script.fish b/test_resources/completion/fish-completion-script.fish
new file mode 100644
--- /dev/null
+++ b/test_resources/completion/fish-completion-script.fish
@@ -0,0 +1,19 @@
+ function _opt_env_conf_completion_example_executable
+    set -l cl (commandline --tokenize --current-process)
+    # Hack around fish issue #3934
+    set -l cn (commandline --tokenize --cut-at-cursor --current-process)
+    set -l cn (count $cn)
+    set -l tmpline --query-opt-env-conf-completion --completion-enriched --completion-index $cn
+    for arg in $cl
+      set tmpline $tmpline --completion-word $arg
+    end
+    for opt in (/usr/bin/example-executable $tmpline)
+      if test -d $opt
+        echo -E "$opt/"
+      else
+        echo -E "$opt"
+      end
+    end
+end
+
+complete --no-files --command /usr/bin/example-executable --arguments '(_opt_env_conf_completion_example_executable)'
diff --git a/test_resources/completion/zsh-completion-script.zsh b/test_resources/completion/zsh-completion-script.zsh
new file mode 100644
--- /dev/null
+++ b/test_resources/completion/zsh-completion-script.zsh
@@ -0,0 +1,32 @@
+#compdef example-executable
+
+local request
+local completions
+local word
+local index=$((CURRENT - 1))
+
+request=(--query-opt-env-conf-completion --completion-enriched --completion-index $index)
+for arg in ${words[@]}; do
+  request=(${request[@]} --completion-word $arg)
+done
+
+IFS=$'\n' completions=($( /usr/bin/example-executable "${request[@]}" ))
+
+for word in $completions; do
+  local -a parts
+
+  # Split the line at a tab if there is one.
+  IFS=$'\t' parts=($( echo $word ))
+
+  if [[ -n $parts[2] ]]; then
+     if [[ $word[1] == "-" ]]; then
+       local desc=("$parts[1] ($parts[2])")
+       compadd -d desc -- $parts[1]
+     else
+       local desc=($(print -f  "%-019s -- %s" $parts[1] $parts[2]))
+       compadd -l -d desc -- $parts[1]
+     fi
+  else
+    compadd -f -- $word
+  fi
+done
diff --git a/test_resources/docs/args/config-docs.txt b/test_resources/docs/args/config-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/args/config-docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/args/config.txt b/test_resources/docs/args/config.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/args/config.txt
diff --git a/test_resources/docs/args/docs.txt b/test_resources/docs/args/docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/args/docs.txt
@@ -0,0 +1,12 @@
+AnyDocsSingle
+  SetDoc
+    { setDocTryArgument = True
+    , setDocTrySwitch = False
+    , setDocTryOption = False
+    , setDocDasheds = []
+    , setDocEnvVars = Nothing
+    , setDocConfKeys = Nothing
+    , setDocDefault = Nothing
+    , setDocMetavar = Just "ARGUMENT"
+    , setDocHelp = Just "Argument"
+    }
diff --git a/test_resources/docs/args/env-docs.txt b/test_resources/docs/args/env-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/args/env-docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/args/env.txt b/test_resources/docs/args/env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/args/env.txt
diff --git a/test_resources/docs/args/help.txt b/test_resources/docs/args/help.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/args/help.txt
@@ -0,0 +1,15 @@
+[36mUsage: [m[33margs[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [33mARGUMENT[m
+
+args parser
+
+[36mAvailable settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mArgument[m
+  argument: [33mARGUMENT[m
+  
+
diff --git a/test_resources/docs/args/man.txt b/test_resources/docs/args/man.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/args/man.txt
@@ -0,0 +1,26 @@
+.Dd $Mdocdate$
+.Dt args 1
+.Os
+.Sh NAME
+.Nm args
+.Nd args parser
+.Sh VERSION
+0.0.0
+.Sh SYNOPSIS
+args (-h|--help) | --version | ARGUMENT
+.Sh SETTINGS
+  Show this help text
+  switch: -h|--help
+
+  Output version information: 0.0.0
+  switch: --version
+
+  Argument
+  argument: ARGUMENT
+  
+
+.Sh OPTIONS
+  -h|--help Show this help text               
+  --version Output version information: 0.0.0 
+  ARGUMENT  Argument                          
+
diff --git a/test_resources/docs/args/opt-docs.txt b/test_resources/docs/args/opt-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/args/opt-docs.txt
@@ -0,0 +1,10 @@
+AnyDocsSingle
+  OptDoc
+    { optDocTryArgument = True
+    , optDocTrySwitch = False
+    , optDocTryOption = False
+    , optDocDasheds = []
+    , optDocDefault = Nothing
+    , optDocMetavar = Just "ARGUMENT"
+    , optDocHelp = Just "Argument"
+    }
diff --git a/test_resources/docs/args/opt-long.txt b/test_resources/docs/args/opt-long.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/args/opt-long.txt
@@ -0,0 +1,3 @@
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m               
+  [37m--version[m [34mOutput version information: 0.0.0[m 
+  [33mARGUMENT[m  [34mArgument[m                          
diff --git a/test_resources/docs/args/opt-short.txt b/test_resources/docs/args/opt-short.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/args/opt-short.txt
@@ -0,0 +1,1 @@
+[33margs[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [33mARGUMENT[m
diff --git a/test_resources/docs/args/reference.txt b/test_resources/docs/args/reference.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/args/reference.txt
@@ -0,0 +1,18 @@
+[36mUsage: [m[33margs[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [33mARGUMENT[m
+
+[36mAll settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mArgument[m
+  argument: [33mARGUMENT[m
+  
+
+[36mOptions[m:
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m               
+  [37m--version[m [34mOutput version information: 0.0.0[m 
+  [33mARGUMENT[m  [34mArgument[m                          
+
diff --git a/test_resources/docs/args/show.txt b/test_resources/docs/args/show.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/args/show.txt
@@ -0,0 +1,18 @@
+Check
+  Nothing
+  True
+  _
+  (Many
+     (Setting
+        Nothing
+        (Setting
+           []
+           [ _ ]
+           True
+           Nothing
+           False
+           Nothing
+           Nothing
+           Nothing
+           (Just "ARGUMENT")
+           (Just "Argument"))))
diff --git a/test_resources/docs/args/version.txt b/test_resources/docs/args/version.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/args/version.txt
@@ -0,0 +1,1 @@
+[33margs[m 0.0.0 
diff --git a/test_resources/docs/big-config/config-docs.txt b/test_resources/docs/big-config/config-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/big-config/config-docs.txt
@@ -0,0 +1,7 @@
+AnyDocsSingle
+  EnvDoc
+    { envDocVars = "CONFIG_FILE" :| []
+    , envDocDefault = Nothing
+    , envDocMetavar = Just "FILE_PATH"
+    , envDocHelp = Just "Path to the configuration file"
+    }
diff --git a/test_resources/docs/big-config/config.txt b/test_resources/docs/big-config/config.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/big-config/config.txt
@@ -0,0 +1,6 @@
+  [34mmulti-line config codec explanation, the same option twice.[m
+  [37mbig[m:
+    # [32mor null[m
+    [37m<key>[m: 
+      [37m<key>[m: 
+        [33m<number>[m # [32m64 bit signed integer[m
diff --git a/test_resources/docs/big-config/docs.txt b/test_resources/docs/big-config/docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/big-config/docs.txt
@@ -0,0 +1,42 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      SetDoc
+        { setDocTryArgument = False
+        , setDocTrySwitch = False
+        , setDocTryOption = True
+        , setDocDasheds = [ DashedLong ('c' :| "onfig-file") ]
+        , setDocEnvVars = Just ("CONFIG_FILE" :| [])
+        , setDocConfKeys = Nothing
+        , setDocDefault = Nothing
+        , setDocMetavar = Just "FILE_PATH"
+        , setDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsSingle
+      SetDoc
+        { setDocTryArgument = False
+        , setDocTrySwitch = False
+        , setDocTryOption = False
+        , setDocDasheds = []
+        , setDocEnvVars = Nothing
+        , setDocConfKeys =
+            Just
+              (( "big" :| []
+               , AnyOfSchema
+                   (NullSchema :|
+                      [ MapSchema
+                          (MapSchema
+                             (NumberSchema
+                                (Just
+                                   NumberBounds
+                                     { numberBoundsLower = -9.223372036854775808e18
+                                     , numberBoundsUpper = 9.223372036854775807e18
+                                     })))
+                      ])
+               ) :|
+                 [])
+        , setDocDefault = Nothing
+        , setDocMetavar = Nothing
+        , setDocHelp =
+            Just "multi-line config codec explanation, the same option twice."
+        }
+  ]
diff --git a/test_resources/docs/big-config/env-docs.txt b/test_resources/docs/big-config/env-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/big-config/env-docs.txt
@@ -0,0 +1,21 @@
+AnyDocsSingle
+  ConfDoc
+    { confDocKeys =
+        ( "big" :| []
+        , AnyOfSchema
+            (NullSchema :|
+               [ MapSchema
+                   (MapSchema
+                      (NumberSchema
+                         (Just
+                            NumberBounds
+                              { numberBoundsLower = -9.223372036854775808e18
+                              , numberBoundsUpper = 9.223372036854775807e18
+                              })))
+               ])
+        ) :|
+          []
+    , confDocDefault = Nothing
+    , confDocHelp =
+        Just "multi-line config codec explanation, the same option twice."
+    }
diff --git a/test_resources/docs/big-config/env.txt b/test_resources/docs/big-config/env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/big-config/env.txt
@@ -0,0 +1,1 @@
+  [37mCONFIG_FILE[m [33mFILE_PATH[m   [34mPath to the configuration file[m
diff --git a/test_resources/docs/big-config/help.txt b/test_resources/docs/big-config/help.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/big-config/help.txt
@@ -0,0 +1,23 @@
+[36mUsage: [m[33mbig-config[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m[36m)[m
+
+example with a big configuration
+
+[36mAvailable settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mPath to the configuration file[m
+  option: [37m--config-file[m [33mFILE_PATH[m
+  env: [37mCONFIG_FILE[m [33mFILE_PATH[m
+  
+  [34mmulti-line config codec explanation, the same option twice.[m
+  config:
+    [37mbig[m: # [32mor null[m
+      [37m<key>[m: 
+        [37m<key>[m: 
+          [33m<number>[m # [32m64 bit signed integer[m
+  
+
diff --git a/test_resources/docs/big-config/man.txt b/test_resources/docs/big-config/man.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/big-config/man.txt
@@ -0,0 +1,45 @@
+.Dd $Mdocdate$
+.Dt big-config 1
+.Os
+.Sh NAME
+.Nm big-config
+.Nd example with a big configuration
+.Sh VERSION
+0.0.0
+.Sh SYNOPSIS
+big-config (-h|--help) | --version | (--config-file FILE_PATH)
+.Sh SETTINGS
+  Show this help text
+  switch: -h|--help
+
+  Output version information: 0.0.0
+  switch: --version
+
+  Path to the configuration file
+  option: --config-file FILE_PATH
+  env: CONFIG_FILE FILE_PATH
+  
+  multi-line config codec explanation, the same option twice.
+  config:
+    big: # or null
+      <key>: 
+        <key>: 
+          <number> # 64 bit signed integer
+  
+
+.Sh OPTIONS
+  -h|--help     Show this help text               
+  --version     Output version information: 0.0.0 
+  --config-file Path to the configuration file    
+
+.Sh ENVIRONMENT VARIABLES
+  CONFIG_FILE FILE_PATH   Path to the configuration file
+
+.Sh CONFIGURATION VALUES
+  multi-line config codec explanation, the same option twice.
+  big:
+    # or null
+    <key>: 
+      <key>: 
+        <number> # 64 bit signed integer
+
diff --git a/test_resources/docs/big-config/opt-docs.txt b/test_resources/docs/big-config/opt-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/big-config/opt-docs.txt
@@ -0,0 +1,10 @@
+AnyDocsSingle
+  OptDoc
+    { optDocTryArgument = False
+    , optDocTrySwitch = False
+    , optDocTryOption = True
+    , optDocDasheds = [ DashedLong ('c' :| "onfig-file") ]
+    , optDocDefault = Nothing
+    , optDocMetavar = Just "FILE_PATH"
+    , optDocHelp = Just "Path to the configuration file"
+    }
diff --git a/test_resources/docs/big-config/opt-long.txt b/test_resources/docs/big-config/opt-long.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/big-config/opt-long.txt
@@ -0,0 +1,3 @@
+  [37m-h[m[36m|[m[37m--help[m     [34mShow this help text[m               
+  [37m--version[m     [34mOutput version information: 0.0.0[m 
+  [37m--config-file[m [34mPath to the configuration file[m    
diff --git a/test_resources/docs/big-config/opt-short.txt b/test_resources/docs/big-config/opt-short.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/big-config/opt-short.txt
@@ -0,0 +1,1 @@
+[33mbig-config[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m[36m)[m
diff --git a/test_resources/docs/big-config/reference.txt b/test_resources/docs/big-config/reference.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/big-config/reference.txt
@@ -0,0 +1,37 @@
+[36mUsage: [m[33mbig-config[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m[36m)[m
+
+[36mAll settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mPath to the configuration file[m
+  option: [37m--config-file[m [33mFILE_PATH[m
+  env: [37mCONFIG_FILE[m [33mFILE_PATH[m
+  
+  [34mmulti-line config codec explanation, the same option twice.[m
+  config:
+    [37mbig[m: # [32mor null[m
+      [37m<key>[m: 
+        [37m<key>[m: 
+          [33m<number>[m # [32m64 bit signed integer[m
+  
+
+[36mOptions[m:
+  [37m-h[m[36m|[m[37m--help[m     [34mShow this help text[m               
+  [37m--version[m     [34mOutput version information: 0.0.0[m 
+  [37m--config-file[m [34mPath to the configuration file[m    
+
+[36mEnvironment Variables[m:
+  [37mCONFIG_FILE[m [33mFILE_PATH[m   [34mPath to the configuration file[m
+
+[36mConfiguration Values[m:
+  [34mmulti-line config codec explanation, the same option twice.[m
+  [37mbig[m:
+    # [32mor null[m
+    [37m<key>[m: 
+      [37m<key>[m: 
+        [33m<number>[m # [32m64 bit signed integer[m
+
diff --git a/test_resources/docs/big-config/show.txt b/test_resources/docs/big-config/show.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/big-config/show.txt
@@ -0,0 +1,64 @@
+WithConfig
+  _
+  (Check
+     Nothing
+     False
+     _
+     (Alt
+        (Check
+           Nothing
+           False
+           _
+           (Setting
+              Nothing
+              (Setting
+                 [ DashedLong ('c' :| "onfig-file") ]
+                 [ _ ]
+                 False
+                 Nothing
+                 True
+                 (Just ("CONFIG_FILE" :| []))
+                 Nothing
+                 Nothing
+                 (Just "FILE_PATH")
+                 (Just "Path to the configuration file"))))
+        (Check Nothing False _ (Pure _))))
+  (Check
+     Nothing
+     True
+     _
+     (Setting
+        Nothing
+        (Setting
+           []
+           []
+           False
+           Nothing
+           False
+           Nothing
+           (Just
+              [ ( "big" :| []
+                , BimapCodec
+                    _
+                    _
+                    (EitherCodec
+                       PossiblyJointUnion
+                       NullCodec
+                       (MapCodec
+                          (MapCodec
+                             (BimapCodec
+                                _
+                                _
+                                (NumberCodec
+                                   Nothing
+                                   (Just
+                                      NumberBounds
+                                        { numberBoundsLower = -9.223372036854775808e18
+                                        , numberBoundsUpper = 9.223372036854775807e18
+                                        }))))))
+                )
+              ])
+           Nothing
+           Nothing
+           (Just
+              "multi-line config codec explanation, the same option twice."))))
diff --git a/test_resources/docs/big-config/version.txt b/test_resources/docs/big-config/version.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/big-config/version.txt
@@ -0,0 +1,1 @@
+[33mbig-config[m 0.0.0 
diff --git a/test_resources/docs/empty/config-docs.txt b/test_resources/docs/empty/config-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/empty/config-docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/empty/config.txt b/test_resources/docs/empty/config.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/empty/config.txt
diff --git a/test_resources/docs/empty/docs.txt b/test_resources/docs/empty/docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/empty/docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/empty/env-docs.txt b/test_resources/docs/empty/env-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/empty/env-docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/empty/env.txt b/test_resources/docs/empty/env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/empty/env.txt
diff --git a/test_resources/docs/empty/help.txt b/test_resources/docs/empty/help.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/empty/help.txt
@@ -0,0 +1,12 @@
+[36mUsage: [m[33mempty[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m
+
+empty parser
+
+[36mAvailable settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+  
+
diff --git a/test_resources/docs/empty/man.txt b/test_resources/docs/empty/man.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/empty/man.txt
@@ -0,0 +1,22 @@
+.Dd $Mdocdate$
+.Dt empty 1
+.Os
+.Sh NAME
+.Nm empty
+.Nd empty parser
+.Sh VERSION
+0.0.0
+.Sh SYNOPSIS
+empty (-h|--help) | --version
+.Sh SETTINGS
+  Show this help text
+  switch: -h|--help
+
+  Output version information: 0.0.0
+  switch: --version
+  
+
+.Sh OPTIONS
+  -h|--help Show this help text               
+  --version Output version information: 0.0.0 
+
diff --git a/test_resources/docs/empty/opt-docs.txt b/test_resources/docs/empty/opt-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/empty/opt-docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/empty/opt-long.txt b/test_resources/docs/empty/opt-long.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/empty/opt-long.txt
@@ -0,0 +1,2 @@
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m               
+  [37m--version[m [34mOutput version information: 0.0.0[m 
diff --git a/test_resources/docs/empty/opt-short.txt b/test_resources/docs/empty/opt-short.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/empty/opt-short.txt
@@ -0,0 +1,1 @@
+[33mempty[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m
diff --git a/test_resources/docs/empty/reference.txt b/test_resources/docs/empty/reference.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/empty/reference.txt
@@ -0,0 +1,14 @@
+[36mUsage: [m[33mempty[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m
+
+[36mAll settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+  
+
+[36mOptions[m:
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m               
+  [37m--version[m [34mOutput version information: 0.0.0[m 
+
diff --git a/test_resources/docs/empty/show.txt b/test_resources/docs/empty/show.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/empty/show.txt
@@ -0,0 +1,1 @@
+Pure _
diff --git a/test_resources/docs/empty/version.txt b/test_resources/docs/empty/version.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/empty/version.txt
@@ -0,0 +1,1 @@
+[33mempty[m 0.0.0 
diff --git a/test_resources/docs/enable-disable/config-docs.txt b/test_resources/docs/enable-disable/config-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/enable-disable/config-docs.txt
@@ -0,0 +1,16 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      EnvDoc
+        { envDocVars = "CONFIG_FILE" :| []
+        , envDocDefault = Nothing
+        , envDocMetavar = Just "FILE_PATH"
+        , envDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsSingle
+      EnvDoc
+        { envDocVars = "EXAMPLE" :| []
+        , envDocDefault = Nothing
+        , envDocMetavar = Just "BOOL"
+        , envDocHelp = Just "Example of an enable/disable switch"
+        }
+  ]
diff --git a/test_resources/docs/enable-disable/config.txt b/test_resources/docs/enable-disable/config.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/enable-disable/config.txt
@@ -0,0 +1,4 @@
+  [34mExample of an enable/disable switch[m
+  [37mexample[m:
+    # [32mor null[m
+    [33m<boolean>[m
diff --git a/test_resources/docs/enable-disable/docs.txt b/test_resources/docs/enable-disable/docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/enable-disable/docs.txt
@@ -0,0 +1,57 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      SetDoc
+        { setDocTryArgument = False
+        , setDocTrySwitch = False
+        , setDocTryOption = True
+        , setDocDasheds = [ DashedLong ('c' :| "onfig-file") ]
+        , setDocEnvVars = Just ("CONFIG_FILE" :| [])
+        , setDocConfKeys = Nothing
+        , setDocDefault = Nothing
+        , setDocMetavar = Just "FILE_PATH"
+        , setDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsOr
+      [ AnyDocsSingle
+          SetDoc
+            { setDocTryArgument = False
+            , setDocTrySwitch = True
+            , setDocTryOption = False
+            , setDocDasheds = [ DashedLong ('(' :| "enable|disable)-example") ]
+            , setDocEnvVars = Nothing
+            , setDocConfKeys = Nothing
+            , setDocDefault = Nothing
+            , setDocMetavar = Nothing
+            , setDocHelp = Just "Example of an enable/disable switch"
+            }
+      , AnyDocsSingle
+          SetDoc
+            { setDocTryArgument = False
+            , setDocTrySwitch = False
+            , setDocTryOption = False
+            , setDocDasheds = []
+            , setDocEnvVars = Just ("EXAMPLE" :| [])
+            , setDocConfKeys = Nothing
+            , setDocDefault = Nothing
+            , setDocMetavar = Just "BOOL"
+            , setDocHelp = Just "Example of an enable/disable switch"
+            }
+      , AnyDocsSingle
+          SetDoc
+            { setDocTryArgument = False
+            , setDocTrySwitch = False
+            , setDocTryOption = False
+            , setDocDasheds = []
+            , setDocEnvVars = Nothing
+            , setDocConfKeys =
+                Just
+                  (( "example" :| []
+                   , AnyOfSchema (NullSchema :| [ BoolSchema ])
+                   ) :|
+                     [])
+            , setDocDefault = Nothing
+            , setDocMetavar = Nothing
+            , setDocHelp = Just "Example of an enable/disable switch"
+            }
+      ]
+  ]
diff --git a/test_resources/docs/enable-disable/env-docs.txt b/test_resources/docs/enable-disable/env-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/enable-disable/env-docs.txt
@@ -0,0 +1,8 @@
+AnyDocsSingle
+  ConfDoc
+    { confDocKeys =
+        ( "example" :| [] , AnyOfSchema (NullSchema :| [ BoolSchema ]) ) :|
+          []
+    , confDocDefault = Nothing
+    , confDocHelp = Just "Example of an enable/disable switch"
+    }
diff --git a/test_resources/docs/enable-disable/env.txt b/test_resources/docs/enable-disable/env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/enable-disable/env.txt
@@ -0,0 +1,2 @@
+  [37mCONFIG_FILE[m [33mFILE_PATH[m   [34mPath to the configuration file[m     
+  [37mEXAMPLE[m [33mBOOL[m            [34mExample of an enable/disable switch[m
diff --git a/test_resources/docs/enable-disable/help.txt b/test_resources/docs/enable-disable/help.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/enable-disable/help.txt
@@ -0,0 +1,23 @@
+[36mUsage: [m[33menable-disable[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [37m--(enable|disable)-example[m[36m)[m
+
+enableDisableSwitch example
+
+[36mAvailable settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mPath to the configuration file[m
+  option: [37m--config-file[m [33mFILE_PATH[m
+  env: [37mCONFIG_FILE[m [33mFILE_PATH[m
+  
+  [34mExample of an enable/disable switch[m
+  switch: [37m--(enable|disable)-example[m
+  env: [37mEXAMPLE[m [33mBOOL[m
+  config:
+    [37mexample[m: # [32mor null[m
+      [33m<boolean>[m
+
+
diff --git a/test_resources/docs/enable-disable/man.txt b/test_resources/docs/enable-disable/man.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/enable-disable/man.txt
@@ -0,0 +1,45 @@
+.Dd $Mdocdate$
+.Dt enable-disable 1
+.Os
+.Sh NAME
+.Nm enable-disable
+.Nd enableDisableSwitch example
+.Sh VERSION
+0.0.0
+.Sh SYNOPSIS
+enable-disable (-h|--help) | --version | (--config-file FILE_PATH --(enable|disable)-example)
+.Sh SETTINGS
+  Show this help text
+  switch: -h|--help
+
+  Output version information: 0.0.0
+  switch: --version
+
+  Path to the configuration file
+  option: --config-file FILE_PATH
+  env: CONFIG_FILE FILE_PATH
+  
+  Example of an enable/disable switch
+  switch: --(enable|disable)-example
+  env: EXAMPLE BOOL
+  config:
+    example: # or null
+      <boolean>
+
+
+.Sh OPTIONS
+  -h|--help                  Show this help text                 
+  --version                  Output version information: 0.0.0   
+  --config-file              Path to the configuration file      
+  --(enable|disable)-example Example of an enable/disable switch 
+
+.Sh ENVIRONMENT VARIABLES
+  CONFIG_FILE FILE_PATH   Path to the configuration file     
+  EXAMPLE BOOL            Example of an enable/disable switch
+
+.Sh CONFIGURATION VALUES
+  Example of an enable/disable switch
+  example:
+    # or null
+    <boolean>
+
diff --git a/test_resources/docs/enable-disable/opt-docs.txt b/test_resources/docs/enable-disable/opt-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/enable-disable/opt-docs.txt
@@ -0,0 +1,22 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      OptDoc
+        { optDocTryArgument = False
+        , optDocTrySwitch = False
+        , optDocTryOption = True
+        , optDocDasheds = [ DashedLong ('c' :| "onfig-file") ]
+        , optDocDefault = Nothing
+        , optDocMetavar = Just "FILE_PATH"
+        , optDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsSingle
+      OptDoc
+        { optDocTryArgument = False
+        , optDocTrySwitch = True
+        , optDocTryOption = False
+        , optDocDasheds = [ DashedLong ('(' :| "enable|disable)-example") ]
+        , optDocDefault = Nothing
+        , optDocMetavar = Nothing
+        , optDocHelp = Just "Example of an enable/disable switch"
+        }
+  ]
diff --git a/test_resources/docs/enable-disable/opt-long.txt b/test_resources/docs/enable-disable/opt-long.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/enable-disable/opt-long.txt
@@ -0,0 +1,4 @@
+  [37m-h[m[36m|[m[37m--help[m                  [34mShow this help text[m                 
+  [37m--version[m                  [34mOutput version information: 0.0.0[m   
+  [37m--config-file[m              [34mPath to the configuration file[m      
+  [37m--(enable|disable)-example[m [34mExample of an enable/disable switch[m 
diff --git a/test_resources/docs/enable-disable/opt-short.txt b/test_resources/docs/enable-disable/opt-short.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/enable-disable/opt-short.txt
@@ -0,0 +1,1 @@
+[33menable-disable[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [37m--(enable|disable)-example[m[36m)[m
diff --git a/test_resources/docs/enable-disable/reference.txt b/test_resources/docs/enable-disable/reference.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/enable-disable/reference.txt
@@ -0,0 +1,37 @@
+[36mUsage: [m[33menable-disable[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [37m--(enable|disable)-example[m[36m)[m
+
+[36mAll settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mPath to the configuration file[m
+  option: [37m--config-file[m [33mFILE_PATH[m
+  env: [37mCONFIG_FILE[m [33mFILE_PATH[m
+  
+  [34mExample of an enable/disable switch[m
+  switch: [37m--(enable|disable)-example[m
+  env: [37mEXAMPLE[m [33mBOOL[m
+  config:
+    [37mexample[m: # [32mor null[m
+      [33m<boolean>[m
+
+
+[36mOptions[m:
+  [37m-h[m[36m|[m[37m--help[m                  [34mShow this help text[m                 
+  [37m--version[m                  [34mOutput version information: 0.0.0[m   
+  [37m--config-file[m              [34mPath to the configuration file[m      
+  [37m--(enable|disable)-example[m [34mExample of an enable/disable switch[m 
+
+[36mEnvironment Variables[m:
+  [37mCONFIG_FILE[m [33mFILE_PATH[m   [34mPath to the configuration file[m     
+  [37mEXAMPLE[m [33mBOOL[m            [34mExample of an enable/disable switch[m
+
+[36mConfiguration Values[m:
+  [34mExample of an enable/disable switch[m
+  [37mexample[m:
+    # [32mor null[m
+    [33m<boolean>[m
+
diff --git a/test_resources/docs/enable-disable/show.txt b/test_resources/docs/enable-disable/show.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/enable-disable/show.txt
@@ -0,0 +1,123 @@
+WithConfig
+  _
+  (Check
+     Nothing
+     False
+     _
+     (Alt
+        (Check
+           Nothing
+           False
+           _
+           (Setting
+              Nothing
+              (Setting
+                 [ DashedLong ('c' :| "onfig-file") ]
+                 [ _ ]
+                 False
+                 Nothing
+                 True
+                 (Just ("CONFIG_FILE" :| []))
+                 Nothing
+                 Nothing
+                 (Just "FILE_PATH")
+                 (Just "Path to the configuration file"))))
+        (Check Nothing False _ (Pure _))))
+  (Alt
+     (Check
+        Nothing
+        True
+        _
+        (Setting
+           Nothing
+           (Setting
+              [ DashedLong ('(' :| "enable|disable)-example") ]
+              []
+              False
+              (Just _)
+              False
+              Nothing
+              Nothing
+              Nothing
+              Nothing
+              (Just "Example of an enable/disable switch"))))
+     (Alt
+        (Check
+           Nothing
+           True
+           _
+           (Setting
+              Nothing
+              (Setting
+                 [ DashedLong ('d' :| "isable-example") ]
+                 []
+                 False
+                 (Just _)
+                 False
+                 Nothing
+                 Nothing
+                 Nothing
+                 Nothing
+                 Nothing)))
+        (Alt
+           (Check
+              Nothing
+              True
+              _
+              (Setting
+                 Nothing
+                 (Setting
+                    [ DashedLong ('e' :| "nable-example") ]
+                    []
+                    False
+                    (Just _)
+                    False
+                    Nothing
+                    Nothing
+                    Nothing
+                    Nothing
+                    Nothing)))
+           (Alt
+              (Check
+                 Nothing
+                 True
+                 _
+                 (Setting
+                    Nothing
+                    (Setting
+                       []
+                       [ _ ]
+                       False
+                       Nothing
+                       False
+                       (Just ("EXAMPLE" :| []))
+                       Nothing
+                       Nothing
+                       (Just "BOOL")
+                       (Just "Example of an enable/disable switch"))))
+              (Alt
+                 (Check
+                    Nothing
+                    True
+                    _
+                    (Setting
+                       Nothing
+                       (Setting
+                          []
+                          []
+                          False
+                          Nothing
+                          False
+                          Nothing
+                          (Just
+                             [ ( "example" :| []
+                               , BimapCodec
+                                   _
+                                   _
+                                   (EitherCodec PossiblyJointUnion NullCodec (BoolCodec Nothing))
+                               )
+                             ])
+                          Nothing
+                          Nothing
+                          (Just "Example of an enable/disable switch"))))
+                 (Pure _))))))
diff --git a/test_resources/docs/enable-disable/version.txt b/test_resources/docs/enable-disable/version.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/enable-disable/version.txt
@@ -0,0 +1,1 @@
+[33menable-disable[m 0.0.0 
diff --git a/test_resources/docs/greet/config-docs.txt b/test_resources/docs/greet/config-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/greet/config-docs.txt
@@ -0,0 +1,23 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      EnvDoc
+        { envDocVars = "GREET_CONFIG_FILE" :| []
+        , envDocDefault = Nothing
+        , envDocMetavar = Just "FILE_PATH"
+        , envDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsSingle
+      EnvDoc
+        { envDocVars = "GREET_GREETING" :| []
+        , envDocDefault = Just "\"Hello\""
+        , envDocMetavar = Just "GREETING"
+        , envDocHelp = Just "Greeting to use"
+        }
+  , AnyDocsSingle
+      EnvDoc
+        { envDocVars = "GREET_POLITE" :| []
+        , envDocDefault = Just "False"
+        , envDocMetavar = Just "ANY"
+        , envDocHelp = Just "Whether to be polite"
+        }
+  ]
diff --git a/test_resources/docs/greet/config.txt b/test_resources/docs/greet/config.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/greet/config.txt
@@ -0,0 +1,8 @@
+  [34mGreeting to use[m
+  [37mgreeting[m:
+    # [32mor null[m
+    [33m<string>[m
+  [34mWhether to be polite[m
+  [37mpolite[m:
+    # [32mor null[m
+    [33m<boolean>[m
diff --git a/test_resources/docs/greet/docs.txt b/test_resources/docs/greet/docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/greet/docs.txt
@@ -0,0 +1,59 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      SetDoc
+        { setDocTryArgument = False
+        , setDocTrySwitch = False
+        , setDocTryOption = True
+        , setDocDasheds = [ DashedLong ('c' :| "onfig-file") ]
+        , setDocEnvVars = Just ("GREET_CONFIG_FILE" :| [])
+        , setDocConfKeys = Nothing
+        , setDocDefault = Nothing
+        , setDocMetavar = Just "FILE_PATH"
+        , setDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsSingle
+      SetDoc
+        { setDocTryArgument = False
+        , setDocTrySwitch = False
+        , setDocTryOption = True
+        , setDocDasheds =
+            [ DashedShort 'g' , DashedLong ('g' :| "reeting") ]
+        , setDocEnvVars = Just ("GREET_GREETING" :| [])
+        , setDocConfKeys =
+            Just
+              (( "greeting" :| []
+               , AnyOfSchema (NullSchema :| [ StringSchema ])
+               ) :|
+                 [])
+        , setDocDefault = Just "\"Hello\""
+        , setDocMetavar = Just "GREETING"
+        , setDocHelp = Just "Greeting to use"
+        }
+  , AnyDocsSingle
+      SetDoc
+        { setDocTryArgument = True
+        , setDocTrySwitch = False
+        , setDocTryOption = False
+        , setDocDasheds = []
+        , setDocEnvVars = Nothing
+        , setDocConfKeys = Nothing
+        , setDocDefault = Just "\"world\""
+        , setDocMetavar = Just "SUBJECT"
+        , setDocHelp = Just "Who to greet"
+        }
+  , AnyDocsSingle
+      SetDoc
+        { setDocTryArgument = False
+        , setDocTrySwitch = True
+        , setDocTryOption = False
+        , setDocDasheds = [ DashedShort 'p' , DashedLong ('p' :| "olite") ]
+        , setDocEnvVars = Just ("GREET_POLITE" :| [])
+        , setDocConfKeys =
+            Just
+              (( "polite" :| [] , AnyOfSchema (NullSchema :| [ BoolSchema ]) ) :|
+                 [])
+        , setDocDefault = Just "False"
+        , setDocMetavar = Just "ANY"
+        , setDocHelp = Just "Whether to be polite"
+        }
+  ]
diff --git a/test_resources/docs/greet/env-docs.txt b/test_resources/docs/greet/env-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/greet/env-docs.txt
@@ -0,0 +1,20 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      ConfDoc
+        { confDocKeys =
+            ( "greeting" :| []
+            , AnyOfSchema (NullSchema :| [ StringSchema ])
+            ) :|
+              []
+        , confDocDefault = Just "\"Hello\""
+        , confDocHelp = Just "Greeting to use"
+        }
+  , AnyDocsSingle
+      ConfDoc
+        { confDocKeys =
+            ( "polite" :| [] , AnyOfSchema (NullSchema :| [ BoolSchema ]) ) :|
+              []
+        , confDocDefault = Just "False"
+        , confDocHelp = Just "Whether to be polite"
+        }
+  ]
diff --git a/test_resources/docs/greet/env.txt b/test_resources/docs/greet/env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/greet/env.txt
@@ -0,0 +1,3 @@
+  [37mGREET_CONFIG_FILE[m [33mFILE_PATH[m   [34mPath to the configuration file[m
+  [37mGREET_GREETING[m [33mGREETING[m       [34mGreeting to use[m               
+  [37mGREET_POLITE[m [33mANY[m              [34mWhether to be polite[m          
diff --git a/test_resources/docs/greet/help.txt b/test_resources/docs/greet/help.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/greet/help.txt
@@ -0,0 +1,33 @@
+[36mUsage: [m[33mgreet[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [37m-g[m[36m|[m[37m--greeting[m [33mGREETING[m [33mSUBJECT[m [37m-p[m[36m|[m[37m--polite[m[36m)[m
+
+hello world example
+
+[36mAvailable settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mPath to the configuration file[m
+  option: [37m--config-file[m [33mFILE_PATH[m
+  env: [37mGREET_CONFIG_FILE[m [33mFILE_PATH[m
+  
+  [34mGreeting to use[m
+  option: [37m-g[m[36m|[m[37m--greeting[m [33mGREETING[m
+  env: [37mGREET_GREETING[m [33mGREETING[m
+  config:
+    [37mgreeting[m: # [32mor null[m
+      [33m<string>[m
+  
+  [34mWho to greet[m
+  argument: [33mSUBJECT[m
+  
+  [34mWhether to be polite[m
+  switch: [37m-p[m[36m|[m[37m--polite[m
+  env: [37mGREET_POLITE[m [33mANY[m
+  config:
+    [37mpolite[m: # [32mor null[m
+      [33m<boolean>[m
+  
+
diff --git a/test_resources/docs/greet/man.txt b/test_resources/docs/greet/man.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/greet/man.txt
@@ -0,0 +1,62 @@
+.Dd $Mdocdate$
+.Dt greet 1
+.Os
+.Sh NAME
+.Nm greet
+.Nd hello world example
+.Sh VERSION
+0.0.0
+.Sh SYNOPSIS
+greet (-h|--help) | --version | (--config-file FILE_PATH -g|--greeting GREETING SUBJECT -p|--polite)
+.Sh SETTINGS
+  Show this help text
+  switch: -h|--help
+
+  Output version information: 0.0.0
+  switch: --version
+
+  Path to the configuration file
+  option: --config-file FILE_PATH
+  env: GREET_CONFIG_FILE FILE_PATH
+  
+  Greeting to use
+  option: -g|--greeting GREETING
+  env: GREET_GREETING GREETING
+  config:
+    greeting: # or null
+      <string>
+  
+  Who to greet
+  argument: SUBJECT
+  
+  Whether to be polite
+  switch: -p|--polite
+  env: GREET_POLITE ANY
+  config:
+    polite: # or null
+      <boolean>
+  
+
+.Sh OPTIONS
+  -h|--help     Show this help text                               
+  --version     Output version information: 0.0.0                 
+  --config-file Path to the configuration file                    
+  -g|--greeting Greeting to use                   default: "Hello"
+  SUBJECT       Who to greet                      default: "world"
+  -p|--polite   Whether to be polite              default: False  
+
+.Sh ENVIRONMENT VARIABLES
+  GREET_CONFIG_FILE FILE_PATH   Path to the configuration file
+  GREET_GREETING GREETING       Greeting to use               
+  GREET_POLITE ANY              Whether to be polite          
+
+.Sh CONFIGURATION VALUES
+  Greeting to use
+  greeting:
+    # or null
+    <string>
+  Whether to be polite
+  polite:
+    # or null
+    <boolean>
+
diff --git a/test_resources/docs/greet/opt-docs.txt b/test_resources/docs/greet/opt-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/greet/opt-docs.txt
@@ -0,0 +1,43 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      OptDoc
+        { optDocTryArgument = False
+        , optDocTrySwitch = False
+        , optDocTryOption = True
+        , optDocDasheds = [ DashedLong ('c' :| "onfig-file") ]
+        , optDocDefault = Nothing
+        , optDocMetavar = Just "FILE_PATH"
+        , optDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsSingle
+      OptDoc
+        { optDocTryArgument = False
+        , optDocTrySwitch = False
+        , optDocTryOption = True
+        , optDocDasheds =
+            [ DashedShort 'g' , DashedLong ('g' :| "reeting") ]
+        , optDocDefault = Just "\"Hello\""
+        , optDocMetavar = Just "GREETING"
+        , optDocHelp = Just "Greeting to use"
+        }
+  , AnyDocsSingle
+      OptDoc
+        { optDocTryArgument = True
+        , optDocTrySwitch = False
+        , optDocTryOption = False
+        , optDocDasheds = []
+        , optDocDefault = Just "\"world\""
+        , optDocMetavar = Just "SUBJECT"
+        , optDocHelp = Just "Who to greet"
+        }
+  , AnyDocsSingle
+      OptDoc
+        { optDocTryArgument = False
+        , optDocTrySwitch = True
+        , optDocTryOption = False
+        , optDocDasheds = [ DashedShort 'p' , DashedLong ('p' :| "olite") ]
+        , optDocDefault = Just "False"
+        , optDocMetavar = Just "ANY"
+        , optDocHelp = Just "Whether to be polite"
+        }
+  ]
diff --git a/test_resources/docs/greet/opt-long.txt b/test_resources/docs/greet/opt-long.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/greet/opt-long.txt
@@ -0,0 +1,6 @@
+  [37m-h[m[36m|[m[37m--help[m     [34mShow this help text[m                               
+  [37m--version[m     [34mOutput version information: 0.0.0[m                 
+  [37m--config-file[m [34mPath to the configuration file[m                    
+  [37m-g[m[36m|[m[37m--greeting[m [34mGreeting to use[m                   default: [33m"Hello"[m
+  [33mSUBJECT[m       [34mWho to greet[m                      default: [33m"world"[m
+  [37m-p[m[36m|[m[37m--polite[m   [34mWhether to be polite[m              default: [33mFalse[m  
diff --git a/test_resources/docs/greet/opt-short.txt b/test_resources/docs/greet/opt-short.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/greet/opt-short.txt
@@ -0,0 +1,1 @@
+[33mgreet[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [37m-g[m[36m|[m[37m--greeting[m [33mGREETING[m [33mSUBJECT[m [37m-p[m[36m|[m[37m--polite[m[36m)[m
diff --git a/test_resources/docs/greet/reference.txt b/test_resources/docs/greet/reference.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/greet/reference.txt
@@ -0,0 +1,54 @@
+[36mUsage: [m[33mgreet[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [37m-g[m[36m|[m[37m--greeting[m [33mGREETING[m [33mSUBJECT[m [37m-p[m[36m|[m[37m--polite[m[36m)[m
+
+[36mAll settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mPath to the configuration file[m
+  option: [37m--config-file[m [33mFILE_PATH[m
+  env: [37mGREET_CONFIG_FILE[m [33mFILE_PATH[m
+  
+  [34mGreeting to use[m
+  option: [37m-g[m[36m|[m[37m--greeting[m [33mGREETING[m
+  env: [37mGREET_GREETING[m [33mGREETING[m
+  config:
+    [37mgreeting[m: # [32mor null[m
+      [33m<string>[m
+  
+  [34mWho to greet[m
+  argument: [33mSUBJECT[m
+  
+  [34mWhether to be polite[m
+  switch: [37m-p[m[36m|[m[37m--polite[m
+  env: [37mGREET_POLITE[m [33mANY[m
+  config:
+    [37mpolite[m: # [32mor null[m
+      [33m<boolean>[m
+  
+
+[36mOptions[m:
+  [37m-h[m[36m|[m[37m--help[m     [34mShow this help text[m                               
+  [37m--version[m     [34mOutput version information: 0.0.0[m                 
+  [37m--config-file[m [34mPath to the configuration file[m                    
+  [37m-g[m[36m|[m[37m--greeting[m [34mGreeting to use[m                   default: [33m"Hello"[m
+  [33mSUBJECT[m       [34mWho to greet[m                      default: [33m"world"[m
+  [37m-p[m[36m|[m[37m--polite[m   [34mWhether to be polite[m              default: [33mFalse[m  
+
+[36mEnvironment Variables[m:
+  [37mGREET_CONFIG_FILE[m [33mFILE_PATH[m   [34mPath to the configuration file[m
+  [37mGREET_GREETING[m [33mGREETING[m       [34mGreeting to use[m               
+  [37mGREET_POLITE[m [33mANY[m              [34mWhether to be polite[m          
+
+[36mConfiguration Values[m:
+  [34mGreeting to use[m
+  [37mgreeting[m:
+    # [32mor null[m
+    [33m<string>[m
+  [34mWhether to be polite[m
+  [37mpolite[m:
+    # [32mor null[m
+    [33m<boolean>[m
+
diff --git a/test_resources/docs/greet/show.txt b/test_resources/docs/greet/show.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/greet/show.txt
@@ -0,0 +1,85 @@
+WithConfig
+  _
+  (Check
+     Nothing
+     False
+     _
+     (Alt
+        (Check
+           Nothing
+           False
+           _
+           (Setting
+              Nothing
+              (Setting
+                 [ DashedLong ('c' :| "onfig-file") ]
+                 [ _ ]
+                 False
+                 Nothing
+                 True
+                 (Just ("GREET_CONFIG_FILE" :| []))
+                 Nothing
+                 Nothing
+                 (Just "FILE_PATH")
+                 (Just "Path to the configuration file"))))
+        (Check Nothing False _ (Pure _))))
+  (Ap
+     (Ap
+        (Check
+           Nothing
+           True
+           _
+           (Setting
+              Nothing
+              (Setting
+                 [ DashedShort 'g' , DashedLong ('g' :| "reeting") ]
+                 [ _ ]
+                 False
+                 Nothing
+                 True
+                 (Just ("GREET_GREETING" :| []))
+                 (Just
+                    [ ( "greeting" :| []
+                      , BimapCodec
+                          _
+                          _
+                          (EitherCodec
+                             PossiblyJointUnion
+                             NullCodec
+                             (BimapCodec _ _ (StringCodec Nothing)))
+                      )
+                    ])
+                 (Just _)
+                 (Just "GREETING")
+                 (Just "Greeting to use"))))
+        (Setting
+           Nothing
+           (Setting
+              []
+              [ _ ]
+              True
+              Nothing
+              False
+              Nothing
+              Nothing
+              (Just _)
+              (Just "SUBJECT")
+              (Just "Who to greet"))))
+     (Setting
+        Nothing
+        (Setting
+           [ DashedShort 'p' , DashedLong ('p' :| "olite") ]
+           [ _ ]
+           False
+           (Just _)
+           False
+           (Just ("GREET_POLITE" :| []))
+           (Just
+              [ ( "polite" :| []
+                , BimapCodec
+                    _ _ (EitherCodec PossiblyJointUnion NullCodec (BoolCodec Nothing))
+                )
+              ])
+           (Just _)
+           (Just "ANY")
+           (Just "Whether to be polite"))))
diff --git a/test_resources/docs/greet/version.txt b/test_resources/docs/greet/version.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/greet/version.txt
@@ -0,0 +1,1 @@
+[33mgreet[m 0.0.0 
diff --git a/test_resources/docs/hidden/config-docs.txt b/test_resources/docs/hidden/config-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/hidden/config-docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/hidden/config.txt b/test_resources/docs/hidden/config.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/hidden/config.txt
diff --git a/test_resources/docs/hidden/docs.txt b/test_resources/docs/hidden/docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/hidden/docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/hidden/env-docs.txt b/test_resources/docs/hidden/env-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/hidden/env-docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/hidden/env.txt b/test_resources/docs/hidden/env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/hidden/env.txt
diff --git a/test_resources/docs/hidden/help.txt b/test_resources/docs/hidden/help.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/hidden/help.txt
@@ -0,0 +1,12 @@
+[36mUsage: [m[33mhidden[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m
+
+example with hidden settings
+
+[36mAvailable settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+  
+
diff --git a/test_resources/docs/hidden/man.txt b/test_resources/docs/hidden/man.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/hidden/man.txt
@@ -0,0 +1,22 @@
+.Dd $Mdocdate$
+.Dt hidden 1
+.Os
+.Sh NAME
+.Nm hidden
+.Nd example with hidden settings
+.Sh VERSION
+0.0.0
+.Sh SYNOPSIS
+hidden (-h|--help) | --version
+.Sh SETTINGS
+  Show this help text
+  switch: -h|--help
+
+  Output version information: 0.0.0
+  switch: --version
+  
+
+.Sh OPTIONS
+  -h|--help Show this help text               
+  --version Output version information: 0.0.0 
+
diff --git a/test_resources/docs/hidden/opt-docs.txt b/test_resources/docs/hidden/opt-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/hidden/opt-docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/hidden/opt-long.txt b/test_resources/docs/hidden/opt-long.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/hidden/opt-long.txt
@@ -0,0 +1,2 @@
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m               
+  [37m--version[m [34mOutput version information: 0.0.0[m 
diff --git a/test_resources/docs/hidden/opt-short.txt b/test_resources/docs/hidden/opt-short.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/hidden/opt-short.txt
@@ -0,0 +1,1 @@
+[33mhidden[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m
diff --git a/test_resources/docs/hidden/reference.txt b/test_resources/docs/hidden/reference.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/hidden/reference.txt
@@ -0,0 +1,14 @@
+[36mUsage: [m[33mhidden[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m
+
+[36mAll settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+  
+
+[36mOptions[m:
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m               
+  [37m--version[m [34mOutput version information: 0.0.0[m 
+
diff --git a/test_resources/docs/hidden/show.txt b/test_resources/docs/hidden/show.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/hidden/show.txt
@@ -0,0 +1,17 @@
+Check
+  Nothing
+  True
+  _
+  (Setting
+     Nothing
+     (Setting
+        []
+        [ _ ]
+        True
+        Nothing
+        False
+        Nothing
+        Nothing
+        (Just _)
+        (Just "STR")
+        (Just "Example of a hidden setting")))
diff --git a/test_resources/docs/hidden/version.txt b/test_resources/docs/hidden/version.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/hidden/version.txt
@@ -0,0 +1,1 @@
+[33mhidden[m 0.0.0 
diff --git a/test_resources/docs/optional/config-docs.txt b/test_resources/docs/optional/config-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/optional/config-docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/optional/config.txt b/test_resources/docs/optional/config.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/optional/config.txt
diff --git a/test_resources/docs/optional/docs.txt b/test_resources/docs/optional/docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/optional/docs.txt
@@ -0,0 +1,12 @@
+AnyDocsSingle
+  SetDoc
+    { setDocTryArgument = True
+    , setDocTrySwitch = False
+    , setDocTryOption = False
+    , setDocDasheds = []
+    , setDocEnvVars = Nothing
+    , setDocConfKeys = Nothing
+    , setDocDefault = Nothing
+    , setDocMetavar = Just "ARGUMENT"
+    , setDocHelp = Just "Argument"
+    }
diff --git a/test_resources/docs/optional/env-docs.txt b/test_resources/docs/optional/env-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/optional/env-docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/optional/env.txt b/test_resources/docs/optional/env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/optional/env.txt
diff --git a/test_resources/docs/optional/help.txt b/test_resources/docs/optional/help.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/optional/help.txt
@@ -0,0 +1,15 @@
+[36mUsage: [m[33moptional[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [33mARGUMENT[m
+
+optional argument
+
+[36mAvailable settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mArgument[m
+  argument: [33mARGUMENT[m
+  
+
diff --git a/test_resources/docs/optional/man.txt b/test_resources/docs/optional/man.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/optional/man.txt
@@ -0,0 +1,26 @@
+.Dd $Mdocdate$
+.Dt optional 1
+.Os
+.Sh NAME
+.Nm optional
+.Nd optional argument
+.Sh VERSION
+0.0.0
+.Sh SYNOPSIS
+optional (-h|--help) | --version | ARGUMENT
+.Sh SETTINGS
+  Show this help text
+  switch: -h|--help
+
+  Output version information: 0.0.0
+  switch: --version
+
+  Argument
+  argument: ARGUMENT
+  
+
+.Sh OPTIONS
+  -h|--help Show this help text               
+  --version Output version information: 0.0.0 
+  ARGUMENT  Argument                          
+
diff --git a/test_resources/docs/optional/opt-docs.txt b/test_resources/docs/optional/opt-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/optional/opt-docs.txt
@@ -0,0 +1,10 @@
+AnyDocsSingle
+  OptDoc
+    { optDocTryArgument = True
+    , optDocTrySwitch = False
+    , optDocTryOption = False
+    , optDocDasheds = []
+    , optDocDefault = Nothing
+    , optDocMetavar = Just "ARGUMENT"
+    , optDocHelp = Just "Argument"
+    }
diff --git a/test_resources/docs/optional/opt-long.txt b/test_resources/docs/optional/opt-long.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/optional/opt-long.txt
@@ -0,0 +1,3 @@
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m               
+  [37m--version[m [34mOutput version information: 0.0.0[m 
+  [33mARGUMENT[m  [34mArgument[m                          
diff --git a/test_resources/docs/optional/opt-short.txt b/test_resources/docs/optional/opt-short.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/optional/opt-short.txt
@@ -0,0 +1,1 @@
+[33moptional[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [33mARGUMENT[m
diff --git a/test_resources/docs/optional/reference.txt b/test_resources/docs/optional/reference.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/optional/reference.txt
@@ -0,0 +1,18 @@
+[36mUsage: [m[33moptional[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [33mARGUMENT[m
+
+[36mAll settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mArgument[m
+  argument: [33mARGUMENT[m
+  
+
+[36mOptions[m:
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m               
+  [37m--version[m [34mOutput version information: 0.0.0[m 
+  [33mARGUMENT[m  [34mArgument[m                          
+
diff --git a/test_resources/docs/optional/show.txt b/test_resources/docs/optional/show.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/optional/show.txt
@@ -0,0 +1,19 @@
+Alt
+  (Check
+     Nothing
+     True
+     _
+     (Setting
+        Nothing
+        (Setting
+           []
+           [ _ ]
+           True
+           Nothing
+           False
+           Nothing
+           Nothing
+           Nothing
+           (Just "ARGUMENT")
+           (Just "Argument"))))
+  (Pure _)
diff --git a/test_resources/docs/optional/version.txt b/test_resources/docs/optional/version.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/optional/version.txt
@@ -0,0 +1,1 @@
+[33moptional[m 0.0.0 
diff --git a/test_resources/docs/sub-commands/config-docs.txt b/test_resources/docs/sub-commands/config-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/sub-commands/config-docs.txt
@@ -0,0 +1,54 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      EnvDoc
+        { envDocVars = "CONFIG_FILE" :| []
+        , envDocDefault = Nothing
+        , envDocMetavar = Just "FILE_PATH"
+        , envDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsCommands
+      [ CommandDoc
+          { commandDocArgument = "top"
+          , commandDocHelp = "command without subcommands"
+          , commandDocs =
+              AnyDocsSingle
+                EnvDoc
+                  { envDocVars = "NAME" :| []
+                  , envDocDefault = Nothing
+                  , envDocMetavar = Just "NAME"
+                  , envDocHelp = Just "name"
+                  }
+          }
+      , CommandDoc
+          { commandDocArgument = "sub"
+          , commandDocHelp = "command with subcommands"
+          , commandDocs =
+              AnyDocsAnd
+                [ AnyDocsCommands
+                    [ CommandDoc
+                        { commandDocArgument = "a"
+                        , commandDocHelp = "A"
+                        , commandDocs = AnyDocsAnd []
+                        }
+                    , CommandDoc
+                        { commandDocArgument = "b"
+                        , commandDocHelp = "B"
+                        , commandDocs = AnyDocsAnd []
+                        }
+                    ]
+                , AnyDocsCommands
+                    [ CommandDoc
+                        { commandDocArgument = "c"
+                        , commandDocHelp = "C"
+                        , commandDocs = AnyDocsAnd []
+                        }
+                    , CommandDoc
+                        { commandDocArgument = "d"
+                        , commandDocHelp = "D"
+                        , commandDocs = AnyDocsAnd []
+                        }
+                    ]
+                ]
+          }
+      ]
+  ]
diff --git a/test_resources/docs/sub-commands/config.txt b/test_resources/docs/sub-commands/config.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/sub-commands/config.txt
@@ -0,0 +1,4 @@
+  [34mname[m
+  [37mname[m:
+    # [32mor null[m
+    [33m<string>[m
diff --git a/test_resources/docs/sub-commands/docs.txt b/test_resources/docs/sub-commands/docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/sub-commands/docs.txt
@@ -0,0 +1,67 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      SetDoc
+        { setDocTryArgument = False
+        , setDocTrySwitch = False
+        , setDocTryOption = True
+        , setDocDasheds = [ DashedLong ('c' :| "onfig-file") ]
+        , setDocEnvVars = Just ("CONFIG_FILE" :| [])
+        , setDocConfKeys = Nothing
+        , setDocDefault = Nothing
+        , setDocMetavar = Just "FILE_PATH"
+        , setDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsCommands
+      [ CommandDoc
+          { commandDocArgument = "top"
+          , commandDocHelp = "command without subcommands"
+          , commandDocs =
+              AnyDocsSingle
+                SetDoc
+                  { setDocTryArgument = False
+                  , setDocTrySwitch = False
+                  , setDocTryOption = True
+                  , setDocDasheds = [ DashedLong ('n' :| "ame") ]
+                  , setDocEnvVars = Just ("NAME" :| [])
+                  , setDocConfKeys =
+                      Just
+                        (( "name" :| [] , AnyOfSchema (NullSchema :| [ StringSchema ]) ) :|
+                           [])
+                  , setDocDefault = Nothing
+                  , setDocMetavar = Just "NAME"
+                  , setDocHelp = Just "name"
+                  }
+          }
+      , CommandDoc
+          { commandDocArgument = "sub"
+          , commandDocHelp = "command with subcommands"
+          , commandDocs =
+              AnyDocsAnd
+                [ AnyDocsCommands
+                    [ CommandDoc
+                        { commandDocArgument = "a"
+                        , commandDocHelp = "A"
+                        , commandDocs = AnyDocsAnd []
+                        }
+                    , CommandDoc
+                        { commandDocArgument = "b"
+                        , commandDocHelp = "B"
+                        , commandDocs = AnyDocsAnd []
+                        }
+                    ]
+                , AnyDocsCommands
+                    [ CommandDoc
+                        { commandDocArgument = "c"
+                        , commandDocHelp = "C"
+                        , commandDocs = AnyDocsAnd []
+                        }
+                    , CommandDoc
+                        { commandDocArgument = "d"
+                        , commandDocHelp = "D"
+                        , commandDocs = AnyDocsAnd []
+                        }
+                    ]
+                ]
+          }
+      ]
+  ]
diff --git a/test_resources/docs/sub-commands/env-docs.txt b/test_resources/docs/sub-commands/env-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/sub-commands/env-docs.txt
@@ -0,0 +1,46 @@
+AnyDocsCommands
+  [ CommandDoc
+      { commandDocArgument = "top"
+      , commandDocHelp = "command without subcommands"
+      , commandDocs =
+          AnyDocsSingle
+            ConfDoc
+              { confDocKeys =
+                  ( "name" :| [] , AnyOfSchema (NullSchema :| [ StringSchema ]) ) :|
+                    []
+              , confDocDefault = Nothing
+              , confDocHelp = Just "name"
+              }
+      }
+  , CommandDoc
+      { commandDocArgument = "sub"
+      , commandDocHelp = "command with subcommands"
+      , commandDocs =
+          AnyDocsAnd
+            [ AnyDocsCommands
+                [ CommandDoc
+                    { commandDocArgument = "a"
+                    , commandDocHelp = "A"
+                    , commandDocs = AnyDocsAnd []
+                    }
+                , CommandDoc
+                    { commandDocArgument = "b"
+                    , commandDocHelp = "B"
+                    , commandDocs = AnyDocsAnd []
+                    }
+                ]
+            , AnyDocsCommands
+                [ CommandDoc
+                    { commandDocArgument = "c"
+                    , commandDocHelp = "C"
+                    , commandDocs = AnyDocsAnd []
+                    }
+                , CommandDoc
+                    { commandDocArgument = "d"
+                    , commandDocHelp = "D"
+                    , commandDocs = AnyDocsAnd []
+                    }
+                ]
+            ]
+      }
+  ]
diff --git a/test_resources/docs/sub-commands/env.txt b/test_resources/docs/sub-commands/env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/sub-commands/env.txt
@@ -0,0 +1,2 @@
+  [37mCONFIG_FILE[m [33mFILE_PATH[m   [34mPath to the configuration file[m
+  [37mNAME[m [33mNAME[m               [34mname[m                          
diff --git a/test_resources/docs/sub-commands/help.txt b/test_resources/docs/sub-commands/help.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/sub-commands/help.txt
@@ -0,0 +1,41 @@
+[36mUsage: [m[33msub-commands[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [35mtop[m [37m--name[m [33mNAME[m [36m|[m [35msub[m [35ma[m [36m|[m [35mb[m [35mc[m [36m|[m [35md[m[36m)[m
+
+example with subcommands
+
+[36mAvailable settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mPath to the configuration file[m
+  option: [37m--config-file[m [33mFILE_PATH[m
+  env: [37mCONFIG_FILE[m [33mFILE_PATH[m
+  
+  [34mcommand without subcommands[m
+  command: [35mtop[m
+    [34mname[m
+    option: [37m--name[m [33mNAME[m
+    env: [37mNAME[m [33mNAME[m
+    config:
+      [37mname[m: # [32mor null[m
+        [33m<string>[m
+    
+  
+  [34mcommand with subcommands[m
+  command: [35msub[m
+    [34mA[m
+    command: [35ma[m
+    
+    [34mB[m
+    command: [35mb[m
+    
+    [34mC[m
+    command: [35mc[m
+    
+    [34mD[m
+    command: [35md[m
+    
+  
+
diff --git a/test_resources/docs/sub-commands/man.txt b/test_resources/docs/sub-commands/man.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/sub-commands/man.txt
@@ -0,0 +1,69 @@
+.Dd $Mdocdate$
+.Dt sub-commands 1
+.Os
+.Sh NAME
+.Nm sub-commands
+.Nd example with subcommands
+.Sh VERSION
+0.0.0
+.Sh SYNOPSIS
+sub-commands (-h|--help) | --version | (--config-file FILE_PATH top --name NAME | sub a | b c | d)
+.Sh SETTINGS
+  Show this help text
+  switch: -h|--help
+
+  Output version information: 0.0.0
+  switch: --version
+
+  Path to the configuration file
+  option: --config-file FILE_PATH
+  env: CONFIG_FILE FILE_PATH
+  
+  command without subcommands
+  command: top
+    name
+    option: --name NAME
+    env: NAME NAME
+    config:
+      name: # or null
+        <string>
+    
+  
+  command with subcommands
+  command: sub
+    A
+    command: a
+    
+    B
+    command: b
+    
+    C
+    command: c
+    
+    D
+    command: d
+    
+  
+
+.Sh OPTIONS
+  -h|--help Show this help text 
+  --version Output version information: 0.0.0 
+  --config-file Path to the configuration file 
+  top command without subcommands
+      --name name 
+  sub command with subcommands
+      a A
+      b B
+      c C
+      d D
+
+.Sh ENVIRONMENT VARIABLES
+  CONFIG_FILE FILE_PATH   Path to the configuration file
+  NAME NAME               name                          
+
+.Sh CONFIGURATION VALUES
+  name
+  name:
+    # or null
+    <string>
+
diff --git a/test_resources/docs/sub-commands/opt-docs.txt b/test_resources/docs/sub-commands/opt-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/sub-commands/opt-docs.txt
@@ -0,0 +1,60 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      OptDoc
+        { optDocTryArgument = False
+        , optDocTrySwitch = False
+        , optDocTryOption = True
+        , optDocDasheds = [ DashedLong ('c' :| "onfig-file") ]
+        , optDocDefault = Nothing
+        , optDocMetavar = Just "FILE_PATH"
+        , optDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsCommands
+      [ CommandDoc
+          { commandDocArgument = "top"
+          , commandDocHelp = "command without subcommands"
+          , commandDocs =
+              AnyDocsSingle
+                OptDoc
+                  { optDocTryArgument = False
+                  , optDocTrySwitch = False
+                  , optDocTryOption = True
+                  , optDocDasheds = [ DashedLong ('n' :| "ame") ]
+                  , optDocDefault = Nothing
+                  , optDocMetavar = Just "NAME"
+                  , optDocHelp = Just "name"
+                  }
+          }
+      , CommandDoc
+          { commandDocArgument = "sub"
+          , commandDocHelp = "command with subcommands"
+          , commandDocs =
+              AnyDocsAnd
+                [ AnyDocsCommands
+                    [ CommandDoc
+                        { commandDocArgument = "a"
+                        , commandDocHelp = "A"
+                        , commandDocs = AnyDocsAnd []
+                        }
+                    , CommandDoc
+                        { commandDocArgument = "b"
+                        , commandDocHelp = "B"
+                        , commandDocs = AnyDocsAnd []
+                        }
+                    ]
+                , AnyDocsCommands
+                    [ CommandDoc
+                        { commandDocArgument = "c"
+                        , commandDocHelp = "C"
+                        , commandDocs = AnyDocsAnd []
+                        }
+                    , CommandDoc
+                        { commandDocArgument = "d"
+                        , commandDocHelp = "D"
+                        , commandDocs = AnyDocsAnd []
+                        }
+                    ]
+                ]
+          }
+      ]
+  ]
diff --git a/test_resources/docs/sub-commands/opt-long.txt b/test_resources/docs/sub-commands/opt-long.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/sub-commands/opt-long.txt
@@ -0,0 +1,10 @@
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m 
+  [37m--version[m [34mOutput version information: 0.0.0[m 
+  [37m--config-file[m [34mPath to the configuration file[m 
+  [35mtop[m [34mcommand without subcommands[m
+      [37m--name[m [34mname[m 
+  [35msub[m [34mcommand with subcommands[m
+      [35ma[m [34mA[m
+      [35mb[m [34mB[m
+      [35mc[m [34mC[m
+      [35md[m [34mD[m
diff --git a/test_resources/docs/sub-commands/opt-short.txt b/test_resources/docs/sub-commands/opt-short.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/sub-commands/opt-short.txt
@@ -0,0 +1,1 @@
+[33msub-commands[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [35mtop[m [37m--name[m [33mNAME[m [36m|[m [35msub[m [35ma[m [36m|[m [35mb[m [35mc[m [36m|[m [35md[m[36m)[m
diff --git a/test_resources/docs/sub-commands/reference.txt b/test_resources/docs/sub-commands/reference.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/sub-commands/reference.txt
@@ -0,0 +1,61 @@
+[36mUsage: [m[33msub-commands[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [35mtop[m [37m--name[m [33mNAME[m [36m|[m [35msub[m [35ma[m [36m|[m [35mb[m [35mc[m [36m|[m [35md[m[36m)[m
+
+[36mAll settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mPath to the configuration file[m
+  option: [37m--config-file[m [33mFILE_PATH[m
+  env: [37mCONFIG_FILE[m [33mFILE_PATH[m
+  
+  [34mcommand without subcommands[m
+  command: [35mtop[m
+    [34mname[m
+    option: [37m--name[m [33mNAME[m
+    env: [37mNAME[m [33mNAME[m
+    config:
+      [37mname[m: # [32mor null[m
+        [33m<string>[m
+    
+  
+  [34mcommand with subcommands[m
+  command: [35msub[m
+    [34mA[m
+    command: [35ma[m
+    
+    [34mB[m
+    command: [35mb[m
+    
+    [34mC[m
+    command: [35mc[m
+    
+    [34mD[m
+    command: [35md[m
+    
+  
+
+[36mOptions[m:
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m 
+  [37m--version[m [34mOutput version information: 0.0.0[m 
+  [37m--config-file[m [34mPath to the configuration file[m 
+  [35mtop[m [34mcommand without subcommands[m
+      [37m--name[m [34mname[m 
+  [35msub[m [34mcommand with subcommands[m
+      [35ma[m [34mA[m
+      [35mb[m [34mB[m
+      [35mc[m [34mC[m
+      [35md[m [34mD[m
+
+[36mEnvironment Variables[m:
+  [37mCONFIG_FILE[m [33mFILE_PATH[m   [34mPath to the configuration file[m
+  [37mNAME[m [33mNAME[m               [34mname[m                          
+
+[36mConfiguration Values[m:
+  [34mname[m
+  [37mname[m:
+    # [32mor null[m
+    [33m<string>[m
+
diff --git a/test_resources/docs/sub-commands/show.txt b/test_resources/docs/sub-commands/show.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/sub-commands/show.txt
@@ -0,0 +1,95 @@
+WithConfig
+  _
+  (Check
+     Nothing
+     False
+     _
+     (Alt
+        (Check
+           Nothing
+           False
+           _
+           (Setting
+              Nothing
+              (Setting
+                 [ DashedLong ('c' :| "onfig-file") ]
+                 [ _ ]
+                 False
+                 Nothing
+                 True
+                 (Just ("CONFIG_FILE" :| []))
+                 Nothing
+                 Nothing
+                 (Just "FILE_PATH")
+                 (Just "Path to the configuration file"))))
+        (Check Nothing False _ (Pure _))))
+  (Commands
+     (Just
+        SrcLoc
+          { srcLocPackage = "main"
+          , srcLocModule = "OptEnvConf.APISpec"
+          , srcLocFile = "test/OptEnvConf/APISpec.hs"
+          , srcLocStartLine = 273
+          , srcLocStartCol = 5
+          , srcLocEndLine = 273
+          , srcLocEndCol = 13
+          })
+     [ Command
+         "top"
+         "command without subcommands"
+         (Check
+            Nothing
+            True
+            _
+            (Setting
+               Nothing
+               (Setting
+                  [ DashedLong ('n' :| "ame") ]
+                  [ _ ]
+                  False
+                  Nothing
+                  True
+                  (Just ("NAME" :| []))
+                  (Just
+                     [ ( "name" :| []
+                       , BimapCodec
+                           _
+                           _
+                           (EitherCodec
+                              PossiblyJointUnion
+                              NullCodec
+                              (BimapCodec _ _ (StringCodec Nothing)))
+                       )
+                     ])
+                  Nothing
+                  (Just "NAME")
+                  (Just "name"))))
+     , Command
+         "sub"
+         "command with subcommands"
+         (Ap
+            (Commands
+               (Just
+                  SrcLoc
+                    { srcLocPackage = "main"
+                    , srcLocModule = "OptEnvConf.APISpec"
+                    , srcLocFile = "test/OptEnvConf/APISpec.hs"
+                    , srcLocStartLine = 289
+                    , srcLocStartCol = 3
+                    , srcLocEndLine = 289
+                    , srcLocEndCol = 11
+                    })
+               [ Command "a" "A" (Pure _) , Command "b" "B" (Pure _) ])
+            (Commands
+               (Just
+                  SrcLoc
+                    { srcLocPackage = "main"
+                    , srcLocModule = "OptEnvConf.APISpec"
+                    , srcLocFile = "test/OptEnvConf/APISpec.hs"
+                    , srcLocStartLine = 298
+                    , srcLocStartCol = 3
+                    , srcLocEndLine = 298
+                    , srcLocEndCol = 11
+                    })
+               [ Command "c" "C" (Pure _) , Command "d" "D" (Pure _) ]))
+     ])
diff --git a/test_resources/docs/sub-commands/version.txt b/test_resources/docs/sub-commands/version.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/sub-commands/version.txt
@@ -0,0 +1,1 @@
+[33msub-commands[m 0.0.0 
diff --git a/test_resources/docs/three-commands/config-docs.txt b/test_resources/docs/three-commands/config-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/three-commands/config-docs.txt
@@ -0,0 +1,42 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      EnvDoc
+        { envDocVars = "CONFIG_FILE" :| []
+        , envDocDefault = Nothing
+        , envDocMetavar = Just "FILE_PATH"
+        , envDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsCommands
+      [ CommandDoc
+          { commandDocArgument = "one"
+          , commandDocHelp = "first"
+          , commandDocs = AnyDocsAnd []
+          }
+      , CommandDoc
+          { commandDocArgument = "two"
+          , commandDocHelp = "second"
+          , commandDocs =
+              AnyDocsAnd
+                [ AnyDocsSingle
+                    EnvDoc
+                      { envDocVars = "NUMBER" :| []
+                      , envDocDefault = Nothing
+                      , envDocMetavar = Just "INT"
+                      , envDocHelp = Just "number"
+                      }
+                , AnyDocsSingle
+                    EnvDoc
+                      { envDocVars = "ENABLE" :| []
+                      , envDocDefault = Nothing
+                      , envDocMetavar = Just "BOOL"
+                      , envDocHelp = Just "enable extra"
+                      }
+                ]
+          }
+      , CommandDoc
+          { commandDocArgument = "three"
+          , commandDocHelp = "third"
+          , commandDocs = AnyDocsAnd []
+          }
+      ]
+  ]
diff --git a/test_resources/docs/three-commands/config.txt b/test_resources/docs/three-commands/config.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/three-commands/config.txt
@@ -0,0 +1,8 @@
+  [34mnumber[m
+  [37mnumber[m:
+    # [32mor null[m
+    [33m<number>[m # [32m64 bit signed integer[m
+  [34menable extra[m
+  [37menable[m:
+    # [32mor null[m
+    [33m<boolean>[m
diff --git a/test_resources/docs/three-commands/docs.txt b/test_resources/docs/three-commands/docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/three-commands/docs.txt
@@ -0,0 +1,111 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      SetDoc
+        { setDocTryArgument = False
+        , setDocTrySwitch = False
+        , setDocTryOption = True
+        , setDocDasheds = [ DashedLong ('c' :| "onfig-file") ]
+        , setDocEnvVars = Just ("CONFIG_FILE" :| [])
+        , setDocConfKeys = Nothing
+        , setDocDefault = Nothing
+        , setDocMetavar = Just "FILE_PATH"
+        , setDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsCommands
+      [ CommandDoc
+          { commandDocArgument = "one"
+          , commandDocHelp = "first"
+          , commandDocs =
+              AnyDocsSingle
+                SetDoc
+                  { setDocTryArgument = True
+                  , setDocTrySwitch = False
+                  , setDocTryOption = False
+                  , setDocDasheds = []
+                  , setDocEnvVars = Nothing
+                  , setDocConfKeys = Nothing
+                  , setDocDefault = Nothing
+                  , setDocMetavar = Just "STR"
+                  , setDocHelp = Just "argument"
+                  }
+          }
+      , CommandDoc
+          { commandDocArgument = "two"
+          , commandDocHelp = "second"
+          , commandDocs =
+              AnyDocsAnd
+                [ AnyDocsSingle
+                    SetDoc
+                      { setDocTryArgument = False
+                      , setDocTrySwitch = False
+                      , setDocTryOption = True
+                      , setDocDasheds = [ DashedLong ('n' :| "umber") , DashedShort 'n' ]
+                      , setDocEnvVars = Just ("NUMBER" :| [])
+                      , setDocConfKeys =
+                          Just
+                            (( "number" :| []
+                             , AnyOfSchema
+                                 (NullSchema :|
+                                    [ NumberSchema
+                                        (Just
+                                           NumberBounds
+                                             { numberBoundsLower = -9.223372036854775808e18
+                                             , numberBoundsUpper = 9.223372036854775807e18
+                                             })
+                                    ])
+                             ) :|
+                               [])
+                      , setDocDefault = Nothing
+                      , setDocMetavar = Just "INT"
+                      , setDocHelp = Just "number"
+                      }
+                , AnyDocsOr
+                    [ AnyDocsSingle
+                        SetDoc
+                          { setDocTryArgument = False
+                          , setDocTrySwitch = True
+                          , setDocTryOption = False
+                          , setDocDasheds = [ DashedLong ('(' :| "enable|disable)-enable") ]
+                          , setDocEnvVars = Nothing
+                          , setDocConfKeys = Nothing
+                          , setDocDefault = Nothing
+                          , setDocMetavar = Nothing
+                          , setDocHelp = Just "enable extra"
+                          }
+                    , AnyDocsSingle
+                        SetDoc
+                          { setDocTryArgument = False
+                          , setDocTrySwitch = False
+                          , setDocTryOption = False
+                          , setDocDasheds = []
+                          , setDocEnvVars = Just ("ENABLE" :| [])
+                          , setDocConfKeys = Nothing
+                          , setDocDefault = Nothing
+                          , setDocMetavar = Just "BOOL"
+                          , setDocHelp = Just "enable extra"
+                          }
+                    , AnyDocsSingle
+                        SetDoc
+                          { setDocTryArgument = False
+                          , setDocTrySwitch = False
+                          , setDocTryOption = False
+                          , setDocDasheds = []
+                          , setDocEnvVars = Nothing
+                          , setDocConfKeys =
+                              Just
+                                (( "enable" :| [] , AnyOfSchema (NullSchema :| [ BoolSchema ]) ) :|
+                                   [])
+                          , setDocDefault = Nothing
+                          , setDocMetavar = Nothing
+                          , setDocHelp = Just "enable extra"
+                          }
+                    ]
+                ]
+          }
+      , CommandDoc
+          { commandDocArgument = "three"
+          , commandDocHelp = "third"
+          , commandDocs = AnyDocsAnd []
+          }
+      ]
+  ]
diff --git a/test_resources/docs/three-commands/env-docs.txt b/test_resources/docs/three-commands/env-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/three-commands/env-docs.txt
@@ -0,0 +1,45 @@
+AnyDocsCommands
+  [ CommandDoc
+      { commandDocArgument = "one"
+      , commandDocHelp = "first"
+      , commandDocs = AnyDocsAnd []
+      }
+  , CommandDoc
+      { commandDocArgument = "two"
+      , commandDocHelp = "second"
+      , commandDocs =
+          AnyDocsAnd
+            [ AnyDocsSingle
+                ConfDoc
+                  { confDocKeys =
+                      ( "number" :| []
+                      , AnyOfSchema
+                          (NullSchema :|
+                             [ NumberSchema
+                                 (Just
+                                    NumberBounds
+                                      { numberBoundsLower = -9.223372036854775808e18
+                                      , numberBoundsUpper = 9.223372036854775807e18
+                                      })
+                             ])
+                      ) :|
+                        []
+                  , confDocDefault = Nothing
+                  , confDocHelp = Just "number"
+                  }
+            , AnyDocsSingle
+                ConfDoc
+                  { confDocKeys =
+                      ( "enable" :| [] , AnyOfSchema (NullSchema :| [ BoolSchema ]) ) :|
+                        []
+                  , confDocDefault = Nothing
+                  , confDocHelp = Just "enable extra"
+                  }
+            ]
+      }
+  , CommandDoc
+      { commandDocArgument = "three"
+      , commandDocHelp = "third"
+      , commandDocs = AnyDocsAnd []
+      }
+  ]
diff --git a/test_resources/docs/three-commands/env.txt b/test_resources/docs/three-commands/env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/three-commands/env.txt
@@ -0,0 +1,3 @@
+  [37mCONFIG_FILE[m [33mFILE_PATH[m   [34mPath to the configuration file[m
+  [37mNUMBER[m [33mINT[m              [34mnumber[m                        
+  [37mENABLE[m [33mBOOL[m             [34menable extra[m                  
diff --git a/test_resources/docs/three-commands/help.txt b/test_resources/docs/three-commands/help.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/three-commands/help.txt
@@ -0,0 +1,42 @@
+[36mUsage: [m[33mthree-commands[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [35mone[m [33mSTR[m [36m|[m [35mtwo[m [37m--number[m[36m|[m[37m-n[m [33mINT[m [37m--(enable|disable)-enable[m [36m|[m [35mthree[m[36m)[m
+
+example with three commands
+
+[36mAvailable settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mPath to the configuration file[m
+  option: [37m--config-file[m [33mFILE_PATH[m
+  env: [37mCONFIG_FILE[m [33mFILE_PATH[m
+  
+  [34mfirst[m
+  command: [35mone[m
+    [34margument[m
+    argument: [33mSTR[m
+    
+  
+  [34msecond[m
+  command: [35mtwo[m
+    [34mnumber[m
+    option: [37m--number[m[36m|[m[37m-n[m [33mINT[m
+    env: [37mNUMBER[m [33mINT[m
+    config:
+      [37mnumber[m: # [32mor null[m
+        [33m<number>[m # [32m64 bit signed integer[m
+    
+    [34menable extra[m
+    switch: [37m--(enable|disable)-enable[m
+    env: [37mENABLE[m [33mBOOL[m
+    config:
+      [37menable[m: # [32mor null[m
+        [33m<boolean>[m
+  
+  
+  [34mthird[m
+  command: [35mthree[m
+  
+
diff --git a/test_resources/docs/three-commands/man.txt b/test_resources/docs/three-commands/man.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/three-commands/man.txt
@@ -0,0 +1,74 @@
+.Dd $Mdocdate$
+.Dt three-commands 1
+.Os
+.Sh NAME
+.Nm three-commands
+.Nd example with three commands
+.Sh VERSION
+0.0.0
+.Sh SYNOPSIS
+three-commands (-h|--help) | --version | (--config-file FILE_PATH one STR | two --number|-n INT --(enable|disable)-enable | three)
+.Sh SETTINGS
+  Show this help text
+  switch: -h|--help
+
+  Output version information: 0.0.0
+  switch: --version
+
+  Path to the configuration file
+  option: --config-file FILE_PATH
+  env: CONFIG_FILE FILE_PATH
+  
+  first
+  command: one
+    argument
+    argument: STR
+    
+  
+  second
+  command: two
+    number
+    option: --number|-n INT
+    env: NUMBER INT
+    config:
+      number: # or null
+        <number> # 64 bit signed integer
+    
+    enable extra
+    switch: --(enable|disable)-enable
+    env: ENABLE BOOL
+    config:
+      enable: # or null
+        <boolean>
+  
+  
+  third
+  command: three
+  
+
+.Sh OPTIONS
+  -h|--help Show this help text 
+  --version Output version information: 0.0.0 
+  --config-file Path to the configuration file 
+  one first
+      STR argument 
+  two second
+      --number|-n               number       
+      --(enable|disable)-enable enable extra 
+  three third
+
+.Sh ENVIRONMENT VARIABLES
+  CONFIG_FILE FILE_PATH   Path to the configuration file
+  NUMBER INT              number                        
+  ENABLE BOOL             enable extra                  
+
+.Sh CONFIGURATION VALUES
+  number
+  number:
+    # or null
+    <number> # 64 bit signed integer
+  enable extra
+  enable:
+    # or null
+    <boolean>
+
diff --git a/test_resources/docs/three-commands/opt-docs.txt b/test_resources/docs/three-commands/opt-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/three-commands/opt-docs.txt
@@ -0,0 +1,61 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      OptDoc
+        { optDocTryArgument = False
+        , optDocTrySwitch = False
+        , optDocTryOption = True
+        , optDocDasheds = [ DashedLong ('c' :| "onfig-file") ]
+        , optDocDefault = Nothing
+        , optDocMetavar = Just "FILE_PATH"
+        , optDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsCommands
+      [ CommandDoc
+          { commandDocArgument = "one"
+          , commandDocHelp = "first"
+          , commandDocs =
+              AnyDocsSingle
+                OptDoc
+                  { optDocTryArgument = True
+                  , optDocTrySwitch = False
+                  , optDocTryOption = False
+                  , optDocDasheds = []
+                  , optDocDefault = Nothing
+                  , optDocMetavar = Just "STR"
+                  , optDocHelp = Just "argument"
+                  }
+          }
+      , CommandDoc
+          { commandDocArgument = "two"
+          , commandDocHelp = "second"
+          , commandDocs =
+              AnyDocsAnd
+                [ AnyDocsSingle
+                    OptDoc
+                      { optDocTryArgument = False
+                      , optDocTrySwitch = False
+                      , optDocTryOption = True
+                      , optDocDasheds = [ DashedLong ('n' :| "umber") , DashedShort 'n' ]
+                      , optDocDefault = Nothing
+                      , optDocMetavar = Just "INT"
+                      , optDocHelp = Just "number"
+                      }
+                , AnyDocsSingle
+                    OptDoc
+                      { optDocTryArgument = False
+                      , optDocTrySwitch = True
+                      , optDocTryOption = False
+                      , optDocDasheds = [ DashedLong ('(' :| "enable|disable)-enable") ]
+                      , optDocDefault = Nothing
+                      , optDocMetavar = Nothing
+                      , optDocHelp = Just "enable extra"
+                      }
+                ]
+          }
+      , CommandDoc
+          { commandDocArgument = "three"
+          , commandDocHelp = "third"
+          , commandDocs = AnyDocsAnd []
+          }
+      ]
+  ]
diff --git a/test_resources/docs/three-commands/opt-long.txt b/test_resources/docs/three-commands/opt-long.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/three-commands/opt-long.txt
@@ -0,0 +1,9 @@
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m 
+  [37m--version[m [34mOutput version information: 0.0.0[m 
+  [37m--config-file[m [34mPath to the configuration file[m 
+  [35mone[m [34mfirst[m
+      [33mSTR[m [34margument[m 
+  [35mtwo[m [34msecond[m
+      [37m--number[m[36m|[m[37m-n[m               [34mnumber[m       
+      [37m--(enable|disable)-enable[m [34menable extra[m 
+  [35mthree[m [34mthird[m
diff --git a/test_resources/docs/three-commands/opt-short.txt b/test_resources/docs/three-commands/opt-short.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/three-commands/opt-short.txt
@@ -0,0 +1,1 @@
+[33mthree-commands[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [35mone[m [33mSTR[m [36m|[m [35mtwo[m [37m--number[m[36m|[m[37m-n[m [33mINT[m [37m--(enable|disable)-enable[m [36m|[m [35mthree[m[36m)[m
diff --git a/test_resources/docs/three-commands/reference.txt b/test_resources/docs/three-commands/reference.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/three-commands/reference.txt
@@ -0,0 +1,66 @@
+[36mUsage: [m[33mthree-commands[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [35mone[m [33mSTR[m [36m|[m [35mtwo[m [37m--number[m[36m|[m[37m-n[m [33mINT[m [37m--(enable|disable)-enable[m [36m|[m [35mthree[m[36m)[m
+
+[36mAll settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mPath to the configuration file[m
+  option: [37m--config-file[m [33mFILE_PATH[m
+  env: [37mCONFIG_FILE[m [33mFILE_PATH[m
+  
+  [34mfirst[m
+  command: [35mone[m
+    [34margument[m
+    argument: [33mSTR[m
+    
+  
+  [34msecond[m
+  command: [35mtwo[m
+    [34mnumber[m
+    option: [37m--number[m[36m|[m[37m-n[m [33mINT[m
+    env: [37mNUMBER[m [33mINT[m
+    config:
+      [37mnumber[m: # [32mor null[m
+        [33m<number>[m # [32m64 bit signed integer[m
+    
+    [34menable extra[m
+    switch: [37m--(enable|disable)-enable[m
+    env: [37mENABLE[m [33mBOOL[m
+    config:
+      [37menable[m: # [32mor null[m
+        [33m<boolean>[m
+  
+  
+  [34mthird[m
+  command: [35mthree[m
+  
+
+[36mOptions[m:
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m 
+  [37m--version[m [34mOutput version information: 0.0.0[m 
+  [37m--config-file[m [34mPath to the configuration file[m 
+  [35mone[m [34mfirst[m
+      [33mSTR[m [34margument[m 
+  [35mtwo[m [34msecond[m
+      [37m--number[m[36m|[m[37m-n[m               [34mnumber[m       
+      [37m--(enable|disable)-enable[m [34menable extra[m 
+  [35mthree[m [34mthird[m
+
+[36mEnvironment Variables[m:
+  [37mCONFIG_FILE[m [33mFILE_PATH[m   [34mPath to the configuration file[m
+  [37mNUMBER[m [33mINT[m              [34mnumber[m                        
+  [37mENABLE[m [33mBOOL[m             [34menable extra[m                  
+
+[36mConfiguration Values[m:
+  [34mnumber[m
+  [37mnumber[m:
+    # [32mor null[m
+    [33m<number>[m # [32m64 bit signed integer[m
+  [34menable extra[m
+  [37menable[m:
+    # [32mor null[m
+    [33m<boolean>[m
+
diff --git a/test_resources/docs/three-commands/show.txt b/test_resources/docs/three-commands/show.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/three-commands/show.txt
@@ -0,0 +1,177 @@
+WithConfig
+  _
+  (Check
+     Nothing
+     False
+     _
+     (Alt
+        (Check
+           Nothing
+           False
+           _
+           (Setting
+              Nothing
+              (Setting
+                 [ DashedLong ('c' :| "onfig-file") ]
+                 [ _ ]
+                 False
+                 Nothing
+                 True
+                 (Just ("CONFIG_FILE" :| []))
+                 Nothing
+                 Nothing
+                 (Just "FILE_PATH")
+                 (Just "Path to the configuration file"))))
+        (Check Nothing False _ (Pure _))))
+  (Commands
+     (Just
+        SrcLoc
+          { srcLocPackage = "main"
+          , srcLocModule = "OptEnvConf.APISpec"
+          , srcLocFile = "test/OptEnvConf/APISpec.hs"
+          , srcLocStartLine = 239
+          , srcLocStartCol = 5
+          , srcLocEndLine = 239
+          , srcLocEndCol = 13
+          })
+     [ Command
+         "one"
+         "first"
+         (Check
+            Nothing
+            True
+            _
+            (Setting
+               Nothing
+               (Setting
+                  []
+                  [ _ ]
+                  True
+                  Nothing
+                  False
+                  Nothing
+                  Nothing
+                  Nothing
+                  (Just "STR")
+                  (Just "argument"))))
+     , Command
+         "two"
+         "second"
+         (Ap
+            (Check
+               Nothing
+               True
+               _
+               (Setting
+                  Nothing
+                  (Setting
+                     [ DashedLong ('n' :| "umber") , DashedShort 'n' ]
+                     [ _ ]
+                     False
+                     Nothing
+                     True
+                     (Just ("NUMBER" :| []))
+                     (Just
+                        [ ( "number" :| []
+                          , BimapCodec
+                              _
+                              _
+                              (EitherCodec
+                                 PossiblyJointUnion
+                                 NullCodec
+                                 (BimapCodec
+                                    _
+                                    _
+                                    (NumberCodec
+                                       Nothing
+                                       (Just
+                                          NumberBounds
+                                            { numberBoundsLower = -9.223372036854775808e18
+                                            , numberBoundsUpper = 9.223372036854775807e18
+                                            }))))
+                          )
+                        ])
+                     Nothing
+                     (Just "INT")
+                     (Just "number"))))
+            (Alt
+               (Setting
+                  Nothing
+                  (Setting
+                     [ DashedLong ('(' :| "enable|disable)-enable") ]
+                     []
+                     False
+                     (Just _)
+                     False
+                     Nothing
+                     Nothing
+                     Nothing
+                     Nothing
+                     (Just "enable extra")))
+               (Alt
+                  (Setting
+                     Nothing
+                     (Setting
+                        [ DashedLong ('d' :| "isable-enable") ]
+                        []
+                        False
+                        (Just _)
+                        False
+                        Nothing
+                        Nothing
+                        Nothing
+                        Nothing
+                        Nothing))
+                  (Alt
+                     (Setting
+                        Nothing
+                        (Setting
+                           [ DashedLong ('e' :| "nable-enable") ]
+                           []
+                           False
+                           (Just _)
+                           False
+                           Nothing
+                           Nothing
+                           Nothing
+                           Nothing
+                           Nothing))
+                     (Alt
+                        (Setting
+                           Nothing
+                           (Setting
+                              []
+                              [ _ ]
+                              False
+                              Nothing
+                              False
+                              (Just ("ENABLE" :| []))
+                              Nothing
+                              Nothing
+                              (Just "BOOL")
+                              (Just "enable extra")))
+                        (Alt
+                           (Setting
+                              Nothing
+                              (Setting
+                                 []
+                                 []
+                                 False
+                                 Nothing
+                                 False
+                                 Nothing
+                                 (Just
+                                    [ ( "enable" :| []
+                                      , BimapCodec
+                                          _
+                                          _
+                                          (EitherCodec
+                                             PossiblyJointUnion NullCodec (BoolCodec Nothing))
+                                      )
+                                    ])
+                                 Nothing
+                                 Nothing
+                                 (Just "enable extra")))
+                           (Pure _)))))))
+     , Command "three" "third" (Pure _)
+     ])
diff --git a/test_resources/docs/three-commands/version.txt b/test_resources/docs/three-commands/version.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/three-commands/version.txt
@@ -0,0 +1,1 @@
+[33mthree-commands[m 0.0.0 
diff --git a/test_resources/docs/verbose/config-docs.txt b/test_resources/docs/verbose/config-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/verbose/config-docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/verbose/config.txt b/test_resources/docs/verbose/config.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/verbose/config.txt
diff --git a/test_resources/docs/verbose/docs.txt b/test_resources/docs/verbose/docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/verbose/docs.txt
@@ -0,0 +1,13 @@
+AnyDocsSingle
+  SetDoc
+    { setDocTryArgument = False
+    , setDocTrySwitch = True
+    , setDocTryOption = False
+    , setDocDasheds = [ DashedShort 'v' ]
+    , setDocEnvVars = Nothing
+    , setDocConfKeys = Nothing
+    , setDocDefault = Nothing
+    , setDocMetavar = Nothing
+    , setDocHelp =
+        Just "Verbosity level. Use multiple to increase verbosity"
+    }
diff --git a/test_resources/docs/verbose/env-docs.txt b/test_resources/docs/verbose/env-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/verbose/env-docs.txt
@@ -0,0 +1,1 @@
+AnyDocsAnd []
diff --git a/test_resources/docs/verbose/env.txt b/test_resources/docs/verbose/env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/verbose/env.txt
diff --git a/test_resources/docs/verbose/help.txt b/test_resources/docs/verbose/help.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/verbose/help.txt
@@ -0,0 +1,15 @@
+[36mUsage: [m[33mverbose[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [37m-v[m
+
+verbosity example
+
+[36mAvailable settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mVerbosity level. Use multiple to increase verbosity[m
+  switch: [37m-v[m
+  
+
diff --git a/test_resources/docs/verbose/man.txt b/test_resources/docs/verbose/man.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/verbose/man.txt
@@ -0,0 +1,26 @@
+.Dd $Mdocdate$
+.Dt verbose 1
+.Os
+.Sh NAME
+.Nm verbose
+.Nd verbosity example
+.Sh VERSION
+0.0.0
+.Sh SYNOPSIS
+verbose (-h|--help) | --version | -v
+.Sh SETTINGS
+  Show this help text
+  switch: -h|--help
+
+  Output version information: 0.0.0
+  switch: --version
+
+  Verbosity level. Use multiple to increase verbosity
+  switch: -v
+  
+
+.Sh OPTIONS
+  -h|--help Show this help text                                 
+  --version Output version information: 0.0.0                   
+  -v        Verbosity level. Use multiple to increase verbosity 
+
diff --git a/test_resources/docs/verbose/opt-docs.txt b/test_resources/docs/verbose/opt-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/verbose/opt-docs.txt
@@ -0,0 +1,11 @@
+AnyDocsSingle
+  OptDoc
+    { optDocTryArgument = False
+    , optDocTrySwitch = True
+    , optDocTryOption = False
+    , optDocDasheds = [ DashedShort 'v' ]
+    , optDocDefault = Nothing
+    , optDocMetavar = Nothing
+    , optDocHelp =
+        Just "Verbosity level. Use multiple to increase verbosity"
+    }
diff --git a/test_resources/docs/verbose/opt-long.txt b/test_resources/docs/verbose/opt-long.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/verbose/opt-long.txt
@@ -0,0 +1,3 @@
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m                                 
+  [37m--version[m [34mOutput version information: 0.0.0[m                   
+  [37m-v[m        [34mVerbosity level. Use multiple to increase verbosity[m 
diff --git a/test_resources/docs/verbose/opt-short.txt b/test_resources/docs/verbose/opt-short.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/verbose/opt-short.txt
@@ -0,0 +1,1 @@
+[33mverbose[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [37m-v[m
diff --git a/test_resources/docs/verbose/reference.txt b/test_resources/docs/verbose/reference.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/verbose/reference.txt
@@ -0,0 +1,18 @@
+[36mUsage: [m[33mverbose[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [37m-v[m
+
+[36mAll settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mVerbosity level. Use multiple to increase verbosity[m
+  switch: [37m-v[m
+  
+
+[36mOptions[m:
+  [37m-h[m[36m|[m[37m--help[m [34mShow this help text[m                                 
+  [37m--version[m [34mOutput version information: 0.0.0[m                   
+  [37m-v[m        [34mVerbosity level. Use multiple to increase verbosity[m 
+
diff --git a/test_resources/docs/verbose/show.txt b/test_resources/docs/verbose/show.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/verbose/show.txt
@@ -0,0 +1,18 @@
+Check
+  Nothing
+  True
+  _
+  (Many
+     (Setting
+        Nothing
+        (Setting
+           [ DashedShort 'v' ]
+           []
+           False
+           (Just _)
+           False
+           Nothing
+           Nothing
+           Nothing
+           Nothing
+           (Just "Verbosity level. Use multiple to increase verbosity"))))
diff --git a/test_resources/docs/verbose/version.txt b/test_resources/docs/verbose/version.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/verbose/version.txt
@@ -0,0 +1,1 @@
+[33mverbose[m 0.0.0 
diff --git a/test_resources/docs/yes-no/config-docs.txt b/test_resources/docs/yes-no/config-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/yes-no/config-docs.txt
@@ -0,0 +1,16 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      EnvDoc
+        { envDocVars = "CONFIG_FILE" :| []
+        , envDocDefault = Nothing
+        , envDocMetavar = Just "FILE_PATH"
+        , envDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsSingle
+      EnvDoc
+        { envDocVars = "EXAMPLE" :| []
+        , envDocDefault = Nothing
+        , envDocMetavar = Just "BOOL"
+        , envDocHelp = Just "Example of a yes/no switch"
+        }
+  ]
diff --git a/test_resources/docs/yes-no/config.txt b/test_resources/docs/yes-no/config.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/yes-no/config.txt
@@ -0,0 +1,4 @@
+  [34mExample of a yes/no switch[m
+  [37mexample[m:
+    # [32mor null[m
+    [33m<boolean>[m
diff --git a/test_resources/docs/yes-no/docs.txt b/test_resources/docs/yes-no/docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/yes-no/docs.txt
@@ -0,0 +1,57 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      SetDoc
+        { setDocTryArgument = False
+        , setDocTrySwitch = False
+        , setDocTryOption = True
+        , setDocDasheds = [ DashedLong ('c' :| "onfig-file") ]
+        , setDocEnvVars = Just ("CONFIG_FILE" :| [])
+        , setDocConfKeys = Nothing
+        , setDocDefault = Nothing
+        , setDocMetavar = Just "FILE_PATH"
+        , setDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsOr
+      [ AnyDocsSingle
+          SetDoc
+            { setDocTryArgument = False
+            , setDocTrySwitch = True
+            , setDocTryOption = False
+            , setDocDasheds = [ DashedLong ('[' :| "no-]example") ]
+            , setDocEnvVars = Nothing
+            , setDocConfKeys = Nothing
+            , setDocDefault = Nothing
+            , setDocMetavar = Nothing
+            , setDocHelp = Just "Example of a yes/no switch"
+            }
+      , AnyDocsSingle
+          SetDoc
+            { setDocTryArgument = False
+            , setDocTrySwitch = False
+            , setDocTryOption = False
+            , setDocDasheds = []
+            , setDocEnvVars = Just ("EXAMPLE" :| [])
+            , setDocConfKeys = Nothing
+            , setDocDefault = Nothing
+            , setDocMetavar = Just "BOOL"
+            , setDocHelp = Just "Example of a yes/no switch"
+            }
+      , AnyDocsSingle
+          SetDoc
+            { setDocTryArgument = False
+            , setDocTrySwitch = False
+            , setDocTryOption = False
+            , setDocDasheds = []
+            , setDocEnvVars = Nothing
+            , setDocConfKeys =
+                Just
+                  (( "example" :| []
+                   , AnyOfSchema (NullSchema :| [ BoolSchema ])
+                   ) :|
+                     [])
+            , setDocDefault = Nothing
+            , setDocMetavar = Nothing
+            , setDocHelp = Just "Example of a yes/no switch"
+            }
+      ]
+  ]
diff --git a/test_resources/docs/yes-no/env-docs.txt b/test_resources/docs/yes-no/env-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/yes-no/env-docs.txt
@@ -0,0 +1,8 @@
+AnyDocsSingle
+  ConfDoc
+    { confDocKeys =
+        ( "example" :| [] , AnyOfSchema (NullSchema :| [ BoolSchema ]) ) :|
+          []
+    , confDocDefault = Nothing
+    , confDocHelp = Just "Example of a yes/no switch"
+    }
diff --git a/test_resources/docs/yes-no/env.txt b/test_resources/docs/yes-no/env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/yes-no/env.txt
@@ -0,0 +1,2 @@
+  [37mCONFIG_FILE[m [33mFILE_PATH[m   [34mPath to the configuration file[m
+  [37mEXAMPLE[m [33mBOOL[m            [34mExample of a yes/no switch[m    
diff --git a/test_resources/docs/yes-no/help.txt b/test_resources/docs/yes-no/help.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/yes-no/help.txt
@@ -0,0 +1,23 @@
+[36mUsage: [m[33myes-no[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [37m--[no-]example[m[36m)[m
+
+yesNoSwitch example
+
+[36mAvailable settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mPath to the configuration file[m
+  option: [37m--config-file[m [33mFILE_PATH[m
+  env: [37mCONFIG_FILE[m [33mFILE_PATH[m
+  
+  [34mExample of a yes/no switch[m
+  switch: [37m--[no-]example[m
+  env: [37mEXAMPLE[m [33mBOOL[m
+  config:
+    [37mexample[m: # [32mor null[m
+      [33m<boolean>[m
+
+
diff --git a/test_resources/docs/yes-no/man.txt b/test_resources/docs/yes-no/man.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/yes-no/man.txt
@@ -0,0 +1,45 @@
+.Dd $Mdocdate$
+.Dt yes-no 1
+.Os
+.Sh NAME
+.Nm yes-no
+.Nd yesNoSwitch example
+.Sh VERSION
+0.0.0
+.Sh SYNOPSIS
+yes-no (-h|--help) | --version | (--config-file FILE_PATH --[no-]example)
+.Sh SETTINGS
+  Show this help text
+  switch: -h|--help
+
+  Output version information: 0.0.0
+  switch: --version
+
+  Path to the configuration file
+  option: --config-file FILE_PATH
+  env: CONFIG_FILE FILE_PATH
+  
+  Example of a yes/no switch
+  switch: --[no-]example
+  env: EXAMPLE BOOL
+  config:
+    example: # or null
+      <boolean>
+
+
+.Sh OPTIONS
+  -h|--help      Show this help text               
+  --version      Output version information: 0.0.0 
+  --config-file  Path to the configuration file    
+  --[no-]example Example of a yes/no switch        
+
+.Sh ENVIRONMENT VARIABLES
+  CONFIG_FILE FILE_PATH   Path to the configuration file
+  EXAMPLE BOOL            Example of a yes/no switch    
+
+.Sh CONFIGURATION VALUES
+  Example of a yes/no switch
+  example:
+    # or null
+    <boolean>
+
diff --git a/test_resources/docs/yes-no/opt-docs.txt b/test_resources/docs/yes-no/opt-docs.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/yes-no/opt-docs.txt
@@ -0,0 +1,22 @@
+AnyDocsAnd
+  [ AnyDocsSingle
+      OptDoc
+        { optDocTryArgument = False
+        , optDocTrySwitch = False
+        , optDocTryOption = True
+        , optDocDasheds = [ DashedLong ('c' :| "onfig-file") ]
+        , optDocDefault = Nothing
+        , optDocMetavar = Just "FILE_PATH"
+        , optDocHelp = Just "Path to the configuration file"
+        }
+  , AnyDocsSingle
+      OptDoc
+        { optDocTryArgument = False
+        , optDocTrySwitch = True
+        , optDocTryOption = False
+        , optDocDasheds = [ DashedLong ('[' :| "no-]example") ]
+        , optDocDefault = Nothing
+        , optDocMetavar = Nothing
+        , optDocHelp = Just "Example of a yes/no switch"
+        }
+  ]
diff --git a/test_resources/docs/yes-no/opt-long.txt b/test_resources/docs/yes-no/opt-long.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/yes-no/opt-long.txt
@@ -0,0 +1,4 @@
+  [37m-h[m[36m|[m[37m--help[m      [34mShow this help text[m               
+  [37m--version[m      [34mOutput version information: 0.0.0[m 
+  [37m--config-file[m  [34mPath to the configuration file[m    
+  [37m--[no-]example[m [34mExample of a yes/no switch[m        
diff --git a/test_resources/docs/yes-no/opt-short.txt b/test_resources/docs/yes-no/opt-short.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/yes-no/opt-short.txt
@@ -0,0 +1,1 @@
+[33myes-no[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [37m--[no-]example[m[36m)[m
diff --git a/test_resources/docs/yes-no/reference.txt b/test_resources/docs/yes-no/reference.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/yes-no/reference.txt
@@ -0,0 +1,37 @@
+[36mUsage: [m[33myes-no[m [36m([m[37m-h[m[36m|[m[37m--help[m[36m)[m [36m|[m [37m--version[m [36m|[m [36m([m[37m--config-file[m [33mFILE_PATH[m [37m--[no-]example[m[36m)[m
+
+[36mAll settings[m:
+  [34mShow this help text[m
+  switch: [37m-h[m[36m|[m[37m--help[m
+
+  [34mOutput version information: 0.0.0[m
+  switch: [37m--version[m
+
+  [34mPath to the configuration file[m
+  option: [37m--config-file[m [33mFILE_PATH[m
+  env: [37mCONFIG_FILE[m [33mFILE_PATH[m
+  
+  [34mExample of a yes/no switch[m
+  switch: [37m--[no-]example[m
+  env: [37mEXAMPLE[m [33mBOOL[m
+  config:
+    [37mexample[m: # [32mor null[m
+      [33m<boolean>[m
+
+
+[36mOptions[m:
+  [37m-h[m[36m|[m[37m--help[m      [34mShow this help text[m               
+  [37m--version[m      [34mOutput version information: 0.0.0[m 
+  [37m--config-file[m  [34mPath to the configuration file[m    
+  [37m--[no-]example[m [34mExample of a yes/no switch[m        
+
+[36mEnvironment Variables[m:
+  [37mCONFIG_FILE[m [33mFILE_PATH[m   [34mPath to the configuration file[m
+  [37mEXAMPLE[m [33mBOOL[m            [34mExample of a yes/no switch[m    
+
+[36mConfiguration Values[m:
+  [34mExample of a yes/no switch[m
+  [37mexample[m:
+    # [32mor null[m
+    [33m<boolean>[m
+
diff --git a/test_resources/docs/yes-no/show.txt b/test_resources/docs/yes-no/show.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/yes-no/show.txt
@@ -0,0 +1,123 @@
+WithConfig
+  _
+  (Check
+     Nothing
+     False
+     _
+     (Alt
+        (Check
+           Nothing
+           False
+           _
+           (Setting
+              Nothing
+              (Setting
+                 [ DashedLong ('c' :| "onfig-file") ]
+                 [ _ ]
+                 False
+                 Nothing
+                 True
+                 (Just ("CONFIG_FILE" :| []))
+                 Nothing
+                 Nothing
+                 (Just "FILE_PATH")
+                 (Just "Path to the configuration file"))))
+        (Check Nothing False _ (Pure _))))
+  (Alt
+     (Check
+        Nothing
+        True
+        _
+        (Setting
+           Nothing
+           (Setting
+              [ DashedLong ('[' :| "no-]example") ]
+              []
+              False
+              (Just _)
+              False
+              Nothing
+              Nothing
+              Nothing
+              Nothing
+              (Just "Example of a yes/no switch"))))
+     (Alt
+        (Check
+           Nothing
+           True
+           _
+           (Setting
+              Nothing
+              (Setting
+                 [ DashedLong ('n' :| "o-example") ]
+                 []
+                 False
+                 (Just _)
+                 False
+                 Nothing
+                 Nothing
+                 Nothing
+                 Nothing
+                 Nothing)))
+        (Alt
+           (Check
+              Nothing
+              True
+              _
+              (Setting
+                 Nothing
+                 (Setting
+                    [ DashedLong ('e' :| "xample") ]
+                    []
+                    False
+                    (Just _)
+                    False
+                    Nothing
+                    Nothing
+                    Nothing
+                    Nothing
+                    Nothing)))
+           (Alt
+              (Check
+                 Nothing
+                 True
+                 _
+                 (Setting
+                    Nothing
+                    (Setting
+                       []
+                       [ _ ]
+                       False
+                       Nothing
+                       False
+                       (Just ("EXAMPLE" :| []))
+                       Nothing
+                       Nothing
+                       (Just "BOOL")
+                       (Just "Example of a yes/no switch"))))
+              (Alt
+                 (Check
+                    Nothing
+                    True
+                    _
+                    (Setting
+                       Nothing
+                       (Setting
+                          []
+                          []
+                          False
+                          Nothing
+                          False
+                          Nothing
+                          (Just
+                             [ ( "example" :| []
+                               , BimapCodec
+                                   _
+                                   _
+                                   (EitherCodec PossiblyJointUnion NullCodec (BoolCodec Nothing))
+                               )
+                             ])
+                          Nothing
+                          Nothing
+                          (Just "Example of a yes/no switch"))))
+                 (Pure _))))))
diff --git a/test_resources/docs/yes-no/version.txt b/test_resources/docs/yes-no/version.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/docs/yes-no/version.txt
@@ -0,0 +1,1 @@
+[33myes-no[m 0.0.0 
diff --git a/test_resources/error/all-or-nothing-relevant.txt b/test_resources/error/all-or-nothing-relevant.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/all-or-nothing-relevant.txt
@@ -0,0 +1,3 @@
+Missing option: [37m--bar[m [34mThis one will not exist[m 
+You are seeing this error because at least one, but not all, of the settings in an allOrNothing (or subSettings) parser have been defined.
+Hit the 'empty' case of the Parser type, this should not happen.
diff --git a/test_resources/error/all-or-nothing.txt b/test_resources/error/all-or-nothing.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/all-or-nothing.txt
@@ -0,0 +1,2 @@
+Missing option: [37m--bar[m [34mThis one will not exist[m 
+You are seeing this error because at least one, but not all, of the settings in an allOrNothing (or subSettings) parser have been defined.
diff --git a/test_resources/error/check-failed-checkEither.txt b/test_resources/error/check-failed-checkEither.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/check-failed-checkEither.txt
@@ -0,0 +1,2 @@
+Check failed: 
+example error
diff --git a/test_resources/error/check-failed-checkMaybe.txt b/test_resources/error/check-failed-checkMaybe.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/check-failed-checkMaybe.txt
@@ -0,0 +1,2 @@
+Check failed: 
+checkMapMaybe failed without a helpful error message
diff --git a/test_resources/error/empty-choice.txt b/test_resources/error/empty-choice.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/empty-choice.txt
@@ -0,0 +1,1 @@
+Hit the 'empty' case of the Parser type, this should not happen.
diff --git a/test_resources/error/empty.txt b/test_resources/error/empty.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/empty.txt
@@ -0,0 +1,1 @@
+Hit the 'empty' case of the Parser type, this should not happen.
diff --git a/test_resources/error/missing-argument.txt b/test_resources/error/missing-argument.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/missing-argument.txt
@@ -0,0 +1,1 @@
+Missing argument: [33mARGUMENT[m [34mexample argument[m 
diff --git a/test_resources/error/missing-env.txt b/test_resources/error/missing-env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/missing-env.txt
@@ -0,0 +1,3 @@
+Missing env var: 
+[37mFOO[m [33mMETAVAR[m
+[31mundocumented[m
diff --git a/test_resources/error/missing-option.txt b/test_resources/error/missing-option.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/missing-option.txt
@@ -0,0 +1,1 @@
+Missing option: [37m--foo[m [34mexample option[m 
diff --git a/test_resources/error/missing-options.txt b/test_resources/error/missing-options.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/missing-options.txt
@@ -0,0 +1,2 @@
+Missing option: [37m--foo[m [34mexample option 1[m 
+Missing option: [37m--bar[m [34mexample option 2[m 
diff --git a/test_resources/error/missing-var.txt b/test_resources/error/missing-var.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/missing-var.txt
@@ -0,0 +1,3 @@
+Missing env var: 
+[37mFOO[m [33mMETAVAR[m
+[31mundocumented[m
diff --git a/test_resources/error/missing-vars.txt b/test_resources/error/missing-vars.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/missing-vars.txt
@@ -0,0 +1,6 @@
+Missing env var: 
+[37mFOO[m [33mMETAVAR[m
+[31mundocumented[m
+Missing env var: 
+[37mBAR[m [33mMETAVAR[m
+[31mundocumented[m
diff --git a/test_resources/error/read-int-argument.txt b/test_resources/error/read-int-argument.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/read-int-argument.txt
@@ -0,0 +1,3 @@
+Failed to read argument: 
+[33mINT[m [34minteger option[m 
+Un-Read-able value: "five"
diff --git a/test_resources/error/read-int-option.txt b/test_resources/error/read-int-option.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/read-int-option.txt
@@ -0,0 +1,3 @@
+Failed to read option: 
+[37m--num[m [34minteger option[m 
+Un-Read-able value: "five"
diff --git a/test_resources/error/read-int-options.txt b/test_resources/error/read-int-options.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/read-int-options.txt
@@ -0,0 +1,6 @@
+Failed to read option: 
+[37m--foo[m [34minteger option 1[m 
+Un-Read-able value: "n"
+Failed to read option: 
+[37m--bar[m [34minteger option 2[m 
+Un-Read-able value: "m"
diff --git a/test_resources/error/required-command.txt b/test_resources/error/required-command.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/required-command.txt
@@ -0,0 +1,2 @@
+Missing command, available commands:
+[33mone[m [33mtwo[m
diff --git a/test_resources/error/some-none.txt b/test_resources/error/some-none.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/some-none.txt
@@ -0,0 +1,1 @@
+Missing argument: [33mMETAVAR[m [31mundocumented[m 
diff --git a/test_resources/error/unfolding-tombstone-option.txt b/test_resources/error/unfolding-tombstone-option.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/unfolding-tombstone-option.txt
@@ -0,0 +1,1 @@
+Missing option: [37m-b[m [31mundocumented[m 
diff --git a/test_resources/error/unfolding-tombstone-switch.txt b/test_resources/error/unfolding-tombstone-switch.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/unfolding-tombstone-switch.txt
@@ -0,0 +1,1 @@
+Missing option: [37m-f[m [31mundocumented[m 
diff --git a/test_resources/error/unreadable-var.txt b/test_resources/error/unreadable-var.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/unreadable-var.txt
@@ -0,0 +1,4 @@
+Failed to read env var: 
+[37mFOO[m [33mMETAVAR[m
+[31mundocumented[m
+Un-Read-able value: "n"
diff --git a/test_resources/error/unreadable-vars.txt b/test_resources/error/unreadable-vars.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/unreadable-vars.txt
@@ -0,0 +1,8 @@
+Failed to read env var: 
+[37mFOO[m [33mMETAVAR[m
+[31mundocumented[m
+Un-Read-able value: "n"
+Failed to read env var: 
+[37mBAR[m [33mMETAVAR[m
+[31mundocumented[m
+Un-Read-able value: "m"
diff --git a/test_resources/error/unrecognised-command.txt b/test_resources/error/unrecognised-command.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/error/unrecognised-command.txt
@@ -0,0 +1,3 @@
+[31mUnrecognised command: [m[33mthree[m
+[34mavailable commands:[m
+[33mone[m [33mtwo[m
diff --git a/test_resources/lint/config-without-load.txt b/test_resources/lint/config-without-load.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/config-without-load.txt
@@ -0,0 +1,5 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  [33mconf[m was called with no way to load configuration.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:120:7 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/dash-in-long.txt b/test_resources/lint/dash-in-long.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/dash-in-long.txt
@@ -0,0 +1,7 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  [33mlong[m may not start with a '-'.
+  Found [33mlong[m "--switch".
+  Try [33mlong[m "switch" instead.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:40:7 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/dash-in-short.txt b/test_resources/lint/dash-in-short.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/dash-in-short.txt
@@ -0,0 +1,6 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  [33mshort[m may not contain a '-'.
+  Found [33mshort[m '-'.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:32:7 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/empty-setting.txt b/test_resources/lint/empty-setting.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/empty-setting.txt
@@ -0,0 +1,6 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  This [33msetting[m parses nothing.
+  Add an [33margument[m, [33mswitch[m, [33moption[m, [33menv[m, [33mconf[m, or [33mvalue[m.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:19:7 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/no-commands.txt b/test_resources/lint/no-commands.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/no-commands.txt
@@ -0,0 +1,5 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  [33mcommands[m was called with an empty list.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:117:6 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/no-dashed-for-option.txt b/test_resources/lint/no-dashed-for-option.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/no-dashed-for-option.txt
@@ -0,0 +1,5 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  [33moption[m has no [33mlong[m or [33mshort[m.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:74:7 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/no-dashed-for-switch.txt b/test_resources/lint/no-dashed-for-switch.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/no-dashed-for-switch.txt
@@ -0,0 +1,5 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  [33mswitch[m has no [33mlong[m or [33mshort[m.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:94:7 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/no-metavar-for-argument.txt b/test_resources/lint/no-metavar-for-argument.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/no-metavar-for-argument.txt
@@ -0,0 +1,5 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  [33margument[m has no [33mmetavar[m.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:56:7 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/no-metavar-for-env.txt b/test_resources/lint/no-metavar-for-env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/no-metavar-for-env.txt
@@ -0,0 +1,5 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  [33menv[m has no [33mmetavar[m.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:108:7 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/no-metavar-for-option.txt b/test_resources/lint/no-metavar-for-option.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/no-metavar-for-option.txt
@@ -0,0 +1,5 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  [33moption[m has no [33mmetavar[m.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:84:7 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/no-reader-for-argument.txt b/test_resources/lint/no-reader-for-argument.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/no-reader-for-argument.txt
@@ -0,0 +1,5 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  [33margument[m has no [33mreader[m.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:48:7 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/no-reader-for-env.txt b/test_resources/lint/no-reader-for-env.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/no-reader-for-env.txt
@@ -0,0 +1,9 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  [33menv[m has no [33mreader[m.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:101:7 in main:OptEnvConf.LintSpec[m
+  
+  [31mInvalid Setting:[m
+  [33menv[m has no [33mmetavar[m.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:101:7 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/no-reader-for-option.txt b/test_resources/lint/no-reader-for-option.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/no-reader-for-option.txt
@@ -0,0 +1,5 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  [33moption[m has no [33mreader[m.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:65:7 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/null-setting.txt b/test_resources/lint/null-setting.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/null-setting.txt
@@ -0,0 +1,10 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  missing [33mhelp[m.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:16:6 in main:OptEnvConf.LintSpec[m
+  
+  [31mInvalid Setting:[m
+  This [33msetting[m parses nothing.
+  Add an [33margument[m, [33mswitch[m, [33moption[m, [33menv[m, [33mconf[m, or [33mvalue[m.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:16:6 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/only-default.txt b/test_resources/lint/only-default.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/only-default.txt
@@ -0,0 +1,6 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  This [33msetting[m parses nothing.
+  Add an [33margument[m, [33mswitch[m, [33moption[m, [33menv[m, [33mconf[m, or [33mvalue[m.
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:25:7 in main:OptEnvConf.LintSpec[m
diff --git a/test_resources/lint/unreadable-example.txt b/test_resources/lint/unreadable-example.txt
new file mode 100644
--- /dev/null
+++ b/test_resources/lint/unreadable-example.txt
@@ -0,0 +1,6 @@
+[31mSetting parser is invalid:[m
+  
+  [31mInvalid Setting:[m
+  [33mexample[m was called with an example that none of the [33mreader[ms succeed in reading.
+  Example: NaN
+  Defined at: [36mtest/OptEnvConf/LintSpec.hs:128:7 in main:OptEnvConf.LintSpec[m
