module Hedgehog.Extras.Stock.String
  ( strip
  , lastLine
  , firstLine
  , readNoteM
  ) where

import           Control.Monad.Catch (MonadCatch)
import           Data.Bifunctor
import           Data.Function
import           Data.Semigroup
import           Data.String
import           GHC.Stack
import           Text.Read
import           Text.Show (Show)

import qualified Data.List as L
import qualified Data.Text as T
import qualified Hedgehog as H
import qualified Hedgehog.Extras.Test.Base as H

-- | Strip whitespace from the beginning and end of the string.
strip :: String -> String
strip :: String -> String
strip = Text -> String
T.unpack (Text -> String) -> (String -> Text) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
T.strip (Text -> Text) -> (String -> Text) -> String -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack

-- | Get the last line in the string
lastLine :: String -> String
lastLine :: String -> String
lastLine = String -> String
strip (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> String
L.unlines ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [String]
forall a. [a] -> [a]
L.reverse ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [String] -> [String]
forall a. Int -> [a] -> [a]
L.take Int
1 ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [String]
forall a. [a] -> [a]
L.reverse ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
L.lines

-- | Get the first line in the string
firstLine :: String -> String
firstLine :: String -> String
firstLine = String -> String
strip (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> String
L.unlines ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [String] -> [String]
forall a. Int -> [a] -> [a]
L.take Int
1 ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
L.lines

-- | Trim leading and trailing whitespace and read the string into a value. Report the read value in the test
-- annotations.
readNoteM :: (Read a, Show a, H.MonadTest m, MonadCatch m, HasCallStack) => String -> m a
readNoteM :: forall a (m :: * -> *).
(Read a, Show a, MonadTest m, MonadCatch m, HasCallStack) =>
String -> m a
readNoteM String
inputStr =
  (HasCallStack => m a) -> m a
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack
  ((HasCallStack => m a) -> m a) -> (HasCallStack => m a) -> m a
forall a b. (a -> b) -> a -> b
$ m a -> m a
forall (m :: * -> *) a.
(MonadTest m, MonadCatch m, HasCallStack, Show a) =>
m a -> m a
H.noteShowM
  (m a -> m a) -> (String -> m a) -> String -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either String a -> m a
forall (m :: * -> *) x a.
(MonadTest m, Show x, HasCallStack) =>
Either x a -> m a
H.evalEither
  (Either String a -> m a)
-> (String -> Either String a) -> String -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> Either String a -> Either String a
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
": " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
inputStr)
  (Either String a -> Either String a)
-> (String -> Either String a) -> String -> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Either String a
forall a. Read a => String -> Either String a
readEither
  (String -> m a) -> String -> m a
forall a b. (a -> b) -> a -> b
$ String -> String
strip String
inputStr