chore: run doctests in parallel

Runs the doctests much faster, which is potentially useful in
combination with postgrest-watch for local development.

This implies that doctests run on compiled code, not in a GHCi session,
which has some implications:
- Only exported functions can be tested.
- Imports need to be made explicit in doctests themselves.

On the flipside, this would allow us to potentially include doctest
results in code coverage, I believe.

This change is a requirement to vendor hasql, which otherwise breaks the
existing doctests: hasql contains a .hsc file, which *needs* to be
compiled - not interpreted - to make the tests work.
This commit is contained in:
Wolfgang Walther
2026-07-14 06:55:32 +00:00
parent aa6c19ebda
commit 44e15e4e9b
13 changed files with 55 additions and 31 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ jobs:
- name: Run doctests
if: always()
run: postgrest-test-doctests
run: nix-shell --run postgrest-test-doctests
- name: Check the spec tests for idempotence
if: always()
+1
View File
@@ -30,3 +30,4 @@ gen_private.json
.pytest_cache
.ruff_cache
postgrest-module-graph.png
.ghc.environment.*
+3
View File
@@ -2,3 +2,6 @@ packages: postgrest.cabal
tests: true
allow-newer:
hasql:postgresql-libpq
-- https://github.com/martijnbastiaan/doctest-parallel/blob/main/example/README.md#cabalproject
write-ghc-environment-files: always
-2
View File
@@ -55,8 +55,6 @@ let
withEnv = postgrest.env;
}
''
# This makes nix-env -iA tests.doctests.bin work.
export NIX_GHC=${postgrest.env.NIX_GHC}
${cabal-install}/bin/cabal v2-run ${devCabalOptions} test:doctests
'';
+1 -4
View File
@@ -352,14 +352,11 @@ test-suite observability
test-suite doctests
type: exitcode-stdio-1.0
default-language: Haskell2010
default-extensions: OverloadedStrings
NoImplicitPrelude
hs-source-dirs: test/doc
main-is: Main.hs
build-depends: base >= 4.9 && < 4.22
, doctest >= 0.8
, doctest-parallel >= 0.4
, postgrest
, pretty-simple
, protolude >= 0.3.1 && < 0.4
ghc-options: -threaded -O0 -Werror -Wall -fwarn-identities
-fno-spec-constr -optP-Wno-nonportable-include-path
+4
View File
@@ -21,6 +21,7 @@ module PostgREST.ApiRequest.Preferences
, shouldCount
, shouldExplainCount
, prefAppliedHeader
, toHeaderValue
) where
import qualified Data.ByteString.Char8 as BS
@@ -34,7 +35,10 @@ import Protolude
-- $setup
-- Setup for doctests
-- >>> :set -XStandaloneDeriving
-- >>> import Text.Pretty.Simple (pPrint)
-- >>> import qualified Data.Set as S
-- >>> import Protolude
-- >>> deriving instance Show PreferResolution
-- >>> deriving instance Show PreferRepresentation
-- >>> deriving instance Show PreferCount
+15
View File
@@ -9,7 +9,18 @@
module PostgREST.ApiRequest.QueryParams
( parse
, QueryParams(..)
, pFieldForest
, pFieldName
, pFieldSelect
, pJsonPath
, pLogicTree
, pOpExpr
, pOrder
, pRelationSelect
, pRequestFilter
, pRequestRange
, pSingleVal
, pSpreadRelationSelect
) where
import qualified Data.ByteString.Char8 as BS
@@ -62,6 +73,10 @@ import PostgREST.Error (QPError (..))
import Protolude hiding (Sum, try)
-- $setup
-- >>> import qualified Text.ParserCombinators.Parsec as P
-- >>> import Protolude hiding (Sum, try)
data QueryParams =
QueryParams
{ qsCanonical :: ByteString
+1
View File
@@ -597,6 +597,7 @@ pgConnString conn | uriDesignator `T.isPrefixOf` conn || shortUriDesignator `T.i
-- | Adds a `fallback_application_name` value to the connection string. This allows querying the PostgREST version on pg_stat_activity.
--
-- >>> import Protolude
-- >>> let ver = "11.1.0 (5a04ec7)"::ByteString
-- >>> let strangeVer = "11'1&0@#$%,.:\"[]{}?+^()=asdfqwer"::ByteString
--
+8
View File
@@ -19,6 +19,8 @@ module PostgREST.Error
, JwtClaimsError(..)
, errorPayload
, status
, noRelBetweenHint
, noRpcHint
) where
import qualified Data.Aeson as JSON
@@ -57,6 +59,12 @@ import PostgREST.Error.Types
import Protolude
-- $setup
-- >>> import qualified Data.HashMap.Strict as HM
-- >>> import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..))
-- >>> import PostgREST.SchemaCache.Relationship (Relationship (..))
-- >>> import PostgREST.SchemaCache.Routine (Routine (..), RoutineParam (..))
-- | Encode Error to ByteString
errorPayload :: (ErrorBody a, ErrorHeaders a) => Verbosity -> a -> LByteString
errorPayload verb = JSON.encode . toJsonPgrstError verb
+4
View File
@@ -9,6 +9,7 @@ module PostgREST.MediaType
, toContentType
, toMime
, decodeMediaType
, tokenizeMediaType
) where
import qualified Data.Aeson as JSON
@@ -22,6 +23,9 @@ import Network.HTTP.Types.Header (Header, hContentType)
import Protolude
-- $setup
-- >>> import qualified Text.ParserCombinators.Parsec as P
-- | Enumeration of currently supported media types
data MediaType
= MTApplicationJSON
+10
View File
@@ -24,6 +24,7 @@ module PostgREST.Plan
, InfoPlan(..)
, CrudPlan(..)
, legacyWarnings
, addNullEmbedFilters
) where
import qualified Data.HashMap.Strict as HM
@@ -87,7 +88,16 @@ import Protolude hiding (from)
-- $setup
-- Setup for doctests
-- >>> :set -XDuplicateRecordFields
-- >>> import Data.Ranged.Ranges (fullRange)
-- >>> import Data.Tree (Tree (..))
-- >>> import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..))
-- >>> import PostgREST.ApiRequest.Types
-- >>> import PostgREST.Plan.CallPlan
-- >>> import PostgREST.Plan.MutatePlan
-- >>> import PostgREST.Plan.ReadPlan as ReadPlan
-- >>> import PostgREST.Plan.Types
-- >>> import Protolude
-- Plan for reading or writing to the db
data CrudPlan
+3
View File
@@ -8,6 +8,9 @@ import qualified Network.HTTP.Types as HTTP
import Numeric (showFFloat)
import Protolude
-- $setup
-- >>> import Protolude
-- | ServerTiming represents the timing data for a request, in seconds.
data ServerTiming =
ServerTiming
+4 -24
View File
@@ -1,27 +1,7 @@
module Main (main) where
import Test.DocTest (doctest)
import Protolude
module Main where
import System.Environment (getArgs)
import Test.DocTest (mainFromCabal)
main :: IO ()
main =
doctest
[ "-XOverloadedStrings"
, "-XNoImplicitPrelude"
, "-XStandaloneDeriving"
, "-XDuplicateRecordFields"
, "-isrc"
, "src/PostgREST/ApiRequest/Preferences.hs"
, "src/PostgREST/ApiRequest/QueryParams.hs"
, "src/PostgREST/Config.hs"
, "src/PostgREST/Error.hs"
, "src/PostgREST/MediaType.hs"
, "src/PostgREST/Network.hs"
, "src/PostgREST/Plan.hs"
, "src/PostgREST/Query/SqlFragment.hs"
, "src/PostgREST/Response.hs"
, "src/PostgREST/Response/Performance.hs"
, "src/PostgREST/SchemaCache/Identifiers.hs"
]
main = mainFromCabal "postgrest" =<< getArgs