packages feed

mdoc-0.1.1.0: test/Autodocodec/Schema/MdocSpec.hs

-- |
--
-- Module      : Autodocodec.Schema.MdocSpec
-- Copyright   : (c) 2026 Patrick Brisbin
-- License     : AGPL-3
-- Maintainer  : pbrisbin@gmail.com
-- Stability   : experimental
-- Portability : POSIX
module Autodocodec.Schema.MdocSpec
  ( spec
  ) where

import Mdoc.Prelude

import Autodocodec.Schema
  ( JSONSchema (..)
  , KeyRequirement (..)
  , ObjectSchema (..)
  )
import Autodocodec.Schema.Mdoc
import Data.Aeson qualified as Aeson
import Data.List.NonEmpty qualified as NE
import Mdoc.Gen.Config
import Mdoc.Gen.Described
import Mdoc.MdocLine
import Mdoc.Test.Render
import Test.Hspec

spec :: Spec
spec = do
  describe "getConfigs" $ do
    let
      renderJSONSchema :: JSONSchema -> [MdocLine]
      renderJSONSchema =
        renderDescribedItems renderConfig . getConfigs Nothing

      renderJSONSchemaAt :: NonEmpty String -> JSONSchema -> [MdocLine]
      renderJSONSchemaAt keys =
        renderDescribedItems renderConfig . getConfigs (Just keys)

    it "primitive" $ do
      renderJSONSchema BoolSchema
        `shouldRender` [".It : Ar boolean"]

    it "array of primitive" $ do
      renderJSONSchema (ArraySchema BoolSchema)
        `shouldRender` [".It : Ar boolean Ns []"]

    it "array of any-of" $ do
      let
        js :: JSONSchema
        js = ArraySchema (AnyOfSchema $ StringSchema :| [BoolSchema])

      renderJSONSchema js
        `shouldRender` [".It : ( Ar string Ns | Ns Ar boolean ) Ns []"]

    it "any-of with array" $ do
      let
        js :: JSONSchema
        js = AnyOfSchema $ StringSchema :| [ArraySchema BoolSchema]

      renderJSONSchema js
        `shouldRender` [".It : Ar string Ns | Ns Ar boolean Ns []"]

    it "log-level example"
      $ do
        let
          keys :: NonEmpty String
          keys = "log" :| ["level"]

          js :: JSONSchema
          js =
            AnyOfSchema
              $ ValueSchema (Aeson.String "info")
                :| [ ValueSchema (Aeson.String "warn")
                   , ValueSchema (Aeson.String "error")
                   ]

        renderJSONSchemaAt keys js
          `shouldRender` [".It Cm log.level : Ar info Ns | Ns Ar warn Ns | Ns Ar error"]

    it "renders types with comments" $ do
      let
        keys :: NonEmpty String
        keys = pure "name"

        js :: JSONSchema
        js = CommentSchema "The person's name" StringSchema

      renderJSONSchemaAt keys js
        `shouldRender` [ ".It Cm name : Ar string"
                       , "The person's name"
                       ]

    context "objects" $ do
      let
        key :: Text -> JSONSchema -> ObjectSchema
        key k s = ObjectKeySchema k Required s Nothing

        keyComment :: Text -> Text -> JSONSchema -> ObjectSchema
        keyComment k d s = ObjectKeySchema k Required s $ Just d

        object :: [ObjectSchema] -> JSONSchema
        object = ObjectSchema . ObjectAllOfSchema . NE.fromList

      it "special case, any" $ do
        renderJSONSchema (ObjectSchema ObjectAnySchema)
          `shouldRender` [".It : Ar any"]

      it "one-level" $ do
        let
          js :: JSONSchema
          js =
            object
              [ key "foo" StringSchema
              , key "bar" BoolSchema
              , key "baz" (RefSchema "custom")
              ]

        renderJSONSchema js
          `shouldRender` [ ".It Cm foo : Ar string"
                         , ".It Cm bar : Ar boolean"
                         , ".It Cm baz : Ar custom"
                         ]

      it "multi-level" $ do
        let
          js :: JSONSchema
          js = object [key "foo" (object [key "bar" (object [key "baz" StringSchema])])]

        renderJSONSchema js
          `shouldRender` [ ".It Cm foo : Ar object"
                         , ".It Cm foo.bar : Ar object"
                         , ".It Cm foo.bar.baz : Ar string"
                         ]

      it "list of object at key" $ do
        let
          js :: JSONSchema
          js =
            ArraySchema
              $ object
                [ key "name" StringSchema
                , keyComment "admin" "Admin?" BoolSchema
                ]

        renderJSONSchema js
          `shouldRender` [ ".It Cm [].name : Ar string"
                         , ".It Cm [].admin : Ar boolean"
                         , "Admin?"
                         ]

      it "list of object at key" $ do
        let
          keys :: NonEmpty String
          keys = pure "people"

          js :: JSONSchema
          js =
            ArraySchema
              $ object
                [ key "name" StringSchema
                , keyComment "admin" "Admin?" BoolSchema
                ]

        renderJSONSchemaAt keys js
          `shouldRender` [ ".It Cm people : Ar object Ns []"
                         , ".It Cm people[].name : Ar string"
                         , ".It Cm people[].admin : Ar boolean"
                         , "Admin?"
                         ]