module Ribosome.Test (
  -- * Introduction
  -- $intro

  -- * Embedded testing
  -- $embed

  -- * tmux testing
  -- $tmux

  -- * Embedded test API
  testPlugin,
  testEmbed,
  testPluginEmbed,
  runEmbedTest,
  runTest,
  testPluginConf,
  testPlugin_,
  testEmbedConf,
  testEmbed_,
  testEmbedLevel,
  testEmbedLevel_,
  testEmbedDebug,
  testEmbedDebug_,
  testEmbedTrace,
  testEmbedTrace_,
  runTestConf,
  runTestLogConf,
  EmbedStackWith,
  EmbedStack,
  EmbedHandlerStack,
  TestEffects,
  TestConfig (TestConfig),
  TmuxTestConfig (TmuxTestConfig),
  -- * Error handling
  module Ribosome.Test.Error,
  module Ribosome.Host.Data.Report,
  -- * Assertions for Neovim UI elements
  windowCountIs,
  cursorIs,
  currentCursorIs,
  awaitScreenshot,
  -- * Assertions that are made repeatedly until the succeed
  assertWait,
  assertWaitFor,
) where

import Ribosome.Host.Data.Report (resumeReportFail, stopReportToFail)
import Ribosome.Test.Data.TestConfig (TestConfig (TestConfig), TmuxTestConfig (TmuxTestConfig))
import Ribosome.Test.Embed (
  EmbedHandlerStack,
  EmbedStack,
  EmbedStackWith,
  TestEffects,
  runEmbedTest,
  runTest,
  runTestConf,
  runTestLogConf,
  testEmbed,
  testEmbedConf,
  testEmbedLevel,
  testEmbedLevel_,
  testEmbedTrace,
  testEmbedDebug,
  testEmbedTrace_,
  testEmbedDebug_,
  testEmbed_,
  testPlugin,
  testPluginConf,
  testPluginEmbed,
  testPlugin_,
  )
import Ribosome.Test.Error
import Ribosome.Test.Screenshot (awaitScreenshot)
import Ribosome.Test.Ui
import Ribosome.Test.Wait

-- $intro
-- This is the test library for the "Ribosome" Neoivm plugin framework.
--
-- Three different test environments are available:
--
-- - "Ribosome.Test.Embed" runs Neovim as a subprocess and connects over stdio
--
-- - "Ribosome.Test.EmbedTmux" is like "Ribosome.Test.Embed", but provides a tmux server
--
-- - "Ribosome.Test.SocketTmux" runs Neovim in a window in a fresh tmux server, either headless in a pseudo terminal
-- or in an @xterm@ instance
--
-- This module reexports "Ribosome.Test.Embed".

-- $embed
-- Running a test against an embedded Neovim process is the simplest approach that is suited for unit testing plugin
-- logic where the integration with Neovim startup isn't important.
--
-- Handlers can be registered in Neovim and triggered via RPC API functions like 'nvimCallFunction' and 'nvimCommand'.
-- Most of the time this is only interesting if a handler has complex parameters and you want to test that they are
-- decoded correctly, or that the handler is triggered properly by an autocmd.
-- In more basic cases, where only the interaction with Neovim from within the handler is relevant, it can simply be run
-- directly.
--
-- > import Polysemy.Test
-- > import Ribosome
-- > import Ribosome.Api
-- > import Ribosome.Test
-- >
-- > store ::
-- >   Member (Rpc !! RpcError) r =>
-- >   Args ->
-- >   Handler r ()
-- > store (Args msg) =
-- >   ignoreRpcError do
-- >     nvimSetVar "message" msg
-- >
-- > test_direct :: UnitTest
-- > test_direct =
-- >   testEmbed_ do
-- >     store "test directly"
-- >     assertEq "test directly" =<< nvimGetVar @Text "message"
-- >
-- > test_rpc :: UnitTest
-- > test_rpc =
-- >   testPlugin_ [rpcCommand "Store" Sync store] do
-- >     nvimCommand "Store test RPC"
-- >     assertEq "test RPC" =<< nvimGetVar @Text "message"
--
-- See [Ribosome.Test.Embed]("Ribosome.Test.Embed") for more options.

-- $tmux
-- It is possible to run a standalone Neovim instance to test against.
-- This is useful to observe the UI's behaviour for debugging purposes, but might also be desired to test a feature in
-- the full environment that is used in production.
--
-- Ribosome provides a testing mode that starts a terminal with a tmux server, in which Neovim is executed as a regular
-- shell process.
-- Variants of this that run tmux in a pseudo terminal that is not rendered, or simply run a tmux server for use in an
-- embedded test, are also available.
--
-- In the terminal case, the test connects the plugin over a socket.
-- It is possible to take \"screenshots\" (capturing the tmux pane running Neovim) that are automatically stored in the
-- @fixtures@ directory of the test suite and compared to previous recordings on subsequent runs, as in this example
-- that runs tmux in a terminal and tests some syntax rules:
--
-- > import Polysemy.Test
-- > import Ribosome.Api
-- > import Ribosome.Syntax
-- > import Ribosome.Test
-- > import Ribosome.Test.SocketTmux
-- >
-- > syntax :: Syntax
-- > syntax =
-- >   Syntax [syntaxMatch "TestColons" "::"] [
-- >     syntaxHighlight "TestColons" [("cterm", "reverse"), ("ctermfg", "1"), ("gui", "reverse"), ("guifg", "#dc322f")]
-- >   ] []
-- >
-- > test_syntax :: UnitTest
-- > test_syntax =
-- >   testSocketTmuxGui do
-- >     setCurrentBufferContent ["function :: String -> Int", "function _ = 5"]
-- >     _ <- executeSyntax syntax
-- >     awaitScreenshot False "syntax" 0
-- >
-- > See [Ribosome.Test.SocketTmux]("Ribosome.Test.SocketTmux") and [Ribosome.Test.EmbedTmux]("Ribosome.Test.EmbedTmux")
-- > for more options.