{-# LANGUAGE OverloadedStrings #-} -- | Unit tests for GHC UnicodeSyntax extension operators -- | See: https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/unicode_syntax.html module UnicodeOperatorSpec (runAllTests) where import qualified Data.Text as T import Data.Text (Text) import Data.Maybe (fromMaybe) import qualified Token.Haskell as Haskell import qualified Token.Skylighting as Sky import Render.Latex (latexInline) -- | Test that ASCII and Unicode versions produce identical LaTeX output testOperatorPair :: (String, Text, Text, Text) -> IO () testOperatorPair (desc, asciiOp, unicodeOp, expectedLatex) = do putStrLn $ " Testing: " ++ desc let haskellAscii = renderHaskell asciiOp haskellUnicode = renderHaskell unicodeOp skyAscii = renderSkylighting asciiOp skyUnicode = renderSkylighting unicodeOp -- Check ASCII versions produce expected LaTeX checkResult "Haskell (ASCII)" haskellAscii expectedLatex checkResult "Skylighting (ASCII)" skyAscii expectedLatex -- Check Unicode versions produce the same LaTeX as ASCII checkResult "Haskell (Unicode)" haskellUnicode expectedLatex checkResult "Skylighting (Unicode)" skyUnicode expectedLatex -- Verify ASCII and Unicode produce identical output if haskellAscii == haskellUnicode then putStrLn " ✓ Haskell: ASCII and Unicode match" else error $ " ✗ Haskell: ASCII (" ++ T.unpack haskellAscii ++ ") != Unicode (" ++ T.unpack haskellUnicode ++ ")" if skyAscii == skyUnicode then putStrLn " ✓ Skylighting: ASCII and Unicode match" else error $ " ✗ Skylighting: ASCII (" ++ T.unpack skyAscii ++ ") != Unicode (" ++ T.unpack skyUnicode ++ ")" putStrLn "" checkResult :: String -> Text -> Text -> IO () checkResult label actual expected | expected `T.isInfixOf` actual = putStrLn $ " ✓ " ++ label ++ ": contains " ++ T.unpack expected | otherwise = error $ " ✗ " ++ label ++ ": expected " ++ T.unpack expected ++ " but got " ++ T.unpack actual renderHaskell :: Text -> Text renderHaskell code = fromMaybe "" $ do tokens <- Haskell.tokenizer code return $ latexInline $ map (\(t,_,txt) -> (t, txt)) tokens renderSkylighting :: Text -> Text renderSkylighting code = fromMaybe "" $ do syntax <- Sky.lookupTokenizer ["haskell"] tokens <- Sky.tokenizer syntax code return $ latexInline $ map (\(t,_,txt) -> (t, txt)) tokens -- | Test cases: (description, ASCII operator, Unicode operator, expected LaTeX command) unicodeOperatorTests :: [(String, Text, Text, Text)] unicodeOperatorTests = [ ("forall", "forall", "∀", "\\forall") , ("type annotation", "::", "∷", "\\:") , ("class constraint", "=>", "⇒", "\\Rightarrow") , ("function type", "->", "→", "\\to") , ("bind/generator", "<-", "←", "\\gets") , ("right arrow-tail", ">-", "⤚", "\\succ") , ("left arrow-tail", "-<", "⤙", "\\prec") , ("right double arrow-tail", ">>-", "⤜", "\\rr") , ("left double arrow-tail", "-<<", "⤛", "\\ll") , ("unicode kind star", "★", "★", "\\star") -- Unicode only (ASCII * is multiplication) , ("linear arrow", "⊸", "⊸", "\\multimap") -- Unicode only , ("parallel array open", "(|", "⦇", "\\llparenthesis") , ("parallel array close", "|)", "⦈", "\\rrparenthesis") , ("quasiquote open", "[|", "⟦", "\\llbracket") , ("quasiquote close", "|]", "⟧", "\\rrbracket") ] runAllTests :: IO () runAllTests = do putStrLn "\n=== GHC UnicodeSyntax Operator Tests ===" mapM_ testOperatorPair unicodeOperatorTests putStrLn "All Unicode operator tests passed! ✓"