module Test.DocTest.Internal.Runner.Example (
Result (..)
, mkResult
) where
import Data.Char
import Data.List
import Test.DocTest.Internal.Util
import Test.DocTest.Internal.Parse
maxBy :: (Ord a) => (b -> a) -> b -> b -> b
maxBy :: (b -> a) -> b -> b -> b
maxBy b -> a
f b
x b
y = case a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (b -> a
f b
x) (b -> a
f b
y) of
Ordering
LT -> b
y
Ordering
EQ -> b
x
Ordering
GT -> b
x
data Result = Equal | NotEqual [String]
deriving (Result -> Result -> Bool
(Result -> Result -> Bool)
-> (Result -> Result -> Bool) -> Eq Result
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Result -> Result -> Bool
$c/= :: Result -> Result -> Bool
== :: Result -> Result -> Bool
$c== :: Result -> Result -> Bool
Eq, Int -> Result -> ShowS
[Result] -> ShowS
Result -> String
(Int -> Result -> ShowS)
-> (Result -> String) -> ([Result] -> ShowS) -> Show Result
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Result] -> ShowS
$cshowList :: [Result] -> ShowS
show :: Result -> String
$cshow :: Result -> String
showsPrec :: Int -> Result -> ShowS
$cshowsPrec :: Int -> Result -> ShowS
Show)
mkResult :: ExpectedResult -> [String] -> Result
mkResult :: ExpectedResult -> [String] -> Result
mkResult ExpectedResult
expected_ [String]
actual_ =
case ExpectedResult
expected ExpectedResult -> [String] -> Match LinesDivergence
`matches` [String]
actual of
Match LinesDivergence
Full -> Result
Equal
Partial LinesDivergence
partial -> [String] -> Result
NotEqual (ExpectedResult -> [String] -> LinesDivergence -> [String]
formatNotEqual ExpectedResult
expected [String]
actual LinesDivergence
partial)
where
escapeOutput :: ShowS
escapeOutput
| (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSafe) (String -> Bool) -> String -> Bool
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([String]
expectedAsString [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
actual_) = ShowS
forall a. [a] -> [a]
init ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
forall a. [a] -> [a]
tail ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
forall a. Show a => a -> String
show ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
stripEnd
| Bool
otherwise = ShowS
forall a. a -> a
id
actual :: [String]
actual :: [String]
actual = ShowS -> [String] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ShowS
escapeOutput [String]
actual_
expected :: ExpectedResult
expected :: ExpectedResult
expected = (ExpectedLine -> ExpectedLine) -> ExpectedResult -> ExpectedResult
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ShowS -> ExpectedLine -> ExpectedLine
transformExcpectedLine ShowS
escapeOutput) ExpectedResult
expected_
expectedAsString :: [String]
expectedAsString :: [String]
expectedAsString = (ExpectedLine -> String) -> ExpectedResult -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (\ExpectedLine
x -> case ExpectedLine
x of
ExpectedLine [LineChunk]
str -> (LineChunk -> String) -> [LineChunk] -> String
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap LineChunk -> String
lineChunkToString [LineChunk]
str
ExpectedLine
WildCardLine -> String
"..." ) ExpectedResult
expected_
isSafe :: Char -> Bool
isSafe :: Char -> Bool
isSafe Char
c = Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ' Bool -> Bool -> Bool
|| (Char -> Bool
isPrint Char
c Bool -> Bool -> Bool
&& (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace) Char
c)
chunksMatch :: [LineChunk] -> String -> Match ChunksDivergence
chunksMatch :: [LineChunk] -> String -> Match ChunksDivergence
chunksMatch [] String
"" = Match ChunksDivergence
forall a. Match a
Full
chunksMatch [LineChunk String
xs] String
ys =
if ShowS
stripEnd String
xs String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== ShowS
stripEnd String
ys
then Match ChunksDivergence
forall a. Match a
Full
else ChunksDivergence -> Match ChunksDivergence
forall a. a -> Match a
Partial (ChunksDivergence -> Match ChunksDivergence)
-> ChunksDivergence -> Match ChunksDivergence
forall a b. (a -> b) -> a -> b
$ String -> String -> ChunksDivergence
matchingPrefix String
xs String
ys
chunksMatch (LineChunk String
x : [LineChunk]
xs) String
ys =
if String
x String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
ys
then (ChunksDivergence -> ChunksDivergence)
-> Match ChunksDivergence -> Match ChunksDivergence
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String -> ChunksDivergence -> ChunksDivergence
prependText String
x) (Match ChunksDivergence -> Match ChunksDivergence)
-> Match ChunksDivergence -> Match ChunksDivergence
forall a b. (a -> b) -> a -> b
$ ([LineChunk]
xs [LineChunk] -> String -> Match ChunksDivergence
`chunksMatch` Int -> ShowS
forall a. Int -> [a] -> [a]
drop (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
x) String
ys)
else ChunksDivergence -> Match ChunksDivergence
forall a. a -> Match a
Partial (ChunksDivergence -> Match ChunksDivergence)
-> ChunksDivergence -> Match ChunksDivergence
forall a b. (a -> b) -> a -> b
$ String -> String -> ChunksDivergence
matchingPrefix String
x String
ys
chunksMatch zs :: [LineChunk]
zs@(LineChunk
WildCardChunk : [LineChunk]
xs) (Char
_:String
ys) =
(ChunksDivergence -> ChunksDivergence)
-> Match ChunksDivergence -> Match ChunksDivergence
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ChunksDivergence -> ChunksDivergence
prependWildcard (Match ChunksDivergence -> Match ChunksDivergence)
-> Match ChunksDivergence -> Match ChunksDivergence
forall a b. (a -> b) -> a -> b
$ (Match ChunksDivergence -> Match Int)
-> Match ChunksDivergence
-> Match ChunksDivergence
-> Match ChunksDivergence
forall a b. Ord a => (b -> a) -> b -> b -> b
maxBy
((ChunksDivergence -> Int) -> Match ChunksDivergence -> Match Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((ChunksDivergence -> Int) -> Match ChunksDivergence -> Match Int)
-> (ChunksDivergence -> Int) -> Match ChunksDivergence -> Match Int
forall a b. (a -> b) -> a -> b
$ String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (String -> Int)
-> (ChunksDivergence -> String) -> ChunksDivergence -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ChunksDivergence -> String
matchText)
([LineChunk] -> String -> Match ChunksDivergence
chunksMatch [LineChunk]
xs String
ys)
([LineChunk] -> String -> Match ChunksDivergence
chunksMatch [LineChunk]
zs String
ys)
chunksMatch [LineChunk
WildCardChunk] [] = Match ChunksDivergence
forall a. Match a
Full
chunksMatch (LineChunk
WildCardChunk:[LineChunk]
_) [] = ChunksDivergence -> Match ChunksDivergence
forall a. a -> Match a
Partial (String -> String -> ChunksDivergence
ChunksDivergence String
"" String
"")
chunksMatch [] (Char
_:String
_) = ChunksDivergence -> Match ChunksDivergence
forall a. a -> Match a
Partial (String -> String -> ChunksDivergence
ChunksDivergence String
"" String
"")
matchingPrefix :: String -> String -> ChunksDivergence
matchingPrefix String
xs String
ys =
let common :: String
common = ((Char, Char) -> Char) -> [(Char, Char)] -> String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Char, Char) -> Char
forall a b. (a, b) -> a
fst (((Char, Char) -> Bool) -> [(Char, Char)] -> [(Char, Char)]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (\(Char
x, Char
y) -> Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
y) (String
xs String -> String -> [(Char, Char)]
forall a b. [a] -> [b] -> [(a, b)]
`zip` String
ys)) in
String -> String -> ChunksDivergence
ChunksDivergence String
common String
common
matches :: ExpectedResult -> [String] -> Match LinesDivergence
matches :: ExpectedResult -> [String] -> Match LinesDivergence
matches (ExpectedLine [LineChunk]
x : ExpectedResult
xs) (String
y : [String]
ys) =
case [LineChunk]
x [LineChunk] -> String -> Match ChunksDivergence
`chunksMatch` String
y of
Match ChunksDivergence
Full -> (LinesDivergence -> LinesDivergence)
-> Match LinesDivergence -> Match LinesDivergence
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap LinesDivergence -> LinesDivergence
incLineNo (Match LinesDivergence -> Match LinesDivergence)
-> Match LinesDivergence -> Match LinesDivergence
forall a b. (a -> b) -> a -> b
$ ExpectedResult
xs ExpectedResult -> [String] -> Match LinesDivergence
`matches` [String]
ys
Partial ChunksDivergence
partial -> LinesDivergence -> Match LinesDivergence
forall a. a -> Match a
Partial (Int -> String -> LinesDivergence
LinesDivergence Int
1 (ChunksDivergence -> String
expandedWildcards ChunksDivergence
partial))
matches zs :: ExpectedResult
zs@(ExpectedLine
WildCardLine : ExpectedResult
xs) us :: [String]
us@(String
_ : [String]
ys) =
let matchWithoutWC :: Match LinesDivergence
matchWithoutWC = ExpectedResult
xs ExpectedResult -> [String] -> Match LinesDivergence
`matches` [String]
us in
let matchWithWC :: Match LinesDivergence
matchWithWC = (LinesDivergence -> LinesDivergence)
-> Match LinesDivergence -> Match LinesDivergence
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap LinesDivergence -> LinesDivergence
incLineNo (ExpectedResult
zs ExpectedResult -> [String] -> Match LinesDivergence
`matches` [String]
ys) in
let key :: LinesDivergence -> (Int, Int)
key (LinesDivergence Int
lineNo String
line) = (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
line, Int
lineNo) in
(Match LinesDivergence -> Match (Int, Int))
-> Match LinesDivergence
-> Match LinesDivergence
-> Match LinesDivergence
forall a b. Ord a => (b -> a) -> b -> b -> b
maxBy ((LinesDivergence -> (Int, Int))
-> Match LinesDivergence -> Match (Int, Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap LinesDivergence -> (Int, Int)
key) Match LinesDivergence
matchWithoutWC Match LinesDivergence
matchWithWC
matches [ExpectedLine
WildCardLine] [] = Match LinesDivergence
forall a. Match a
Full
matches [] [] = Match LinesDivergence
forall a. Match a
Full
matches [] [String]
_ = LinesDivergence -> Match LinesDivergence
forall a. a -> Match a
Partial (Int -> String -> LinesDivergence
LinesDivergence Int
1 String
"")
matches ExpectedResult
_ [] = LinesDivergence -> Match LinesDivergence
forall a. a -> Match a
Partial (Int -> String -> LinesDivergence
LinesDivergence Int
1 String
"")
data Match a = Partial a | Full
deriving (Match a -> Match a -> Bool
(Match a -> Match a -> Bool)
-> (Match a -> Match a -> Bool) -> Eq (Match a)
forall a. Eq a => Match a -> Match a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Match a -> Match a -> Bool
$c/= :: forall a. Eq a => Match a -> Match a -> Bool
== :: Match a -> Match a -> Bool
$c== :: forall a. Eq a => Match a -> Match a -> Bool
Eq, Eq (Match a)
Eq (Match a)
-> (Match a -> Match a -> Ordering)
-> (Match a -> Match a -> Bool)
-> (Match a -> Match a -> Bool)
-> (Match a -> Match a -> Bool)
-> (Match a -> Match a -> Bool)
-> (Match a -> Match a -> Match a)
-> (Match a -> Match a -> Match a)
-> Ord (Match a)
Match a -> Match a -> Bool
Match a -> Match a -> Ordering
Match a -> Match a -> Match a
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Ord a => Eq (Match a)
forall a. Ord a => Match a -> Match a -> Bool
forall a. Ord a => Match a -> Match a -> Ordering
forall a. Ord a => Match a -> Match a -> Match a
min :: Match a -> Match a -> Match a
$cmin :: forall a. Ord a => Match a -> Match a -> Match a
max :: Match a -> Match a -> Match a
$cmax :: forall a. Ord a => Match a -> Match a -> Match a
>= :: Match a -> Match a -> Bool
$c>= :: forall a. Ord a => Match a -> Match a -> Bool
> :: Match a -> Match a -> Bool
$c> :: forall a. Ord a => Match a -> Match a -> Bool
<= :: Match a -> Match a -> Bool
$c<= :: forall a. Ord a => Match a -> Match a -> Bool
< :: Match a -> Match a -> Bool
$c< :: forall a. Ord a => Match a -> Match a -> Bool
compare :: Match a -> Match a -> Ordering
$ccompare :: forall a. Ord a => Match a -> Match a -> Ordering
$cp1Ord :: forall a. Ord a => Eq (Match a)
Ord, Int -> Match a -> ShowS
[Match a] -> ShowS
Match a -> String
(Int -> Match a -> ShowS)
-> (Match a -> String) -> ([Match a] -> ShowS) -> Show (Match a)
forall a. Show a => Int -> Match a -> ShowS
forall a. Show a => [Match a] -> ShowS
forall a. Show a => Match a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Match a] -> ShowS
$cshowList :: forall a. Show a => [Match a] -> ShowS
show :: Match a -> String
$cshow :: forall a. Show a => Match a -> String
showsPrec :: Int -> Match a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Match a -> ShowS
Show)
instance Functor Match where
fmap :: (a -> b) -> Match a -> Match b
fmap a -> b
f (Partial a
a) = b -> Match b
forall a. a -> Match a
Partial (a -> b
f a
a)
fmap a -> b
_ Match a
Full = Match b
forall a. Match a
Full
data ChunksDivergence = ChunksDivergence { ChunksDivergence -> String
matchText :: String, ChunksDivergence -> String
expandedWildcards :: String }
deriving (Int -> ChunksDivergence -> ShowS
[ChunksDivergence] -> ShowS
ChunksDivergence -> String
(Int -> ChunksDivergence -> ShowS)
-> (ChunksDivergence -> String)
-> ([ChunksDivergence] -> ShowS)
-> Show ChunksDivergence
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ChunksDivergence] -> ShowS
$cshowList :: [ChunksDivergence] -> ShowS
show :: ChunksDivergence -> String
$cshow :: ChunksDivergence -> String
showsPrec :: Int -> ChunksDivergence -> ShowS
$cshowsPrec :: Int -> ChunksDivergence -> ShowS
Show)
prependText :: String -> ChunksDivergence -> ChunksDivergence
prependText :: String -> ChunksDivergence -> ChunksDivergence
prependText String
s (ChunksDivergence String
mt String
wct) = String -> String -> ChunksDivergence
ChunksDivergence (String
sString -> ShowS
forall a. [a] -> [a] -> [a]
++String
mt) (String
sString -> ShowS
forall a. [a] -> [a] -> [a]
++String
wct)
prependWildcard :: ChunksDivergence -> ChunksDivergence
prependWildcard :: ChunksDivergence -> ChunksDivergence
prependWildcard (ChunksDivergence String
mt String
wct) = String -> String -> ChunksDivergence
ChunksDivergence String
mt (Char
'.'Char -> ShowS
forall a. a -> [a] -> [a]
:String
wct)
data LinesDivergence = LinesDivergence { LinesDivergence -> Int
_mismatchLineNo :: Int, LinesDivergence -> String
_partialLine :: String }
deriving (Int -> LinesDivergence -> ShowS
[LinesDivergence] -> ShowS
LinesDivergence -> String
(Int -> LinesDivergence -> ShowS)
-> (LinesDivergence -> String)
-> ([LinesDivergence] -> ShowS)
-> Show LinesDivergence
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [LinesDivergence] -> ShowS
$cshowList :: [LinesDivergence] -> ShowS
show :: LinesDivergence -> String
$cshow :: LinesDivergence -> String
showsPrec :: Int -> LinesDivergence -> ShowS
$cshowsPrec :: Int -> LinesDivergence -> ShowS
Show)
incLineNo :: LinesDivergence -> LinesDivergence
incLineNo :: LinesDivergence -> LinesDivergence
incLineNo (LinesDivergence Int
lineNo String
partialLineMatch) = Int -> String -> LinesDivergence
LinesDivergence (Int
lineNo Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) String
partialLineMatch
formatNotEqual :: ExpectedResult -> [String] -> LinesDivergence -> [String]
formatNotEqual :: ExpectedResult -> [String] -> LinesDivergence -> [String]
formatNotEqual ExpectedResult
expected_ [String]
actual LinesDivergence
partial = String -> [String] -> [String]
formatLines String
"expected: " [String]
expected [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ String -> [String] -> [String]
formatLines String
" but got: " (Bool -> LinesDivergence -> [String] -> [String]
lineMarker Bool
wildcard LinesDivergence
partial [String]
actual)
where
expected :: [String]
expected :: [String]
expected = (ExpectedLine -> String) -> ExpectedResult -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (\ExpectedLine
x -> case ExpectedLine
x of
ExpectedLine [LineChunk]
str -> (LineChunk -> String) -> [LineChunk] -> String
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap LineChunk -> String
lineChunkToString [LineChunk]
str
ExpectedLine
WildCardLine -> String
"..." ) ExpectedResult
expected_
formatLines :: String -> [String] -> [String]
formatLines :: String -> [String] -> [String]
formatLines String
message [String]
xs = case [String]
xs of
String
y:[String]
ys -> (String
message String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
y) String -> [String] -> [String]
forall a. a -> [a] -> [a]
: ShowS -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String
padding String -> ShowS
forall a. [a] -> [a] -> [a]
++) [String]
ys
[] -> [String
message]
where
padding :: String
padding = Int -> Char -> String
forall a. Int -> a -> [a]
replicate (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
message) Char
' '
wildcard :: Bool
wildcard :: Bool
wildcard = (ExpectedLine -> Bool) -> ExpectedResult -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\ExpectedLine
x -> case ExpectedLine
x of
ExpectedLine [LineChunk]
xs -> (LineChunk -> Bool) -> [LineChunk] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\LineChunk
y -> case LineChunk
y of { LineChunk
WildCardChunk -> Bool
True; LineChunk
_ -> Bool
False }) [LineChunk]
xs
ExpectedLine
WildCardLine -> Bool
True ) ExpectedResult
expected_
lineChunkToString :: LineChunk -> String
lineChunkToString :: LineChunk -> String
lineChunkToString LineChunk
WildCardChunk = String
"..."
lineChunkToString (LineChunk String
str) = String
str
transformExcpectedLine :: (String -> String) -> ExpectedLine -> ExpectedLine
transformExcpectedLine :: ShowS -> ExpectedLine -> ExpectedLine
transformExcpectedLine ShowS
f (ExpectedLine [LineChunk]
xs) =
[LineChunk] -> ExpectedLine
ExpectedLine ([LineChunk] -> ExpectedLine) -> [LineChunk] -> ExpectedLine
forall a b. (a -> b) -> a -> b
$ (LineChunk -> LineChunk) -> [LineChunk] -> [LineChunk]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\LineChunk
el -> case LineChunk
el of
LineChunk String
s -> String -> LineChunk
LineChunk (String -> LineChunk) -> String -> LineChunk
forall a b. (a -> b) -> a -> b
$ ShowS
f String
s
LineChunk
WildCardChunk -> LineChunk
WildCardChunk
) [LineChunk]
xs
transformExcpectedLine ShowS
_ ExpectedLine
WildCardLine = ExpectedLine
WildCardLine
lineMarker :: Bool -> LinesDivergence -> [String] -> [String]
lineMarker :: Bool -> LinesDivergence -> [String] -> [String]
lineMarker Bool
wildcard (LinesDivergence Int
row String
expanded) [String]
actual =
let ([String]
pre, [String]
post) = Int -> [String] -> ([String], [String])
forall a. Int -> [a] -> ([a], [a])
splitAt Int
row [String]
actual in
[String]
pre [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++
[(if Bool
wildcard Bool -> Bool -> Bool
&& String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
expanded Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
30
then String
expanded
else Int -> Char -> String
forall a. Int -> a -> [a]
replicate (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
expanded) Char
' ') String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"^"] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++
[String]
post