diff options
Diffstat (limited to 'testsuite')
| -rw-r--r-- | testsuite/pmcfg/fixtures/PmcfgDiff.gf | 11 | ||||
| -rw-r--r-- | testsuite/pmcfg/fixtures/PmcfgDiffCnc.gf | 40 | ||||
| -rw-r--r-- | testsuite/pmcfg/run.hs | 268 |
3 files changed, 319 insertions, 0 deletions
diff --git a/testsuite/pmcfg/fixtures/PmcfgDiff.gf b/testsuite/pmcfg/fixtures/PmcfgDiff.gf new file mode 100644 index 000000000..3ea7b3cae --- /dev/null +++ b/testsuite/pmcfg/fixtures/PmcfgDiff.gf @@ -0,0 +1,11 @@ +abstract PmcfgDiff = { +cat + S ; + NP ; + +fun + Use : NP -> S ; + Pair : NP -> NP -> S ; + One : NP ; + Two : NP ; +} diff --git a/testsuite/pmcfg/fixtures/PmcfgDiffCnc.gf b/testsuite/pmcfg/fixtures/PmcfgDiffCnc.gf new file mode 100644 index 000000000..4bbafa174 --- /dev/null +++ b/testsuite/pmcfg/fixtures/PmcfgDiffCnc.gf @@ -0,0 +1,40 @@ +concrete PmcfgDiffCnc of PmcfgDiff = { +param + Number = Sg | Pl ; + Person = P1 | P2 ; + Case = Nom | Acc | Poss Number Person ; + +lincat + S = {s : Str} ; + NP = {s : Case => Str ; n : Number ; p : Person} ; + +lin + Use np = {s = np.s ! Poss np.n np.p} ; + Pair x y = {s = x.s ! Nom ++ y.s ! Acc} ; + + One = { + s = table { + Nom => "one" ; + Acc => "one-acc" ; + Poss Sg P1 => "one-sg-p1" ; + Poss Sg P2 => "one-sg-p2" ; + Poss Pl P1 => "one-pl-p1" ; + Poss Pl P2 => "one-pl-p2" + } ; + n = Sg ; + p = P1 + } ; + + Two = { + s = table { + Nom => "two" ; + Acc => "two-acc" ; + Poss Sg P1 => "two-sg-p1" ; + Poss Sg P2 => "two-sg-p2" ; + Poss Pl P1 => "two-pl-p1" ; + Poss Pl P2 => "two-pl-p2" + } ; + n = Pl ; + p = P2 + } ; +} diff --git a/testsuite/pmcfg/run.hs b/testsuite/pmcfg/run.hs new file mode 100644 index 000000000..1a110d3c4 --- /dev/null +++ b/testsuite/pmcfg/run.hs @@ -0,0 +1,268 @@ +{-# LANGUAGE ScopedTypeVariables #-} + +module Main where + +import GF.Compile.PMCFGTestHooks + +import Control.Exception (SomeException, evaluate, try) +import Control.Monad (unless) +import Data.List (nub) +import System.Exit (exitFailure) + +data Test = Test String (IO (Either String ())) + +main :: IO () +main = do + let tests = enumerationTests ++ singletonTests ++ finalizerTests + results <- mapM runTest tests + let failures = [(name,msg) | (name,Left msg) <- results] + unless (null failures) $ do + putStrLn "" + putStrLn (show (length failures) ++ " PMCFG differential test(s) failed") + mapM_ printFailure failures + exitFailure + +runTest :: Test -> IO (String, Either String ()) +runTest (Test name action) = do + result <- action + putStrLn (name ++ ": " ++ either (const "FAIL") (const "OK") result) + return (name,result) + +printFailure :: (String, String) -> IO () +printFailure (name,msg) = do + putStrLn ("--- " ++ name) + putStrLn msg + +enumerationTests :: [Test] +enumerationTests = + [ enumCase "no parameters" TestStr + , enumCase "one parameter" (TestPar 1 [0,1,2]) + , enumCase "multiple parameters" (TestRec [TestPar 1 [0,1], TestPar 2 [0,1]]) + , enumCase "record nesting" (TestRec [TestStr, TestRec [TestPar 3 [0,1], TestPar 9 [0,1]]]) + , enumCase "table nesting" (TestTbl [TestPar 1 [0,1], TestRec [TestStr, TestPar 4 [0,1]]]) + , enumCase "restricted singleton" (TestPar 3 [2]) + , enumCase "mixed singleton and multi-choice" (TestRec [TestPar 1 [0], TestPar 10 [0,1,2]]) + , enumCase "duplicate weighted choices" (TestRec [TestPar 2 [0,0,1], TestPar 1 [0,1]]) + , enumCorpusCase "generated small schema corpus" generatedSchemas + ] + +enumCase :: String -> TestSchema -> Test +enumCase name schema = + Test ("getFIds/" ++ name) (return (compareSchema schema)) + +enumCorpusCase :: String -> [TestSchema] -> Test +enumCorpusCase name schemas = + Test ("getFIds/" ++ name) $ + return $ + case [(schema,msg) | schema <- schemas, Left msg <- [compareSchema schema]] of + [] -> Right () + failures -> + Left $ + unlines $ + ("checked: " ++ show (length schemas) ++ " schemas") + : concatMap describeFailure (take 5 failures) + where + describeFailure (schema,msg) = + [ "schema: " ++ show schema + , msg + ] + +compareSchema :: TestSchema -> Either String () +compareSchema schema = + let pre = getFIdsPre schema + optimized = getFIdsOptimized schema + (cached1,cached2) = getFIdsOptimizedCached schema + in if pre == optimized && pre == cached1 && pre == cached2 + then Right () + else Left $ + unlines [ "schema: " ++ show schema + , "pre: " ++ show pre + , "optimized: " ++ show optimized + , "cached #1: " ++ show cached1 + , "cached #2: " ++ show cached2 + ] + +singletonTests :: [Test] +singletonTests = + [ singleCase "no-parameter singleton" TestStr + , singleCase "restricted singleton" (TestRec [TestPar 3 [2], TestStr]) + , singleFailureCase "non-singleton result" (TestPar 1 [0,1]) + , singleFailureCase "nested non-singleton result" (TestRec [TestPar 1 [0], TestPar 4 [0,1]]) + ] + +singleCase :: String -> TestSchema -> Test +singleCase name schema = + Test ("getSingleFId/" ++ name) $ + return $ + let pre = getSingleFIdPre schema + optimized = getSingleFIdOptimized schema + in if pre == optimized + then Right () + else Left $ + unlines [ "schema: " ++ show schema + , "pre: " ++ show pre + , "optimized: " ++ show optimized + ] + +singleFailureCase :: String -> TestSchema -> Test +singleFailureCase name schema = + Test ("getSingleFId/" ++ name) $ do + pre <- throws (getSingleFIdPre schema) + optimized <- throws (getSingleFIdOptimized schema) + return $ + if pre && optimized + then Right () + else Left $ + unlines [ "schema: " ++ show schema + , "pre threw: " ++ show pre + , "optimized threw: " ++ show optimized + ] + +throws :: a -> IO Bool +throws value = do + result <- try (evaluate value) + return $ case result of + Left (_ :: SomeException) -> True + Right _ -> False + +finalizerTests :: [Test] +finalizerTests = + [ pmcfgCase "duplicate rectangles are ignored" + [ TestProduction 0 [1,2] [[10],[20]] + , TestProduction 0 [1,2] [[10],[20]] + ] + , pmcfgCase "complete products are compressed" + [ TestProduction 0 [1] [[1],[10]] + , TestProduction 0 [1] [[1],[20]] + , TestProduction 0 [1] [[2],[10]] + , TestProduction 0 [1] [[2],[20]] + ] + , pmcfgCase "incomplete products remain uncompressed" + [ TestProduction 0 [1] [[1],[10]] + , TestProduction 0 [1] [[1],[20]] + , TestProduction 0 [1] [[2],[10]] + ] + , pmcfgCase "overlapping rectangles preserve area predicate" + [ TestProduction 0 [1] [[1,2],[10]] + , TestProduction 0 [1] [[1],[10,20]] + ] + , pmcfgCase "different arities remain equivalent" + [ TestProduction 0 [1] [[1]] + , TestProduction 0 [1] [[1],[2]] + ] + , pmcfgCase "fun ids are first-encounter based" + [ TestProduction 0 [5] [[1]] + , TestProduction 0 [6] [[2]] + , TestProduction 1 [5] [[3]] + , TestProduction 1 [6] [[4]] + ] + , pmcfgCase "nullary production" + [ TestProduction 0 [10] [] + ] + , pmcfgCase "lindef-shaped production" + [ TestProduction 0 [7,8] [[-4]] + ] + , pmcfgCase "linref-shaped production" + [ TestProduction (-4) [9] [[1,2,3]] + ] + , pmcfgCorpusCase "generated production corpus" generatedProductionCorpora + ] + +pmcfgCase :: String -> [TestProduction] -> Test +pmcfgCase name prods = + Test ("pmcfg/" ++ name) (return (compareProductions prods)) + +pmcfgCorpusCase :: String -> [[TestProduction]] -> Test +pmcfgCorpusCase name corpora = + Test ("pmcfg/" ++ name) $ + return $ + case [(i,prods,msg) | (i,prods) <- zip [(1 :: Int)..] corpora, Left msg <- [compareProductions prods]] of + [] -> Right () + failures -> + Left $ + unlines $ + ("checked: " ++ show (length corpora) ++ " corpora") + : concatMap describeFailure (take 5 failures) + where + describeFailure (i,prods,msg) = + [ "corpus: " ++ show i + , "inputs: " ++ show prods + , msg + ] + +compareProductions :: [TestProduction] -> Either String () +compareProductions prods = + let results = pmcfgResults prods + pre = pmcfgPre results + optimized = pmcfgOptimized results + in if pre == optimized + then Right () + else Left $ + unlines [ "inputs: " ++ show prods + , "pre: " ++ show pre + , "optimized: " ++ show optimized + ] + +generatedSchemas :: [TestSchema] +generatedSchemas = + take 160 $ + filter ((<= 128) . schemaAlternatives) $ + nub $ + concat levels + where + leafs = + [ TestStr + , TestPar 1 [0] + , TestPar 1 [0,1] + , TestPar 2 [0,1] + , TestPar 3 [1,2] + , TestPar 2 [0,0,1] + ] + + levels = take 4 (iterate grow leafs) + + grow schemas = + leafs ++ + [ TestRec [a,b] | a <- schemas, b <- leafs, schemaAlternatives a * schemaAlternatives b <= 128 ] ++ + [ TestTbl [a,b] | a <- schemas, b <- leafs, schemaAlternatives a * schemaAlternatives b <= 128 ] ++ + [ TestRec [a, TestTbl [b,c]] + | a <- take 8 schemas + , b <- take 4 leafs + , c <- take 4 leafs + , schemaAlternatives a * schemaAlternatives b * schemaAlternatives c <= 128 + ] + +schemaAlternatives :: TestSchema -> Int +schemaAlternatives TestStr = 1 +schemaAlternatives (TestPar _ choices) = length choices +schemaAlternatives (TestRec schemas) = product (map schemaAlternatives schemas) +schemaAlternatives (TestTbl schemas) = product (map schemaAlternatives schemas) + +generatedProductionCorpora :: [[TestProduction]] +generatedProductionCorpora = + [ take n generatedProductions + | n <- [1..40] + ] ++ + [ [generatedProductions !! i | i <- indexes] + | indexes <- [ [0,1,2,1] + , [3,4,5,6,7] + , [8,9,10,11,12,13] + , [14,15,16,17,18,19,20] + ] + ] + +generatedProductions :: [TestProduction] +generatedProductions = + [ TestProduction fid seqs args + | fid <- [0,1,2,-4] + , seqs <- [[1], [1,2], [2,1], [3,4,5]] + , args <- [ [] + , [[1]] + , [[1,2]] + , [[1],[10]] + , [[1],[10,20]] + , [[1,2],[10]] + , [[1],[10],[20,30]] + , [[-4]] + ] + ] |
