packages feed

grisette-0.7.0.0: test/Grisette/Core/Data/UnionBaseTests.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}

module Grisette.Core.Data.UnionBaseTests (unionBaseTests) where

import GHC.Generics (Generic)
import Grisette
  ( ITEOp (symIte),
    LogicalOp (symNot, (.&&), (.||)),
    Mergeable (rootStrategy),
    MergingStrategy (SortedStrategy),
    Solvable (con),
    SymInteger,
    wrapStrategy,
  )
import Grisette.Internal.Core.Data.UnionBase
  ( UnionBase (UnionIf, UnionSingle),
    fullReconstruct,
    ifWithLeftMost,
    ifWithStrategy,
  )
import Test.Framework (Test, testGroup)
import Test.Framework.Providers.HUnit (testCase)
import Test.HUnit ((@?=))

data TripleSum a b c = TS1 a | TS2 b | TS3 c deriving (Show, Eq, Generic)

instance
  (Mergeable a, Mergeable b, Mergeable c) =>
  Mergeable (TripleSum a b c)
  where
  rootStrategy =
    SortedStrategy
      (\case TS1 _ -> (0 :: Int); TS2 _ -> (1 :: Int); TS3 _ -> (2 :: Int))
      ( \case
          0 -> wrapStrategy rootStrategy TS1 (\(TS1 x) -> x)
          1 -> wrapStrategy rootStrategy TS2 (\(TS2 x) -> x)
          2 -> wrapStrategy rootStrategy TS3 (\(TS3 x) -> x)
          _ -> error "Bad"
      )

unionBaseTests :: Test
unionBaseTests =
  testGroup
    "UnionBase"
    [ testGroup
        "ifWithLeftMost"
        [ testCase
            "ifWithLeftMost should maintain left most info on Singles"
            $ do
              ifWithLeftMost
                False
                "a"
                (UnionSingle (1 :: Integer))
                (UnionSingle 2)
                @?= UnionIf 1 False "a" (UnionSingle 1) (UnionSingle 2),
          testCase "ifWithLeftMost should maintain left most info on Ifs" $ do
            ifWithLeftMost
              True
              "a"
              (UnionIf 1 True "b" (UnionSingle (1 :: Integer)) (UnionSingle 2))
              (UnionIf 3 True "c" (UnionSingle 3) (UnionSingle 4))
              @?= UnionIf
                1
                True
                "a"
                ( UnionIf
                    1
                    True
                    "b"
                    (UnionSingle (1 :: Integer))
                    (UnionSingle 2)
                )
                (UnionIf 3 True "c" (UnionSingle 3) (UnionSingle 4))
        ],
      testGroup
        "ifWithStrategy"
        [ testGroup
            "ifWithStrategy with concrete condition"
            [ testCase "true" $ do
                ifWithStrategy
                  rootStrategy
                  (con True)
                  (UnionSingle (1 :: Integer))
                  (UnionSingle 2)
                  @?= UnionSingle 1,
              testCase "false" $ do
                ifWithStrategy
                  rootStrategy
                  (con False)
                  (UnionSingle (1 :: Integer))
                  (UnionSingle 2)
                  @?= UnionSingle 2
            ],
          let a =
                ifWithStrategy
                  rootStrategy
                  "a"
                  (UnionSingle (1 :: Integer))
                  (UnionSingle 2)
           in testGroup
                "ifWithStrategy with condition equal to sub conditions"
                [ testCase "ifTrue" $ do
                    ifWithStrategy rootStrategy "a" a (UnionSingle 3)
                      @?= UnionIf 1 True "a" (UnionSingle 1) (UnionSingle 3),
                  testCase "ifFalse" $ do
                    ifWithStrategy rootStrategy "a" (UnionSingle 0) a
                      @?= UnionIf 0 True "a" (UnionSingle 0) (UnionSingle 2)
                ],
          testCase "ifWithStrategy with simple mergeables" $ do
            ifWithStrategy
              rootStrategy
              "a"
              (UnionSingle ("b" :: SymInteger))
              (UnionSingle "c")
              @?= UnionSingle (symIte "a" "b" "c"),
          testGroup
            "ifWithStrategy with ordered mergeables"
            [ testGroup
                "ifWithStrategy on Single/Single"
                [ testGroup
                    "idxt < idxf"
                    [ testCase "Integer" $
                        ifWithStrategy
                          rootStrategy
                          "a"
                          (UnionSingle (1 :: Integer))
                          (UnionSingle 2)
                          @?= UnionIf
                            1
                            True
                            "a"
                            (UnionSingle 1)
                            (UnionSingle 2),
                      testCase "Maybe Integer" $
                        ifWithStrategy
                          rootStrategy
                          "a"
                          (UnionSingle Nothing)
                          (UnionSingle (Just (2 :: Integer)))
                          @?= UnionIf
                            Nothing
                            True
                            "a"
                            (UnionSingle Nothing)
                            (UnionSingle (Just 2))
                    ],
                  testGroup
                    "idxt == idxf"
                    [ testGroup
                        "idxt == idxf as terminal"
                        [ testCase "Integer" $
                            ifWithStrategy
                              rootStrategy
                              "a"
                              (UnionSingle (1 :: Integer))
                              (UnionSingle 1)
                              @?= UnionSingle 1,
                          testCase "Maybe Integer" $
                            ifWithStrategy
                              rootStrategy
                              "a"
                              (UnionSingle (Just ("b" :: SymInteger)))
                              (UnionSingle (Just "c"))
                              @?= UnionSingle (Just (symIte "a" "b" "c"))
                        ],
                      testGroup
                        "idxt == idxf but not terminal"
                        [ testCase "Maybe Integer" $
                            ifWithStrategy
                              rootStrategy
                              "a"
                              (UnionSingle (Just (1 :: Integer)))
                              (UnionSingle (Just (2 :: Integer)))
                              @?= UnionIf
                                (Just 1)
                                True
                                "a"
                                (UnionSingle $ Just 1)
                                (UnionSingle (Just 2)),
                          testCase "Maybe (Maybe Integer)" $
                            ifWithStrategy
                              rootStrategy
                              "a"
                              (UnionSingle $ Just $ Just ("b" :: SymInteger))
                              (UnionSingle $ Just $ Just "c")
                              @?= UnionSingle (Just (Just (symIte "a" "b" "c")))
                        ]
                    ],
                  testGroup
                    "idxt > idxf"
                    [ testCase "Integer" $
                        ifWithStrategy
                          rootStrategy
                          "a"
                          (UnionSingle (2 :: Integer))
                          (UnionSingle 1)
                          @?= UnionIf
                            1
                            True
                            (symNot "a")
                            (UnionSingle 1)
                            (UnionSingle 2),
                      testCase "Maybe Integer" $
                        ifWithStrategy
                          rootStrategy
                          "a"
                          (UnionSingle (Just (2 :: Integer)))
                          (UnionSingle Nothing)
                          @?= UnionIf
                            Nothing
                            True
                            (symNot "a")
                            (UnionSingle Nothing)
                            (UnionSingle (Just 2))
                    ]
                ],
              testGroup
                "ifWithStrategy on Single/If"
                [ testGroup
                    "Degenerate to Single/Single when idxft == idxff"
                    [ testCase "Degenerated case with idxt < idxf" $ do
                        let x =
                              ifWithStrategy
                                rootStrategy
                                "a"
                                (UnionSingle (Just (1 :: Integer)))
                                (UnionSingle (Just (2 :: Integer)))
                        ifWithStrategy rootStrategy "b" (UnionSingle Nothing) x
                          @?= UnionIf
                            Nothing
                            True
                            "b"
                            (UnionSingle Nothing)
                            ( UnionIf
                                (Just 1)
                                True
                                "a"
                                (UnionSingle $ Just 1)
                                (UnionSingle (Just 2))
                            ),
                      let x =
                            ifWithStrategy
                              rootStrategy
                              "a"
                              (UnionSingle (Just (1 :: Integer)))
                              (UnionSingle (Just (3 :: Integer)))
                       in testGroup
                            "Degenerated case with idxt == idxf"
                            [ testCase "sub-idxt < sub-idxft" $
                                ifWithStrategy
                                  rootStrategy
                                  "b"
                                  (UnionSingle $ Just 0)
                                  x
                                  @?= UnionIf
                                    (Just 0)
                                    True
                                    "b"
                                    (UnionSingle $ Just 0)
                                    ( UnionIf
                                        (Just 1)
                                        True
                                        "a"
                                        (UnionSingle $ Just 1)
                                        (UnionSingle (Just 3))
                                    ),
                              testCase "sub-idxt == sub-idxft" $
                                ifWithStrategy
                                  rootStrategy
                                  "b"
                                  (UnionSingle $ Just 1)
                                  x
                                  @?= UnionIf
                                    (Just 1)
                                    True
                                    ("b" .|| "a")
                                    (UnionSingle $ Just 1)
                                    (UnionSingle (Just 3)),
                              testCase "subidxft < sub-idxt < sub-idxff" $
                                ifWithStrategy
                                  rootStrategy
                                  "b"
                                  (UnionSingle $ Just 2)
                                  x
                                  @?= UnionIf
                                    (Just 1)
                                    True
                                    ((symNot "b") .&& "a")
                                    (UnionSingle $ Just 1)
                                    ( UnionIf
                                        (Just 2)
                                        True
                                        "b"
                                        (UnionSingle $ Just 2)
                                        (UnionSingle $ Just 3)
                                    ),
                              testCase "sub-idxt == sub-idxff" $
                                ifWithStrategy
                                  rootStrategy
                                  "b"
                                  (UnionSingle $ Just 3)
                                  x
                                  @?= UnionIf
                                    (Just 1)
                                    True
                                    ((symNot "b") .&& "a")
                                    (UnionSingle $ Just 1)
                                    (UnionSingle (Just 3)),
                              testCase "sub-idxff < sub-idxt" $
                                ifWithStrategy
                                  rootStrategy
                                  "b"
                                  (UnionSingle $ Just 4)
                                  x
                                  @?= UnionIf
                                    (Just 1)
                                    True
                                    ((symNot "b") .&& "a")
                                    (UnionSingle $ Just 1)
                                    ( UnionIf
                                        (Just 3)
                                        True
                                        (symNot "b")
                                        (UnionSingle $ Just 3)
                                        (UnionSingle $ Just 4)
                                    )
                            ],
                      testCase "Degenerated case with idxt > idxf" $ do
                        let x =
                              ifWithStrategy
                                rootStrategy
                                "a"
                                (UnionSingle (Left (1 :: Integer)))
                                (UnionSingle (Left (2 :: Integer)))
                        ifWithStrategy
                          rootStrategy
                          "b"
                          (UnionSingle $ Right (1 :: Integer))
                          x
                          @?= UnionIf
                            (Left 1)
                            True
                            (symNot "b")
                            ( UnionIf
                                (Left 1)
                                True
                                "a"
                                (UnionSingle $ Left 1)
                                (UnionSingle (Left 2))
                            )
                            (UnionSingle $ Right 1)
                    ],
                  testCase "idxt < idxft" $ do
                    let x =
                          ifWithStrategy
                            rootStrategy
                            "a"
                            (UnionSingle (1 :: Integer))
                            (UnionSingle (3 :: Integer))
                    ifWithStrategy rootStrategy "b" (UnionSingle 0) x
                      @?= UnionIf
                        0
                        True
                        "b"
                        (UnionSingle 0)
                        ( UnionIf
                            1
                            True
                            "a"
                            (UnionSingle 1)
                            (UnionSingle 3)
                        ),
                  testCase "idxt == idxft" $ do
                    let x =
                          ifWithStrategy
                            rootStrategy
                            "a"
                            (UnionSingle $ Left (1 :: Integer))
                            (UnionSingle $ Right (3 :: Integer))
                    ifWithStrategy rootStrategy "b" (UnionSingle $ Left 0) x
                      @?= UnionIf
                        (Left 0)
                        True
                        ("b" .|| "a")
                        ( UnionIf
                            (Left 0)
                            True
                            "b"
                            (UnionSingle $ Left 0)
                            (UnionSingle $ Left 1)
                        )
                        (UnionSingle $ Right 3),
                  testCase "idxt > idxft" $ do
                    let x =
                          ifWithStrategy
                            rootStrategy
                            "a"
                            (UnionSingle $ Left (1 :: Integer))
                            (UnionSingle $ Right (3 :: Integer))
                    ifWithStrategy rootStrategy "b" (UnionSingle $ Right 0) x
                      @?= UnionIf
                        (Left 1)
                        True
                        ((symNot "b") .&& "a")
                        (UnionSingle $ Left 1)
                        ( UnionIf
                            (Right 0)
                            True
                            "b"
                            (UnionSingle $ Right 0)
                            (UnionSingle $ Right 3)
                        )
                ],
              testGroup
                "ifWithStrategy on If/Single"
                [ testGroup
                    "Degenerate to Single/Single when idxtt == idxtf"
                    [ testCase "Degenerated case with idxt < idxf" $ do
                        let x =
                              ifWithStrategy
                                rootStrategy
                                "a"
                                (UnionSingle (Left (1 :: Integer)))
                                (UnionSingle (Left (2 :: Integer)))
                        ifWithStrategy
                          rootStrategy
                          "b"
                          x
                          (UnionSingle $ Right (2 :: Integer))
                          @?= UnionIf
                            (Left 1)
                            True
                            "b"
                            ( UnionIf
                                (Left 1)
                                True
                                "a"
                                (UnionSingle $ Left 1)
                                (UnionSingle (Left 2))
                            )
                            (UnionSingle $ Right 2),
                      let x =
                            ifWithStrategy
                              rootStrategy
                              "a"
                              (UnionSingle (Just (1 :: Integer)))
                              (UnionSingle (Just (3 :: Integer)))
                       in testGroup
                            "Degenerated case with idxt == idxf"
                            [ testCase "sub-idxf < sub-idxtt" $
                                ifWithStrategy
                                  rootStrategy
                                  "b"
                                  x
                                  (UnionSingle $ Just 0)
                                  @?= UnionIf
                                    (Just 0)
                                    True
                                    (symNot "b")
                                    (UnionSingle $ Just 0)
                                    ( UnionIf
                                        (Just 1)
                                        True
                                        "a"
                                        (UnionSingle $ Just 1)
                                        (UnionSingle (Just 3))
                                    ),
                              testCase "sub-idxf == sub-idxtt" $
                                ifWithStrategy
                                  rootStrategy
                                  "b"
                                  x
                                  (UnionSingle $ Just 1)
                                  @?= UnionIf
                                    (Just 1)
                                    True
                                    ((symNot "b") .|| "a")
                                    (UnionSingle $ Just 1)
                                    (UnionSingle (Just 3)),
                              testCase "sub-idxtt < sub-idxf < sub-idxtf" $
                                ifWithStrategy
                                  rootStrategy
                                  "b"
                                  x
                                  (UnionSingle $ Just 2)
                                  @?= UnionIf
                                    (Just 1)
                                    True
                                    ("b" .&& "a")
                                    (UnionSingle $ Just 1)
                                    ( UnionIf
                                        (Just 2)
                                        True
                                        (symNot "b")
                                        (UnionSingle $ Just 2)
                                        (UnionSingle $ Just 3)
                                    ),
                              testCase "sub-idxf == sub-idxtf" $
                                ifWithStrategy
                                  rootStrategy
                                  "b"
                                  x
                                  (UnionSingle $ Just 3)
                                  @?= UnionIf
                                    (Just 1)
                                    True
                                    ("b" .&& "a")
                                    (UnionSingle $ Just 1)
                                    (UnionSingle (Just 3)),
                              testCase "sub-idxtf < sub-idxf" $
                                ifWithStrategy
                                  rootStrategy
                                  "b"
                                  x
                                  (UnionSingle $ Just 4)
                                  @?= UnionIf
                                    (Just 1)
                                    True
                                    ("b" .&& "a")
                                    (UnionSingle $ Just 1)
                                    ( UnionIf
                                        (Just 3)
                                        True
                                        "b"
                                        (UnionSingle $ Just 3)
                                        (UnionSingle $ Just 4)
                                    )
                            ],
                      testCase "Degenerated case with idxt > idxf" $ do
                        let x =
                              ifWithStrategy
                                rootStrategy
                                "a"
                                (UnionSingle (Right (1 :: Integer)))
                                (UnionSingle (Right (2 :: Integer)))
                        ifWithStrategy
                          rootStrategy
                          "b"
                          x
                          (UnionSingle $ Left (1 :: Integer))
                          @?= UnionIf
                            (Left 1)
                            True
                            (symNot "b")
                            (UnionSingle $ Left 1)
                            ( UnionIf
                                (Right 1)
                                True
                                "a"
                                (UnionSingle $ Right 1)
                                (UnionSingle (Right 2))
                            )
                    ],
                  testCase "idxtt < idxf" $ do
                    let x =
                          ifWithStrategy
                            rootStrategy
                            "a"
                            (UnionSingle $ Left (1 :: Integer))
                            (UnionSingle $ Right (3 :: Integer))
                    ifWithStrategy rootStrategy "b" x (UnionSingle $ Right 0)
                      @?= UnionIf
                        (Left 1)
                        True
                        ("b" .&& "a")
                        (UnionSingle $ Left 1)
                        ( UnionIf
                            (Right 0)
                            True
                            (symNot "b")
                            (UnionSingle $ Right 0)
                            (UnionSingle $ Right 3)
                        ),
                  testCase "idxtt == idxf" $ do
                    let x =
                          ifWithStrategy
                            rootStrategy
                            "a"
                            (UnionSingle $ Left (1 :: Integer))
                            (UnionSingle $ Right (3 :: Integer))
                    ifWithStrategy rootStrategy "b" x (UnionSingle $ Left 0)
                      @?= UnionIf
                        (Left 0)
                        True
                        ((symNot "b") .|| "a")
                        ( UnionIf
                            (Left 0)
                            True
                            (symNot "b")
                            (UnionSingle $ Left 0)
                            (UnionSingle $ Left 1)
                        )
                        (UnionSingle $ Right 3),
                  testCase "idxtt > idxf" $ do
                    let x =
                          ifWithStrategy
                            rootStrategy
                            "a"
                            (UnionSingle (1 :: Integer))
                            (UnionSingle (3 :: Integer))
                    ifWithStrategy rootStrategy "b" x (UnionSingle 0)
                      @?= UnionIf
                        0
                        True
                        (symNot "b")
                        (UnionSingle 0)
                        (UnionIf 1 True "a" (UnionSingle 1) (UnionSingle 3))
                ],
              testGroup
                "ifWithStrategy on If/If"
                [ testCase "Degenerate to Single/If when idxtt == idxtf" $ do
                    let x =
                          ifWithStrategy
                            rootStrategy
                            "a"
                            (UnionSingle $ Left (1 :: Integer))
                            (UnionSingle $ Left (2 :: Integer))
                    let y =
                          ifWithStrategy
                            rootStrategy
                            "b"
                            (UnionSingle $ Left (1 :: Integer))
                            (UnionSingle $ Right (2 :: Integer))
                    ifWithStrategy rootStrategy "c" x y
                      @?= UnionIf
                        (Left 1)
                        True
                        ("c" .|| "b")
                        ( UnionIf
                            (Left 1)
                            True
                            ((symNot "c") .|| "a")
                            (UnionSingle $ Left 1)
                            (UnionSingle $ Left 2)
                        )
                        (UnionSingle $ Right 2),
                  testCase "Degenerate to Single/If when idxff == idxft" $ do
                    let x =
                          ifWithStrategy
                            rootStrategy
                            "a"
                            (UnionSingle $ Left (1 :: Integer))
                            (UnionSingle $ Left (2 :: Integer))
                    let y =
                          ifWithStrategy
                            rootStrategy
                            "b"
                            (UnionSingle $ Left (1 :: Integer))
                            (UnionSingle $ Right (2 :: Integer))
                    ifWithStrategy rootStrategy "c" y x
                      @?= UnionIf
                        (Left 1)
                        True
                        ((symNot "c") .|| "b")
                        ( UnionIf
                            (Left 1)
                            True
                            ("c" .|| "a")
                            (UnionSingle $ Left 1)
                            (UnionSingle $ Left 2)
                        )
                        (UnionSingle $ Right 2),
                  testCase "Non-degenerated case when idxtt < idxft" $ do
                    let x =
                          ifWithStrategy
                            rootStrategy
                            "a"
                            (UnionSingle $ TS1 (1 :: Integer))
                            (UnionSingle $ TS2 (2 :: Integer))
                    let y =
                          ifWithStrategy
                            rootStrategy
                            "b"
                            (UnionSingle $ TS2 (1 :: Integer))
                            (UnionSingle $ TS3 (2 :: Integer))
                    ifWithStrategy rootStrategy "c" x y
                      @?= UnionIf
                        (TS1 1)
                        True
                        ("c" .&& "a")
                        (UnionSingle $ TS1 1)
                        ( UnionIf
                            (TS2 1)
                            True
                            ("c" .|| "b")
                            ( UnionIf
                                (TS2 1)
                                True
                                (symNot "c")
                                (UnionSingle $ TS2 1)
                                (UnionSingle $ TS2 2)
                            )
                            (UnionSingle $ TS3 2)
                        ),
                  testCase "Non-degenerated case when idxtt == idxft" $ do
                    let x =
                          ifWithStrategy
                            rootStrategy
                            "a"
                            (UnionSingle $ TS1 (1 :: Integer))
                            (UnionSingle $ TS2 (2 :: Integer))
                    let y =
                          ifWithStrategy
                            rootStrategy
                            "b"
                            (UnionSingle $ TS1 (2 :: Integer))
                            (UnionSingle $ TS3 (2 :: Integer))
                    ifWithStrategy rootStrategy "c" x y
                      @?= UnionIf
                        (TS1 1)
                        True
                        (symIte "c" "a" "b")
                        ( UnionIf
                            (TS1 1)
                            True
                            "c"
                            (UnionSingle $ TS1 1)
                            (UnionSingle $ TS1 2)
                        )
                        ( UnionIf
                            (TS2 2)
                            True
                            "c"
                            (UnionSingle $ TS2 2)
                            (UnionSingle $ TS3 2)
                        ),
                  testCase "Non-degenerated case when idxtt > idxft" $ do
                    let x =
                          ifWithStrategy
                            rootStrategy
                            "a"
                            (UnionSingle $ TS2 (1 :: Integer))
                            (UnionSingle $ TS3 (2 :: Integer))
                    let y =
                          ifWithStrategy
                            rootStrategy
                            "b"
                            (UnionSingle $ TS1 (1 :: Integer))
                            (UnionSingle $ TS2 (2 :: Integer))
                    ifWithStrategy rootStrategy "c" x y
                      @?= UnionIf
                        (TS1 1)
                        True
                        ((symNot "c") .&& "b")
                        (UnionSingle $ TS1 1)
                        ( UnionIf
                            (TS2 1)
                            True
                            ((symNot "c") .|| "a")
                            ( UnionIf
                                (TS2 1)
                                True
                                "c"
                                (UnionSingle $ TS2 1)
                                (UnionSingle $ TS2 2)
                            )
                            (UnionSingle $ TS3 2)
                        )
                ],
              testCase "ifWithStrategy should tolerate non-merged Ifs" $ do
                let x =
                      UnionIf
                        (Right 2)
                        False
                        "a"
                        (UnionSingle $ Right (2 :: Integer))
                        (UnionSingle $ Left (2 :: Integer))
                let y =
                      UnionIf
                        (Right 3)
                        False
                        "b"
                        (UnionSingle $ Right 3)
                        (UnionSingle $ Left 1)
                ifWithStrategy rootStrategy "c" x y
                  @?= UnionIf
                    (Left 1)
                    True
                    (symIte "c" (symNot "a") (symNot "b"))
                    ( UnionIf
                        (Left 1)
                        True
                        (symNot "c")
                        (UnionSingle $ Left 1)
                        (UnionSingle $ Left 2)
                    )
                    ( UnionIf
                        (Right 2)
                        True
                        "c"
                        (UnionSingle $ Right 2)
                        (UnionSingle $ Right 3)
                    )
            ]
        ],
      testGroup
        "fullReconstruct"
        [ testCase "fullReconstruct should work" $ do
            let x =
                  UnionIf
                    (Right 2)
                    False
                    "a"
                    (UnionSingle $ Right (2 :: Integer))
                    (UnionSingle $ Left (2 :: Integer))
            let y =
                  UnionIf
                    (Right 3)
                    False
                    "b"
                    (UnionSingle $ Right 3)
                    (UnionSingle $ Left 1)
            let z = UnionIf (Right 2) False "c" x y
            fullReconstruct rootStrategy z
              @?= UnionIf
                (Left 1)
                True
                (symIte "c" (symNot "a") (symNot "b"))
                ( UnionIf
                    (Left 1)
                    True
                    (symNot "c")
                    (UnionSingle $ Left 1)
                    (UnionSingle $ Left 2)
                )
                ( UnionIf
                    (Right 2)
                    True
                    "c"
                    (UnionSingle $ Right 2)
                    (UnionSingle $ Right 3)
                )
        ]
    ]