70 lines
4.2 KiB
Haskell
70 lines
4.2 KiB
Haskell
{-# LANGUAGE PatternSynonyms #-}
|
|||
|
|
|
||
|
|
module NormalizationSpec (spec) where
|
||
|
|
|
||
|
|
import ChuSQL.Core.Engine.Normalization
|
||
|
|
import ChuSQL.Core.Model (pattern TInt)
|
||
|
|
import Test.Hspec
|
||
|
|
|
||
|
|
-- 范式分析回归:公理闭包、候选键、信息不足与分解性质。
|
||
|
|
|
||
|
|
-- 执行范式检查回归。
|
||
|
|
spec :: Spec
|
||
|
|
spec = do
|
||
|
|
describe "Armstrong normalization" $ do
|
||
|
|
it "computes reflexivity, augmentation and transitivity" $ do
|
||
|
|
attributeClosure [Dependency ["a"] ["b"], Dependency ["b"] ["c"]] ["a"]
|
||
|
|
`shouldBe` ["a", "b", "c"]
|
||
|
|
implies [Dependency ["a"] ["b"]] (Dependency ["a", "c"] ["b", "c"])
|
||
|
|
`shouldBe` True
|
||
|
|
attributeClosure [] ["a"] `shouldBe` ["a"]
|
||
|
|
it "accepts BCNF with a declared key" $ do
|
||
|
|
fmap (map verdict . findings) (analyzeNormalization schema
|
||
|
|
(Declaration [["a"]] [] True (Just True)))
|
||
|
|
`shouldBe` Right (replicate 4 Satisfied)
|
||
|
|
it "detects partial dependencies of composite keys" $ do
|
||
|
|
fmap (map verdict . findings) (analyzeNormalization schema
|
||
|
|
(Declaration [["a", "b"]] [Dependency ["a"] ["c"]] True (Just True)))
|
||
|
|
`shouldBe` Right [Satisfied, Violated, Violated, Violated]
|
||
|
|
it "detects transitive dependencies" $ do
|
||
|
|
fmap (map verdict . findings) (analyzeNormalization schema
|
||
|
|
(Declaration [["a"]] [Dependency ["b"] ["c"]] True (Just True)))
|
||
|
|
`shouldBe` Right [Satisfied, Satisfied, Violated, Violated]
|
||
|
|
it "distinguishes 3NF from BCNF using all candidate keys" $ do
|
||
|
|
fmap (map verdict . findings) (analyzeNormalization schema
|
||
|
|
(Declaration [["a", "b"]] [Dependency ["c"] ["b"]] True (Just True)))
|
||
|
|
`shouldBe` Right [Satisfied, Satisfied, Satisfied, Violated]
|
||
|
|
it "reports lossless decomposition that loses dependencies" $ do
|
||
|
|
fmap suggestions (analyzeNormalization schema
|
||
|
|
(Declaration [["a", "b"]] [Dependency ["c"] ["b"]] True (Just True)))
|
||
|
|
`shouldBe` Right [Decomposition [["b", "c"], ["a", "c"]] Satisfied Violated]
|
||
|
|
it "reports dependency preserving transitive split" $ do
|
||
|
|
fmap suggestions (analyzeNormalization schema
|
||
|
|
(Declaration [["a"]] [Dependency ["b"] ["c"]] True (Just True)))
|
||
|
|
`shouldBe` Right [Decomposition [["b", "c"], ["a", "b"]] Satisfied Satisfied]
|
||
|
|
it "does not certify incomplete dependencies" $ do
|
||
|
|
fmap (map verdict . findings) (analyzeNormalization schema
|
||
|
|
(Declaration [["a"]] [] False (Just True)))
|
||
|
|
`shouldBe` Right [Satisfied, Insufficient, Insufficient, Insufficient]
|
||
|
|
it "requires an atomicity declaration" $ do
|
||
|
|
fmap (map verdict . findings) (analyzeNormalization schema
|
||
|
|
(Declaration [] [] True Nothing)) `shouldBe` Right (replicate 4 Insufficient)
|
||
|
|
it "propagates a declared 1NF violation" $ do
|
||
|
|
fmap (map verdict . findings) (analyzeNormalization schema
|
||
|
|
(Declaration [] [] True (Just False))) `shouldBe` Right (replicate 4 Violated)
|
||
|
|
it "rejects unknown attributes" $ do
|
||
|
|
analyzeNormalization schema (Declaration [] [Dependency ["z"] ["a"]] True (Just True))
|
||
|
|
`shouldBe` Left "normalization: unknown or duplicate dependency attributes"
|
||
|
|
it "rejects nonminimal declared candidate keys" $ do
|
||
|
|
analyzeNormalization schema (Declaration [["a", "b"]]
|
||
|
|
[Dependency ["a"] ["b", "c"]] True (Just True))
|
||
|
|
`shouldBe` Left "normalization: declared candidate key is not minimal"
|
||
|
|
it "includes the empty candidate key for constant relations" $ do
|
||
|
|
fmap candidateKeys (analyzeNormalization schema
|
||
|
|
(Declaration [] [Dependency [] ["a", "b", "c"]] True (Just True))) `shouldBe` Right [[]]
|
||
|
|
it "rejects excessive exhaustive searches" $ do
|
||
|
|
analyzeNormalization [(show n, TInt) | n <- [1 :: Int .. 13]]
|
||
|
|
(Declaration [] [] True (Just True))
|
||
|
|
`shouldBe` Left "normalization: exhaustive analysis supports at most 12 columns"
|
||
|
|
where
|
||
|
|
schema = [("a", TInt), ("b", TInt), ("c", TInt)]
|