project-m36-0.2: test/Relation/Basic.hs
import Test.HUnit
import ProjectM36.Base
import ProjectM36.Relation
import ProjectM36.Error
import ProjectM36.DateExamples
import ProjectM36.DataTypes.Primitive
import ProjectM36.RelationalExpression
import ProjectM36.Tuple
import qualified ProjectM36.DatabaseContext as DBC
import Control.Monad.Trans.Reader
import qualified ProjectM36.Attribute as A
import qualified Data.Map as M
import qualified Data.Vector as V
import qualified Data.Set as S
import System.Exit
testList :: Test
testList = TestList [testRelation "relationTrue" relationTrue, testRelation "relationFalse" relationFalse,
testMkRelation1,
testRename1, testRename2,
testRelation "suppliers" suppliersRel,
testRelation "products" productsRel,
testRelation "supplierProducts" supplierProductsRel,
testMkRelationFromExprsBadAttrs]
main :: IO ()
main = do
tcounts <- runTestTT testList
if errors tcounts + failures tcounts > 0 then exitFailure else exitSuccess
testRelation :: String -> Relation -> Test
testRelation testName rel = TestCase $ assertEqual testName relationValidation (Right rel)
where
relationValidation = validateRelation rel
-- run common relation checks
validateRelation :: Relation -> Either RelationalError Relation
validateRelation rel = do
_ <- validateAttrNamesMatchTupleAttrNames rel
validateAttrTypesMatchTupleAttrTypes rel
validateAttrNamesMatchTupleAttrNames :: Relation -> Either RelationalError Relation
validateAttrNamesMatchTupleAttrNames rel@(Relation _ tupSet)
| null invalidSet = Right rel
| otherwise = Left $ AttributeNamesMismatchError S.empty
where
nameCheck tuple = attributeNames rel == tupleAttributeNameSet tuple
invalidSet = filter (not . nameCheck) (asList tupSet)
validateAttrTypesMatchTupleAttrTypes :: Relation -> Either RelationalError Relation
validateAttrTypesMatchTupleAttrTypes rel@(Relation attrs tupSet) = foldr (\tuple acc ->
if tupleAttributes tuple == attrs && tupleAtomCheck tuple then
acc
else
Left $ TupleAttributeTypeMismatchError A.emptyAttributes
) (Right rel) (asList tupSet)
where
tupleAtomCheck tuple = V.all (== True) (attrChecks tuple)
attrChecks tuple = V.map (\attr -> case atomForAttributeName (A.attributeName attr) tuple of
Left _ -> False
Right atom -> (Right $ atomTypeForAtom atom) ==
A.atomTypeForAttributeName (A.attributeName attr) attrs) (attributes rel)
simpleRel :: Relation
simpleRel = case mkRelation attrs tupleSet of
Right rel -> rel
Left _ -> undefined
where
attrs = A.attributesFromList [Attribute "a" TextAtomType, Attribute "b" TextAtomType]
tupleSet = RelationTupleSet [mkRelationTuple attrs (V.fromList [TextAtom "spam", TextAtom "spam2"])]
--rename tests
testRename1 :: Test
testRename1 = TestCase $ assertEqual "attribute invalid" (rename "a" "b" relationTrue) (Left $ AttributeNamesMismatchError (S.singleton "a"))
testRename2 :: Test
testRename2 = TestCase $ assertEqual "attribute in use" (rename "b" "a" simpleRel) (Left $ AttributeNameInUseError "a")
--mkRelation tests
--test tupleset key mismatch failure
testMkRelation1 :: Test
testMkRelation1 = TestCase $ assertEqual "key mismatch" expectedError (mkRelation testAttrs testTupSet) -- the error attribute set is empty due to an optimization- the tuple attrs do not match the atoms' types
where
expectedError = Left (AtomTypeMismatchError TextAtomType IntAtomType)
testAttrs = A.attributesFromList [Attribute "a" TextAtomType]
testTupSet = RelationTupleSet [mkRelationTuple testAttrs $ V.fromList [TextAtom "v"],
mkRelationTuple testAttrs $ V.fromList [IntAtom 2]]
testMkRelationFromExprsBadAttrs :: Test
testMkRelationFromExprsBadAttrs = TestCase $ do
let context = DBC.empty
case runReader (evalRelationalExpr (MakeRelationFromExprs (Just [AttributeAndTypeNameExpr "badAttr1" (PrimitiveTypeConstructor "Int" IntAtomType) ()]) [TupleExpr (M.singleton "badAttr2" (NakedAtomExpr (IntAtom 1)))])) (mkRelationalExprState context) of
Left err -> assertEqual "tuple type mismatch" (TupleAttributeTypeMismatchError (A.attributesFromList [Attribute "badAttr2" IntAtomType])) err
Right _ -> assertFailure "expected tuple type mismatch"