on 6cd3cb1 help sign in
project-m36/TutorialDInterpreterTest.hs
148 lines 9.1 kB history raw
1import TutorialDInterpreter
2import Test.HUnit
3import RelationExpr
4import Relation
5import RelationalError
6import RelationType
7import RelationalTransaction
8import qualified Data.HashSet as HS
9import qualified Data.Map as M
10import qualified Data.Set as S
11import System.Exit
12import Data.UUID.V4 (nextRandom)
13import Data.UUID (nil)
14import Data.Either (isRight)
16main = do
17 counts <- runTestTT (TestList tests)
18 if errors counts + failures counts > 0 then exitFailure else exitSuccess
19 where
20 tests = map (\(tutd, expected) -> TestCase $ assertTutdEqual basicDatabaseContext tutd expected) simpleRelTests ++ map (\(tutd, expected) -> TestCase $ assertTutdEqual dateExamples tutd expected) dateExampleRelTests ++ [transactionGraphBasicTest, transactionGraphAddCommitTest, transactionRollbackTest, transactionJumpTest, transactionBranchTest]
21 simpleRelTests = [("x:=true", Right relationTrue),
22 ("x:=false", Right relationFalse),
23 ("x:=true union false", Right relationTrue),
24 ("x:=true; x:=false", Right relationFalse),
25 ("x:=relation{a int}", mkRelation simpleAAttributes HS.empty),
26 ("x:=relation{c int} rename {c as d}", mkRelation simpleBAttributes HS.empty),
27 ("y:=relation{b int, c int}; x:=y{c}", mkRelation simpleProjectionAttributes HS.empty),
28 ("x:=relation{tuple{a char(\"spam\"), b int(5)}}", mkRelation simpleCAttributes (HS.fromList $ map RelationTuple [M.fromList [("a", StringAtom "spam"),("b",IntAtom 5)]])),
29 ("constraint failc true in false; x:=true", Left $ InclusionDependencyCheckError "failc"),
30 ("x:=true where true", Right relationTrue),
31 ("x:=true where false", Right relationFalse),
32 ("x:=true where true or false", Right relationTrue),
33 ("x:=true where false or false", Right relationFalse),
34 ("x:=true where true and false", Right relationFalse),
35 ("x:=true where true and true", Right relationTrue),
36 ("x:=true=true", Right relationTrue),
37 ("x:=true=false", Right relationFalse),
38 ("x:=relation {b int, a char}; insert x relation{tuple{b int(5), a char(\"spam\")}}", mkRelation simpleCAttributes (HS.fromList [RelationTuple $ M.fromList [("a", StringAtom "spam"), ("b", IntAtom 5)]]))
39 ]
40 simpleAAttributes = M.fromList [("a", Attribute "a" IntAtomType)]
41 simpleBAttributes = M.fromList [("d", Attribute "d" IntAtomType)]
42 simpleCAttributes = M.fromList [("a", Attribute "a" StringAtomType), ("b", Attribute "b" IntAtomType)]
43 simpleProjectionAttributes = M.fromList [("c", Attribute "c" IntAtomType)]
44 dateExampleRelTests = [("x:=S where true", Right s),
45 ("x:=S where CITY = \"London\"", restrict (\(RelationTuple tupMap) -> tupMap M.! "CITY" == StringAtom "London") s),
46 ("x:=S where false", Right $ Relation (attributes s) HS.empty),
47 ("a:=S; update a (STATUS:=50); x:=a{STATUS}", mkRelation (M.fromList [("STATUS", Attribute "STATUS" IntAtomType)]) (HS.fromList [RelationTuple $ M.fromList [("STATUS", IntAtom 50)]])),
48 ("x:=S; update x where SNAME=\"Blake\" (CITY:=\"Boston\")", relMap (\(RelationTuple tupMap) -> RelationTuple $ if tupMap M.! "SNAME" == StringAtom "Blake" then M.insert "CITY" (StringAtom "Boston") tupMap else tupMap) s)
49 ]
51testSimple1 = TestCase $ assertTutdEqual basicDatabaseContext "true" (Right relationTrue)
53assertTutdEqual databaseContext tutd expected = assertEqual tutd interpreted expected
54 where
55 interpreted = case interpret databaseContext tutd of
56 (Just err, _) -> Left err
57 (Nothing, context) -> Right $ (relationVariables context) M.! "x"
59transactionGraphBasicTest = TestCase $ do
60 (discon, graph) <- dateExamplesGraph
61 assertEqual "validate bootstrapped graph" (validateGraph graph) Nothing
63--add a new transaction to the graph, validate it is in the graph
64transactionGraphAddCommitTest = TestCase $ do
65 (discon@(DisconnectedTransaction firstUUID context), graph) <- dateExamplesGraph
66 freshUUID <- nextRandom
67 case interpret context "x:=S" of
68 (Just err, newContext) -> assertFailure (show err)
69 (Nothing, newContext) -> do
70 let discon = newDisconnectedTransaction firstUUID newContext
71 let addTrans = addDisconnectedTransaction freshUUID "master" discon graph
72 case addTrans of
73 Left err -> assertFailure (show err)
74 Right (newTrans, graph) -> do
75 assertBool "transaction in graph" (isRight $ transactionForUUID freshUUID graph)
76 assertEqual "validate fresh commit with deleted S" (validateGraph graph) Nothing
77 assertEqual "ensure S was deleted in newContext" (M.lookup "x" (relationVariables (transactionContext newTrans))) (Just s)
79transactionRollbackTest = TestCase $ do
80 (origDiscon@(DisconnectedTransaction firstUUID origContext), graph) <- dateExamplesGraph
81 freshUUID <- nextRandom
82 case transactionForUUID firstUUID graph of
83 Left err -> assertFailure (show err)
84 Right firstTrans -> do
85 case interpret origContext "x:=S" of
86 (Just err, _) -> assertFailure (show err)
87 (Nothing, newContext) -> do
88 let discon = newDisconnectedTransaction firstUUID newContext
89 let (updatedDiscon@(DisconnectedTransaction _ newContext2), newGraph, result) = interpretOps freshUUID discon graph ":rollback"
90 assertEqual "validate context" (M.lookup "x" (relationVariables newContext2)) Nothing
91 assertEqual "validate graph" graph newGraph
93--commit a new transaction with "x" relation, jump to first transaction, verify that "x" is not present
94transactionJumpTest = TestCase $ do
95 (origDiscon@(DisconnectedTransaction firstUUID origContext), graph) <- dateExamplesGraph
96 freshUUID <- nextRandom
97 case transactionForUUID firstUUID graph of
98 Left err -> assertFailure (show err)
99 Right firstTrans -> do
100 case interpret origContext "x:=S" of
101 (Just err, _) -> assertFailure (show err)
102 (Nothing, newContext) -> do
103 --modify the second transaction
104 case interpret newContext "x:=S" of
105 (Just err, _) -> assertFailure (show err)
106 (Nothing, newContext2) -> do
107 --add the transaction
108 let discon = newDisconnectedTransaction firstUUID newContext2
109 let addTrans = addDisconnectedTransaction freshUUID "master" discon graph
110 case addTrans of
111 Left err -> assertFailure (show err)
112 Right (newTrans, graph) -> do
113 --jump to the first transaction
114 let (updatedDiscon@(DisconnectedTransaction parentUUID newContext3), newGraph, result) = interpretOps freshUUID discon graph (":jump " ++ show firstUUID)
115 assertEqual "validate discon" parentUUID firstUUID
116 assertEqual "validate discon2" Nothing (M.lookup "x" (relationVariables newContext3))
117 assertEqual "validate graph" transactionUUIDs (S.map transactionUUID (transactionsForGraph newGraph))
118 where
119 transactionUUIDs = S.fromList [firstUUID, freshUUID]
121--branch from the first transaction and verify that there are two heads
122transactionBranchTest = TestCase $ do
123 (origDiscon@(DisconnectedTransaction firstUUID origContext), graph) <- dateExamplesGraph
124 freshUUID1 <- nextRandom
125 freshUUID2 <- nextRandom
126 case transactionForUUID firstUUID graph of
127 Left err -> assertFailure (show err)
128 Right firstTrans -> do
129 let disconMaster = newDisconnectedTransaction firstUUID origContext
130 let addTransMaster = addDisconnectedTransaction freshUUID1 "master" disconMaster graph
131 --add a second transaction to the "master" branch
132 case addTransMaster of
133 Left err -> assertFailure (show err)
134 Right (newTrans, graph) -> do
135 --add a third transaction to the "test" branch
136 let (updatedDiscon, newGraph, result) = interpretOps freshUUID2 origDiscon graph ":branch test"
137 assertEqual "verify test head" freshUUID2 $ maybeTransUUID (transactionForHead "test" newGraph)
138 assertEqual "verify master head" freshUUID1 $ maybeTransUUID (transactionForHead "master" newGraph)
139 where
140 maybeTransUUID t = maybe nil transactionUUID t
142dateExamplesGraph :: IO (DisconnectedTransaction, TransactionGraph)
143dateExamplesGraph = do
144 firstTransactionUUID <- nextRandom
145 let graph = bootstrapTransactionGraph firstTransactionUUID dateExamples
146 let discon = newDisconnectedTransaction firstTransactionUUID dateExamples
147 return (discon, graph)