packages feed

mdoc-0.2.0.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
import Autodocodec.Schema.Mdoc
import Data.Aeson qualified as Aeson
import Data.List.NonEmpty qualified as NE
import Mdoc.Pretty
import Mdoc.Test.Render
import Test.Hspec

spec :: Spec
spec = do
  it "primitive" $ do
    schemaDoc BoolSchema
      `shouldRender` [".It : Ar boolean"]

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

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

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

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

    schemaDoc 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")
               ]

    schemaDocAt 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

    schemaDocAt 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
      schemaDoc (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")
            ]

      schemaDoc 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])])]

      schemaDoc 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
              ]

      schemaDoc 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
              ]

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

schemaDoc :: JSONSchema -> Doc ann
schemaDoc = vsep . map pretty . getConfigs Nothing

schemaDocAt :: NonEmpty String -> JSONSchema -> Doc ann
schemaDocAt keys = vsep . map pretty . getConfigs (Just keys)