module Test.Hspec.Core.Formatters.PrettySpec (spec) where

import           Prelude ()
import           Helper

import           Test.Hspec.Core.Formatters.Pretty.ParserSpec hiding (spec)

import           Test.Hspec.Core.Formatters.Pretty

spec :: Spec
spec = do
  describe "pretty2" $ do
    context "with single-line string literals" $ do
      context "with --unicode" $ do
        it "recovers unicode" $ do
          pretty2 True (show "foo\955bar") (show "foo-bar") `shouldBe` ("\"foo\955bar\"", "\"foo-bar\"")

      context "with --no-unicode" $ do
        it "does not recover unicode" $ do
          pretty2 False (show "foo\955bar") (show "foo-bar") `shouldBe` ("\"foo\\955bar\"", "\"foo-bar\"")

      context "when expected and actual would be equal after pretty-printing" $ do
        it "returns the original values unmodified" $ do
          pretty2 True (show "foo") (show "foo" <> "   ") `shouldBe` (show "foo", show "foo" <> "   ")

  describe "recoverString" $ do
    it "recovers a string" $ do
      recoverString (show "foo") `shouldBe` Just "foo"

    it "recovers the empty string" $ do
      recoverString (show "") `shouldBe` Just ""

    it "does not recover a string with leading space" $ do
      recoverString ("   " <> show "foo") `shouldBe` Nothing

    it "does not recover a string with trailing space" $ do
      recoverString (show "foo" <> "   ") `shouldBe` Nothing

    it "does not recover an empty list" $ do
      recoverString "[]" `shouldBe` Nothing

  describe "recoverMultiLineString" $ do
    let
      multiLineString :: String
      multiLineString = "foo\nbar\nbaz\n"

    it "recovers multi-line string literals" $ do
      recoverMultiLineString True (show multiLineString) `shouldBe` Just multiLineString

    it "does not recover string literals that contain control characters" $ do
      recoverMultiLineString True (show "foo\n\tbar\nbaz\n") `shouldBe` Nothing

    it "does not recover string literals that span a single line" $ do
      recoverMultiLineString True (show "foo\n") `shouldBe` Nothing

    it "does not recover a string with trailing space" $ do
      recoverMultiLineString True ("   " <> show multiLineString) `shouldBe` Nothing

    it "does not recover a string with trailing space" $ do
      recoverMultiLineString True (show multiLineString <> "   ") `shouldBe` Nothing

    context "when unicode is True" $ do
      it "recovers string literals that contain unicode" $ do
        recoverMultiLineString True (show "foo\n\955\nbaz\n") `shouldBe` Just "foo\n\955\nbaz\n"

    context "when unicode is False" $ do
      it "does not recover string literals that contain unicode" $ do
        recoverMultiLineString False (show "foo\n\955\nbaz\n") `shouldBe` Nothing

  describe "pretty" $ do
    it "pretty-prints records" $ do
      pretty True (show person) `shouldBe` just [
          "Person {"
        , "  personName = \"Joe\","
        , "  personAge = 23,"
        , "  personAddress = Just Address {"
        , "    addressStreet = \"Main Street\","
        , "    addressPostalCode = 50000"
        , "  }"
        , "}"
        ]

    it "pretty-prints Just-values" $ do
      pretty True (show $ Just person) `shouldBe` just [
          "Just Person {"
        , "  personName = \"Joe\","
        , "  personAge = 23,"
        , "  personAddress = Just Address {"
        , "    addressStreet = \"Main Street\","
        , "    addressPostalCode = 50000"
        , "  }"
        , "}"
        ]

    it "pretty-prints tuples" $ do
      pretty True (show (person, -0.5 :: Rational)) `shouldBe` just [
          "(Person {"
        , "  personName = \"Joe\","
        , "  personAge = 23,"
        , "  personAddress = Just Address {"
        , "    addressStreet = \"Main Street\","
        , "    addressPostalCode = 50000"
        , "  }"
        , "}, (-1) % 2)"
        ]

    it "pretty-prints lists" $ do
      pretty True (show [Just person, Nothing]) `shouldBe` just [
          "[Just Person {"
        , "  personName = \"Joe\","
        , "  personAge = 23,"
        , "  personAddress = Just Address {"
        , "    addressStreet = \"Main Street\","
        , "    addressPostalCode = 50000"
        , "  }"
        , "}, Nothing]"
        ]

    context "with --unicode" $ do
      it "retains unicode characters in record fields" $ do
        pretty True (show $ Person "λ-Joe" 23 Nothing) `shouldBe` just [
            "Person {"
          , "  personName = \"λ-Joe\","
          , "  personAge = 23,"
          , "  personAddress = Nothing"
          , "}"
          ]

      it "retains unicode characters in list elements" $ do
        pretty True (show ["foo", "λ", "bar"]) `shouldBe` just ["[\"foo\", \"λ\", \"bar\"]"]

    context "with --no-unicode" $ do
      it "does not retain unicode characters in record fields" $ do
        pretty False (show $ Person "λ-Joe" 23 Nothing) `shouldBe` just [
            "Person {"
          , "  personName = \"\\955-Joe\","
          , "  personAge = 23,"
          , "  personAddress = Nothing"
          , "}"
          ]

      it "does not retain unicode characters in list elements" $ do
        pretty False (show ["foo", "λ", "bar"]) `shouldBe` just ["[\"foo\", \"\\955\", \"bar\"]"]

    context "with input that looks like a list" $ do
      it "it returns Nothing" $ do
        pretty True "[23,42]" `shouldBe` Nothing

    context "with input that looks like a tuple" $ do
      it "it returns Nothing" $ do
        pretty True "(23,42)" `shouldBe` Nothing

    context "with input that looks like function applications" $ do
      it "it returns Nothing" $ do
        let input = unlines ["foo", "bar", "baz"]
        pretty True input `shouldBe` Nothing
  where
    just = Just . intercalate "\n"
