pqi-conformance: Differential conformance tests for pqi adapters

[ database, library, mit, postgresql, testing ] [ Propose Tags ] [ Report a vulnerability ]

A reusable hspec toolkit that checks any pqi Pqi.IsConnection adapter against the FFI reference adapter. It boots a throwaway PostgreSQL container (via testcontainers), runs the same operation on the candidate and the FFI connection, and asserts that the protocol-derived observations match.

Each adapter's own test suite reuses these spec builders, wiring itself in as the candidate.


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.0.1.0, 0.0.1.1, 0.0.1.2
Change log CHANGELOG.md
Dependencies base (>=4.11 && <5), bytestring (>=0.10 && <0.13), containers (>=0.6 && <0.9), directory (>=1.3 && <1.4), hspec (>=2.11 && <2.12), postgresql-libpq (>=0.11 && <0.12), pqi (>=0.0 && <0.1), testcontainers-postgresql (>=0.2 && <0.3), text (>=1.2 && <3) [details]
License MIT
Copyright (c) 2026, Nikita Volkov
Author Nikita Volkov <nikita.y.volkov@mail.ru>
Maintainer Nikita Volkov <nikita.y.volkov@mail.ru>
Uploaded by NikitaVolkov at 2026-06-18T11:34:31Z
Category Database, PostgreSQL, Testing
Home page https://github.com/nikita-volkov/pqi-conformance
Bug tracker https://github.com/nikita-volkov/pqi-conformance/issues
Source repo head: git clone https://github.com/nikita-volkov/pqi-conformance
Distributions
Downloads 0 total (0 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user
Build status unknown [no reports yet]

Readme for pqi-conformance-0.0.1.2

[back to package description]

pqi-conformance

Hackage Continuous Haddock

A reusable hspec toolkit that checks any pqi adapter against the battle-tested postgresql-libpq library as a reference.

Goal: full libpq fidelity

The purpose of this suite is to enforce byte-identical output to libpq for every protocol-derived value. This means error message strings, notice text, result status, field metadata, cell data, and all structured error fields must all match libpq's output exactly, not just in shape or presence.

The suite runs the same operation on the candidate adapter and on a direct postgresql-libpq reference connection (the fidelity reference, which delegates directly to the C libpq library), connected to the same throwaway PostgreSQL container. It then asserts that the protocol-derived observations are equal.

Structurally incomparable values

A small number of values are structurally incomparable across connections and are handled differently:

  • backendPID — the OS process ID of the backend. Each connection gets a distinct backend, so the two PIDs will never match. The spec asserts > 0 independently for each adapter.
  • socket — the file descriptor of the client socket. Also connection-specific. Covered only by its own presence check.
  • Notify.bePid — the PID of the notifying backend. Since each adapter's connection has its own backend, cross-adapter comparison would always fail. Instead, each adapter asserts independently that notification.bePid == backendPID connection (a within-connection assertion that verifies the PID field is correctly populated).

These omissions are a structural constraint of the differential testing approach, not an intentional leniency in the suite. All other values — including error message text, notice text, and cancel error text — are compared in full.

Structure: one module per operation

The suite is organised as one spec module per API operation, under Pqi.Conformance.Operation.*...Operation.Exec, ...Operation.ExecParams, ...Operation.LoSeek, ...Operation.Fnumber, and so on, one for every public method of Pqi.IsConnection, Pqi.IsResult, and Pqi.IsCancel, plus the standalone Pqi.unescapeBytea. Each module holds the differential scenarios that exercise that one operation (its happy paths, its edge cases, and its error paths). Shared scenario fragments live in Pqi.Conformance.Scenario.

Usage

An adapter's own test suite is a one-liner — it hands specs a Proxy of its connection type and specs takes care of booting the container and running the whole battery (every operation, the coverage meta-test, and SCRAM):

module Main (main) where

import Data.Proxy (Proxy (..))
import Pqi.Conformance (specs)
import MyAdapter (MyConnection)
import Test.Hspec (hspec)

main :: IO ()
main = hspec (specs (Proxy @MyConnection))

MyConnection only needs a Pqi.IsConnection instance; the candidate and the postgresql-libpq reference are both driven through that interface.

Contributing

Contributions extending the suite are very welcome. The more thoroughly we cover the operations, the more confidence we can have in the adapters.