phino-0.0.95: test/CSTSpec.hs
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
-- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
-- SPDX-License-Identifier: MIT
module CSTSpec (spec) where
import AST
import CST
import Control.Monad (forM_)
import Data.Aeson
import Data.Text qualified as T
import Data.Yaml qualified as Yaml
import Encoding (Encoding (ASCII), withEncoding)
import Files (allPathsIn)
import GHC.Generics (Generic)
import Lining (LineFormat (SINGLELINE), withLineFormat)
import Margin (defaultMargin, withMargin)
import Parser (parseProgramThrows)
import Render (Render (render))
import Sugar
import System.FilePath
import Test.Hspec
data CSTPack = CSTPack
{ program :: String
, result :: T.Text
}
deriving (Generic, Show, FromJSON)
cstPack :: FilePath -> IO CSTPack
cstPack = Yaml.decodeFileThrow
spec :: Spec
spec = do
describe "builds valid CST" $
forM_
[ ("Q -> Q", PR_SWEET LCB (EX_GLOBAL Φ) RCB NO_SPACE)
,
( "{[[ x -> Q.y ]]}"
, PR_SWEET
LCB
( EX_FORMATION
LSB
EOL
(TAB 1)
(BI_PAIR (PA_TAU (AT_LABEL "x") ARROW (EX_DISPATCH (EX_GLOBAL Φ) NO_SPACE (AT_LABEL "y"))) (BDS_EMPTY (TAB 1)) (TAB 1))
EOL
(TAB 0)
RSB
)
RCB
NO_SPACE
)
]
( \(prog, cst) -> it prog $ do
ast <- parseProgramThrows prog
programToCST ast `shouldBe` cst
)
describe "build valid CST with wrapped phinoAgain{} " $ do
let number = BaseObject "number"
again = ExPhiAgain Nothing 1
bts = BaseObject "bytes"
bt = ArAlpha (Alpha 0)
app = ExApplication
form = ExFormation [BiDelta (BtMany ["40", "18", "00", "00", "00", "00", "00", "00"]), BiVoid AtRho]
isCSTNumber (EX_NUMBER{}) = True
isCSTNumber _ = False
forM_
[ ("number(bytes(data))", app number (bt (app bts (bt form))))
, ("again(number)(bytes(data))", app (again number) (bt (app bts (bt form))))
, ("number(again(bytes(data)))", app number (bt (again (app bts (bt form)))))
, ("number(again(bytes)(data))", app number (bt (app (again bts) (bt form))))
, ("again(number)(again(bytes)(data))", app (again number) (bt (app (again bts) (bt form))))
, ("number(bytes(again(data)))", app number (bt (app bts (bt (again form)))))
, ("again(number)(again(bytes)(again(data)))", app (again number) (bt (app (again bts) (bt (again form)))))
]
(\(desc, ex) -> it desc (toCST ex (0, EOL) `shouldSatisfy` isCSTNumber))
describe "CST printing packs" $ do
let resources = "test-resources/cst/printing-packs"
packs <- runIO (allPathsIn resources)
forM_
packs
( \pth -> it (makeRelative resources pth) $ do
pack <- cstPack pth
prog <- parseProgramThrows (program pack)
render (withMargin defaultMargin (programToCST prog)) `shouldBe` result pack
)
describe "converts to salty CST" $ do
let resources = "test-resources/cst/to-salty-packs"
packs <- runIO (allPathsIn resources)
forM_
packs
( \pth -> it (makeRelative resources pth) $ do
pack <- cstPack pth
prog <- parseProgramThrows (program pack)
let cst = programToCST prog
salty = toSalty cst
render salty `shouldBe` result pack
)
describe "converts to ascii CST" $ do
let resources = "test-resources/cst/to-ascii-packs"
packs <- runIO (allPathsIn resources)
forM_
packs
( \pth -> it (makeRelative resources pth) $ do
pack <- cstPack pth
prog <- parseProgramThrows (program pack)
let cst = programToCST prog
ascii = withMargin defaultMargin (withEncoding ASCII cst)
render ascii `shouldBe` result pack
)
describe "converts to singleline CST" $ do
let resources = "test-resources/cst/to-singleline-packs"
packs <- runIO (allPathsIn resources)
forM_
packs
( \pth -> it (makeRelative resources pth) $ do
pack <- cstPack pth
prog <- parseProgramThrows (program pack)
let cst = programToCST prog
ascii = withLineFormat SINGLELINE cst
render ascii `shouldBe` result pack
)