packages feed

shikumi-tools-0.3.0.0: test/RestrictedSpec.hs

-- | EP-27 M1: the hermetic restricted-DSL evaluator behind 'restrictedInterpreter'.
-- Pure unit tests over 'runRestricted': it computes arithmetic/string/list results
-- and returns a @Left@ error message for division by zero, a parse error, or an
-- unknown function — the recoverable errors the @programOfThought@ loop feeds back.
module RestrictedSpec (tests) where

import Data.Text (Text)
import Data.Text qualified as T
import Shikumi.CodeExec.Interpreter (runRestricted)
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (assertBool, testCase, (@?=))

assertLeft :: Either Text Text -> IO ()
assertLeft r = assertBool ("expected Left, got " <> show r) (isLeft r)
  where
    isLeft (Left _) = True
    isLeft _ = False

assertLeftMentions :: Text -> Either Text Text -> IO ()
assertLeftMentions needle = \case
  Left msg -> assertBool ("error should mention " <> show needle <> ", got " <> show msg) (needle `T.isInfixOf` msg)
  Right v -> assertBool ("expected Left mentioning " <> show needle <> ", got Right " <> show v) False

tests :: TestTree
tests =
  testGroup
    "RestrictedSpec"
    [ testCase "2 + 3 * 4 evaluates to 14 (precedence)" $
        runRestricted "2 + 3 * 4" @?= Right "14",
      testCase "37 * 19 + 6 evaluates to 709" $
        runRestricted "37 * 19 + 6" @?= Right "709",
      testCase "result = 42 evaluates to 42" $
        runRestricted "result = 42" @?= Right "42",
      testCase "parentheses override precedence" $
        runRestricted "(2 + 3) * 4" @?= Right "20",
      testCase "unary minus works for literals, products, and parenthesized expressions" $ do
        runRestricted "-3" @?= Right "-3"
        runRestricted "2 * -3" @?= Right "-6"
        runRestricted "-(2 + 3)" @?= Right "-5",
      testCase "1 / 0 reports a division error" $
        assertLeftMentions "division" (runRestricted "1 / 0"),
      testCase "len(\"hello\") evaluates to 5" $
        runRestricted "len(\"hello\")" @?= Right "5",
      testCase "string escapes parse in literals" $ do
        runRestricted "\"a\\\"b\"" @?= Right "a\"b"
        runRestricted "\"a\\\\b\"" @?= Right "a\\b"
        runRestricted "\"a\\n\\t\"" @?= Right "a\n\t",
      testCase "upper(\"ab\") ++ \"C\" concatenates to ABC" $
        runRestricted "upper(\"ab\") ++ \"C\"" @?= Right "ABC",
      testCase "sum([1, 2, 3]) evaluates to 6" $
        runRestricted "sum([1, 2, 3])" @?= Right "6",
      testCase "a malformed expression (extra paren) is a parse error" $
        assertLeft (runRestricted "upper(\"ab\") ++ \"C\")"),
      testCase "an unknown function is an error" $
        assertLeftMentions "unknown" (runRestricted "frobnicate(3)")
    ]