packages feed

tomland-1.3.3.3: test/Test/Toml/Parser/Toml.hs

{-# 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