phino-0.0.0.56: test/LiningSpec.hs
-- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
-- SPDX-License-Identifier: MIT
{- | Tests for the Lining module that converts CST to single-line format.
The module provides functions to remove line breaks and indentation from
phi-calculus concrete syntax trees while preserving structural semantics.
-}
module LiningSpec (spec) where
import CST
import Control.Monad (forM_)
import Lining (LineFormat (..), toSingleLine, withLineFormat)
import Test.Hspec (Spec, describe, it, shouldBe, shouldNotBe)
spec :: Spec
spec = do
describe "withLineFormat preserves multiline programs" $
it "returns program unchanged" $
let prog = PR_SWEET LCB (EX_GLOBAL Φ) RCB
in withLineFormat MULTILINE prog `shouldBe` prog
describe "withLineFormat converts to singleline" $
it "applies toSingleLine transformation" $
let prog = PR_SWEET LCB (EX_FORMATION LSB EOL (TAB 1) (BI_EMPTY (TAB 1)) EOL (TAB 0) RSB) RCB
result = withLineFormat SINGLELINE prog
in result `shouldBe` PR_SWEET LCB (EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY (TAB 1)) NO_EOL NO_TAB RSB) RCB
describe "LineFormat Eq instance" $
forM_
[ ("SINGLELINE equals SINGLELINE", SINGLELINE, SINGLELINE, True)
, ("MULTILINE equals MULTILINE", MULTILINE, MULTILINE, True)
, ("SINGLELINE differs from MULTILINE", SINGLELINE, MULTILINE, False)
]
( \(desc, fmt1, fmt2, expected) ->
it desc $
if expected
then fmt1 `shouldBe` fmt2
else fmt1 `shouldNotBe` fmt2
)
describe "LineFormat Show instance" $
forM_
[ ("SINGLELINE shows correctly", SINGLELINE, "SINGLELINE")
, ("MULTILINE shows correctly", MULTILINE, "MULTILINE")
]
( \(desc, fmt, expected) ->
it desc (show fmt `shouldBe` expected)
)
describe "toSingleLine PROGRAM for PR_SWEET" $
it "removes newlines from expression" $
let prog = PR_SWEET LCB (EX_FORMATION LSB EOL (TAB 1) (BI_EMPTY (TAB 1)) EOL (TAB 0) RSB) RCB
in toSingleLine prog `shouldBe` PR_SWEET LCB (EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY (TAB 1)) NO_EOL NO_TAB RSB) RCB
describe "toSingleLine PROGRAM for PR_SALTY" $
it "converts salty program to singleline" $
let prog = PR_SALTY Φ ARROW (EX_FORMATION LSB EOL (TAB 1) (BI_EMPTY (TAB 1)) EOL (TAB 0) RSB)
in toSingleLine prog `shouldBe` PR_SALTY Φ ARROW (EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY (TAB 1)) NO_EOL NO_TAB RSB)
describe "toSingleLine EXPRESSION for EX_FORMATION with empty binding" $
it "removes tabs and newlines" $
let ex = EX_FORMATION LSB EOL (TAB 1) (BI_EMPTY (TAB 1)) EOL (TAB 0) RSB
in toSingleLine ex `shouldBe` EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY (TAB 1)) NO_EOL NO_TAB RSB
describe "toSingleLine EXPRESSION for EX_FORMATION with bindings" $
it "converts to singleline with TAB markers" $
let bd = BI_PAIR (PA_TAU (AT_LABEL "x") ARROW (EX_GLOBAL Φ)) (BDS_EMPTY (TAB 1)) (TAB 1)
ex = EX_FORMATION LSB EOL (TAB 1) bd EOL (TAB 0) RSB
result = toSingleLine ex
in result `shouldBe` EX_FORMATION LSB NO_EOL TAB' (BI_PAIR (PA_TAU (AT_LABEL "x") ARROW (EX_GLOBAL Φ)) (BDS_EMPTY (TAB 1)) TAB') NO_EOL TAB' RSB
describe "toSingleLine EXPRESSION for EX_DISPATCH" $
it "converts nested expression" $
let ex = EX_DISPATCH (EX_FORMATION LSB EOL (TAB 1) (BI_EMPTY (TAB 1)) EOL (TAB 0) RSB) (AT_LABEL "attr")
in toSingleLine ex `shouldBe` EX_DISPATCH (EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY (TAB 1)) NO_EOL NO_TAB RSB) (AT_LABEL "attr")
describe "toSingleLine EXPRESSION for EX_APPLICATION" $
it "converts with proper spacing" $
let t = APP_BINDING (PA_TAU (AT_LABEL "y") ARROW (EX_GLOBAL Φ))
ex = EX_APPLICATION (EX_GLOBAL Φ) EOL (TAB 1) t EOL (TAB 0) 1
in toSingleLine ex `shouldBe` EX_APPLICATION (EX_GLOBAL Φ) NO_EOL TAB' (APP_BINDING (PA_TAU (AT_LABEL "y") ARROW (EX_GLOBAL Φ))) NO_EOL TAB' 1
describe "toSingleLine EXPRESSION for EX_APPLICATION_TAUS" $
it "converts taus application" $
let ts = BI_PAIR (PA_TAU (AT_LABEL "z") ARROW (EX_GLOBAL Φ)) (BDS_EMPTY (TAB 1)) (TAB 1)
ex = EX_APPLICATION_TAUS (EX_GLOBAL Φ) EOL (TAB 1) ts EOL (TAB 0) 1
in toSingleLine ex `shouldBe` EX_APPLICATION_TAUS (EX_GLOBAL Φ) NO_EOL TAB' (BI_PAIR (PA_TAU (AT_LABEL "z") ARROW (EX_GLOBAL Φ)) (BDS_EMPTY (TAB 1)) TAB') NO_EOL TAB' 1
describe "toSingleLine EXPRESSION for EX_APPLICATION_EXPRS" $
it "converts expressions application" $
let as = APP_ARG (EX_GLOBAL Φ) AAS_EMPTY
ex = EX_APPLICATION_EXPRS (EX_GLOBAL Φ) EOL (TAB 1) as EOL (TAB 0) 1
in toSingleLine ex `shouldBe` EX_APPLICATION_EXPRS (EX_GLOBAL Φ) NO_EOL TAB' (APP_ARG (EX_GLOBAL Φ) AAS_EMPTY) NO_EOL TAB' 1
describe "toSingleLine EXPRESSION for EX_PHI_MEET" $
it "converts meet expression" $
let ex = EX_PHI_MEET Nothing 0 (EX_FORMATION LSB EOL (TAB 1) (BI_EMPTY (TAB 1)) EOL (TAB 0) RSB)
in toSingleLine ex `shouldBe` EX_PHI_MEET Nothing 0 (EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY (TAB 1)) NO_EOL NO_TAB RSB)
describe "toSingleLine EXPRESSION for EX_PHI_AGAIN" $
it "converts again expression" $
let ex = EX_PHI_AGAIN Nothing 1 (EX_FORMATION LSB EOL (TAB 1) (BI_EMPTY (TAB 1)) EOL (TAB 0) RSB)
in toSingleLine ex `shouldBe` EX_PHI_AGAIN Nothing 1 (EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY (TAB 1)) NO_EOL NO_TAB RSB)
describe "toSingleLine EXPRESSION leaves primitives unchanged" $
forM_
[ ("EX_GLOBAL", EX_GLOBAL Φ)
, ("EX_DEF_PACKAGE", EX_DEF_PACKAGE Φ̇)
, ("EX_XI", EX_XI XI)
, ("EX_ATTR", EX_ATTR (AT_LABEL "attr"))
, ("EX_TERMINATION", EX_TERMINATION DEAD)
, ("EX_STRING", EX_STRING "тест" (TAB 0) [])
, ("EX_NUMBER", EX_NUMBER (Left 42) (TAB 0) [])
, ("EX_META", EX_META (MT_EXPRESSION "e"))
, ("EX_META_TAIL", EX_META_TAIL (EX_GLOBAL Φ) (MT_TAIL "t"))
]
( \(desc, ex) ->
it desc (toSingleLine ex `shouldBe` ex)
)
describe "toSingleLine APP_BINDING" $
it "converts nested pair expression" $
let bd = APP_BINDING (PA_TAU (AT_LABEL "x") ARROW (EX_FORMATION LSB EOL (TAB 1) (BI_EMPTY (TAB 1)) EOL (TAB 0) RSB))
in toSingleLine bd `shouldBe` APP_BINDING (PA_TAU (AT_LABEL "x") ARROW (EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY (TAB 1)) NO_EOL NO_TAB RSB))
describe "toSingleLine BINDING for BI_PAIR" $
it "converts to singleline" $
let bd = BI_PAIR (PA_TAU (AT_LABEL "x") ARROW (EX_GLOBAL Φ)) (BDS_EMPTY (TAB 1)) (TAB 1)
in toSingleLine bd `shouldBe` BI_PAIR (PA_TAU (AT_LABEL "x") ARROW (EX_GLOBAL Φ)) (BDS_EMPTY (TAB 1)) TAB'
describe "toSingleLine BINDING for BI_META" $
it "converts meta binding" $
let bd = BI_META (MT_BINDING "B") (BDS_EMPTY (TAB 1)) (TAB 1)
in toSingleLine bd `shouldBe` BI_META (MT_BINDING "B") (BDS_EMPTY (TAB 1)) TAB'
describe "toSingleLine BINDING for BI_EMPTY" $
it "returns binding unchanged" $
let bd = BI_EMPTY (TAB 1)
in toSingleLine bd `shouldBe` bd
describe "toSingleLine BINDINGS for BDS_PAIR" $
it "converts to singleline" $
let bds = BDS_PAIR EOL (TAB 1) (PA_TAU (AT_LABEL "y") ARROW (EX_GLOBAL Φ)) (BDS_EMPTY (TAB 1))
in toSingleLine bds `shouldBe` BDS_PAIR NO_EOL TAB' (PA_TAU (AT_LABEL "y") ARROW (EX_GLOBAL Φ)) (BDS_EMPTY (TAB 1))
describe "toSingleLine BINDINGS for BDS_META" $
it "converts meta bindings" $
let bds = BDS_META EOL (TAB 1) (MT_BINDING "B") (BDS_EMPTY (TAB 1))
in toSingleLine bds `shouldBe` BDS_META NO_EOL TAB' (MT_BINDING "B") (BDS_EMPTY (TAB 1))
describe "toSingleLine BINDINGS for BDS_EMPTY" $
it "returns bindings unchanged" $
let bds = BDS_EMPTY (TAB 1)
in toSingleLine bds `shouldBe` bds
describe "toSingleLine PAIR for PA_TAU" $
it "converts expression" $
let pr = PA_TAU (AT_LABEL "x") ARROW (EX_FORMATION LSB EOL (TAB 1) (BI_EMPTY (TAB 1)) EOL (TAB 0) RSB)
in toSingleLine pr `shouldBe` PA_TAU (AT_LABEL "x") ARROW (EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY (TAB 1)) NO_EOL NO_TAB RSB)
describe "toSingleLine PAIR for PA_FORMATION" $
it "converts formation pair" $
let pr = PA_FORMATION (AT_LABEL "f") [AT_LABEL "v"] ARROW (EX_FORMATION LSB EOL (TAB 1) (BI_EMPTY (TAB 1)) EOL (TAB 0) RSB)
in toSingleLine pr `shouldBe` PA_FORMATION (AT_LABEL "f") [AT_LABEL "v"] ARROW (EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY (TAB 1)) NO_EOL NO_TAB RSB)
describe "toSingleLine PAIR leaves non-expression pairs unchanged" $
forM_
[ ("PA_VOID", PA_VOID (AT_LABEL "v") ARROW EMPTY)
, ("PA_LAMBDA", PA_LAMBDA "λфункция")
, ("PA_LAMBDA'", PA_LAMBDA' "Function")
, ("PA_META_LAMBDA", PA_META_LAMBDA (MT_FUNCTION "F"))
, ("PA_META_LAMBDA'", PA_META_LAMBDA' (MT_FUNCTION "F"))
, ("PA_DELTA", PA_DELTA (BT_ONE "FF"))
, ("PA_DELTA'", PA_DELTA' (BT_MANY ["00", "01"]))
, ("PA_META_DELTA", PA_META_DELTA (MT_BYTES "d"))
, ("PA_META_DELTA'", PA_META_DELTA' (MT_BYTES "d"))
]
( \(desc, pr) ->
it desc (toSingleLine pr `shouldBe` pr)
)
describe "toSingleLine APP_ARG" $
it "converts expression and args" $
let arg = APP_ARG (EX_FORMATION LSB EOL (TAB 1) (BI_EMPTY (TAB 1)) EOL (TAB 0) RSB) AAS_EMPTY
in toSingleLine arg `shouldBe` APP_ARG (EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY (TAB 1)) NO_EOL NO_TAB RSB) AAS_EMPTY
describe "toSingleLine APP_ARGS for AAS_EXPR" $
it "converts nested expression" $
let as = AAS_EXPR EOL (TAB 1) (EX_FORMATION LSB EOL (TAB 1) (BI_EMPTY (TAB 1)) EOL (TAB 0) RSB) AAS_EMPTY
in toSingleLine as `shouldBe` AAS_EXPR NO_EOL TAB' (EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY (TAB 1)) NO_EOL NO_TAB RSB) AAS_EMPTY
describe "toSingleLine APP_ARGS for AAS_EMPTY" $
it "returns unchanged" $
toSingleLine AAS_EMPTY `shouldBe` AAS_EMPTY