content: {-# LANGUAGE BangPatterns      #-}
  {-# LANGUAGE CPP               #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE TupleSections     #-}
  {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
  module Data.Conduit.AttoparsecSpec (spec) where
  import           Control.Exception                (fromException)
  import           Test.Hspec
  
  import           Control.Applicative              ((<*), (<|>))
  import           Control.Monad
  import qualified Data.Attoparsec.ByteString.Char8
  import qualified Data.Attoparsec.Text
  import           Data.Conduit
  import           Data.Conduit.Attoparsec
  import qualified Data.Conduit.List                as CL
  
  spec :: Spec
  spec = describe "Data.Conduit.AttoparsecSpec" $ do
      describe "error position" $ do
          it "works for text" $ do
              let input = ["aaa\na", "aaa\n\n", "aaa", "aab\n\naaaa"]
                  badLine = 4
                  badCol = 6
                  badOff = 15
                  parser = Data.Attoparsec.Text.endOfInput <|> (Data.Attoparsec.Text.notChar 'b' >> parser)
                  sink = sinkParser parser
                  sink' = sinkParserEither parser
                  ea = runConduit $ CL.sourceList input .| sink
              case ea of
                  Left e ->
                      case fromException e of
                          Just pe -> do
                              errorPosition pe `shouldBe` Position badLine badCol badOff
              ea' <- runConduit $ CL.sourceList input .| sink'
              case ea' of
                  Left pe ->
                      errorPosition pe `shouldBe` Position badLine badCol badOff
          it "works for bytestring" $ do
              let input = ["aaa\na", "aaa\n\n", "aaa", "aab\n\naaaa"]
                  badLine = 4
                  badCol = 6
                  badOff = 15
                  parser = Data.Attoparsec.ByteString.Char8.endOfInput <|> (Data.Attoparsec.ByteString.Char8.notChar 'b' >> parser)
                  sink = sinkParser parser
                  sink' = sinkParserEither parser
                  ea = runConduit $ CL.sourceList input .| sink
              case ea of
                  Left e ->
                      case fromException e of
                          Just pe -> do
                              errorPosition pe `shouldBe` Position badLine badCol badOff
              ea' <- runConduit $ CL.sourceList input .| sink'
              case ea' of
                  Left pe ->
                      errorPosition pe `shouldBe` Position badLine badCol badOff
          it "works in last chunk" $ do
              let input = ["aaa\na", "aaa\n\n", "aaa", "aab\n\naaaa"]
                  badLine = 6
                  badCol = 5
                  badOff = 22
                  parser = Data.Attoparsec.Text.char 'c' <|> (Data.Attoparsec.Text.anyChar >> parser)
                  sink = sinkParser parser
                  sink' = sinkParserEither parser
                  ea = runConduit $ CL.sourceList input .| sink
              case ea of
                  Left e ->
                      case fromException e of
                          Just pe -> do
                              errorPosition pe `shouldBe` Position badLine badCol badOff
              ea' <- runConduit $ CL.sourceList input .| sink'
              case ea' of
                  Left pe ->
                      errorPosition pe `shouldBe` Position badLine badCol badOff
          it "works in last chunk" $ do
              let input = ["aaa\na", "aaa\n\n", "aaa", "aa\n\naaaab"]
                  badLine = 6
                  badCol = 6
                  badOff = 22
                  parser = Data.Attoparsec.Text.string "bc" <|> (Data.Attoparsec.Text.anyChar >> parser)
                  sink = sinkParser parser
                  sink' = sinkParserEither parser
                  ea = runConduit $ CL.sourceList input .| sink
              case ea of
                  Left e ->
                      case fromException e of
                          Just pe -> do
                              errorPosition pe `shouldBe` Position badLine badCol badOff
              ea' <- runConduit $ CL.sourceList input .| sink'
              case ea' of
                  Left pe ->
                      errorPosition pe `shouldBe` Position badLine badCol badOff
          it "works after new line in text" $ do
              let input = ["aaa\n", "aaa\n\n", "aaa", "aa\nb\naaaa"]
                  badLine = 5
                  badCol = 1
                  badOff = 15
                  parser = Data.Attoparsec.Text.endOfInput <|> (Data.Attoparsec.Text.notChar 'b' >> parser)
                  sink = sinkParser parser
                  sink' = sinkParserEither parser
                  ea = runConduit $ CL.sourceList input .| sink
              case ea of
                  Left e ->
                      case fromException e of
                          Just pe -> do
                              errorPosition pe `shouldBe` Position badLine badCol badOff
              ea' <- runConduit $ CL.sourceList input .| sink'
              case ea' of
                  Left pe ->
                      errorPosition pe `shouldBe` Position badLine badCol badOff
          it "works after new line in bytestring" $ do
              let input = ["aaa\n", "aaa\n\n", "aaa", "aa\nb\naaaa"]
                  badLine = 5
                  badCol = 1
                  badOff = 15
                  parser = Data.Attoparsec.ByteString.Char8.endOfInput <|> (Data.Attoparsec.ByteString.Char8.notChar 'b' >> parser)
                  sink = sinkParser parser
                  sink' = sinkParserEither parser
                  ea = runConduit $ CL.sourceList input .| sink
              case ea of
                  Left e ->
                      case fromException e of
                          Just pe -> do
                              errorPosition pe `shouldBe` Position badLine badCol badOff
              ea' <- runConduit $ CL.sourceList input .| sink'
              case ea' of
                  Left pe ->
                      errorPosition pe `shouldBe` Position badLine badCol badOff
          it "works for first line" $ do
              let input = ["aab\na", "aaa\n\n", "aaa", "aab\n\naaaa"]
                  badLine = 1
                  badCol = 3
                  badOff = 2
                  parser = Data.Attoparsec.Text.endOfInput <|> (Data.Attoparsec.Text.notChar 'b' >> parser)
                  sink = sinkParser parser
                  sink' = sinkParserEither parser
                  ea = runConduit $ CL.sourceList input .| sink
              case ea of
                  Left e ->
                      case fromException e of
                          Just pe -> do
                              errorPosition pe `shouldBe` Position badLine badCol badOff
              ea' <- runConduit $ CL.sourceList input .| sink'
              case ea' of
                  Left pe ->
                      errorPosition pe `shouldBe` Position badLine badCol badOff
  
      describe "conduitParser" $ do
          it "parses a repeated stream" $ do
              let input = ["aaa\n", "aaa\naaa\n", "aaa\n"]
                  parser = Data.Attoparsec.Text.string "aaa" <* Data.Attoparsec.Text.endOfLine
                  sink = conduitParserEither parser .| CL.consume
                  (Right !ea) = runConduit $ CL.sourceList input .| sink
              let chk a = case a of
                            Left{} -> False
                            Right (_, xs) -> xs == "aaa"
                  chkp l = PositionRange (Position l 1 ((l - 1) * 4)) (Position (l+1) 1 (l * 4))
              forM_ ea $ \ a -> a `shouldSatisfy` chk :: Expectation
              forM_ (zip ea [1..]) $ \ (Right (pos, _), l) -> pos `shouldBe` chkp l
              length ea `shouldBe` 4
  
          it "positions on first line" $ do
              results <- runConduit $ yield "hihihi\nhihi"
                  .| conduitParser (Data.Attoparsec.Text.string "\n" <|> Data.Attoparsec.Text.string "hi")
                  .| CL.consume
              let f (a, b, c, d, e, f', g) = (PositionRange (Position a b c) (Position d e f'), g)
              results `shouldBe` map f
                  [ (1, 1, 0, 1, 3, 2, "hi")
                  , (1, 3, 2, 1, 5, 4, "hi")
                  , (1, 5, 4, 1, 7, 6, "hi")
  
                  , (1, 7, 6, 2, 1, 7, "\n")
  
                  , (2, 1, 7, 2, 3, 9, "hi")
                  , (2, 3, 9, 2, 5, 11, "hi")
                  ]
  