content: {-# LANGUAGE PatternSynonyms #-}
  
  module Test.Toml.Parser.Toml
      ( tomlSpecs
      ) where
  
  import Data.List.NonEmpty (NonEmpty ((:|)))
  import Data.Text (Text)
  import Test.Hspec (Spec, describe, it, xit)
  
  import Test.Toml.Parser.Common (day2, failOn, parseToml, tomlFailOn)
  import Toml.Parser.Item (keyValP)
  import Toml.Type.Edsl (empty, mkToml, table, tableArray, (=:))
  import Toml.Type.Key (pattern (:||))
  import Toml.Type.TOML (TOML (..))
  import Toml.Type.Value (Value (..))
  
  import qualified Data.List.NonEmpty as NE
  import qualified Data.Text as T
  
  
  tomlSpecs :: Spec
  tomlSpecs = do
      describe "Key/values" $ do
          it "can parse key/value pairs" $ do
              parseToml "x='abcdef'" $ mkToml ("x" =: "abcdef")
              parseToml "x= 1"  $ mkToml ("x" =: 1)
              parseToml "x =5.2" $ mkToml ("x" =: Double 5.2)
              parseToml "x = true" $ mkToml ("x" =: Bool True)
              parseToml "x= [1, 2, 3]" $ mkToml ("x" =: Array [1, 2, 3])
              parseToml "x =1920-12-10" $ mkToml ("x" =: Day day2)
          it "ignores white spaces around key names and values" $ do
              let toml = mkToml ("x" =: 1)
              parseToml "x=1    "   toml
              parseToml "x=    1"   toml
              parseToml "x    =1"   toml
              parseToml "x\t= 1 "   toml
              parseToml "\"x\" = 1" $ mkToml ("\"x\"" =: 1)
          xit "fails if the key, equals sign, and value are not on the same line" $ do
              failOn keyValP "x\n=\n1"
              failOn keyValP "x=\n1"
              failOn keyValP "\"x\"\n=\n1"
          it "works if the value is broken over multiple lines" $
              parseToml "x=[1, \n2\n]" $ mkToml ("x" =: Array [1, 2])
          it "fails if the value is not specified" $
              tomlFailOn "x="
  
      describe "tables" $ do
          it "can parse a TOML table" $ do
              let t  = mkToml $
                          table "table" $ do
                              "key1" =: "some string"
                              "key2" =: 123
  
              parseToml "[table] \n key1 = \"some string\"\nkey2 = 123" t
          it "can parse an empty TOML table" $
              parseToml "[table]" $ mkToml (table "table" empty)
          it "can parse a table with subarrays" $ do
              let t = mkToml $
                          table "table" $
                              tableArray "array" ("key1" =: "some string" :| ["key2" =: 123])
  
              parseToml "[table] \n [[table.array]] \nkey1 = \"some string\"\n \
                                    \[[table.array]] \nkey2 = 123" t
          it "can parse a TOML inline table" $
              parseToml "table={key1 = \"some string\", key2 = 123}" $
                  mkToml $
                      table "table" $ do
                          "key1" =: "some string"
                          "key2" =: 123
          it "can parse an empty inline TOML table" $
              parseToml "table = {}" $ mkToml (table "table" empty)
          it "can parse a table followed by an inline table" $
              parseToml "[table1] \n  key1 = \"some string\" \n table2 = {key2 = 123}" $
                  mkToml $
                      table "table1" $ do
                          "key1" =: "some string"
                          table "table2" $ "key2" =: 123
          it "can parse an empty table followed by an inline table" $
              parseToml "[table1] \n table2 = {key2 = 123}" $
                  mkToml $
                      table "table1" $
                          table "table2" $
                              "key2" =: 123
          it "allows the name of the table to be any valid TOML key" $ do
              parseToml "dog.\"tater.man\"={}" $ mkToml $ table ("dog" :|| ["\"tater.man\""]) empty
              parseToml "j.\"ʞ\".'l'={}" $ mkToml $ table "j.\"ʞ\".'l'" empty
  
      describe "array of tables" $ do
          it "can parse an empty array" $
              parseToml "[[array]]" $ mkToml $ tableArray "array" (empty :| [])
          it "can parse an array of key/values" $ do
              let array = mkToml $
                          tableArray "array" $
                              "key1" =: "some string" :|
                              ["key2" =: 123]
  
              parseToml "[[array]]\n key1 = \"some string\"\n \
                         \[[array]]\n key2 = 123" array
          it "can parse an array of tables" $ do
              let table1 = table "table1" ("key1" =: "some string")
                  table2 = table "table2" ("key2" =: 123)
                  array = mkToml $ tableArray "array" $ table1 :| [table2]
  
              parseToml "[[array]]\n[array.table1] \n key1 = \"some string\"\n \
                         \[[array]]\n[array.table2] \n key2 = 123" array
          it "can parse an array of array" $ do
              let arr = tableArray "subarray" ("key1" =: "some string" :| ["key2" =: 123])
                  array = mkToml $ tableArray "array" (arr :| [])
  
              parseToml "[[array]] \n [[array.subarray]] \nkey1 = \"some string\"\n \
                         \[[array.subarray]] \nkey2 = 123" array
          it "can parse an array of arrays" $ do
              let
                  arr1 = tableArray "table-1" ("key1" =: Text "some string" :| [])
                  arr2 = tableArray "table-2" ("key2" =: Integer 123 :| [])
                  array = mkToml $ tableArray "array" $ (arr1 >> arr2) :| []
  
              parseToml "[[array]]\n [[array.table-1]] \nkey1 = \"some string\"\n \
                                       \[[array.table-2]] \nkey2 = 123" array
          it "can parse very large arrays" $ do
              let array = mkToml $ tableArray "array" $ NE.fromList $ replicate 1000 empty
              parseToml (mconcat $ replicate 1000 "[[array]]\n") array
          it "can parse an inline array of tables" $ do
              let array = mkToml $ tableArray "table" $ NE.fromList ["key1" =: "some string", "key2" =: 123]
              parseToml "table = [{key1 = \"some string\"}, {key2 = 123}]" array
  
      describe "TOML" $ do
          it "can parse TOML files" $
             parseToml tomlStr1 toml1
          it "can parse mix of tables and arrays" $
             parseToml tomlStr2 toml2
        where
          tomlStr1, tomlStr2 :: Text
          tomlStr1 = T.unlines
              [ " # This is a TOML document.\n\n"
              , "title = \"TOML Example\" # Comment \n\n"
              , "[owner]\n"
              , "  name = \"Tom Preston-Werner\" "
              , "  enabled = true # First class dates"
              ]
          tomlStr2 = T.unlines
              [ "[[array1]]\n key1 = \"some string\" \n"
              , ""
              , "[table1]  \n key2 = 123 \n"
              , "[[array2]]\n key3 = 3.14 \n"
              , "  [table2]  \n key4 = true"
              ]
  
          toml1, toml2 :: TOML
          toml1 = mkToml $ do
              "title" =: "TOML Example"
              table "owner" $ do
                  "name" =: "Tom Preston-Werner"
                  "enabled" =: Bool True
  
          toml2 = mkToml $ do
              tableArray "array1" $
                  "key1" =: "some string" :| []
              table "table1" $ "key2" =: 123
              tableArray "array2" $
                  "key3" =: Double 3.14 :| []
              table "table2" $ "key4" =: Bool True
  