commit cf7839ee92c469c284a7adf7ad192f072aa205f2
parent 98faf1318937a356e86868f4d1c16ed1dd6ae954
Author: James Eversole <james@eversole.co>
Date: Wed, 14 Oct 2026 18:55:08 -0500
Migrate remaining behavior tests and remove recovery test bridges
Diffstat:
7 files changed, 1121 insertions(+), 1359 deletions(-)
diff --git a/docs/validation.md b/docs/validation.md
@@ -178,8 +178,10 @@ published fixture imports and a definition body. This test-only header adapter i
not native module resolution; it returns local definitions, not imported names.
Preparation has a 30-second deadline and checks Result/list/name structure without
forcing unused definition values. Invalid source and import shadowing fail without
-fallback. Remaining recovery-specific tests still use the historical frontend;
-production module resolution never does.
+fallback. Useful library program tests use the same bounded portable compilation route
+with an explicit published prelude. `div` and `mod` zero-divisor expectations
+follow the checked numeric contract, not the retired host cohort's zero result.
+No test uses the historical frontend or reconstructs its ambient import scopes.
```sh
# Reference-source/bundle fingerprints only; no working-tree freshness claim.
diff --git a/test/InteractionInspectionTests.hs b/test/InteractionInspectionTests.hs
@@ -1,7 +1,7 @@
module InteractionInspectionTests (interactionInspectionTests) where
import InteractionInspection
-import Research (T(..), ofNumber, ofString, ofList)
+import Runtime (T(..), ofNumber, ofString, ofList)
import qualified Wire as W
import qualified Data.Sequence as S
import qualified Data.Text as Text
diff --git a/test/LibraryProgramTests.hs b/test/LibraryProgramTests.hs
@@ -0,0 +1,1005 @@
+-- Behavioral expectations survive the retirement of the historical frontend.
+-- Compile tiny test programs against published portable library interfaces only.
+module LibraryProgramTests (maybeTests, providedLibraries, contractsTests, arithmetic) where
+
+import Runtime
+import ReferenceFixtures (fixtureExports)
+import PortableTestCompiler (compileFixtureDefinitions)
+import qualified Data.Map as Map
+import Test.Tasty
+import Test.Tasty.HUnit
+
+runExpression :: String -> IO T
+runExpression expression = runProgram ("main = " ++ expression)
+
+runProgram :: String -> IO T
+runProgram source = do
+ env <- compileFixtureDefinitions (fixtureExports "prelude") source
+ maybe (assertFailure "library test program has no main" >> pure Leaf) pure (Map.lookup "main" env)
+
+trueT, falseT, nothingT :: T
+trueT = Stem Leaf
+falseT = Leaf
+nothingT = Leaf
+justT :: T -> T
+justT = Stem
+pairT :: T -> T -> T
+pairT = Fork
+
+maybeTests :: TestTree
+maybeTests = testGroup "Maybe Tests"
+ [ testCase "nothing is Leaf" $ do
+ let input = "nothing"
+ env <- runExpression input
+ env @?= Leaf
+
+ , testCase "just wraps value in Stem" $ do
+ let input = "just (t t)"
+ env <- runExpression input
+ env @?= Stem (Stem Leaf)
+
+ , testCase "matchMaybe on nothing returns default" $ do
+ let input = "matchMaybe \"empty\" (x : x) nothing"
+ env <- runExpression input
+ env @?= ofString "empty"
+
+ , testCase "matchMaybe on just extracts value" $ do
+ let input = "matchMaybe \"empty\" (x : x) (just (t t))"
+ env <- runExpression input
+ env @?= Stem Leaf
+
+ , testCase "maybe applies f inside just" $ do
+ let input = "maybe 0 (x : succ x) (just 5)"
+ env <- runExpression input
+ env @?= ofNumber 6
+
+ , testCase "maybe returns default on nothing" $ do
+ let input = "maybe 0 (x : succ x) nothing"
+ env <- runExpression input
+ env @?= ofNumber 0
+
+ , testCase "maybeMap transforms just value" $ do
+ let input = "maybeMap (x : succ x) (just 3)"
+ env <- runExpression input
+ env @?= justT (ofNumber 4)
+
+ , testCase "maybeMap returns nothing on nothing" $ do
+ let input = "maybeMap (x : succ x) nothing"
+ env <- runExpression input
+ env @?= nothingT
+
+ , testCase "maybeBind flattens just" $ do
+ let input = "maybeBind (just 3) (x : just (succ x))"
+ env <- runExpression input
+ env @?= justT (ofNumber 4)
+
+ , testCase "maybeBind returns nothing on nothing" $ do
+ let input = "maybeBind nothing (x : just (succ x))"
+ env <- runExpression input
+ env @?= Leaf
+
+ , testCase "maybeOr returns just value" $ do
+ let input = "maybeOr 99 (just 5)"
+ env <- runExpression input
+ env @?= ofNumber 5
+
+ , testCase "maybeOr returns default on nothing" $ do
+ let input = "maybeOr 99 nothing"
+ env <- runExpression input
+ env @?= ofNumber 99
+
+ , testCase "maybe? on just is true" $ do
+ let input = "maybe? (just t)"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "maybe? on nothing is false" $ do
+ let input = "maybe? nothing"
+ env <- runExpression input
+ env @?= falseT
+ ]
+
+providedLibraries :: TestTree
+providedLibraries = testGroup "Library Tests"
+ [ testCase "Triage test Leaf" $ do
+ let input = "test t"
+ value <- runExpression input
+ let env = decodeResult value
+ env @?= "\"Leaf\""
+
+ , testCase "Triage test (Stem Leaf)" $ do
+ let input = "test (t t)"
+ value <- runExpression input
+ let env = decodeResult value
+ env @?= "\"Stem\""
+
+ , testCase "Triage test (Fork Leaf Leaf)" $ do
+ let input = "test (t t t)"
+ value <- runExpression input
+ let env = decodeResult value
+ env @?= "\"Fork\""
+
+ , testCase "Boolean NOT: true" $ do
+ let input = "not? true"
+ env <- runExpression input
+ env @?= Leaf
+
+ , testCase "Boolean NOT: false" $ do
+ let input = "not? false"
+ env <- runExpression input
+ env @?= Stem Leaf
+
+
+ , testCase "Boolean AND TF" $ do
+ let input = "and? (t t) (t)"
+ env <- runExpression input
+ env @?= Leaf
+
+ , testCase "Boolean AND FT" $ do
+ let input = "and? (t) (t t)"
+ env <- runExpression input
+ env @?= Leaf
+
+ , testCase "Boolean AND FF" $ do
+ let input = "and? (t) (t)"
+ env <- runExpression input
+ env @?= Leaf
+
+ , testCase "Boolean AND TT" $ do
+ let input = "and? (t t) (t t)"
+ env <- runExpression input
+ env @?= Stem Leaf
+
+ , testCase "List head" $ do
+ let input = "head [(t) (t t) (t t t)]"
+ env <- runExpression input
+ env @?= Leaf
+
+ , testCase "List tail" $ do
+ let input = "head (tail (tail [(t) (t t) (t t t)]))"
+ env <- runExpression input
+ env @?= Fork Leaf Leaf
+
+ , testCase "List map" $ do
+ let input = "head (tail (map (a : (t t t)) [(t) (t) (t)]))"
+ env <- runExpression input
+ env @?= Fork Leaf Leaf
+
+ , testCase "Empty list check" $ do
+ let input = "emptyList? []"
+ env <- runExpression input
+ env @?= Stem Leaf
+
+ , testCase "Non-empty list check" $ do
+ let input = "not? (emptyList? [(1) (2) (3)])"
+ env <- runExpression input
+ env @?= Stem Leaf
+
+ , testCase "Concatenate strings" $ do
+ let input = "append \"Hello, \" \"world!\""
+ value <- runExpression input
+ let env = decodeResult value
+ env @?= "\"Hello, world!\""
+
+ , testCase "Verifying Equality" $ do
+ let input = "equal? (t t t) (t t t)"
+ env <- runExpression input
+ env @?= Stem Leaf
+
+ , testCase "headMaybe on empty list" $ do
+ let input = "headMaybe []"
+ env <- runExpression input
+ env @?= nothingT
+
+ , testCase "headMaybe on non-empty list" $ do
+ let input = "headMaybe [(t) (t t)]"
+ env <- runExpression input
+ env @?= justT Leaf
+
+ , testCase "lastMaybe on empty list" $ do
+ let input = "lastMaybe []"
+ env <- runExpression input
+ env @?= nothingT
+
+ , testCase "lastMaybe on single element" $ do
+ let input = "lastMaybe [(t t)]"
+ env <- runExpression input
+ env @?= justT (Stem Leaf)
+
+ , testCase "lastMaybe on multi-element list" $ do
+ let input = "lastMaybe [(t) (t t) (t t t)]"
+ env <- runExpression input
+ env @?= justT (Fork Leaf Leaf)
+
+ , testCase "nthMaybe first element" $ do
+ let input = "nthMaybe 0 [(t) (t t)]"
+ env <- runExpression input
+ env @?= justT Leaf
+
+ , testCase "nthMaybe middle element" $ do
+ let input = "nthMaybe 1 [(t) (t t) (t t t)]"
+ env <- runExpression input
+ env @?= justT (Stem Leaf)
+
+ , testCase "nthMaybe out of bounds" $ do
+ let input = "nthMaybe 5 [(t) (t t)]"
+ env <- runExpression input
+ env @?= nothingT
+
+ , testCase "reverse empty list" $ do
+ let input = "reverse []"
+ env <- runExpression input
+ env @?= ofList []
+
+ , testCase "reverse non-empty list" $ do
+ let input = "reverse [(1) (2) (3)]"
+ env <- runExpression input
+ env @?= ofList [ofNumber 3, ofNumber 2, ofNumber 1]
+
+ , testCase "take 0 any list = empty" $ do
+ let input = "take 0 [(1) (2) (3)]"
+ env <- runExpression input
+ env @?= ofList []
+
+ , testCase "take 2 [1,2,3] = [1,2]" $ do
+ let input = "take 2 [(1) (2) (3)]"
+ env <- runExpression input
+ env @?= ofList [ofNumber 1, ofNumber 2]
+
+ , testCase "take overlong returns whole list" $ do
+ let input = "take 5 [(1) (2)]"
+ env <- runExpression input
+ env @?= ofList [ofNumber 1, ofNumber 2]
+
+ , testCase "drop 0 any list = list" $ do
+ let input = "drop 0 [(1) (2) (3)]"
+ env <- runExpression input
+ env @?= ofList [ofNumber 1, ofNumber 2, ofNumber 3]
+
+ , testCase "drop 2 [1,2,3] = [3]" $ do
+ let input = "drop 2 [(1) (2) (3)]"
+ env <- runExpression input
+ env @?= ofList [ofNumber 3]
+
+ , testCase "drop overlong returns empty" $ do
+ let input = "drop 5 [(1) (2)]"
+ env <- runExpression input
+ env @?= ofList []
+
+ , testCase "splitAt 0 [1,2] = pair [] [1,2]" $ do
+ let input = "splitAt 0 [(1) (2)]"
+ env <- runExpression input
+ env @?= pairT (ofList []) (ofList [ofNumber 1, ofNumber 2])
+
+ , testCase "splitAt 2 [1,2,3] = pair [1,2] [3]" $ do
+ let input = "splitAt 2 [(1) (2) (3)]"
+ env <- runExpression input
+ env @?= pairT (ofList [ofNumber 1, ofNumber 2]) (ofList [ofNumber 3])
+
+ , testCase "splitAt overlong = pair [1,2] []" $ do
+ let input = "splitAt 5 [(1) (2)]"
+ env <- runExpression input
+ env @?= pairT (ofList [ofNumber 1, ofNumber 2]) (ofList [])
+
+ , testCase "concatMap on empty list" $ do
+ let input = "concatMap (x : [(x) (x)]) []"
+ env <- runExpression input
+ env @?= ofList []
+
+ , testCase "concatMap doubles elements" $ do
+ let input = "concatMap (x : [(x) (x)]) [(1) (2)]"
+ env <- runExpression input
+ env @?= ofList [ofNumber 1, ofNumber 1, ofNumber 2, ofNumber 2]
+
+ , testCase "find on empty list" $ do
+ let input = "find (x : equal? x 2) []"
+ env <- runExpression input
+ env @?= nothingT
+
+ , testCase "find finds element" $ do
+ let input = "find (x : equal? x 2) [(1) (2) (3)]"
+ env <- runExpression input
+ env @?= justT (ofNumber 2)
+
+ , testCase "find missing element" $ do
+ let input = "find (x : equal? x 9) [(1) (2) (3)]"
+ env <- runExpression input
+ env @?= nothingT
+
+ , testCase "partition empty list" $ do
+ let input = "partition (x : equal? x 2) []"
+ env <- runExpression input
+ env @?= pairT (ofList []) (ofList [])
+
+ , testCase "partition splits list" $ do
+ let input = "partition (x : lt? 2 x) [(1) (2) (3) (4)]"
+ env <- runExpression input
+ env @?= pairT (ofList [ofNumber 3, ofNumber 4]) (ofList [ofNumber 1, ofNumber 2])
+
+ , testCase "zipWith on empty lists" $ do
+ let input = "zipWith add [] []"
+ env <- runExpression input
+ env @?= ofList []
+
+ , testCase "zipWith adds pairwise" $ do
+ let input = "zipWith add [(1) (2)] [(10) (20)]"
+ env <- runExpression input
+ env @?= ofList [ofNumber 11, ofNumber 22]
+
+ , testCase "zipWith truncates to shorter list" $ do
+ let input = "zipWith add [(1) (2)] [(10)]"
+ env <- runExpression input
+ env @?= ofList [ofNumber 11]
+
+ , testCase "strLength" $ do
+ let input = "strLength \"hello\""
+ env <- runExpression input
+ env @?= ofNumber 5
+
+ , testCase "strAppend" $ do
+ let input = "strAppend \"hello\" \" world\""
+ env <- runExpression input
+ env @?= ofString "hello world"
+
+ , testCase "equal? equal strings" $ do
+ let input = "equal? \"abc\" \"abc\""
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "equal? different strings" $ do
+ let input = "equal? \"abc\" \"def\""
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "strEmpty? on empty" $ do
+ let input = "strEmpty? \"\""
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "strEmpty? on non-empty" $ do
+ let input = "strEmpty? \"a\""
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "startsWith? prefix matches" $ do
+ let input = "startsWith? \"he\" \"hello\""
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "startsWith? prefix too long" $ do
+ let input = "startsWith? \"hello\" \"he\""
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "startsWith? empty prefix" $ do
+ let input = "startsWith? \"\" \"hello\""
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "endsWith? suffix matches" $ do
+ let input = "endsWith? \"lo\" \"hello\""
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "endsWith? suffix too long" $ do
+ let input = "endsWith? \"hello\" \"lo\""
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "endsWith? empty suffix" $ do
+ let input = "endsWith? \"\" \"hello\""
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "contains? substring found" $ do
+ let input = "contains? \"ell\" \"hello\""
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "contains? substring missing" $ do
+ let input = "contains? \"xyz\" \"hello\""
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "contains? empty needle" $ do
+ let input = "contains? \"\" \"hello\""
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "lines splits on newline" $ do
+ let input = "lines \"a\\nb\\nc\""
+ env <- runExpression input
+ env @?= ofList [ofString "a", ofString "b", ofString "c"]
+
+ , testCase "lines single line" $ do
+ let input = "lines \"hello\""
+ env <- runExpression input
+ env @?= ofList [ofString "hello"]
+
+ , testCase "lines empty string" $ do
+ let input = "lines \"\""
+ env <- runExpression input
+ env @?= ofList [ofString ""]
+
+ , testCase "lines trailing newline" $ do
+ let input = "lines \"a\\n\""
+ env <- runExpression input
+ env @?= ofList [ofString "a", ofString ""]
+
+ , testCase "unlines joins with newline" $ do
+ let input = "unlines [(\"a\") (\"b\")]"
+ env <- runExpression input
+ env @?= ofString "a\nb\n"
+
+ , testCase "unlines empty list" $ do
+ let input = "unlines []"
+ env <- runExpression input
+ env @?= ofString ""
+
+ , testCase "words splits on space" $ do
+ let input = "words \"hello world\""
+ env <- runExpression input
+ env @?= ofList [ofString "hello", ofString "world"]
+
+ , testCase "words empty string" $ do
+ let input = "words \"\""
+ env <- runExpression input
+ env @?= ofList []
+
+ , testCase "words multiple spaces" $ do
+ let input = "words \" hello world \""
+ env <- runExpression input
+ env @?= ofList [ofString "hello", ofString "world"]
+
+ , testCase "unwords joins with space" $ do
+ let input = "unwords [(\"hello\") (\"world\")]"
+ env <- runExpression input
+ env @?= ofString "hello world"
+
+ , testCase "unwords single word" $ do
+ let input = "unwords [(\"hello\")]"
+ env <- runExpression input
+ env @?= ofString "hello"
+
+ , testCase "unwords empty list" $ do
+ let input = "unwords []"
+ env <- runExpression input
+ env @?= ofString ""
+
+ , testCase "intercalate joins fields" $ do
+ let input = "intercalate \", \" [(\"a\") (\"b\") (\"c\")]"
+ env <- runExpression input
+ env @?= ofString "a, b, c"
+
+ , testCase "intercalate leaves a lone field alone" $ do
+ let input = "intercalate \", \" [(\"a\")]"
+ env <- runExpression input
+ env @?= ofString "a"
+
+ , testCase "intercalate empty list" $ do
+ let input = "intercalate \", \" []"
+ env <- runExpression input
+ env @?= ofString ""
+
+ , testCase "joinSuffix terminates every field" $ do
+ let input = "joinSuffix \"-\" [(\"a\") (\"b\")]"
+ env <- runExpression input
+ env @?= ofString "a-b-"
+
+ , testCase "splitOnByte splits on a byte" $ do
+ let input = "splitOnByte 58 \"a:b:c\""
+ env <- runExpression input
+ env @?= ofList [ofString "a", ofString "b", ofString "c"]
+
+ , testCase "splitOnByte keeps empty fields" $ do
+ let input = "splitOnByte 58 \"a::b\""
+ env <- runExpression input
+ env @?= ofList [ofString "a", ofString "", ofString "b"]
+
+ , testCase "splitOnByte trailing separator leaves an empty field" $ do
+ let input = "splitOnByte 58 \"a:\""
+ env <- runExpression input
+ env @?= ofList [ofString "a", ofString ""]
+
+ , testCase "splitOnByte without a match" $ do
+ let input = "splitOnByte 58 \"abc\""
+ env <- runExpression input
+ env @?= ofList [ofString "abc"]
+
+ , testCase "splitOnByte empty input" $ do
+ let input = "splitOnByte 58 \"\""
+ env <- runExpression input
+ env @?= ofList [ofString ""]
+
+ , testCase "intercalate round trips splitOnByte" $ do
+ let input = "equal? (intercalate \":\" (splitOnByte 58 \"a:b:c\")) \"a:b:c\""
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "takeWhile keeps the matching prefix" $ do
+ let input = "takeWhile (n : lt? n 3) [(1) (2) (3) (1)]"
+ env <- runExpression input
+ env @?= ofList [ofNumber 1, ofNumber 2]
+
+ , testCase "takeWhile stops at the first mismatch" $ do
+ let input = "takeWhile (n : lt? n 3) [(3) (1)]"
+ env <- runExpression input
+ env @?= ofList []
+
+ , testCase "dropWhile drops the matching prefix" $ do
+ let input = "dropWhile (n : lt? n 3) [(1) (2) (3) (1)]"
+ env <- runExpression input
+ env @?= ofList [ofNumber 3, ofNumber 1]
+
+ , testCase "dropWhile on an all matching list" $ do
+ let input = "dropWhile (n : lt? n 3) [(1) (2)]"
+ env <- runExpression input
+ env @?= ofList []
+
+ , testCase "trim strips surrounding spaces and tabs" $ do
+ let input = "trim \" \\ttrimmed \\t\""
+ env <- runExpression input
+ env @?= ofString "trimmed"
+
+ , testCase "trim leaves interior bytes alone" $ do
+ let input = "trim \" a b \""
+ env <- runExpression input
+ env @?= ofString "a b"
+
+ , testCase "trim all whitespace is empty" $ do
+ let input = "trim \" \\t \""
+ env <- runExpression input
+ env @?= ofString ""
+ ]
+
+contractsTests :: TestTree
+contractsTests = testGroup "Contracts library tests"
+ [ testCase "anyC passes any value" $ do
+ let input = "main = resultIsOk (checkContract anyC 7)"
+ env <- runProgram input
+ env @?= trueT
+
+ , testCase "guardC rejects failures" $ do
+ let input = "main = resultIsErr (checkContract (guardC \"odd\" even?) 5)"
+ env <- runProgram input
+ env @?= trueT
+
+ , testCase "andC combines contracts" $ do
+ let input = "main = resultIsOk (checkContract (andC (guardC \"odd\" odd?) (guardC \"gt0\" (n : gt? n 0))) 5)"
+ env <- runProgram input
+ env @?= trueT
+
+ , testCase "listOf checks every element" $ do
+ let input = "main = resultIsOk (checkContract (listOf (guardC \"odd\" odd?)) [1 3 5])"
+ env <- runProgram input
+ env @?= trueT
+
+ , testCase "fnContract wraps a function" $ do
+ let input = "main = resultIsOk (checkContract (fnContract (guardC \"odd\" odd?) anyC) (x : x))"
+ env <- runProgram input
+ env @?= trueT
+
+ , testCase "runM reduces pureM" $ do
+ let input = "main = resultIsOk (runM (pureM 42))"
+ env <- runProgram input
+ env @?= trueT
+
+ , testCase "do notation chains checkM and pureM" $ do
+ let input = unlines
+ [ "program = (xs :"
+ , " do bindM"
+ , " n <- pureM (length xs)"
+ , " _ <- checkM (guardC \"positive\" (n : gte? n 1)) n"
+ , " pureM n)"
+ , "main = runM (program [1 2 3 4])"
+ ]
+ env <- runProgram input
+ decodeResult (env) @?= "[t t, 4]"
+
+ , testCase "handleM replaces exception with a new action" $ do
+ let input = unlines
+ [ "lookupConfig = (key defaultValue :"
+ , " exceptE \"missing\" key (resume : pureM defaultValue))"
+ , "pipeline = (xs :"
+ , " do bindM"
+ , " divisor <- lookupConfig \"divisor\" 1"
+ , " total <- pureM (sum xs)"
+ , " scaled <- liftM (x : div x divisor) total"
+ , " pureM scaled)"
+ , "handled = handleM \"missing\" (key k : pureM 2) (pipeline [10 20 30])"
+ , "main = runM handled"
+ ]
+ env <- runProgram input
+ decodeResult (env) @?= "[t t, 30]"
+
+ , testCase "=@ return annotation passes" $ do
+ let input = unlines
+ [ "five =@anyC 5"
+ , "main = five"
+ ]
+ env <- runProgram input
+ env @?= ofNumber 5
+
+ , testCase "=@ return annotation fails" $ do
+ let input = unlines
+ [ "boom =@(neverC \"boom\") 5"
+ , "main = boom"
+ ]
+ env <- runProgram input
+ decodeResult (env) @?= "[t, \"boom\"]"
+
+ , testCase "@ argument annotation passes" $ do
+ let input = unlines
+ [ "idNat x@anyC =@anyC x"
+ , "main = idNat 5"
+ ]
+ env <- runProgram input
+ env @?= ofNumber 5
+
+ , testCase "@ argument annotation fails" $ do
+ let input = unlines
+ [ "idNat x@(neverC \"bad\") =@anyC x"
+ , "main = idNat 5"
+ ]
+ env <- runProgram input
+ decodeResult (env) @?= "[t, \"bad\"]"
+ ]
+
+arithmetic :: TestTree
+arithmetic = testGroup "Arithmetic Tests"
+ [ testCase "isZero? on 0" $ do
+ let input = "isZero? 0"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "isZero? on 5" $ do
+ let input = "isZero? 5"
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "add 0 3 = 3" $ do
+ let input = "add 0 3"
+ env <- runExpression input
+ env @?= ofNumber 3
+
+ , testCase "add 3 0 = 3" $ do
+ let input = "add 3 0"
+ env <- runExpression input
+ env @?= ofNumber 3
+
+ , testCase "add 2 3 = 5" $ do
+ let input = "add 2 3"
+ env <- runExpression input
+ env @?= ofNumber 5
+
+ , testCase "sub 5 2 = 3" $ do
+ let input = "sub 5 2"
+ env <- runExpression input
+ env @?= ofNumber 3
+
+ , testCase "sub 2 5 = 0 (saturated)" $ do
+ let input = "sub 2 5"
+ env <- runExpression input
+ env @?= ofNumber 0
+
+ , testCase "sub 5 5 = 0" $ do
+ let input = "sub 5 5"
+ env <- runExpression input
+ env @?= ofNumber 0
+
+ , testCase "lt? 2 3 = true" $ do
+ let input = "lt? 2 3"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "lt? 3 2 = false" $ do
+ let input = "lt? 3 2"
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "lt? 2 2 = false" $ do
+ let input = "lt? 2 2"
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "lte? 2 3 = true" $ do
+ let input = "lte? 2 3"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "lte? 3 2 = false" $ do
+ let input = "lte? 3 2"
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "lte? 2 2 = true" $ do
+ let input = "lte? 2 2"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "mul 0 5 = 0" $ do
+ let input = "mul 0 5"
+ env <- runExpression input
+ env @?= ofNumber 0
+
+ , testCase "mul 5 0 = 0" $ do
+ let input = "mul 5 0"
+ env <- runExpression input
+ env @?= ofNumber 0
+
+ , testCase "mul 2 3 = 6" $ do
+ let input = "mul 2 3"
+ env <- runExpression input
+ env @?= ofNumber 6
+
+ , testCase "mul 3 3 = 9" $ do
+ let input = "mul 3 3"
+ env <- runExpression input
+ env @?= ofNumber 9
+
+ , testCase "pred 0 = 0" $ do
+ let input = "pred 0"
+ env <- runExpression input
+ env @?= ofNumber 0
+
+ , testCase "pred 1 = 0" $ do
+ let input = "pred 1"
+ env <- runExpression input
+ env @?= ofNumber 0
+
+ , testCase "pred 5 = 4" $ do
+ let input = "pred 5"
+ env <- runExpression input
+ env @?= ofNumber 4
+
+ , testCase "add is commutative" $ do
+ let input = "equal? (add 4 7) (add 7 4)"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "add is associative" $ do
+ let input = "equal? (add (add 2 3) 4) (add 2 (add 3 4))"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "sub x 0 = x" $ do
+ let input = "sub 7 0"
+ env <- runExpression input
+ env @?= ofNumber 7
+
+ , testCase "sub chained" $ do
+ let input = "sub (sub 10 3) 2"
+ env <- runExpression input
+ env @?= ofNumber 5
+
+ , testCase "mul identity 1" $ do
+ let input = "mul 1 5"
+ env <- runExpression input
+ env @?= ofNumber 5
+
+ , testCase "mul identity 2" $ do
+ let input = "mul 5 1"
+ env <- runExpression input
+ env @?= ofNumber 5
+
+ , testCase "mul is commutative" $ do
+ let input = "equal? (mul 3 4) (mul 4 3)"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "mul is associative" $ do
+ let input = "equal? (mul (mul 2 3) 4) (mul 2 (mul 3 4))"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "mul distributes over add" $ do
+ let input = "equal? (mul 2 (add 3 4)) (add (mul 2 3) (mul 2 4))"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "lt? reflexive is false" $ do
+ let input = "lt? 5 5"
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "lte? reflexive is true" $ do
+ let input = "lte? 5 5"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "lt? transitivity" $ do
+ let input = "and? (lt? 2 5) (lt? 5 7)"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "add larger numbers" $ do
+ let input = "add 12 15"
+ env <- runExpression input
+ env @?= ofNumber 27
+
+ , testCase "mul larger numbers" $ do
+ let input = "mul 5 6"
+ env <- runExpression input
+ env @?= ofNumber 30
+
+ , testCase "isZero? on add 0 0" $ do
+ let input = "isZero? (add 0 0)"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "div 10 3 = 3" $ do
+ let input = "div 10 3"
+ env <- runExpression input
+ env @?= ofNumber 3
+
+ , testCase "div 12 4 = 3 (exact)" $ do
+ let input = "div 12 4"
+ env <- runExpression input
+ env @?= ofNumber 3
+
+ , testCase "div 3 5 = 0 (divisor larger)" $ do
+ let input = "div 3 5"
+ env <- runExpression input
+ env @?= ofNumber 0
+
+ , testCase "div 7 1 = 7 (identity)" $ do
+ let input = "div 7 1"
+ env <- runExpression input
+ env @?= ofNumber 7
+
+ , testCase "div 0 5 = 0" $ do
+ let input = "div 0 5"
+ env <- runExpression input
+ env @?= ofNumber 0
+
+ , testCase "div rejects a zero divisor" $ do
+ let input = "div 5 0"
+ env <- runExpression input
+ env @?= Fork Leaf (Fork (ofString "non-zero") Leaf)
+
+ , testCase "mod 10 3 = 1" $ do
+ let input = "mod 10 3"
+ env <- runExpression input
+ env @?= ofNumber 1
+
+ , testCase "mod 12 4 = 0 (exact)" $ do
+ let input = "mod 12 4"
+ env <- runExpression input
+ env @?= ofNumber 0
+
+ , testCase "mod 3 5 = 3 (divisor larger)" $ do
+ let input = "mod 3 5"
+ env <- runExpression input
+ env @?= ofNumber 3
+
+ , testCase "mod 7 1 = 0" $ do
+ let input = "mod 7 1"
+ env <- runExpression input
+ env @?= ofNumber 0
+
+ , testCase "mod rejects a zero divisor" $ do
+ let input = "mod 5 0"
+ env <- runExpression input
+ env @?= Fork Leaf (Fork (ofString "non-zero") Leaf)
+
+ , testCase "div mod consistency" $ do
+ let input = "equal? (add (mul 3 7) 4) 25"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "pow 2 0 = 1" $ do
+ let input = "pow 2 0"
+ env <- runExpression input
+ env @?= ofNumber 1
+
+ , testCase "pow 2 3 = 8" $ do
+ let input = "pow 2 3"
+ env <- runExpression input
+ env @?= ofNumber 8
+
+ , testCase "pow 3 2 = 9" $ do
+ let input = "pow 3 2"
+ env <- runExpression input
+ env @?= ofNumber 9
+
+ , testCase "pow 0 0 = 1" $ do
+ let input = "pow 0 0"
+ env <- runExpression input
+ env @?= ofNumber 1
+
+ , testCase "pow 0 5 = 0" $ do
+ let input = "pow 0 5"
+ env <- runExpression input
+ env @?= ofNumber 0
+
+ , testCase "pow 1 10 = 1" $ do
+ let input = "pow 1 10"
+ env <- runExpression input
+ env @?= ofNumber 1
+
+ , testCase "pow 5 1 = 5" $ do
+ let input = "pow 5 1"
+ env <- runExpression input
+ env @?= ofNumber 5
+
+ , testCase "min 3 7 = 3" $ do
+ let input = "min 3 7"
+ env <- runExpression input
+ env @?= ofNumber 3
+
+ , testCase "min 7 3 = 3" $ do
+ let input = "min 7 3"
+ env <- runExpression input
+ env @?= ofNumber 3
+
+ , testCase "min 5 5 = 5" $ do
+ let input = "min 5 5"
+ env <- runExpression input
+ env @?= ofNumber 5
+
+ , testCase "min 0 5 = 0" $ do
+ let input = "min 0 5"
+ env <- runExpression input
+ env @?= ofNumber 0
+
+ , testCase "max 3 7 = 7" $ do
+ let input = "max 3 7"
+ env <- runExpression input
+ env @?= ofNumber 7
+
+ , testCase "max 7 3 = 7" $ do
+ let input = "max 7 3"
+ env <- runExpression input
+ env @?= ofNumber 7
+
+ , testCase "max 5 5 = 5" $ do
+ let input = "max 5 5"
+ env <- runExpression input
+ env @?= ofNumber 5
+
+ , testCase "max 0 5 = 5" $ do
+ let input = "max 0 5"
+ env <- runExpression input
+ env @?= ofNumber 5
+
+ , testCase "even? 0 = true" $ do
+ let input = "even? 0"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "even? 1 = false" $ do
+ let input = "even? 1"
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "even? 2 = true" $ do
+ let input = "even? 2"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "even? 7 = false" $ do
+ let input = "even? 7"
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "odd? 0 = false" $ do
+ let input = "odd? 0"
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "odd? 1 = true" $ do
+ let input = "odd? 1"
+ env <- runExpression input
+ env @?= trueT
+
+ , testCase "odd? 2 = false" $ do
+ let input = "odd? 2"
+ env <- runExpression input
+ env @?= falseT
+
+ , testCase "odd? 7 = true" $ do
+ let input = "odd? 7"
+ env <- runExpression input
+ env @?= trueT
+ ]
+
diff --git a/test/PackageTests.hs b/test/PackageTests.hs
@@ -14,7 +14,7 @@ import qualified Data.Sequence as Seq
import qualified Data.ByteString as BS
import qualified Data.Text as T
import Wire (buildBundleShared, encodeBundle)
-import Research (T(..), ofNumber)
+import Runtime (T(..), ofNumber)
import System.IO.Temp (withSystemTempDirectory)
import System.FilePath ((</>))
import System.Directory (doesFileExist)
diff --git a/test/PatternLowering.hs b/test/PatternLowering.hs
@@ -1,7 +1,7 @@
-- Opt-in candidate controls. Built through Nix by pattern_lowering.py.
-- The reference compiler constructs independent authored oracles, never candidate expectations.
module Main where
-import Research
+import Runtime
import Wire
import TreeObservation
import qualified Data.ByteString as BS
diff --git a/test/Spec.hs b/test/Spec.hs
@@ -2,17 +2,15 @@ module Main where
import ScriptedEffects (runScriptedEffects)
import IODriverTests (ioDriverTests)
-import Eval
+import LibraryProgramTests (maybeTests, providedLibraries, contractsTests, arithmetic)
import qualified ParserValueTests
import qualified LibraryValueTests
import PortableTestCompiler (compileFixtureFile, compileFixtureDefinitions)
import ReferenceFixtures
import PackageTests (packageTests)
import InteractionInspectionTests (interactionInspectionTests)
-import FileEval
-import Parser
import REPL
-import Research
+import Runtime
import TreeObservation (forceTreeShared)
import qualified NodeTable as Nodes
import Wire
@@ -21,7 +19,6 @@ import SupportFixture (canonicalEnvs, verifyReuseProviders, verifySupportSources
import ContentStore
import ContentStore.Bundle
import Module.Manifest
-import Module.Resolver
import IODriver (IOPermissions(..), checkIOSentinel, runIO, runIOWithEnv, runIOWith, unsafePerms, defaultPerms)
import Control.Exception (bracket, evaluate, try, SomeException)
@@ -61,19 +58,6 @@ testStore :: StorePath
testStore = StorePath "/tmp/tricu-test-store"
{-# NOINLINE testStore #-}
-allTestLibsEnv :: Env
-allTestLibsEnv = unsafePerformIO $ do
- base <- recoveryFoundationEnv "base"
- bytes <- recoveryFoundationEnv "bytes"
- bin <- evaluateTestSupportFile "./lib/binary.tri"
- http <- evaluateTestSupportFile "./lib/http.tri"
- arbor <- evaluateTestSupportFile "./lib/arboricx/arboricx.tri"
- io <- recoveryFoundationEnv "io"
- sock <- evaluateTestSupportFile "./lib/socket.tri"
- intensional <- evaluateTestSupportFile "./lib/intensionalContracts.tri"
- pure (injectKernel (Map.unions [base, bytes, bin, http, arbor, io, sock, intensional]))
-{-# NOINLINE allTestLibsEnv #-}
-
tests :: TestTree
tests = testGroup "Tricu Tests"
[ runtimePresentationTests
@@ -273,11 +257,11 @@ artifactSafetyTests = testGroup "artifact safety" $
BS.writeFile (objectPath store h) (encodeTreeTerm (Stem Leaf))
resolverObject resolver (treeTermRef h) >>= (@?= Just (encodeTreeTerm Leaf))
blocked "digest mismatch" (resolverObject (filesystemResolver store) (treeTermRef h))
- , testCase "module imports verify bytes from custom resolver callbacks" $ fresh $ \store -> do
+ , testCase "object resolution verifies bytes from custom resolver callbacks" $ fresh $ \store -> do
h <- putTreeTerm store Leaf
mh <- putManifest store (ModuleManifest [] [ModuleExport "x" (treeTermRef h) "arboricx.abi.tree.v1"])
let resolver = (filesystemResolver store) { resolverObject = \_ -> pure (Just (encodeTreeTerm (Stem Leaf))) }
- blocked "digest mismatch" (resolveModuleImport resolver (unpack mh) "Demo")
+ blocked "digest mismatch" (resolveObjectByHash resolver (unDomain treeTermDomain) h)
, testGroup "execution contract"
[ testCase label $ do
let base = buildBundle [("first", Leaf), ("second", Stem Leaf)]
@@ -304,7 +288,7 @@ artifactSafetyTests = testGroup "artifact safety" $
mh <- putManifest store (ModuleManifest [] [ModuleExport "x" (treeTermRef h) "arboricx.abi.tree.v1"])
BS.writeFile (objectPath store h) (encodeTreeTerm (Stem Leaf))
resolver <- makeResolver store
- blocked "digest mismatch" (resolveModuleImport resolver (unpack mh) "Demo")
+ blocked "digest mismatch" (resolveObjectByHash resolver (unDomain treeTermDomain) h)
blocked "digest mismatch" (getTreeTerm store h)
, testCase "tampered Merkle child" $ fresh $ \store -> do
h <- putTree store (Stem Leaf)
@@ -329,11 +313,8 @@ artifactSafetyTests = testGroup "artifact safety" $
h <- putTreeTerm store Leaf
resolver <- makeResolver store
blocked "digest mismatch" (resolverObject resolver (ObjectRef (unDomain manifestDomain) h))
- , testCase "unsupported module export ABI" $ fresh $ \store -> do
- h <- putTreeTerm store Leaf
- mh <- putManifest store (ModuleManifest [] [ModuleExport "x" (treeTermRef h) "foreign.abi"])
- resolver <- makeResolver store
- blocked "unsupported export ABI" (resolveModuleImport resolver (unpack mh) "Demo")
+ -- Export ABI rejection is exercised against the production executable in
+ -- executable_arguments.py, not the retired source-module resolver.
, testCase "valid objects and genuine missing objects" $ fresh $ \store -> do
h <- putTreeTerm store (Stem Leaf)
mh <- putManifest store (ModuleManifest [] [ModuleExport "x" (treeTermRef h) "arboricx.abi.tree.v1"])
@@ -341,8 +322,8 @@ artifactSafetyTests = testGroup "artifact safety" $
resolver <- makeResolver store
resolveManifest resolver mh >>= (@?= Just (ModuleManifest [] [ModuleExport "x" (treeTermRef h) "arboricx.abi.tree.v1"]))
resolveTree resolver nh >>= (@?= Just (Stem Leaf))
- resolved <- resolveModuleImport resolver (unpack mh) "Demo"
- map resolvedExportTerm (resolvedModuleExports resolved) @?= [Stem Leaf]
+ resolveObjectByHash resolver (unDomain treeTermDomain) h >>= (@?= Just (encodeTreeTerm (Stem Leaf)))
+ loadExecutableObject store (treeTermRef h) >>= (@?= Stem Leaf)
resolverObject resolver (treeTermRef (pack (replicate 64 '0'))) >>= (@?= Nothing)
]
| (label, makeResolver) <- [("filesystem integrity", pure . filesystemResolver), ("cached integrity", cachedFilesystemResolver)]
@@ -704,1006 +685,28 @@ sourceObjectCodecTests = testGroup "Portable tree object codec"
apply decoder encoded @?= Fork (Stem Leaf) (Fork tree Leaf)
]
-maybeTests :: TestTree
-maybeTests = testGroup "Maybe Tests"
- [ testCase "nothing is Leaf" $ do
- let input = "nothing"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Leaf
-
- , testCase "just wraps value in Stem" $ do
- let input = "just (t t)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Stem (Stem Leaf)
-
- , testCase "matchMaybe on nothing returns default" $ do
- let input = "matchMaybe \"empty\" (x : x) nothing"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString "empty"
-
- , testCase "matchMaybe on just extracts value" $ do
- let input = "matchMaybe \"empty\" (x : x) (just (t t))"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Stem Leaf
-
- , testCase "maybe applies f inside just" $ do
- let input = "maybe 0 (x : succ x) (just 5)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 6
-
- , testCase "maybe returns default on nothing" $ do
- let input = "maybe 0 (x : succ x) nothing"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "maybeMap transforms just value" $ do
- let input = "maybeMap (x : succ x) (just 3)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= justT (ofNumber 4)
-
- , testCase "maybeMap returns nothing on nothing" $ do
- let input = "maybeMap (x : succ x) nothing"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= nothingT
-
- , testCase "maybeBind flattens just" $ do
- let input = "maybeBind (just 3) (x : just (succ x))"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= justT (ofNumber 4)
-
- , testCase "maybeBind returns nothing on nothing" $ do
- let input = "maybeBind nothing (x : just (succ x))"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Leaf
-
- , testCase "maybeOr returns just value" $ do
- let input = "maybeOr 99 (just 5)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 5
-
- , testCase "maybeOr returns default on nothing" $ do
- let input = "maybeOr 99 nothing"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 99
-
- , testCase "maybe? on just is true" $ do
- let input = "maybe? (just t)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "maybe? on nothing is false" $ do
- let input = "maybe? nothing"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
- ]
-
-providedLibraries :: TestTree
-providedLibraries = testGroup "Library Tests"
- [ testCase "Triage test Leaf" $ do
- let input = "test t"
- env = decodeResult $ result $ evalTricu allTestLibsEnv (parseTricu input)
- env @?= "\"Leaf\""
-
- , testCase "Triage test (Stem Leaf)" $ do
- let input = "test (t t)"
- env = decodeResult $ result $ evalTricu allTestLibsEnv (parseTricu input)
- env @?= "\"Stem\""
-
- , testCase "Triage test (Fork Leaf Leaf)" $ do
- let input = "test (t t t)"
- env = decodeResult $ result $ evalTricu allTestLibsEnv (parseTricu input)
- env @?= "\"Fork\""
-
- , testCase "Boolean NOT: true" $ do
- let input = "not? true"
- env = result $ evalTricu allTestLibsEnv (parseTricu input)
- env @?= Leaf
-
- , testCase "Boolean NOT: false" $ do
- let input = "not? false"
- env = result $ evalTricu allTestLibsEnv (parseTricu input)
- env @?= Stem Leaf
-
-
- , testCase "Boolean AND TF" $ do
- let input = "and? (t t) (t)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Leaf
-
- , testCase "Boolean AND FT" $ do
- let input = "and? (t) (t t)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Leaf
-
- , testCase "Boolean AND FF" $ do
- let input = "and? (t) (t)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Leaf
-
- , testCase "Boolean AND TT" $ do
- let input = "and? (t t) (t t)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Stem Leaf
-
- , testCase "List head" $ do
- let input = "head [(t) (t t) (t t t)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Leaf
-
- , testCase "List tail" $ do
- let input = "head (tail (tail [(t) (t t) (t t t)]))"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Fork Leaf Leaf
-
- , testCase "List map" $ do
- let input = "head (tail (map (a : (t t t)) [(t) (t) (t)]))"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Fork Leaf Leaf
-
- , testCase "Empty list check" $ do
- let input = "emptyList? []"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Stem Leaf
-
- , testCase "Non-empty list check" $ do
- let input = "not? (emptyList? [(1) (2) (3)])"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Stem Leaf
-
- , testCase "Concatenate strings" $ do
- let input = "append \"Hello, \" \"world!\""
- env = decodeResult $ result $ evalTricu allTestLibsEnv (parseTricu input)
- env @?= "\"Hello, world!\""
-
- , testCase "Verifying Equality" $ do
- let input = "equal? (t t t) (t t t)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= Stem Leaf
-
- , testCase "headMaybe on empty list" $ do
- let input = "headMaybe []"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= nothingT
-
- , testCase "headMaybe on non-empty list" $ do
- let input = "headMaybe [(t) (t t)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= justT Leaf
-
- , testCase "lastMaybe on empty list" $ do
- let input = "lastMaybe []"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= nothingT
-
- , testCase "lastMaybe on single element" $ do
- let input = "lastMaybe [(t t)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= justT (Stem Leaf)
-
- , testCase "lastMaybe on multi-element list" $ do
- let input = "lastMaybe [(t) (t t) (t t t)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= justT (Fork Leaf Leaf)
-
- , testCase "nthMaybe first element" $ do
- let input = "nthMaybe 0 [(t) (t t)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= justT Leaf
-
- , testCase "nthMaybe middle element" $ do
- let input = "nthMaybe 1 [(t) (t t) (t t t)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= justT (Stem Leaf)
-
- , testCase "nthMaybe out of bounds" $ do
- let input = "nthMaybe 5 [(t) (t t)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= nothingT
-
- , testCase "reverse empty list" $ do
- let input = "reverse []"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList []
-
- , testCase "reverse non-empty list" $ do
- let input = "reverse [(1) (2) (3)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofNumber 3, ofNumber 2, ofNumber 1]
-
- , testCase "take 0 any list = empty" $ do
- let input = "take 0 [(1) (2) (3)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList []
-
- , testCase "take 2 [1,2,3] = [1,2]" $ do
- let input = "take 2 [(1) (2) (3)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofNumber 1, ofNumber 2]
-
- , testCase "take overlong returns whole list" $ do
- let input = "take 5 [(1) (2)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofNumber 1, ofNumber 2]
-
- , testCase "drop 0 any list = list" $ do
- let input = "drop 0 [(1) (2) (3)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofNumber 1, ofNumber 2, ofNumber 3]
-
- , testCase "drop 2 [1,2,3] = [3]" $ do
- let input = "drop 2 [(1) (2) (3)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofNumber 3]
-
- , testCase "drop overlong returns empty" $ do
- let input = "drop 5 [(1) (2)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList []
-
- , testCase "splitAt 0 [1,2] = pair [] [1,2]" $ do
- let input = "splitAt 0 [(1) (2)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= pairT (ofList []) (ofList [ofNumber 1, ofNumber 2])
-
- , testCase "splitAt 2 [1,2,3] = pair [1,2] [3]" $ do
- let input = "splitAt 2 [(1) (2) (3)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= pairT (ofList [ofNumber 1, ofNumber 2]) (ofList [ofNumber 3])
-
- , testCase "splitAt overlong = pair [1,2] []" $ do
- let input = "splitAt 5 [(1) (2)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= pairT (ofList [ofNumber 1, ofNumber 2]) (ofList [])
-
- , testCase "concatMap on empty list" $ do
- let input = "concatMap (x : [(x) (x)]) []"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList []
-
- , testCase "concatMap doubles elements" $ do
- let input = "concatMap (x : [(x) (x)]) [(1) (2)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofNumber 1, ofNumber 1, ofNumber 2, ofNumber 2]
-
- , testCase "find on empty list" $ do
- let input = "find (x : equal? x 2) []"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= nothingT
-
- , testCase "find finds element" $ do
- let input = "find (x : equal? x 2) [(1) (2) (3)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= justT (ofNumber 2)
-
- , testCase "find missing element" $ do
- let input = "find (x : equal? x 9) [(1) (2) (3)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= nothingT
-
- , testCase "partition empty list" $ do
- let input = "partition (x : equal? x 2) []"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= pairT (ofList []) (ofList [])
-
- , testCase "partition splits list" $ do
- let input = "partition (x : lt? 2 x) [(1) (2) (3) (4)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= pairT (ofList [ofNumber 3, ofNumber 4]) (ofList [ofNumber 1, ofNumber 2])
-
- , testCase "zipWith on empty lists" $ do
- let input = "zipWith add [] []"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList []
-
- , testCase "zipWith adds pairwise" $ do
- let input = "zipWith add [(1) (2)] [(10) (20)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofNumber 11, ofNumber 22]
-
- , testCase "zipWith truncates to shorter list" $ do
- let input = "zipWith add [(1) (2)] [(10)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofNumber 11]
-
- , testCase "strLength" $ do
- let input = "strLength \"hello\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 5
-
- , testCase "strAppend" $ do
- let input = "strAppend \"hello\" \" world\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString "hello world"
-
- , testCase "equal? equal strings" $ do
- let input = "equal? \"abc\" \"abc\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "equal? different strings" $ do
- let input = "equal? \"abc\" \"def\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "strEmpty? on empty" $ do
- let input = "strEmpty? \"\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "strEmpty? on non-empty" $ do
- let input = "strEmpty? \"a\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "startsWith? prefix matches" $ do
- let input = "startsWith? \"he\" \"hello\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "startsWith? prefix too long" $ do
- let input = "startsWith? \"hello\" \"he\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "startsWith? empty prefix" $ do
- let input = "startsWith? \"\" \"hello\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "endsWith? suffix matches" $ do
- let input = "endsWith? \"lo\" \"hello\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "endsWith? suffix too long" $ do
- let input = "endsWith? \"hello\" \"lo\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "endsWith? empty suffix" $ do
- let input = "endsWith? \"\" \"hello\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "contains? substring found" $ do
- let input = "contains? \"ell\" \"hello\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "contains? substring missing" $ do
- let input = "contains? \"xyz\" \"hello\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "contains? empty needle" $ do
- let input = "contains? \"\" \"hello\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "lines splits on newline" $ do
- let input = "lines \"a\\nb\\nc\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofString "a", ofString "b", ofString "c"]
-
- , testCase "lines single line" $ do
- let input = "lines \"hello\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofString "hello"]
-
- , testCase "lines empty string" $ do
- let input = "lines \"\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofString ""]
-
- , testCase "lines trailing newline" $ do
- let input = "lines \"a\\n\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofString "a", ofString ""]
-
- , testCase "unlines joins with newline" $ do
- let input = "unlines [(\"a\") (\"b\")]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString "a\nb\n"
-
- , testCase "unlines empty list" $ do
- let input = "unlines []"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString ""
-
- , testCase "words splits on space" $ do
- let input = "words \"hello world\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofString "hello", ofString "world"]
-
- , testCase "words empty string" $ do
- let input = "words \"\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList []
-
- , testCase "words multiple spaces" $ do
- let input = "words \" hello world \""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofString "hello", ofString "world"]
-
- , testCase "unwords joins with space" $ do
- let input = "unwords [(\"hello\") (\"world\")]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString "hello world"
-
- , testCase "unwords single word" $ do
- let input = "unwords [(\"hello\")]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString "hello"
-
- , testCase "unwords empty list" $ do
- let input = "unwords []"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString ""
-
- , testCase "intercalate joins fields" $ do
- let input = "intercalate \", \" [(\"a\") (\"b\") (\"c\")]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString "a, b, c"
-
- , testCase "intercalate leaves a lone field alone" $ do
- let input = "intercalate \", \" [(\"a\")]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString "a"
-
- , testCase "intercalate empty list" $ do
- let input = "intercalate \", \" []"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString ""
-
- , testCase "joinSuffix terminates every field" $ do
- let input = "joinSuffix \"-\" [(\"a\") (\"b\")]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString "a-b-"
-
- , testCase "splitOnByte splits on a byte" $ do
- let input = "splitOnByte 58 \"a:b:c\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofString "a", ofString "b", ofString "c"]
-
- , testCase "splitOnByte keeps empty fields" $ do
- let input = "splitOnByte 58 \"a::b\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofString "a", ofString "", ofString "b"]
-
- , testCase "splitOnByte trailing separator leaves an empty field" $ do
- let input = "splitOnByte 58 \"a:\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofString "a", ofString ""]
-
- , testCase "splitOnByte without a match" $ do
- let input = "splitOnByte 58 \"abc\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofString "abc"]
-
- , testCase "splitOnByte empty input" $ do
- let input = "splitOnByte 58 \"\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofString ""]
-
- , testCase "intercalate round trips splitOnByte" $ do
- let input = "equal? (intercalate \":\" (splitOnByte 58 \"a:b:c\")) \"a:b:c\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "takeWhile keeps the matching prefix" $ do
- let input = "takeWhile (n : lt? n 3) [(1) (2) (3) (1)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofNumber 1, ofNumber 2]
-
- , testCase "takeWhile stops at the first mismatch" $ do
- let input = "takeWhile (n : lt? n 3) [(3) (1)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList []
-
- , testCase "dropWhile drops the matching prefix" $ do
- let input = "dropWhile (n : lt? n 3) [(1) (2) (3) (1)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList [ofNumber 3, ofNumber 1]
-
- , testCase "dropWhile on an all matching list" $ do
- let input = "dropWhile (n : lt? n 3) [(1) (2)]"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofList []
-
- , testCase "trim strips surrounding spaces and tabs" $ do
- let input = "trim \" \\ttrimmed \\t\""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString "trimmed"
-
- , testCase "trim leaves interior bytes alone" $ do
- let input = "trim \" a b \""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString "a b"
-
- , testCase "trim all whitespace is empty" $ do
- let input = "trim \" \\t \""
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofString ""
- ]
-
-contractsTests :: TestTree
-contractsTests = testGroup "Contracts library tests"
- [ testCase "anyC passes any value" $ do
- let input = "main = resultIsOk (checkContract anyC 7)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "guardC rejects failures" $ do
- let input = "main = resultIsErr (checkContract (guardC \"odd\" even?) 5)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "andC combines contracts" $ do
- let input = "main = resultIsOk (checkContract (andC (guardC \"odd\" odd?) (guardC \"gt0\" (n : gt? n 0))) 5)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "listOf checks every element" $ do
- let input = "main = resultIsOk (checkContract (listOf (guardC \"odd\" odd?)) [1 3 5])"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "fnContract wraps a function" $ do
- let input = "main = resultIsOk (checkContract (fnContract (guardC \"odd\" odd?) anyC) (x : x))"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "runM reduces pureM" $ do
- let input = "main = resultIsOk (runM (pureM 42))"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "do notation chains checkM and pureM" $ do
- let input = unlines
- [ "program = (xs :"
- , " do bindM"
- , " n <- pureM (length xs)"
- , " _ <- checkM (guardC \"positive\" (n : gte? n 1)) n"
- , " pureM n)"
- , "main = runM (program [1 2 3 4])"
- ]
- env = evalTricu allTestLibsEnv (parseTricu input)
- decodeResult (result env) @?= "[t t, 4]"
-
- , testCase "handleM replaces exception with a new action" $ do
- let input = unlines
- [ "lookupConfig = (key defaultValue :"
- , " exceptE \"missing\" key (resume : pureM defaultValue))"
- , "pipeline = (xs :"
- , " do bindM"
- , " divisor <- lookupConfig \"divisor\" 1"
- , " total <- pureM (sum xs)"
- , " scaled <- liftM (x : div x divisor) total"
- , " pureM scaled)"
- , "handled = handleM \"missing\" (key k : pureM 2) (pipeline [10 20 30])"
- , "main = runM handled"
- ]
- env = evalTricu allTestLibsEnv (parseTricu input)
- decodeResult (result env) @?= "[t t, 30]"
-
- , testCase "=@ return annotation passes" $ do
- let input = unlines
- [ "five =@anyC 5"
- , "main = five"
- ]
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 5
-
- , testCase "=@ return annotation fails" $ do
- let input = unlines
- [ "boom =@(neverC \"boom\") 5"
- , "main = boom"
- ]
- env = evalTricu allTestLibsEnv (parseTricu input)
- decodeResult (result env) @?= "[t, \"boom\"]"
-
- , testCase "@ argument annotation passes" $ do
- let input = unlines
- [ "idNat x@anyC =@anyC x"
- , "main = idNat 5"
- ]
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 5
-
- , testCase "@ argument annotation fails" $ do
- let input = unlines
- [ "idNat x@(neverC \"bad\") =@anyC x"
- , "main = idNat 5"
- ]
- env = evalTricu allTestLibsEnv (parseTricu input)
- decodeResult (result env) @?= "[t, \"bad\"]"
- ]
-
-arithmetic :: TestTree
-arithmetic = testGroup "Arithmetic Tests"
- [ testCase "isZero? on 0" $ do
- let input = "isZero? 0"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "isZero? on 5" $ do
- let input = "isZero? 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "add 0 3 = 3" $ do
- let input = "add 0 3"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 3
-
- , testCase "add 3 0 = 3" $ do
- let input = "add 3 0"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 3
-
- , testCase "add 2 3 = 5" $ do
- let input = "add 2 3"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 5
-
- , testCase "sub 5 2 = 3" $ do
- let input = "sub 5 2"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 3
-
- , testCase "sub 2 5 = 0 (saturated)" $ do
- let input = "sub 2 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "sub 5 5 = 0" $ do
- let input = "sub 5 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "lt? 2 3 = true" $ do
- let input = "lt? 2 3"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "lt? 3 2 = false" $ do
- let input = "lt? 3 2"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "lt? 2 2 = false" $ do
- let input = "lt? 2 2"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "lte? 2 3 = true" $ do
- let input = "lte? 2 3"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "lte? 3 2 = false" $ do
- let input = "lte? 3 2"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "lte? 2 2 = true" $ do
- let input = "lte? 2 2"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "mul 0 5 = 0" $ do
- let input = "mul 0 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "mul 5 0 = 0" $ do
- let input = "mul 5 0"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "mul 2 3 = 6" $ do
- let input = "mul 2 3"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 6
-
- , testCase "mul 3 3 = 9" $ do
- let input = "mul 3 3"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 9
-
- , testCase "pred 0 = 0" $ do
- let input = "pred 0"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "pred 1 = 0" $ do
- let input = "pred 1"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "pred 5 = 4" $ do
- let input = "pred 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 4
-
- , testCase "add is commutative" $ do
- let input = "equal? (add 4 7) (add 7 4)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "add is associative" $ do
- let input = "equal? (add (add 2 3) 4) (add 2 (add 3 4))"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "sub x 0 = x" $ do
- let input = "sub 7 0"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 7
-
- , testCase "sub chained" $ do
- let input = "sub (sub 10 3) 2"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 5
-
- , testCase "mul identity 1" $ do
- let input = "mul 1 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 5
-
- , testCase "mul identity 2" $ do
- let input = "mul 5 1"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 5
-
- , testCase "mul is commutative" $ do
- let input = "equal? (mul 3 4) (mul 4 3)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "mul is associative" $ do
- let input = "equal? (mul (mul 2 3) 4) (mul 2 (mul 3 4))"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "mul distributes over add" $ do
- let input = "equal? (mul 2 (add 3 4)) (add (mul 2 3) (mul 2 4))"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "lt? reflexive is false" $ do
- let input = "lt? 5 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "lte? reflexive is true" $ do
- let input = "lte? 5 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "lt? transitivity" $ do
- let input = "and? (lt? 2 5) (lt? 5 7)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "add larger numbers" $ do
- let input = "add 12 15"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 27
-
- , testCase "mul larger numbers" $ do
- let input = "mul 5 6"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 30
-
- , testCase "isZero? on add 0 0" $ do
- let input = "isZero? (add 0 0)"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "div 10 3 = 3" $ do
- let input = "div 10 3"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 3
-
- , testCase "div 12 4 = 3 (exact)" $ do
- let input = "div 12 4"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 3
-
- , testCase "div 3 5 = 0 (divisor larger)" $ do
- let input = "div 3 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "div 7 1 = 7 (identity)" $ do
- let input = "div 7 1"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 7
-
- , testCase "div 0 5 = 0" $ do
- let input = "div 0 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "div 5 0 = 0 (div by zero)" $ do
- let input = "div 5 0"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "mod 10 3 = 1" $ do
- let input = "mod 10 3"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 1
-
- , testCase "mod 12 4 = 0 (exact)" $ do
- let input = "mod 12 4"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "mod 3 5 = 3 (divisor larger)" $ do
- let input = "mod 3 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 3
-
- , testCase "mod 7 1 = 0" $ do
- let input = "mod 7 1"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "mod 5 0 = 0 (mod by zero)" $ do
- let input = "mod 5 0"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "div mod consistency" $ do
- let input = "equal? (add (mul 3 7) 4) 25"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "pow 2 0 = 1" $ do
- let input = "pow 2 0"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 1
-
- , testCase "pow 2 3 = 8" $ do
- let input = "pow 2 3"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 8
-
- , testCase "pow 3 2 = 9" $ do
- let input = "pow 3 2"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 9
-
- , testCase "pow 0 0 = 1" $ do
- let input = "pow 0 0"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 1
-
- , testCase "pow 0 5 = 0" $ do
- let input = "pow 0 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "pow 1 10 = 1" $ do
- let input = "pow 1 10"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 1
-
- , testCase "pow 5 1 = 5" $ do
- let input = "pow 5 1"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 5
-
- , testCase "min 3 7 = 3" $ do
- let input = "min 3 7"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 3
-
- , testCase "min 7 3 = 3" $ do
- let input = "min 7 3"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 3
-
- , testCase "min 5 5 = 5" $ do
- let input = "min 5 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 5
-
- , testCase "min 0 5 = 0" $ do
- let input = "min 0 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 0
-
- , testCase "max 3 7 = 7" $ do
- let input = "max 3 7"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 7
-
- , testCase "max 7 3 = 7" $ do
- let input = "max 7 3"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 7
-
- , testCase "max 5 5 = 5" $ do
- let input = "max 5 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 5
-
- , testCase "max 0 5 = 5" $ do
- let input = "max 0 5"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= ofNumber 5
-
- , testCase "even? 0 = true" $ do
- let input = "even? 0"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "even? 1 = false" $ do
- let input = "even? 1"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "even? 2 = true" $ do
- let input = "even? 2"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "even? 7 = false" $ do
- let input = "even? 7"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "odd? 0 = false" $ do
- let input = "odd? 0"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "odd? 1 = true" $ do
- let input = "odd? 1"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
-
- , testCase "odd? 2 = false" $ do
- let input = "odd? 2"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= falseT
-
- , testCase "odd? 7 = true" $ do
- let input = "odd? 7"
- env = evalTricu allTestLibsEnv (parseTricu input)
- result env @?= trueT
- ]
-
fileEval :: TestTree
-fileEval = testGroup "File evaluation tests"
- [ testCase "Forks" $ do
- res <- liftIO $ evaluateFileResult "./test/fork.tri"
- res @?= Fork Leaf Leaf
-
- , testCase "File ends with comment" $ do
- res <- liftIO $ evaluateFileResult "./test/comments-1.tri"
- res @?= Fork (Stem Leaf) Leaf
-
- , testCase "Mapping and Equality" $ do
- fEnv <- liftIO $ evaluateFileWithContext allTestLibsEnv "./test/map.tri"
- (mainResult fEnv) @?= Stem Leaf
-
- , testCase "Eval and decoding string" $ do
- res <- liftIO $ evaluateFileWithContext allTestLibsEnv "./test/string.tri"
- decodeResult (result res) @?= "\"String test!\""
+fileEval = testGroup "Portable source file tests"
+ [ testCase "Forks" $ check "./test/fork.tri" (Fork Leaf Leaf)
+ , testCase "File ends with comment" $ check "./test/comments-1.tri" (Fork (Stem Leaf) Leaf)
+ , testCase "Mapping and Equality" $ check "./test/map.tri" (Stem Leaf)
+ , testCase "Eval and decoding string" $ check "./test/string.tri" (ofString "String test!")
]
+ where
+ check path expected = do
+ source <- readFile path
+ let external = ofList [Fork (ofString name) value | (name,value) <- Map.toList (fixtureExports "prelude")]
+ foldl apply (fixtureExports "source.unit" Map.! "compileGateProgram")
+ [external, ofString source] @?= parserOk expected Leaf
-- All of our demo tests are also module tests
demos :: TestTree
demos = testGroup "Test provided demo functionality"
[ testCase "Stable demo distinguishes structural from extensional equality" $ do
- env <- evaluateTestSupportFile "./demos/equality.tri"
+ env <- evaluateCompilerFile "./demos/equality.tri"
-- The former optimized fixture identified these trees. Stable lowering
-- does not: that intensional difference is observable, not a Boolean bug.
- mainResult env @?= Leaf
+ env Map.! "main" @?= Leaf
assertBool "stable lambda and hand-authored TC trees must differ"
(env Map.! "not_TC?" /= env Map.! "not_Lambda?")
forM_ ["not_TC?", "not_Lambda?"] $ \name -> do
@@ -1712,29 +715,29 @@ demos = testGroup "Test provided demo functionality"
env Map.! "bothTrueEqual?" @?= Stem Leaf
env Map.! "bothFalseEqual?" @?= Stem Leaf
, testCase "Convert values back to source code demo" $ do
- res <- liftIO $ (mainResult <$> evaluateTestSupportFile "./demos/toSource.tri")
+ res <- liftIO $ ((Map.! "main") <$> evaluateCompilerFile "./demos/toSource.tri")
-- Native portable foundation trees, not the Haskell recovery cohort.
decodeResult res @?= "\"(t (t (t t) (t t t)) (t (t (t t (t t))) (t t t)))\""
, testCase "Determining the size of stable-compiled functions" $ do
- env <- evaluateTestSupportFile "./demos/size.tri"
+ env <- evaluateCompilerFile "./demos/size.tri"
-- Count the actual executable independently of the compiled size worker.
- -- The old optimized demo was 1038; other source/recovery cohorts below
- -- have their own distinct intensional goldens.
+ -- This is a representation check of the retained stable artifact,
+ -- not a parity requirement across compiler backends.
let nodes Leaf = 1 :: Integer
nodes (Stem child) = 1 + nodes child
nodes (Fork left right) = 1 + nodes left + nodes right
actual = nodes (env Map.! "size")
-- Current stable native libraries; pre-modernization stable size was 1606.
actual @?= 1845
- mainResult env @?= ofNumber actual
+ env Map.! "main" @?= ofNumber actual
, testCase "Level Order Traversal demo" $ do
- res <- liftIO $ (mainResult <$> evaluateTestSupportFile "./demos/levelOrderTraversal.tri")
+ res <- liftIO $ ((Map.! "main") <$> evaluateCompilerFile "./demos/levelOrderTraversal.tri")
decodeResult res @?= "\"\n1 \n2 3 \n4 5 6 7 \n8 11 10 9 12 \""
, testCase "Contract effect demo with do notation" $ do
- res <- liftIO $ (mainResult <$> evaluateTestSupportFile "./demos/contractEffects.tri")
+ res <- liftIO $ ((Map.! "main") <$> evaluateCompilerFile "./demos/contractEffects.tri")
decodeResult res @?= "[t t, 10]"
, testCase "Safe base wrappers demo" $ do
- res <- liftIO $ (mainResult <$> evaluateTestSupportFile "./demos/contractBasics.tri")
+ res <- liftIO $ ((Map.! "main") <$> evaluateCompilerFile "./demos/contractBasics.tri")
decodeResult res @?= "[3, t t, t, t t]"
]
@@ -1978,101 +981,6 @@ contentStoreTests = testGroup "Content Store Tests"
resolveManifest resolver manifestH >>= (@?= Just manifest)
resolveTree resolver rootH >>= (@?= Just term)
- , testCase "Workspace modules: exported names are local top-level definitions only" $
- withSystemTempDirectory "tricu-workspace-local-exports" $ \dir -> do
- let store = StorePath (dir </> "store")
- depPath = dir </> "dep.tri"
- libPath = dir </> "util.tri"
- mainPath = dir </> "main.tri"
- writeFile (dir </> "tricu.workspace") "module dep = dep.tri\nmodule util = util.tri\n"
- writeFile depPath "helper = t t\n"
- writeFile libPath "!import \"dep\" !Local\n\nvalue = helper\n"
- writeFile mainPath "!import \"util\" Util\n\nmain = Util.value\n"
- env <- evaluateFileWithStore (Just store) mainPath
- result env @?= Stem Leaf
- mAlias <- readAlias store ModuleAlias "util"
- case mAlias of
- Nothing -> assertFailure "expected workspace build to write util module alias"
- Just ref -> do
- mManifest <- getManifest store (objectRefHash ref)
- case mManifest of
- Nothing -> assertFailure "expected workspace module manifest"
- Just manifest -> map moduleExportName (moduleManifestExports manifest) @?= ["value"]
-
- , testCase "Workspace modules: contract annotations travel with exported definitions" $
- withSystemTempDirectory "tricu-workspace-contract-export" $ \dir -> do
- let store = StorePath (dir </> "store")
- libPath = dir </> "util.tri"
- mainPath = dir </> "main.tri"
- -- Exercise the real recovery resolver with an explicit temporary body
- -- fixture, not an attempt to parse native library headers as legacy.
- reference <- recoveryFoundationBody "base"
- writeFile (dir </> "base.tri") reference
- writeFile (dir </> "tricu.workspace") "module base = base.tri\nmodule util = util.tri\n"
- writeFile libPath "!import \"base\" !Local\n\nalwaysOk = (value rest : ok value rest)\n\nneverOk = (value rest : err \"nope\" rest)\n\nsafeId n@alwaysOk =@alwaysOk n\n\nbadId n@neverOk =@neverOk n\n"
- writeFile mainPath "!import \"util\" Util\n\nmain = Util.safeId 5\n"
- env <- evaluateFileWithStore (Just store) mainPath
- result env @?= ofNumber 5
- writeFile mainPath "!import \"util\" Util\n\nmain = Util.badId 5\n"
- envFail <- evaluateFileWithStore (Just store) mainPath
- decodeResult (result envFail) @?= "[t, \"nope\"]"
-
- , testCase "Module imports: resolve manifest exports from store" $
- withSystemTempDirectory "tricu-module-import" $ \dir -> do
- let store = StorePath (dir </> "store")
- sourcePath = dir </> "consumer.tri"
- term = Fork Leaf (Stem Leaf)
- manifestFor root = ModuleManifest []
- [ ModuleExport
- "value"
- (ObjectRef (unDomain treeTermDomain) root)
- "arboricx.abi.tree.v1"
- ]
- root <- putTreeTerm store term
- manifestHash <- putManifest store (manifestFor root)
- writeAlias store ModuleAlias "demo" (ObjectRef (unDomain manifestDomain) manifestHash)
- writeFile sourcePath "!import \"demo\" Demo\n\nmain = Demo.value\n"
- env <- evaluateFileWithStore (Just store) sourcePath
- result env @?= term
-
- , testCase "Module resolver diagnostics: missing alias names workspace/module guidance" $ do
- let resolver = filesystemResolver (StorePath "/tmp/tricu-test-missing-module-store")
- outcome <- try (resolveModuleImport resolver "definitely-not-a-module" "Demo") :: IO (Either SomeException ResolvedModule)
- case outcome of
- Right _ -> assertFailure "expected missing module alias failure"
- Left err -> show err `containsAll` ["Module alias not found", "definitely-not-a-module", "tricu.workspace", "ModuleAlias"]
-
- , testCase "Module resolver diagnostics: alias kind mismatch names expected kind" $ do
- let resolver = ObjectResolver
- { resolverAlias = \kind name -> return $ if kind == ModuleAlias && name == "demo"
- then Just (ObjectRef "arboricx.tree-root.v1" "abc123")
- else Nothing
- , resolverObject = \_ -> return Nothing
- , resolverManifest = \_ -> return Nothing
- , resolverTree = \_ -> return Nothing
- }
- outcome <- try (resolveModuleImport resolver "demo" "Demo") :: IO (Either SomeException ResolvedModule)
- case outcome of
- Right _ -> assertFailure "expected alias kind mismatch failure"
- Left err -> show err `containsAll` ["Module alias", "demo", "unsupported object kind", "arboricx.tree-root.v1", "arboricx.module-manifest.v1"]
-
- , testCase "Module resolver diagnostics: missing tree term names export and hash" $ do
- let root = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- manifest = ModuleManifest []
- [ ModuleExport "value" (ObjectRef (unDomain treeTermDomain) root) "arboricx.abi.tree.v1" ]
- resolver = ObjectResolver
- { resolverAlias = \kind name -> return $ if kind == ModuleAlias && name == "demo"
- then Just (ObjectRef (unDomain manifestDomain) "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
- else Nothing
- , resolverObject = \_ -> return Nothing
- , resolverManifest = \_ -> return (Just manifest)
- , resolverTree = \_ -> return Nothing
- }
- outcome <- try (resolveModuleImport resolver "demo" "Demo") :: IO (Either SomeException ResolvedModule)
- case outcome of
- Right _ -> assertFailure "expected missing tree term failure"
- Left err -> show err `containsAll` ["Module export", "value", "missing tree term", unpack root]
-
, testCase "Arboricx bundle: unpack transport bundle into CAS tree terms" $
withSystemTempDirectory "tricu-store" $ \dir -> do
let store = StorePath dir
@@ -2238,7 +1146,7 @@ countStoredObjects store@(StorePath root) = do
wireTests :: TestTree
wireTests = testGroup "Wire Tests"
[ testCase "Indexed bundle: header and manifest declare indexed format" $ do
- let term = result $ evalTricu Map.empty $ parseTricu "id = a : a\nmain = id t"
+ let term = Leaf
bundle = buildBundle [("main", term)]
wireData = encodeBundle bundle
BS.take 8 wireData @?= BS.pack [0x41, 0x52, 0x42, 0x4f, 0x52, 0x49, 0x43, 0x58]
@@ -2265,13 +1173,13 @@ wireTests = testGroup "Wire Tests"
exports -> assertFailure $ "Expected one export, got: " ++ show exports
, testCase "Indexed bundle: deterministic encoding" $ do
- let term = result $ evalTricu Map.empty $ parseTricu "x = t t\nmain = t x"
+ let term = Stem (Stem Leaf)
bundle1 = buildBundle [("main", term)]
bundle2 = buildBundle [("main", term)]
encodeBundle bundle1 @?= encodeBundle bundle2
, testCase "Indexed bundle: renaming export changes bytes" $ do
- let term = result $ evalTricu Map.empty $ parseTricu "f = a : a\nmain = f t"
+ let term = Leaf
mainBundle = buildBundle [("main", term)]
renamedBundle = buildBundle [("validate", term)]
encodeBundle mainBundle /= encodeBundle renamedBundle @? "different export names should produce different bytes"
@@ -2333,7 +1241,7 @@ wireTests = testGroup "Wire Tests"
, testCase "Indexed bundle: unpack into filesystem CAS" $
withSystemTempDirectory "tricu-store" $ \dir -> do
- let term = result $ evalTricu Map.empty $ parseTricu "validateEmail = a : a\nmain = validateEmail t"
+ let term = Leaf
bundle = buildBundle [("validateEmail", term)]
wireData = encodeBundle bundle
store = StorePath dir
@@ -2343,7 +1251,7 @@ wireTests = testGroup "Wire Tests"
other -> assertFailure $ "unexpected roots: " ++ show other
, testCase "Indexed bundle: round-trip decode and verify" $ do
- let term = result $ evalTricu Map.empty $ parseTricu "x = t\ny = t x\nz = t y\nmain = z"
+ let term = Stem (Stem Leaf)
bundle = buildBundle [("main", term)]
wireData = encodeBundle bundle
case decodeBundle wireData of
@@ -2396,33 +1304,15 @@ wireTests = testGroup "Wire Tests"
tricuReaderTests :: TestTree
tricuReaderTests = testGroup "Tricu Reader Tests"
- [ testCase "Tricu reader parses indexed bundle (id fixture)" $ do
- bundleBytes <- BS.readFile "./test/fixtures/id.arboricx"
- let bundleT = ofBytes bundleBytes
- let env = Map.insert "testBundle" bundleT allTestLibsEnv
- tagExpr = parseTricu "fst (runArboricx testBundle t)"
- tag = result (evalTricu env tagExpr)
- codeExpr = parseTricu "fst (snd (runArboricx testBundle t))"
- code = result (evalTricu env codeExpr)
- tag @?= trueT
-
- , testCase "Tricu reader parses indexed bundle (append fixture)" $ do
- bundleBytes <- BS.readFile "./test/fixtures/append.arboricx"
- let bundleT = ofBytes bundleBytes
- let env = Map.insert "testBundle" bundleT allTestLibsEnv
- tagExpr = parseTricu "fst (runArboricx testBundle t)"
- tag = result (evalTricu env tagExpr)
- tag @?= trueT
-
- , testCase "Tricu reader parses indexed bundle (bool fixtures)" $ do
- forM_ ["true", "false"] $ \name -> do
- bundleBytes <- BS.readFile ("./test/fixtures/" ++ name ++ ".arboricx")
- let bundleT = ofBytes bundleBytes
- let env = Map.insert "testBundle" bundleT allTestLibsEnv
- tagExpr = parseTricu "fst (runArboricx testBundle t)"
- tag = result (evalTricu env tagExpr)
- tag @?= trueT
+ [ testCase "Tricu reader parses indexed bundle (id fixture)" $ check "id"
+ , testCase "Tricu reader parses indexed bundle (append fixture)" $ check "append"
+ , testCase "Tricu reader parses indexed bundle (bool fixtures)" $ mapM_ check ["true", "false"]
]
+ where
+ check name = do
+ bytes <- BS.readFile ("./test/fixtures/" ++ name ++ ".arboricx")
+ let reply = foldl apply (fixtureExports "arboricx" Map.! "runArboricx") [ofBytes bytes, Leaf]
+ apply (fixtureExports "base" Map.! "fst") reply @?= trueT
-- --------------------------------------------------------------------------
-- Byte-list utility tests
@@ -2773,146 +1663,16 @@ gateLexerTests = testGroup "Feasibility-gate source lexer"
-- Single-expression feasibility-gate surface parser
-- --------------------------------------------------------------------------
-compiledModuleEnv :: String -> IO Env
-compiledModuleEnv legacy = do
- let (rows, exports) = compiledLibraries
- (alias, path) <- case [(alias, path) | (name, alias, path) <- rows, name == legacy] of
- [entry] -> pure entry
- _ -> error ("missing compiled compiler module: " ++ legacy)
- text <- readTestSource path
- imported <- compilerTestImports text
- let prefix = alias ++ "."
- owned = Map.fromList
- [ (drop (length prefix) name, tree)
- | (name, tree) <- Map.toList exports, prefix `isPrefixOf` name ]
- pure (injectKernel (Map.union owned imported))
-
-compilerTestImports :: String -> IO Env
-compilerTestImports text = do
- let legacyFor alias = case [legacy | (legacy, mapped, _) <- fst compiledLibraries,
- mapped == alias] of
- [legacy] -> legacy
- _ -> error ("unknown native compiler-test import: " ++ alias)
- modules <- forM [words line | line <- lines text, "!import " `isPrefixOf` line] $ \row ->
- case row of
- [_, encoded, namespace] | "\"" `isPrefixOf` encoded -> do
- -- Explicit recovery spelling, never native resolver fallback.
- env <- compiledModuleEnv (read encoded)
- pure $ if namespace == "!Local" then env
- else Map.mapKeys (\name -> namespace ++ "." ++ name) env
- [_, alias, "*"] -> compiledModuleEnv (legacyFor alias)
- [_, alias, "as", namespace] ->
- Map.mapKeys (\name -> namespace ++ "." ++ name) <$> compiledModuleEnv (legacyFor alias)
- [_, alias] ->
- Map.mapKeys (\name -> alias ++ "." ++ name) <$> compiledModuleEnv (legacyFor alias)
- _ -> error "unsupported compiler-test import"
- pure (Map.unions modules)
-
+-- Library paths select authenticated published interfaces. Unmapped test units
+-- use the portable compiler; neither path interprets historical frontend syntax.
evaluateCompilerFile :: FilePath -> IO Env
evaluateCompilerFile path =
case [legacy | (legacy, _, source) <- fst compiledLibraries,
source == maybe path id (stripPrefix "./" path)] of
- [legacy] -> compiledModuleEnv legacy
+ [legacy] -> pure (fixtureExports legacy)
[] -> compileFixtureFile path
_ -> error "ambiguous compiler fixture module"
--- Explicit unit-test support bridge for portable libraries.
--- Compiler/parser and migrated support payloads come from fingerprinted portable
--- fixtures. The six foundational bodies have a SEPARATE, explicit Haskell
--- reference cohort for recovery/shape tests; this never supplies native compiler
--- libraries or portable applications. Still-legacy wrappers use that cohort.
--- This is not a production module resolver or a compilation-failure fallback.
-testSupportCache :: IORef (Map.Map FilePath Env)
-testSupportCache = unsafePerformIO (newIORef Map.empty)
-{-# NOINLINE testSupportCache #-}
-
-evaluateTestSupportFile :: FilePath -> IO Env
-evaluateTestSupportFile input = do
- let path = maybe input id (stripPrefix "./" input)
- cached <- Map.lookup path <$> readIORef testSupportCache
- case cached of
- Just env -> pure env
- Nothing -> do
- text <- readTestSource path
- let foundation = [name | name <- Map.keys recoveryFoundationDependencies,
- path == "lib/" ++ name ++ ".tri"]
- env <- if not (null foundation)
- then recoveryFoundationEnv (head foundation)
- else if any (\line -> any (`isPrefixOf` line) ["!source ", "!export "]) (lines text)
- then evaluateCompilerFile path
- else do
- imports <- forM [words line | line <- lines text, "!import " `isPrefixOf` line] $ \row ->
- case row of
- [_, encoded, namespace] -> do
- let name = read encoded :: String
- source = if name == "arboricx" then "lib/arboricx/arboricx.tri"
- else "lib/" ++ map (\c -> if c == '.' then '/' else c) name ++ ".tri"
- imported <- evaluateTestSupportFile source
- pure $ if namespace == "!Local" then imported
- else Map.mapKeys (\key -> namespace ++ "." ++ key) imported
- _ -> error "unsupported legacy unit-test support import"
- let body = unlines [line | line <- lines text, not (any (`isPrefixOf` line) ["!import ", "!export ", "!source "])]
- pure (evalTricu (injectKernel (Map.unions imports)) (parseTricu body))
- atomicModifyIORef' testSupportCache (\cache -> (Map.insert path env cache, ()))
- pure env
-
--- A deliberately restricted source-body reference, NOT a native module
--- implementation. Exact native headers are required; no namespaces, selective
--- imports/exports or arbitrary native sources can be interpreted here. These
--- six bodies are host-compiled only to preserve independent recovery semantics
--- (including intensional size goldens), while compiledModuleEnv stays artifact-only.
-recoveryFoundationDependencies :: Map.Map String [String]
-recoveryFoundationDependencies = Map.fromList
- [("base", []), ("bytes", ["base"]), ("conversions", ["base"]),
- ("prelude", ["base", "bytes", "conversions"]),
- ("patterns", ["prelude"]), ("io", ["prelude", "patterns"])]
-
--- Immutable pre-foundations cohort. These are authenticated source-object
--- digests already retained in reference-source, not current fixture metadata.
--- Native source publication must never teach the recovery parser new syntax
--- by accident or silently change its intensional reference goldens.
-recoveryFoundationSources :: Map.Map String String
-recoveryFoundationSources = Map.fromList
- [ ("base", "fc210e5cdd97d60ce7290b4ac4227adc51119e2786bcacb671b7ad9cb6cda427")
- , ("bytes", "da07ad9055f71d6a751659772f900cb06a7e7cd73ab953c5c374e776190a788e")
- , ("conversions", "3e1da4f0212f5016539a66f17c704389ebeaba2da1d4bea96d95023d3058c559")
- , ("prelude", "0c26a0142d15cc2a11a4317264491c797944e76ea8afa07a1efef240a70f4289")
- , ("patterns", "89381a44435f725ed9ac70b13855a1a86fee4db0c05c231c7940bafdc9c62518")
- , ("io", "687cd83bc56d246e2126875cf894e08a82e8e59c470debb56f11263e7fd9ceeb")
- ]
-
-recoveryFoundationEnv :: String -> IO Env
-recoveryFoundationEnv name = do
- deps <- maybe (error "unknown recovery reference foundation") pure
- (Map.lookup name recoveryFoundationDependencies)
- -- Force source-fingerprint verification before using any reference body.
- _ <- evaluate (length (fst compilerFixture))
- let key = "recovery-reference:" ++ name
- cached <- Map.lookup key <$> readIORef testSupportCache
- case cached of
- Just env -> pure env
- Nothing -> do
- body <- recoveryFoundationBody name
- imported <- mapM recoveryFoundationEnv deps
- let env = evalTricu (injectKernel (Map.unions imported)) (parseTricu body)
- atomicModifyIORef' testSupportCache (\cache -> (Map.insert key env cache, ()))
- pure env
-
-recoveryFoundationBody :: String -> IO String
-recoveryFoundationBody name = do
- deps <- maybe (error "unknown recovery reference foundation") pure
- (Map.lookup name recoveryFoundationDependencies)
- _ <- evaluate (length (fst compilerFixture))
- pin <- maybe (error "unknown pinned recovery reference source") pure
- (Map.lookup name recoveryFoundationSources)
- text <- unpack . decodeUtf8 <$> readPinnedSource "test/fixtures/reference-source" pin
- let headers = if name == "prelude"
- then "!export *" : map ("!export * from " ++) deps
- else map (\dep -> "!import " ++ dep ++ " *") deps ++ ["!export *"]
- (actual, body) = span ("!" `isPrefixOf`) (lines text)
- unless (actual == headers) $ error "unsupported recovery reference foundation headers"
- pure (unlines body)
-
-- Test wrappers are compiled by the retained portable stable unit API; library
-- payloads come from authenticated fixtures. Packing remains a host mechanism.
packCompilerFile :: FilePath -> FilePath -> [Text] -> IO ()
@@ -3051,7 +1811,7 @@ compilerFixtureTests = testGroup "self-built reference compiler fixture"
(alias ++ ".") `isPrefixOf` name]
owned "prelude" @?= Map.unions (map owned ["base", "bytes", "conversions"])
, testCase "native base effect interpreter and guard use the rebuilt kernels" $ do
- env <- compiledModuleEnv "base"
+ env <- pure (fixtureExports "base")
let pureValue value = Fork (ofNumber 0) value
success value rest = Fork (Stem Leaf) (Fork value rest)
failure value = Fork Leaf (Fork value Leaf)
@@ -3172,7 +1932,7 @@ compilerFixtureTests = testGroup "self-built reference compiler fixture"
verifySupportDependencies providers
(replicate 2 ["local","http","new-manifest","source"]) @?= Left "duplicate local dependency"
, testCase "native staging preserves namespaces and explicit exports" $ do
- env <- compiledModuleEnv "source.map"
+ env <- pure (fixtureExports "source.map")
let row = pairT (ofString "example") (pairT (ofString "example")
(pairT (ofString "example.tri")
(pairT (ofList [ofString "native_math"]) (ofString "native"))))
@@ -3181,9 +1941,9 @@ compilerFixtureTests = testGroup "self-built reference compiler fixture"
prepare source @?= pairT (Stem Leaf) (pairT source Leaf)
apply (apply (env Map.! "sourceMapOverlay") row) source @?= source
forM_ ["", "!source other\n", "!source extra\n"] $ \bad ->
- apply (env Map.! "fst") (prepare (ofString bad)) @?= Leaf
+ apply (fixtureExports "base" Map.! "fst") (prepare (ofString bad)) @?= Leaf
, testCase "shared native header derives ordered deduplicated edges and masks positions" $ do
- env <- compiledModuleEnv "source.module"
+ env <- pure (fixtureExports "source.module")
let header = "-- lead\r\n!import math\n!export * from base\n!import math as M\n!source build_only\n!export main\n"
body = "main = missing\n"
masked = map (\c -> if c == '\n' || c == '\r' then c else ' ') header ++ body
@@ -3194,25 +1954,25 @@ compilerFixtureTests = testGroup "self-built reference compiler fixture"
apply (env Map.! "sourceModuleHeaderStage") (ofString (header ++ body)) @?=
pairT (Stem Leaf) (pairT staged Leaf)
, testCase "native header rejects redundant edges and bare hashes at original locations" $ do
- env <- compiledModuleEnv "source.module"
+ env <- pure (fixtureExports "source.module")
let bad sources = forM_ sources $ \source ->
- apply (env Map.! "fst") (apply (env Map.! "sourceModuleHeaderStage") (ofString source)) @?= Leaf
+ apply (fixtureExports "base" Map.! "fst") (apply (env Map.! "sourceModuleHeaderStage") (ofString source)) @?= Leaf
bad ["!source dep\n!import dep\n", "!import dep\n!source dep\n",
"!source dep\n!export * from dep\n", "!source dep\n!source dep\n",
"!import " ++ replicate 64 'a' ++ "\n", "!use dep *\n", "!import \"dep\" !Local\n"]
let outcome = apply (env Map.! "sourceModuleHeaderStage")
(ofString "-- lead\n\n!use dep *\n")
- problem = apply (env Map.! "fst") (apply (env Map.! "snd") outcome)
- apply (env Map.! "parserDiagnosticLocation") problem @?= gatePosition 3 1 9
+ problem = apply (fixtureExports "base" Map.! "fst") (apply (fixtureExports "base" Map.! "snd") outcome)
+ apply (fixtureExports "parser" Map.! "parserDiagnosticLocation") problem @?= gatePosition 3 1 9
, testCase "native math exports are public only and general equality remains" $ do
- env <- compiledModuleEnv "math.native"
+ env <- pure (fixtureExports "math.native")
assertBool "missing math decimal" (Map.member "decimal" env)
let owned = [name | name <- Map.keys (snd compilerFixture), "native_math." `isPrefixOf` name]
length owned @?= 27
forM_ ["divMod", "quotient", "remainder", "power"] $ \name ->
assertBool ("missing native arithmetic export: " ++ name) (Map.member name env)
assertBool "private math helper exported" (not ("native_math.compareStep" `elem` owned))
- prelude <- compiledModuleEnv "prelude"
+ prelude <- pure (fixtureExports "prelude")
assertBool "general equality removed" (Map.member "equal?" prelude)
]
@@ -3488,7 +2248,7 @@ gateProgramEnv = fixtureExports "source.program"
gateProgramTests :: TestTree
gateProgramTests = testGroup "Feasibility-gate program parser"
- [ testCase "fresh-store import normalizes the definition parser" $ do
+ [ testCase "portable wrapper normalizes the definition parser" $ do
env <- evaluateCompilerFile
"./test/sourceGateProgramImport.tri"
Map.lookup "main" env @?= Just programResult
@@ -3566,7 +2326,7 @@ gateOrderingEnv = fixtureExports "source.order"
gateOrderingTests :: TestTree
gateOrderingTests = testGroup "Feasibility-gate definition ordering"
- [ testCase "fresh-store import orders forward references" $ do
+ [ testCase "portable wrapper orders forward references" $ do
env <- evaluateCompilerFile
"./test/sourceGateOrderImport.tri"
Map.lookup "main" env @?= Just (parserOk
@@ -3667,7 +2427,7 @@ gateUnitTests = testGroup "Feasibility-gate program compiler"
packCompilerFile
"./test/sourceGateUnitCompiler.tri" path [pack "matchesExpected"]
bytes <- BS.readFile path
- goldenEnv <- evaluateTestSupportFile "./test/sourceGateExpected.tri"
+ goldenEnv <- evaluateCompilerFile "./test/sourceGateExpected.tri"
let name = gateToken 2 (ofString "f")
(gatePosition 2 1 6) (gatePosition 2 2 7)
body = gateAst 1 Leaf
@@ -3826,7 +2586,7 @@ gateUnitTests = testGroup "Feasibility-gate program compiler"
packCompilerFile
"./test/sourceGateUnitCompiler.tri" path [pack "matchesOutput"]
bytes <- BS.readFile path
- goldenEnv <- evaluateTestSupportFile "./test/sourceGateExpected.tri"
+ goldenEnv <- evaluateCompilerFile "./test/sourceGateExpected.tri"
case decodeBundle bytes of
Left diagnostic -> assertFailure diagnostic
Right bundle -> do
@@ -3846,21 +2606,18 @@ gateUnitTests = testGroup "Feasibility-gate program compiler"
apply (apply artifact (ofString source)) expected @?= trueT
, testCase "output includes root and definitions in dependency order" $ do
let source = "main = value\nvalue = t"
- output = result (evalTricu gateUnitEnv
- (parseTricu ("compileGateProgramOutput [] " ++ show source)))
+ output = foldl apply (gateUnitEnv Map.! "compileGateProgramOutput") [Leaf, ofString source]
definitions = ofList
[ pairT (ofString "value") Leaf
, pairT (ofString "main") Leaf
]
output @?= parserOk (pairT Leaf definitions) Leaf
- check "[]" source (parserOk Leaf Leaf)
+ check Leaf source (parserOk Leaf Leaf)
, testCase "empty output environment still carries the selected root" $
- result (evalTricu gateUnitEnv
- (parseTricu "compileGateProgramOutput [] \"t\"")) @?=
+ foldl apply (gateUnitEnv Map.! "compileGateProgramOutput") [Leaf, ofString "t"] @?=
parserOk (pairT Leaf Leaf) Leaf
, testCase "output entrypoint preserves structured diagnostics" $
- result (evalTricu gateUnitEnv
- (parseTricu "compileGateProgramOutput [] \"helper = t\"")) @?=
+ foldl apply (gateUnitEnv Map.! "compileGateProgramOutput") [Leaf, ofString "helper = t"] @?=
parserErr (portableDiagnostic (ofNumber 32)
(ofString "main") Leaf Leaf Leaf) Leaf
, testCase "public compileSource normalizes with abstract environment and source" $ do
@@ -3928,7 +2685,7 @@ gateUnitTests = testGroup "Feasibility-gate program compiler"
(ofList [pairT (ofString "main") root])) Leaf
let externalNames = ["map", "append", "equal?", "head", "y", "triage"]
external = ofList
- [ pairT (ofString name) (allTestLibsEnv Map.! name)
+ [ pairT (ofString name) (fixtureExports "base" Map.! name)
| name <- externalNames ]
stringSource <- readFile "./test/string.tri"
apply (apply artifact external) (ofString stringSource) @?=
@@ -3975,18 +2732,17 @@ gateUnitTests = testGroup "Feasibility-gate program compiler"
Map.lookup "main" env @?= Just (parserOk Leaf Leaf)
, testCase "forward definitions with arguments evaluate before main" $ do
let source = "main = id 42\nid x = x"
- check "[]" source (parserOk (ofNumber 42) Leaf)
+ check Leaf source (parserOk (ofNumber 42) Leaf)
, testCase "final expression selects root in absence of main" $
- check "[]" "id x = x\nid t" (parserOk Leaf Leaf)
+ check Leaf "id x = x\nid t" (parserOk Leaf Leaf)
, testCase "a local main wins over a final expression" $
- check "[]" "main = 2\n3" (parserOk (ofNumber 2) Leaf)
+ check Leaf "main = 2\n3" (parserOk (ofNumber 2) Leaf)
, testCase "provided environment is visible inside definitions" $
- check "[(pair \"host\" (t t))]" "main = host t"
+ check (ofList [Fork (ofString "host") (Stem Leaf)]) "main = host t"
(parserOk (Fork Leaf Leaf) Leaf)
, testCase "multiple definition arguments preserve binder order" $
let source = "main x y = x"
- program = result (evalTricu gateUnitEnv (parseTricu
- ("compileGateProgram [] " ++ show source)))
+ program = foldl apply (gateUnitEnv Map.! "compileGateProgram") [Leaf, ofString source]
in case program of
Fork tag (Fork fun Leaf) | tag == trueT ->
apply (apply fun Leaf) (Stem Leaf) @?= Leaf
@@ -3994,9 +2750,9 @@ gateUnitTests = testGroup "Feasibility-gate program compiler"
, testCase "recursive top-level function and triage compile from source" $ do
let source = "triage leaf stem fork = t (t leaf stem) fork\n"
++ "main xs = y (self : rest : triage t (h : self h) (a : b : self a) rest) xs"
- input = "compileGateProgram [(pair \"y\" y)] " ++ show source
- env = evalTricu (Map.union gateUnitEnv gateCompileBaseEnv) (parseTricu input)
- case result env of
+ external = ofList [Fork (ofString "y") (gateCompileBaseEnv Map.! "y")]
+ compiled = foldl apply (gateUnitEnv Map.! "compileGateProgram") [external, ofString source]
+ case compiled of
Fork tag (Fork fun Leaf) | tag == trueT -> do
apply fun Leaf @?= Leaf
apply fun (Stem Leaf) @?= Leaf
@@ -4008,8 +2764,7 @@ gateUnitTests = testGroup "Feasibility-gate program compiler"
++ "triage leaf stem fork = t (t leaf stem) fork\n"
++ "main xs = y (self : rest : triage t (h : self h) "
++ "(a : b : self a) rest) xs"
- input = "compileGateProgram [] " ++ show source
- compiled = result (evalTricu gateUnitEnv (parseTricu input))
+ compiled = foldl apply (gateUnitEnv Map.! "compileGateProgram") [Leaf, ofString source]
case compiled of
Fork tag (Fork fun Leaf) | tag == trueT -> do
apply fun Leaf @?= Leaf
@@ -4026,7 +2781,7 @@ gateUnitTests = testGroup "Feasibility-gate program compiler"
, ("main =\n value\n where value = t", Leaf)
]
forM_ sources $ \(source, value) -> do
- check "[]" source (parserOk value Leaf)
+ check Leaf source (parserOk value Leaf)
, testCase "multiline grouped applications retain expected results" $ do
let sources =
[ ("main = (t\n t)", Stem Leaf)
@@ -4035,17 +2790,16 @@ gateUnitTests = testGroup "Feasibility-gate program compiler"
, ("main = (x\n where x = t)", Leaf)
]
forM_ sources $ \(source, value) -> do
- check "[]" source (parserOk value Leaf)
+ check Leaf source (parserOk value Leaf)
, testCase "an unindented do block has a located diagnostic" $
let diagnostic = portableDiagnostic (ofNumber 40)
(ofString "indented do block") (ofNumber 2)
(gatePosition 2 1 15) Leaf
- expression = "parserReplyPayload (parseGateProgram "
- ++ show "main = do bind\nx <- 2\n x" ++ ")"
- in result (evalTricu (Map.union portableParserEnv gateProgramEnv)
- (parseTricu expression)) @?= diagnostic
+ reply = apply (gateProgramEnv Map.! "parseGateProgram")
+ (ofString "main = do bind\nx <- 2\n x")
+ in apply (fixtureExports "parser" Map.! "parserReplyPayload") reply @?= diagnostic
, testCase "pipe followed by a local assignment stays a final expression" $
- check "[]" "f = 2\nf |> let id x = x in id"
+ check Leaf "f = 2\nf |> let id x = x in id"
(parserOk (ofNumber 2) Leaf)
, testCase "explicit-bind do with nested statements retains expected results" $ do
let sources =
@@ -4056,7 +2810,7 @@ gateUnitTests = testGroup "Feasibility-gate program compiler"
, "main = do bind\n x <- 2\n do bind\n y <- x\n y\nbind a f = f a"
]
forM_ sources $ \source -> do
- check "[]" source (parserOk (ofNumber 2) Leaf)
+ check Leaf source (parserOk (ofNumber 2) Leaf)
, testCase "pipe directions, precedence, and local names retain expected results" $ do
let sources =
[ ("main = 2 |> (x : x)", ofNumber 2)
@@ -4069,8 +2823,8 @@ gateUnitTests = testGroup "Feasibility-gate program compiler"
, ("main = 2 |>\n (x : x)", ofNumber 2)
]
forM_ sources $ \(source, value) -> do
- check "[]" source (parserOk value Leaf)
- , testCase "multiline local let/where layout matches the bootstrap" $ do
+ check Leaf source (parserOk value Leaf)
+ , testCase "multiline local let/where layout retains expected results" $ do
let sources =
[ ("main = let x =\n 2\nin x", ofNumber 2)
, ("main = let x = t in\n x", Leaf)
@@ -4082,7 +2836,7 @@ gateUnitTests = testGroup "Feasibility-gate program compiler"
, ("main = let id x = x in\n id\n 2", ofNumber 2)
]
forM_ sources $ \(source, value) -> do
- check "[]" source (parserOk value Leaf)
+ check Leaf source (parserOk value Leaf)
, testCase "local bindings preserve lexical scope and argument order" $ do
let sources =
[ ("main = let x = 2 in x", ofNumber 2)
@@ -4092,50 +2846,49 @@ gateUnitTests = testGroup "Feasibility-gate program compiler"
, ("main = let x = t in (y : x) 2", Leaf)
]
forM_ sources $ \(source, value) -> do
- check "[]" source (parserOk value Leaf)
+ check Leaf source (parserOk value Leaf)
, testCase "local binding value has no self-reference" $
- check "[]" "main = let x = x in x" (parserErr
+ check Leaf "main = let x = x in x" (parserErr
(portableDiagnostic (ofNumber 20) (ofString "x") Leaf
(gatePosition 1 16 15) Leaf)
(gateAst 2 (ofString "x")
(gatePosition 1 16 15) (gatePosition 1 17 16)))
, testCase "a local binder shadows a top-level definition" $
- check "[]" "main = local where local = t\nlocal = 2"
+ check Leaf "main = local where local = t\nlocal = 2"
(parserOk Leaf Leaf)
, testCase "local free names order forward-referenced definitions" $
- check "[]" "main = value where value = helper t\nhelper x = x"
+ check Leaf "main = value where value = helper t\nhelper x = x"
(parserOk Leaf Leaf)
, testCase "lists may refer to forward definitions" $
- check "[]" "main = [(id 2)]\nid x = x"
+ check Leaf "main = [(id 2)]\nid x = x"
(parserOk (ofList [ofNumber 2]) Leaf)
, testCase "unused divergent body is checked but not demanded" $ do
let source = "unused = (x : x x) (x : x x)\nmain = t"
- check "[]" source (parserOk Leaf Leaf)
+ check Leaf source (parserOk Leaf Leaf)
, testCase "missing multiline definition body is a structured diagnostic" $
- check "[]" "main =\n" (parserErr
+ check Leaf "main =\n" (parserErr
(portableDiagnostic (ofNumber 40) (ofString "definition body")
Leaf Leaf Leaf) Leaf)
, testCase "missing local value or body returns a structured diagnostic" $ do
- check "[]" "main = let x =\n" (parserErr
+ check Leaf "main = let x =\n" (parserErr
(portableDiagnostic (ofNumber 40)
(ofString "local binding value") Leaf Leaf Leaf) Leaf)
- check "[]" "main = let x = t in\n" (parserErr
+ check Leaf "main = let x = t in\n" (parserErr
(portableDiagnostic (ofNumber 40)
(ofString "local binding body") Leaf Leaf Leaf) Leaf)
, testCase "no root is a structured diagnostic" $
- check "[]" "helper = t" (parserErr
+ check Leaf "helper = t" (parserErr
(portableDiagnostic (ofNumber 32) (ofString "main") Leaf Leaf Leaf)
Leaf)
, testCase "cycle fails before result selection" $
- check "[]" "a = b\nb = a\nmain = t" (parserErr
+ check Leaf "a = b\nb = a\nmain = t" (parserErr
(portableDiagnostic (ofNumber 31) (ofString "acyclic")
(ofString "a") (gatePosition 1 1 0)
(ofList [ofString "a"])) Leaf)
]
where
check external source expected =
- result (evalTricu gateUnitEnv
- (parseTricu ("compileGateProgram " ++ external ++ " " ++ show source)))
+ foldl apply (gateUnitEnv Map.! "compileGateProgram") [external, ofString source]
@?= expected
-- --------------------------------------------------------------------------
@@ -4271,7 +3024,7 @@ gateCompilationTests = testGroup "Feasibility-gate source compiler"
packCompilerFile "./test/sourceGateCompiler.tri"
path [pack "matchesExpected"]
bytes <- BS.readFile path
- goldenEnv <- evaluateTestSupportFile "./test/sourceGateExpected.tri"
+ goldenEnv <- evaluateCompilerFile "./test/sourceGateExpected.tri"
let unknown = parserErr
(portableDiagnostic (ofNumber 20) (ofString "u") Leaf
(gatePosition 1 1 0) Leaf)
@@ -4490,8 +3243,9 @@ runRegistryEffects readReply = go (100 :: Int)
registryContractTests :: TestTree
registryContractTests = testCase "Registry hash contract: values, bounded rejection and read effects" $
withSystemTempDirectory "registry-contract" $ \dir -> do
- env <- evaluateTestSupportFile "./lib/arboricx/server.tri"
+ env <- evaluateCompilerFile "./lib/arboricx/server.tri"
let call name = foldl apply (env Map.! name)
+ http name = foldl apply (fixtureExports "http" Map.! name)
valid = concat (replicate 4 "0123456789abcdef")
hash = ofString valid
diagnostic = ofString "expected 64 lowercase hexadecimal hash characters"
@@ -4535,7 +3289,7 @@ registryContractTests = testCase "Registry hash contract: values, bounded reject
[root, ofString "GET", ofString ("/_arboricx/bundle/hash/" ++ value)]
router value = call "arboricxRouter"
[root, ofString "GET", ofString ("/_arboricx/bundle/hash/" ++ value), Leaf, Leaf]
- rejected = call "badRequestResponse" [diagnostic]
+ rejected = http "badRequestResponse" [diagnostic]
forM_ invalid $ \bad -> do
runRegistryEffects present (get (ofString bad)) >>= (@?= ([], err (ofNumber 400) diagnostic))
forM_ [serve (ofString bad), route bad, router bad] $ \action ->
@@ -4549,9 +3303,9 @@ registryContractTests = testCase "Registry hash contract: values, bounded reject
forM_ [serve hash, route valid, router valid] $ \action -> do
runRegistryEffects present action >>= (@?= ([expectedPath], response))
runRegistryEffects missing action >>=
- (@?= ([expectedPath], call "errorResponse" [ofNumber 404, ofString "missing"]))
- forM_ [("/_arboricx/health", call "okResponse" [ofString "OK\n"]),
- ("/", call "htmlResponse" [env Map.! "htmlLandingPage"])] $ \(target, expected) ->
+ (@?= ([expectedPath], http "errorResponse" [ofNumber 404, ofString "missing"]))
+ forM_ [("/_arboricx/health", http "okResponse" [ofString "OK\n"]),
+ ("/", http "htmlResponse" [env Map.! "htmlLandingPage"])] $ \(target, expected) ->
runRegistryEffects present
(call "arboricxRouter" [root, ofString "GET", ofString target, Leaf, Leaf]) >>=
(@?= ([], expected))
@@ -4559,7 +3313,7 @@ registryContractTests = testCase "Registry hash contract: values, bounded reject
registryPipelineTests :: TestTree
registryPipelineTests = testGroup "Registry publication and startup"
[ testCase "complete effects: atomic upload, traversal rejection, init and socket failures" $ do
- env <- evaluateTestSupportFile "./lib/arboricx/server.tri"
+ env <- evaluateCompilerFile "./lib/arboricx/server.tri"
let call name = foldl apply (env Map.! name)
root = ofString "/registry"
bytes = ofBytes (BS.pack [0,255,1])
@@ -4600,7 +3354,7 @@ registryPipelineTests = testGroup "Registry publication and startup"
>>= (@?= prefix "denied")
, testCase "filesystem: initialization, binary publication, replacement and concurrent uploads" $
withSystemTempDirectory "registry-publication" $ \dir -> do
- env <- evaluateTestSupportFile "./lib/arboricx/server.tri"
+ env <- evaluateCompilerFile "./lib/arboricx/server.tri"
let call name = foldl apply (env Map.! name)
rootPath = dir </> "store"
root = ofString rootPath
@@ -4656,8 +3410,8 @@ localControlTests = testGroup "Local control construction and non-strictness"
first <- compileLocalControl [] "main input = case input of\n (head, _) = head\n _ = t"
apply first (Fork (ofNumber 23) (error "case forced an ignored sibling")) @?= ofNumber 23
, testCase "local recursive hash worker rejects poisoned byte/tail with bounded inspection" $ do
- server <- evaluateTestSupportFile "./lib/arboricx/server.tri"
- math <- evaluateTestSupportFile "./lib/math/native.tri"
+ server <- evaluateCompilerFile "./lib/arboricx/server.tri"
+ math <- evaluateCompilerFile "./lib/math/native.tri"
function <- compileLocalControl
[("true", Stem Leaf), ("false", Leaf),
("hex", server Map.! "bundleHexByte?"), ("subtract", math Map.! "subtract")] $ unlines
@@ -4682,7 +3436,7 @@ localControlTests = testGroup "Local control construction and non-strictness"
compileLocalControl :: [(String, T)] -> String -> IO T
compileLocalControl bindings source = do
- unit <- evaluateTestSupportFile "./lib/source/unit.tri"
+ unit <- evaluateCompilerFile "./lib/source/unit.tri"
let external = ofList [Fork (ofString name) value | (name,value) <- bindings]
answer = apply (apply (unit Map.! "compileStableModuleDefinitions") external) (ofString source)
forceTree Leaf = ()
diff --git a/tricu.cabal b/tricu.cabal
@@ -207,6 +207,7 @@ test-suite tricu-tests
Wire
SupportFixture
LibraryValueTests
+ LibraryProgramTests
ParserValueTests
PortableTestCompiler
IODriverTests