packages feed

baikai-openai-0.6.0.0: test/Contract.hs

-- | The stream protocol, as an assertion.
--
-- Lives in its own module rather than in @Main@ because three suites
-- need it — the end-to-end cases in @Main@, the failure-stream cases in
-- @SseSpec@, and the evidence cases in @EvidenceSpec@ — and a protocol
-- asserted three slightly different ways is not asserted at all.
module Contract (assertErrorContract, assertOneErrorTerminal) where

import Baikai.Stream.Event
  ( AssistantMessageEvent (..),
    StartPayload (..),
    TerminalPayload (..),
    isTerminal,
  )
import Test.Tasty.HUnit (Assertion, assertFailure, (@?=))

-- | The whole documented protocol for a failing stream: exactly one
-- 'EventStart', first; exactly one terminal; and that terminal an
-- 'EventError' carrying structured 'errorInfo'.
--
-- Use this on anything that drains a provider stream. A fragment folded
-- straight through @translate@ never carried a start event, so it gets
-- 'assertOneErrorTerminal' instead.
assertErrorContract :: [AssistantMessageEvent] -> Assertion
assertErrorContract events = do
  case events of
    EventStart StartPayload {} : _ -> pure ()
    other -> assertFailure ("stream must begin with EventStart, got: " <> show (take 1 other))
  length [() | EventStart {} <- events] @?= 1
  assertOneErrorTerminal events
  case reverse events of
    (EventError TerminalPayload {} : _) -> pure ()
    other -> assertFailure ("stream must end with EventError, got: " <> show (take 1 other))

-- | The terminal half of 'assertErrorContract', for translator-level
-- fragments that never carried a start event.
assertOneErrorTerminal :: [AssistantMessageEvent] -> Assertion
assertOneErrorTerminal events = do
  let terminals = filter isTerminal events
  length terminals @?= 1
  case terminals of
    [EventError TerminalPayload {errorInfo = Nothing}] ->
      assertFailure "terminal EventError omitted errorInfo"
    [EventError TerminalPayload {errorInfo = Just _}] -> pure ()
    other -> assertFailure ("expected exactly one terminal EventError, got: " <> show other)