Adds basic tests for modules

Basic tests for modules. Fixes for parsing multiple import statements.
This commit is contained in:
James Eversole 2025-01-27 16:03:03 -06:00
parent ae971ec968
commit f97bd84050
13 changed files with 75 additions and 4 deletions

View File

@ -10,12 +10,13 @@ tricu is the word for "tree" in Lojban: `(x1) is a tree of species/cultivar (x2)
- Tree Calculus operator: `t` - Tree Calculus operator: `t`
- Assignments: `x = t t` - Assignments: `x = t t`
- Immutabile definitions
- Lambda abstraction syntax: `id = (\a : a)` - Lambda abstraction syntax: `id = (\a : a)`
- List, Number, and String literals: `[(2) ("Hello")]` - List, Number, and String literals: `[(2) ("Hello")]`
- Function application: `not (not false)` - Function application: `not (not false)`
- Higher order/first-class functions: `map (\a : lconcat a "!") [("Hello")]` - Higher order/first-class functions: `map (\a : lconcat a "!") [("Hello")]`
- Intensionality blurs the distinction between functions and data (see REPL examples) - Intensionality blurs the distinction between functions and data (see REPL examples)
- Immutability - Simple module system for code organization
## REPL examples ## REPL examples

View File

@ -76,12 +76,16 @@ parseProgramM = do
skipMany topLevelNewline skipMany topLevelNewline
moduleNode <- optional parseModuleM moduleNode <- optional parseModuleM
skipMany topLevelNewline skipMany topLevelNewline
importNodes <- many parseImportM importNodes <- many (do
node <- parseImportM
skipMany topLevelNewline
return node)
skipMany topLevelNewline skipMany topLevelNewline
exprs <- sepEndBy parseOneExpression (some topLevelNewline) exprs <- sepEndBy parseOneExpression (some topLevelNewline)
skipMany topLevelNewline skipMany topLevelNewline
return (maybe [] (: []) moduleNode ++ importNodes ++ exprs) return (maybe [] (: []) moduleNode ++ importNodes ++ exprs)
parseModuleM :: ParserM TricuAST parseModuleM :: ParserM TricuAST
parseModuleM = do parseModuleM = do
LModule moduleName <- satisfyM isModule LModule moduleName <- satisfyM isModule

View File

@ -9,6 +9,7 @@ import Research
import Control.Exception (evaluate, try, SomeException) import Control.Exception (evaluate, try, SomeException)
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import Data.List (isInfixOf)
import Test.Tasty import Test.Tasty
import Test.Tasty.HUnit import Test.Tasty.HUnit
import Test.Tasty.QuickCheck import Test.Tasty.QuickCheck
@ -31,6 +32,7 @@ tests = testGroup "Tricu Tests"
, lambdas , lambdas
, baseLibrary , baseLibrary
, fileEval , fileEval
, modules
, demos , demos
] ]
@ -498,6 +500,42 @@ fileEval = testGroup "File evaluation tests"
decodeResult (result res) @?= "\"String test!\"" decodeResult (result res) @?= "\"String test!\""
] ]
modules :: TestTree
modules = testGroup "Test modules"
[ testCase "Detect cyclic dependencies" $ do
result <- try (liftIO $ evaluateFileResult "./test/cycle-1.tri") :: IO (Either SomeException T)
case result of
Left e -> do
let errorMsg = show e
if "Encountered cyclic import" `isInfixOf` errorMsg
then return ()
else assertFailure $ "Unexpected error: " ++ errorMsg
Right _ -> assertFailure "Expected cyclic dependencies"
, testCase "Module imports and namespacing" $ do
res <- liftIO $ evaluateFileResult "./test/namespace-A.tri"
res @?= Leaf
, testCase "Multiple imports" $ do
res <- liftIO $ evaluateFileResult "./test/vars-A.tri"
res @?= Leaf
, testCase "Error on unresolved variable" $ do
result <- try (liftIO $ evaluateFileResult "./test/unresolved-A.tri") :: IO (Either SomeException T)
case result of
Left e -> do
let errorMsg = show e
if "undefinedVar" `isInfixOf` errorMsg
then return ()
else assertFailure $ "Unexpected error: " ++ errorMsg
Right _ -> assertFailure "Expected unresolved variable error"
, testCase "Multi-level imports" $ do
res <- liftIO $ evaluateFileResult "./test/multi-level-A.tri"
res @?= Leaf
, testCase "Lambda expression namespaces" $ do
res <- liftIO $ evaluateFileResult "./test/lambda-A.tri"
res @?= Leaf
]
-- All of our demo tests are also module tests
demos :: TestTree demos :: TestTree
demos = testGroup "Test provided demo functionality" demos = testGroup "Test provided demo functionality"
[ testCase "Structural equality demo" $ do [ testCase "Structural equality demo" $ do

2
test/lambda-A.tri Normal file
View File

@ -0,0 +1,2 @@
!module A
main = (\x : x) t

3
test/multi-level-A.tri Normal file
View File

@ -0,0 +1,3 @@
!module A
!import "./test/multi-level-B.tri" B
main = B.main

3
test/multi-level-B.tri Normal file
View File

@ -0,0 +1,3 @@
!module B
!import "./test/multi-level-C.tri" C
main = C.val

2
test/multi-level-C.tri Normal file
View File

@ -0,0 +1,2 @@
!module C
val = t

3
test/namespace-A.tri Normal file
View File

@ -0,0 +1,3 @@
!module A
!import "./test/namespace-B.tri" B
main = B.x

2
test/namespace-B.tri Normal file
View File

@ -0,0 +1,2 @@
!module B
x = t

2
test/unresolved-A.tri Normal file
View File

@ -0,0 +1,2 @@
!module A
main = undefinedVar

7
test/vars-A.tri Normal file
View File

@ -0,0 +1,7 @@
!module A
!import "./test/vars-B.tri" B
!import "./test/vars-C.tri" C
main = B.y (C.z)

2
test/vars-B.tri Normal file
View File

@ -0,0 +1,2 @@
!module B
y = \x : x

2
test/vars-C.tri Normal file
View File

@ -0,0 +1,2 @@
!module C
z = t