packages feed

pqi-conformance-0.1.0.0: src/library/Pqi/Conformance/Operation/ErrorMessage.hs

-- | Coverage for 'Pqi.errorMessage': the connection-level error string.
--
-- The goal is byte-identical output to libpq's @PQerrorMessage@ in all
-- documented scenarios. Error strings are compared in full — not just for
-- presence — so formatting bugs are caught. Scenarios are chosen to avoid
-- statement-position fields (@'P'@), which depend on the client-stored query
-- text and cannot be reproduced from wire fields alone.
--
-- The one structurally incomparable value is the null-connection sentinel
-- @\"connection pointer is NULL\\n\"@: it is hardcoded in libpq rather than
-- derived from a wire response, but both adapters must return exactly that
-- string.
module Pqi.Conformance.Operation.ErrorMessage
  ( spec,
  )
where

import qualified Pqi
import Pqi.Conformance.Harness
import Pqi.Conformance.Prelude
import Pqi.Conformance.Scenario (drainResults)
import Test.Hspec

spec :: Pqi.Adapter -> SpecWith ByteString
spec adapter =
  describe "errorMessage" do
    it "is empty on a healthy connection" \conninfo ->
      differential adapter conninfo \connection -> do
        _ <- connection.exec "select 1"
        connection.errorMessage

    it "is populated after a failed exec and cleared by a subsequent success" \conninfo ->
      differential adapter conninfo \connection -> do
        _ <- connection.exec "do $$ begin raise exception 'conformance error'; end $$"
        afterFail <- connection.errorMessage
        _ <- connection.exec "select 1"
        afterSuccess <- connection.errorMessage
        pure (afterFail, afterSuccess)

    it "is populated after a failed getResult and cleared by a subsequent success" \conninfo ->
      differential adapter conninfo \connection -> do
        _ <- connection.sendQuery "do $$ begin raise exception 'conformance error'; end $$"
        _ <- drainResults connection
        afterFail <- connection.errorMessage
        _ <- connection.sendQuery "select 1"
        _ <- drainResults connection
        afterSuccess <- connection.errorMessage
        pure (afterFail, afterSuccess)

    it "is populated after a connection failure" \conninfo ->
      differentialConnect adapter conninfo \adapter' conninfo' -> do
        conn <- adapter'.connectdb (conninfo' <> " user=pqi_no_such_user")
        msg <- conn.errorMessage
        conn.finish
        pure msg

    it "is the null-connection sentinel on a null connection" \conninfo ->
      differentialConnect adapter conninfo \adapter' _ -> do
        conn <- adapter'.newNullConnection
        msg <- conn.errorMessage
        conn.finish
        pure msg