tuispec-0.1.0.0: src/TuiSpec/Types.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{- |
Module : TuiSpec.Types
Description : Core types for TUI test specs, selectors, and runtime options.
These types are the public DSL surface used by test programs.
-}
module TuiSpec.Types (
AmbiguityMode (..),
App (..),
Key (..),
Modifier (..),
PtyHandle (..),
Rect (..),
RunOptions (..),
Selector (..),
SnapshotName (..),
Spec (..),
StepOptions (..),
Tui (..),
TuiState (..),
Viewport (..),
WaitOptions (..),
defaultRunOptions,
defaultStepOptions,
defaultWaitOptions,
) where
import Data.IORef (IORef)
import Data.String (IsString (..))
import Data.Text (Text)
import Data.Text qualified as T
import System.Posix.Pty (Pty)
import System.Process (ProcessHandle)
-- | A single test specification: name + executable body.
data Spec = Spec
{ specName :: String
, specBody :: Tui -> IO ()
}
-- | The command to launch inside the PTY.
data App = App
{ command :: FilePath
, args :: [String]
}
deriving (Eq, Show)
-- | How selector ambiguity is handled for assertion helpers.
data AmbiguityMode
= FailOnAmbiguous
| FirstVisibleMatch
deriving (Eq, Show, Read)
-- | Runtime options for a @tuiTest@ execution.
data RunOptions = RunOptions
{ timeoutSeconds :: Int
, retries :: Int
, stepRetries :: Int
, terminalCols :: Int
, terminalRows :: Int
, artifactsDir :: FilePath
, ambiguityMode :: AmbiguityMode
, updateSnapshots :: Bool
, snapshotTheme :: String
}
deriving (Eq, Show)
{- | Sensible defaults for local and CI runs.
Defaults:
- timeout: 5s
- retries: 0
- viewport: 134x40
- artifacts dir: @artifacts@
-}
defaultRunOptions :: RunOptions
defaultRunOptions =
RunOptions
{ timeoutSeconds = 5
, retries = 0
, stepRetries = 0
, terminalCols = 134
, terminalRows = 40
, artifactsDir = "artifacts"
, ambiguityMode = FailOnAmbiguous
, updateSnapshots = False
, snapshotTheme = "auto"
}
-- | Key modifiers for combo key presses.
data Modifier
= Control
| Alt
| Shift
deriving (Eq, Show, Read)
-- | Input key model used by @press@ and @pressCombo@.
data Key
= Enter
| Esc
| Tab
| Backspace
| ArrowUp
| ArrowDown
| ArrowLeft
| ArrowRight
| Ctrl Char
| AltKey Char
| FunctionKey Int
| CharKey Char
| NamedKey Text
deriving (Eq, Show, Read)
-- | A rectangular region within the terminal viewport.
data Rect = Rect
{ rectCol :: Int
, rectRow :: Int
, rectWidth :: Int
, rectHeight :: Int
}
deriving (Eq, Show, Read)
-- | Selector language used by visibility and text assertions.
data Selector
= Exact Text
| Regex Text
| At Int Int
| Within Rect Selector
| Nth Int Selector
deriving (Eq, Show, Read)
-- | Polling behavior for @waitFor@.
data WaitOptions = WaitOptions
{ timeoutMs :: Int
, pollIntervalMs :: Int
}
deriving (Eq, Show, Read)
-- | Default wait behavior: 30s timeout with 100ms polling.
defaultWaitOptions :: WaitOptions
defaultWaitOptions =
WaitOptions
{ timeoutMs = 30000
, pollIntervalMs = 100
}
-- | Strongly-typed snapshot identifier.
newtype SnapshotName = SnapshotName
{ unSnapshotName :: Text
}
deriving (Eq, Ord, Show)
instance IsString SnapshotName where
fromString = SnapshotName . T.pack
-- | Retry behavior for a single logical test step.
data StepOptions = StepOptions
{ stepMaxRetries :: Int
, stepRetryDelayMs :: Int
}
deriving (Eq, Show, Read)
-- | Default step retries: no retries, no delay.
defaultStepOptions :: StepOptions
defaultStepOptions =
StepOptions
{ stepMaxRetries = 0
, stepRetryDelayMs = 0
}
-- | The current terminal viewport text plus dimensions.
data Viewport = Viewport
{ viewportCols :: Int
, viewportRows :: Int
, viewportText :: Text
}
deriving (Eq, Show)
-- | Handle to the child process and PTY master descriptor.
data PtyHandle = PtyHandle
{ ptyMaster :: Pty
, ptyProcess :: ProcessHandle
}
-- | Mutable runtime state tracked while a test executes.
data TuiState = TuiState
{ launchedApp :: Maybe App
, visibleBuffer :: Text
, rawBuffer :: Text
, actionLog :: [Text]
, snapshotLog :: [Text]
, runtimeWarnings :: [Text]
, frameLog :: [Text]
}
{- | Runtime test handle passed into each spec body.
This is intentionally opaque in normal test usage, even though
record fields are exported for advanced integrations.
-}
data Tui = Tui
{ tuiName :: String
, tuiOptions :: RunOptions
, tuiRootDir :: FilePath
, tuiTestRoot :: FilePath
, tuiSnapshotRoot :: FilePath
, tuiPty :: IORef (Maybe PtyHandle)
, tuiStateRef :: IORef TuiState
}