content: {-# LANGUAGE CPP                 #-}
  {-# LANGUAGE OverloadedStrings   #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  import Test.Tasty.Bench
  import Data.Text (Text)
  import Data.Functor.Identity  -- base >= 4.8
  import Commonmark
  import qualified Data.Text as T
  import qualified Data.Text.IO as TIO
  
  main :: IO ()
  main = do
    sample <- T.replicate 10 <$> TIO.readFile "benchmark/sample.md"
    defaultMain
      [ bgroup "tokenize"
        [ benchTokenize ("sample.md", sample) ]
      , bgroup "parse sample.md"
        [ benchCommonmark defaultSyntaxSpec ("commonmark default", sample)
        ]
      , bgroup "pathological"
        (map toPathBench pathtests)
      ]
  
  toPathBench :: (String, Int -> T.Text) -> Benchmark
  toPathBench (name, ptest) =
    bgroup name
    [ bgroup "commonmark"
      (map (\n -> benchCommonmark defaultSyntaxSpec (show n, ptest n))
        [1000, 2000, 3000, 4000])
    ]
  
  pathtests :: [(String, Int -> T.Text)]
  pathtests =
    [ ("nested strong emph", \n ->
       let num = n `div` 14 in
       T.replicate num "*a **a " <> "b" <>
       T.replicate num " a** a*")
    , ("many emph closers with no openers", \n ->
       let num = n `div` 3 in
       T.replicate num "a_ ")
    , ("many emph openers with no closers", \n ->
       let num = n `div` 3 in
       T.replicate num "_a ")
    , ("many link closers with no openers", \n ->
      let num = n `div` 2 in
       T.replicate num "a]")
    , ("many link openers with no closers", \n ->
      let num = n `div` 2 in
       T.replicate num "[a")
    , ("mismatched openers and closers", \n ->
      let num = n `div` 3 in
       T.replicate num "*a_ ")
    , ("openers and closers multiple of 3", \n ->
      let num = n `div` 7 in
       T.replicate num "a**b" <> T.replicate num "c* ")
    , ("link openers and emph closers", \n ->
      let num = n `div` 4 in
       mconcat (replicate num "[ a_"))
    , ("nested brackets", \n ->
      let num = n `div` 2 in
       T.replicate num "[" <> "a" <> T.replicate num "]")
    , ("inline link openers without closers", \n ->
      let num = n `div` 3 in
      T.replicate num "[](")
    , ("repeated pattern '[ (]('" , \n ->
      let num = n `div` 5 in
      T.replicate num "[ (](")
    , ("nested block quotes", \n ->
      let num = n `div` 2 in
       T.replicate num "> " <> "a")
    , ("nested list", \n ->
      let num = floor (sqrt (fromIntegral n :: Double)) in
      mconcat (map (\ind -> T.replicate ind " " <> "- a\n") [0..(num - 1)]))
    , ("nested list 2", \n ->
      let num = n `div` 2 in
      T.replicate num "* " <> "a\n")
    , ("backticks", \n ->
      let num = floor (sqrt (9 + (8 * (fromIntegral n :: Double))) / 2) in
      mconcat $ map (\x -> "e" <> T.replicate x "`") [1..num])
    , ("CDATA", \n ->
      let num = n `div` 11 in
      T.replicate num "a <![CDATA[")
    , ("<?", \n ->
      let num = n `div` 2 in
      ("a" <> T.replicate num "<?"))
    , ("<!A ", \n ->
      let num = n `div` 4 in
      ("a" <> T.replicate num "<!A "))
    ]
  
  benchCommonmark :: SyntaxSpec Identity (Html ()) (Html ())
                  -> (String, Text)
                  -> Benchmark
  benchCommonmark spec (name, contents) =
    bench name $
      nf (either (error . show) renderHtml
          . runIdentity . parseCommonmarkWith spec . tokenize name)
      contents
  
  benchTokenize :: (String, Text) -> Benchmark
  benchTokenize (name, contents) =
    bench ("tokenize " ++ name) $ nf (length . tokenize name) contents
  